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