In this tutorial, I am going to show you how to backup Docker containers for services WordPress and MySQL in a docker-compose.yml file. If you read enough backup articles like me, you will find that some articles relate to just backing up a container as an image without the data volumes and others on both docker image plus volumes. Since we are dealing with WordPress here, it is necessary to backup the data volumes.
Backup WordPress Files and Database
This is how a typical docker-compose.yml for WordPress looks like.
version: '3.7' services: db: image: mysql:8.0.19 container_name: db ... volumes: - dbdata:/var/lib/mysql ... wordpress: depends_on: - db image: wordpress:5.4.0-php7.4-fpm-alpine container_name: wordpress ... volumes: - ./wordpress:/var/www/html ...
Backup Container as Image (optional)
As you can see, we execute docker commit -p wordpress wp-backup to backup the WordPress container (container name: wordpress) as an image (backup name: wp-backup). When we execute docker images again, we can see that there is an additional image which is our backup image wp-backup. This backup has a file size of 201MB similar to the current WordPress image which was pulled from Docker Hub two weeks ago. Thus, this shows that files (e.g. themes and plugins) in the WordPress directory are not included in the backup image and you are just making an exact copy of what is already available on Docker Hub.
user@server:~/wordpress-docker$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE wordpress 5.4.0-php7.4-fpm-alpine 78ac3963ff95 2 weeks ago 201MB mysql 8.0.19 9228ee8bac7a 2 weeks ago 547MB nginx 1.17.9-alpine 377c0837328f 6 weeks ago 19.7MB user@server:~/wordpress-docker$ docker commit -p wordpress wp-backup sha256:10f73e5ecac57f7e3800020d9a30f66acc74c59797ed7440cc90537c2a658d2a user@server:~/wordpress-docker$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE wp-backup latest 10f73e5ecac5 11 seconds ago 201MB wordpress 5.4.0-php7.4-fpm-alpine 78ac3963ff95 2 weeks ago 201MB mysql 8.0.19 9228ee8bac7a 2 weeks ago 547MB nginx 1.17.9-alpine 377c0837328f 6 weeks ago 19.7MB
Step 1 – Backup WordPress Database with mysqldump
We will use mysqldump to dump out the WordPress database instead of doing a full backup of dbdata:/var/lib/mysql which is the entire MySQL filesystem and a total directory size of 237MB.
user@server:~/wordpress-docker$ docker exec -i db ls -l /var/lib/mysql total 217620 drwxr-x--- 2 mysql mysql 4096 Apr 10 19:00 #innodb_temp -rw-r----- 1 mysql mysql 56 Apr 10 07:30 auto.cnf -rw-r----- 1 mysql mysql 3102175 Apr 10 07:30 binlog.000001 -rw-r----- 1 mysql mysql 2313794 Apr 10 17:42 binlog.000002 -rw-r----- 1 mysql mysql 4382 Apr 10 19:00 ib_buffer_pool -rw-r----- 1 mysql mysql 50331648 Apr 16 04:03 ib_logfile0 -rw-r----- 1 mysql mysql 50331648 Apr 16 04:03 ib_logfile1 -rw-r----- 1 mysql mysql 12582912 Apr 16 04:03 ibdata1 -rw-r----- 1 mysql mysql 12582912 Apr 10 19:00 ibtmp1 drwxr-x--- 2 mysql mysql 4096 Apr 10 07:30 mysql -rw-r----- 1 mysql mysql 30408704 Apr 16 04:03 mysql.ibd -rw-r----- 1 mysql mysql 12582912 Apr 16 04:03 undo_001 -rw-r----- 1 mysql mysql 12582912 Apr 16 04:03 undo_002 drwxr-x--- 2 mysql mysql 4096 Apr 10 07:45 wordpress ... user@server:~/wordpress-docker$ docker exec -i db du -sh /var/lib/mysql 237M /var/lib/mysql
We can achieve this by docker exec and replacing db with your database container name. For example, my wordpress-backup.sql from a two weeks old WordPress with a couple of posts and plugins etc. is only 3MB. Note that single quotes are required to escape the password with special characters.
docker exec db mysqldump -uwp_databaseuser -p'wp_databasepassword' wordpress > wordpress-database-backup.sql
Step 2 – Backup WordPress wp-config.php, Themes and Plugins Directory etc.
wp-config.php is stored in docker-project/wordpress folder and downloaded themes and plugins are stored in docker-project/wordpress/wp-content folder. Irregardless, we will backup the entire WordPress directory.
2a. The Docker Way
Here we run a temporary (–rm) WordPress container with pulled image wordpress:5.4.0-php7.4-fpm-alpine and mount the volume from –volumes-from wordpress (existing container name) into this temporary container. This will create the directory /var/www/html where WordPress files and directories reside in, inside the container. Then we use the -v flag to mount our current server directory $(pwd) as /backup (in the temporary container). Lastly, we execute the tar compress command in the container and the final backup file wordpress-files-backup.tar.gz will be stored in our actual server directory ($pwd).
docker run --rm --volumes-from wordpress -v $(pwd):/backup wordpress:5.4.0-php7.4-fpm-alpine tar zcvf /backup/wordpress-files-backup.tar.gz /var/www/html
2b. Using tar command
I was left wondering why can’t I just tar up the whole WordPress directory in docker-project/wordpress? So, I decided to try this simply by using tar.
tar zcvf wordpress-files-backup.tar.gz docker-project/wordpress
Are both backups from 2a and 2b the same?
I copied both tar.gz files created by docker and tar command respectively from remote webserver to my local desktop. Then untar them to their folder and ran WinMerge to compare both directories. The result was both tar.gz files are identical!
It is pretty straightforward that we dump the WordPress database regularly for our backup strategy, more often than we need to backup the WordPress directory unless one adds new themes and plugins frequently. That being said, I will go opt for the tar method which I am more familiar with to backup the WordPress directory. There is a one liner tar zcvf – docker-project/wordpress | ssh user@server “cat > /path/to/backup/wordpress-files-backup.tar.gz” which you can add to cron to transfer wordpress-files-backup.tar.gz to another backup server easily.