Backup and Restore Docker-Compose named volumes

April 10, 2020

Thanks to the magic of Docker Compose, you can put this docker-compose.yml file into a folder:

version: "2.1"

services:
  openmrs-referenceapplication-mysql:
    restart: "always"
    image: mysql:5.6
    command: "mysqld --character-set-server=utf8 --collation-server=utf8_general_ci"
    environment:
      MYSQL_DATABASE: ${MYSQL_DB:-openmrs}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-Admin123}
      MYSQL_USER: ${MYSQL_USER:-openmrs}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Admin123}
    healthcheck:
      test: "exit 0"
    volumes:
      # - ./dbdump:/docker-entrypoint-initdb.d #uncomment this if you need to use a backup sql to initialize the databse
      - openmrs-referenceapplication-mysql-data:/var/lib/mysql

  openmrs-referenceapplication:
    restart: "always"
    image: openmrs/openmrs-reference-application-distro:demo
    # image: openmrs/openmrs-reference-application-distro:demo
    depends_on:
      - openmrs-referenceapplication-mysql
    ports:
      - "127.0.0.1:8080:8080" #when using without nginx use 8080:8080 instead
    environment:
      DB_DATABASE: ${MYSQL_DB:-openmrs}
      DB_HOST: openmrs-referenceapplication-mysql
      DB_USERNAME: ${MYSQL_USER:-openmrs}
      DB_PASSWORD: ${MYSQL_PASSWORD:-Admin123}
      DB_CREATE_TABLES: "true"
      DB_AUTO_UPDATE: "true"
      MODULE_WEB_ADMIN: "true"
      _JAVA_OPTIONS: -Xmx1g -Xms1g # change this depending on the server config
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/openmrs/"]
      timeout: 20s
    volumes:
      - openmrs-referenceapplication-data:/usr/local/tomcat/.OpenMRS/
      - /usr/local/tomcat/.OpenMRS/modules/ # do not store modules in data
      - /usr/local/tomcat/.OpenMRS/owa/ # do not store owa in data

volumes:
  openmrs-referenceapplication-mysql-data:
  openmrs-referenceapplication-data:

and you can have a demo OpenMRS running at http://localhost:8080 with a single comand:

$ docker-compose up -d

The first time you bring up OpenMRS, it can take while for the database to be initialized. In my case, it takes at least 4-5 minutes each time it’s started.

To improve startup time from a given state, I created a couple bash scripts, one to backup named values and another to restore them:

backup-volumes.sh

#!/bin/bash

docker-compose pause

dirname=${PWD##*/}
for nv in `docker volume ls -q`
do
  if [[ $nv = ${dirname}* ]]; then
    f=${nv//${dirname}_/}
    echo -n "Backing up $f ..."
    docker run -it --rm \
      -v $nv:/data -v $PWD:/backup alpine \
      tar -cjf /backup/$f.tar.bz2 -C /data ./
    echo "done"
  fi
done

docker-compose unpause

restore-volumes.sh

#!/bin/bash

dirname=${PWD##*/}
for f in `ls *.tar.bz2`
do
  nv="${dirname}_${f%.tar.bz2}"
  echo -n "Restoring $nv ..."
  docker run -it --rm \
    -v $nv:/data -v $PWD:/backup alpine \
    sh -c "rm -rf /data/* /data/..?* /data/.[!.]* ; tar -C /data/ -xjf /backup/$f"
  echo "done"
done

Using the backup script to take a “snapshot” of OpenMRS, I’m able to restore that state with the restore script and start OpenMRS in about have the time (~2 minutes).

Usage

Notes

Mount Rushmore

October 16, 2017

Just got back from a wonderful trip to South Dakota with Lorrie. I wanted to see Mount Rushmore before it became this:

Recipe to see changes in repo in real time

February 27, 2016

Today, I was playing with Markdown in a README.md file for a repository and thought it’d be helpful if I could see my changes in real time (this was a junk repo I was going to delete, so I wasn’t worried about a bunch of commits). Just thought I’d blog this for my own future reference.

Create a script to commit changes and reload Safari…

update.sh

#!/bin/bash

# Commit changes
git add README.md
git commit -m "formatting"
git push

# Reload Safari
osascript -e 'tell first window of application "Safari" to do JavaScript "window.location.reload(true)" in current tab'

Install fswatch (Mac’s version of inotifywait), a tool to monitor for changes to a file or folder.

brew install fswatch

With the following command, any change to our file will get committed and the page in Safari will be reloaded.

fswatch -o README.md | xargs -n1 ./update.sh

We both look at it. I see a circle. You see a triangle.

January 27, 2016

I have always loved Chuck Swindoll‘s famous quote:

“Life is 10% what happens to you and 90% of how you react to it.”

It underscores how so much in life depends on perspective. When I started working in clinic, I was stressed by crunch of chart reviews, seeing patients, answering pages, and writing notes while constantly feeling rushed and falling behind. I would leave clinic exhausted with a hard knot between by shoulders. Then one clinic day, I decided to try an experiment. I would work as effectively as I could, but I would consciously avoid worrying about the chaos around me. Whether or not the charts stacked up, I was going to see people as efficiently and effectively as I could, so worrying about the stack of charts wasn’t going to help. Surprisingly, I accomplished the same amount of work that day (in fact, nothing changed about my clinic whatsoever), but I left clinic completely relaxed. I realized simply changing my point of view could massively reduce my level of stress (and increase happiness).

Speaking of perspective…

Today, I listened to a Work In Progress talk from Dr. Rich Frankel at Regenstrief and he mentioned Judy Brown’s “Cone in the box.”  What a wonderful lesson in perspective: two people looking at the same object and one sees a circle while the other sees a triangle. Who’s right? Are they both right? Are they both wrong? Not surprisingly, it depends on your perspective.

cone-perspective

The next time you find yourself arguing with someone about whether it’s a circle or a triangle, take a moment to realize you might both be right (or wrong, depending on your perspective).

“We don’t see things as they are, we see them as we are.” –Anaïs Nin

For another example of how your perspective can change what you see, wait for a large moon on the horizon and try the One-Eyed Pinky Trick. 🙂

Open Source ftw!

December 16, 2015

I got an email this morning from Luis in Düsseldorf about a suggestion to improve OpenMRS. I help Luis with his ticket and bring it to the attention of the OpenMRS Google Code-In team. Teenagers from Cameroon, Uruguay, and New Jersey discuss the ticket with a mentor in Indianapolis. No doubt, one of these bright young students will submit a pull request soon.

It’s a small, wonderful world full of awesome people!

Another typical day in the OpenMRS community… 🙂

jenv ftw!

At the recent OpenMRS Worldwide Summit #OMRS15, I was helping out with the Saptarshi’s introductory tutorial and realized that the OpenMRS Standalone requires Java 7, meaning that it fails to run on Java 8. Yikes! But my Mac runs Java 8. How do I get Java 7 on my laptop without making a mess of things?

jenv to the rescue! jenv provides an easy way to manage multiple Java versions. Not only can you easily switch between Java versions, but you can configure different folders to run specific versions of Java. So, for example, you can run Java 7 for the OpenMRS Standalone and run Java 8 everywhere else.

Step zero. Install Homebrew. I already had this installed. I used to use Macports to install utilities on my Mac, but it was fairly invasive. Homebrew installs most everything under your user account, so it doesn’t mess with Mac’s view of the world and rarely, if ever, requires the use of sudo.

Step one. Install jenv.

brew install jenv

Step two. Install Java 7.

Grab the latest version of Java 7 SDK from Oracle’s Java 7 archive. For me, this meant navigating to the  Java SE Development Kit 7u80 downloads, accepting the license agreement, and then downloading and installing from the dmg package for Mac OS X x64.

Step three. Tell jenv about Java 7.

jenv add /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/

If your version number differs, then your command may differ slightly. You can always navigate into /Library/Java/JavaVirtualMachines/ to find your installed version folders.

Done!

Now you can navigate into your OpenMRS Standalone folder, set the preferred Java version with a command like:

jenv local oracle64-1.7.0.80

and then execute the standalone with:

jenv exec java -jar openmrs-standalone.jar

Tab Stack for Safari

December 1, 2015

I recently decided to try switching from Chrome to Safari for a while… to see if it might buy me a little more battery life on my aging MacBook Pro. One of the immediate drawbacks I discovered was realizing how accustomed I had become to the Tab Stack extension for Chrome. It’s a simple workaround for MRU (most recently used) tab ordering that moves the active tab to the left after a brief delay (the delays lets you scan through tabs without re-ordering them). It’s a bit hacky and I’m sure a lot of people wouldn’t care for the approach, but I’m used to it and immediately noticed its absence in Safari.

I googled around and didn’t find an equivalent extension for Safari… so I made one and submitted it to Apple’s gallery. I’ve added an extra hack to mitigate Safari’s insistence on clearing the address bar when tabs are moved (move new tabs immediately) as a version 1.1.

Logout of Citrix XenApp with Shortcut Key

logoff propertiesI use Citrix XenApp to connect to a virtual desktop for hospital apps and, being a keyboard junkie, I prefer to have a hotkey to logout from the Citrix session on my Mac. I keep having to reinvent this, so I’m “microblogging” it for future me.

Right-click on the desktop and create a shortcut

From then on (until the desktop gets reset), pressing ⌘⌥L will logout of Citrix XenApp.

A Phone-centric World

July 13, 2015

No Laptops

Can you picture a world without tablets, desktops and laptops? It’s only a matter of time.

SanDisk has introduced a 200 GB microSD card. That’s 200 GB in a mere 15x11mm package. With processors like Qualcomm’s Snapdragon 810 and beyond, it’s not hard to imagine reaching a point where your phone can provide all the computing power you need. The phone has several advantages:

Tablets, laptops and desktops (as we know them today) disappear altogether, once your phone, backed by the unlimited resources of the cloud, can provide all the computing power you need. All that is missing are the interfaces to that computing power. Tablets need only provide the convenience of a touch screen interface. Laptops and desktops can be replace with commodity keyboards and monitors, drawing all the computing experience from your phone. I just hope I can get some sleep when the two-finger typist behind me on the plane is using their tray table as a keyboard.

Making an octagonal picnic table

My wife and I take a week vacation around July 4th each year to relax at our cottage in Michigan. Last year, I dipped my toes back into carpentry with mentorship from a kind neighbor and replaced our wood platform. This year I decided it was time to replace our old picnic table. I wanted an octagonal picnic table and settled on plans from Woodcraft Magazine Issue 58: April/May 2014 by Bill Sands (downloaded from Sawtooth Ideas). The deciding factor was Laney Shaughnessy‘s four part Build an Octagon Picnic Table YouTube series detailing each step of the plans. Menards had the cedar wood (16 8-foot 2x6s, 8 8-foot 2x4s, and one 8-foot 2×2), sawhorses, exterior screws, back saw, chisel, pocket hole jig, hand router + 1/4-inch roundover bit, sander, and wood glue. My neighbor had a mitre saw and a cozy garage that helped when it was raining. It took most of the week and I must’ve watched Laney’s videos a few dozen times in the process for guidance and encouragement, but – thanks to Bill Sands’ great plans and Laney Shaughnessy’s awesome videos – I was able to make a nice new cedar octagonal picnic table from scratch:

Octagonal Picnic Table