We do have a blog
Running a self-hosted blog is not an easy task, but rewarding at the same time. It can teach many useful skills and techniques. In previous two posts “How to own a blog for FREE” Part 1 and Part 2 we deployed a blog to a cloud virtual machine, and run it in containers with docker-compose.
Here is a reminder of our blog architecture that looks like below.
Time goes by, everything runs smoothly, we have multiple posts, but that strange feeling started creeping in… What if everything goes down? What if we lose database or WordPress container with all files? Well, that is a sign to start thinking about a backup!
Backup
For our setup we have two containers that do have permanent storage. One is obviously MySQL database. The other is WordPress. Why to backup WordPress? Because it stores many things on a file system, among which are source code files, configs, customizations and most importantly media uploads (images that we use in our blog posts). Therefore, we need to backup both containers, so we can restore entire blog at any point of time.
When we setup our blog we made crucial decision that will make our life so much easier. We store all MySQL and WordPress file in docker volumes.
What are Docker volumes?
Docker volumes are abstraction around file system that can be managed with Docker CLI. Among other advantages, volumes can be shared between containers and are easy to backup and restore.
pavel@pavel-UBUNTU:~$ sudo docker volume ls DRIVER VOLUME NAME local wordpressblog_db local wordpressblog_wordpress
Steps to backup
First, we would need to stop all running containers. The reason is simple, MySQL database or WordPress may still write data while we perform backup. That may render our backup corrupted, so it’s safer to stop all containers before doing backup. Of course, this will result in downtime, however backup shouldn’t take more than a minute, so in our case it’s acceptable.
#!/bin/bash set -e DOCKER="sudo docker" DOCKER_COMPOSE="sudo docker-compose" DOCKER_COMPOSE_FILE="/usr/local/etc/myblog/docker-compose.yaml" # Stop containers ${DOCKER_COMPOSE} -f ${DOCKER_COMPOSE_FILE} down
Second step is to backup WordPress and MySQL files. To do that we run third container (in our case from debian:stretch-slim
image) with the following options and commands.
- Mount WordPress and MySQL volumes one at a time.
- Mount local folder, in our case it is
~/backup
. - Archive WordPress and MySQL database folders into
~/backup
folder.
# Create backup folder if not exists mkdir -p ~/backup # WordPress $DOCKER run --rm \ --mount source=myblog_wordpress,target=/var/www/html \ -v ~/backup:/backup \ debian:stretch-slim bash -c "cd /var/www/html && tar cvf /backup/myblog_wordpress.tar ." #MySQL $DOCKER run --rm \ --mount source=myblog_db,target=/var/lib/mysql \ -v ~/backup:/backup \ debian:stretch-slim bash -c "cd /var/lib/mysql && tar cvf /backup/myblog_db.tar ."
Third step, we need to bring docker-compose up.
# Start containers ${DOCKER_COMPOSE} -f ${DOCKER_COMPOSE_FILE} up -d
And we all done. Our blog is available again and we have two backup files.
pavel@pavel-UBUNTU:~$ ls -l ~/backup/ total 310908 -rw-r--r-- 1 pavel pavel 232888320 Apr 26 06:18 myblog_db.tar -rw-r--r-- 1 pavel pavel 85473280 Apr 26 06:18 myblog_wordpress.tar
Restore from a backup
If we have million backups but never tried to restore – we do not have backups!
Restore is similarly simple as backup. So first we need to stop containers. Reason is the same as for making a backup.
Second, we need to run third container, we are using debian:stretch-slim
image again. This time we need to run the following commands.
- Mount MySQL and WordPress volumes one at a time.
- Mount a folder with backups, we have ~/backup.
- Delete all existing files from the WordPress and MySQL folders.
- Extract all files from backup archives into corresponding folders.
# WordPress $DOCKER run --rm \ --mount source=myblog_wordpress,target=/var/www/html \ -v ~/backup:/backup \ debian:stretch-slim bash -c "cd /var/www/html && rm -rf /var/www/html/* && tar -xvf /backup/myblog_wordpress.tar -C /var/www/html" #MySQL $DOCKER run --rm \ --mount source=myblog_db,target=/var/lib/mysql \ -v ~/backup:/backup \ debian:stretch-slim \ bash -c "cd /var/lib/mysql && rm -rf /var/lib/mysql/* && tar -xvf /backup/myblog_db.tar -C /var/lib/mysql"
Third step is to bring docker-compose up. And we should be all set!
Summary
Containerization helps a lot with replicating entire environment, which gives us tremendous advantage.
We can backup blog that runs in the cloud and restore from the backup locally, so we can try updates, new plugins or customizations without impacting our real blog running in the cloud! If we mess up locally, not a big deal, we can easily start over.
If machine gets lost in the cloud, we can bring up all containers on new machine and restore our blog from a backup with minimum disruption.
Backup blog often and try restore locally once in a while to make sure restore process works. Happy blogging!