Site, resurrected

Lately I’ve been busy resurrecting this site, using Docker containers to automate the creation of the runtime environment. In case you haven’t heard of Docker containers, here’s what the official Docker site has to say about them:

Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code, runtime, system tools, system libraries – anything that can be installed on a server. This guarantees that the software will always run the same, regardless of its environment.

While a technology like Docker is probably more likely to be used for enterprise applications, the need for software to “always run the same” is just as applicable to personal sites like this. In this post I’ll try to show you how I’ve leveraged Docker to bring some consistency to my site’s development and production environments.

Software requirements

A WordPress site such as this needs a few different pieces of software in order to run:

  • WordPress
  • Apache HTTPD (for serving WordPress files)
  • MySQL (for storing WordPress data)

Without something like Docker I would have to install and configure this software manually both on my local machine (for development) and on my remote machine (for production). With Docker, however, I can simply create some YAML-based config files and have the Docker Compose component do the work for me. Following’s how I did this.

Docker Compose config

To define the software requirements, or “services” in Dockerspeak, I created three config files: one config file per environment (development and production) and one config file for the attributes of the services that are common to these environments.

common-services.yml
Contains service definitions for development and production.
docker-compose.yml
Contains service definitions for development only. Extends services defined in common-services.yml via the extends config option.
docker-compose.production.yml
Contains service definitions for production only. Extends services defined in common-services.yml via the extends config option.

MySQL service definition

The MySQL service definition is identical in both development and production. As such it can be defined in common-services.yml and brought into a specific environment by extension.

Here’s the definition (from common-services.yml):

services:

...

  wordpressdb:

    image: mysql:5.7

    container_name: wordpressdb

    env_file: ./wordpressdb/env/wordpress.common.env

    volumes:

      - ./wordpressdb/cnf:/etc/mysql/conf.d/

      - ../data:/var/lib/mysql

...

volumes:

  data:

… and here’s the extension (from docker-compose.yml and docker-compose.production.yml):

  wordpressdb:

    extends:

      file: common-services.yml

      service: wordpressdb



MySQL service config options

image
Defines the MySQL image upon which to base the container.
container_name
Defines the name to use for the container. Not strictly necessary but without it Docker will create a name by itself.
env_file
Points to a plain-text file that defines environment variables that will be accessible within the container, e.g., the username and password for the database.
volumes
Defines directory mappings between host and container. One such mapping is a data volume that will be used to persist data to the host. (See top-level volumes config option in common-services.yml.)

WordPress service definition

The WordPress service definition has some differences between development and production. As such it can be defined in part in common-services.yml and extended in a specific environment.

Here’s the definiton (from common-services.yml):

  wordpress:

    image: wordpress:4.7-apache

    container_name: wordpress

    ports:

      - 80:80

… and here’s the extension (from docker-compose.yml and docker-compose.production.yml):

  wordpress:

    extends:

      file: common-services.yml

      service: wordpress

    volumes:

      - ../html:/var/www/html

      - ./wordpress/conf:/etc/apache2/sites-available

    links:

      - wordpressdb:mysql

    env_file:

      - ./wordpress/env/wordpress.common.env

      - ./wordpress/env/wordpress.${environment}.env

WordPress service config options

image
Defines the WordPress image upon which to base the container. This particular version of WordPress includes Apache HTTPD, so I don’t have to worry about creating a separate service just for this.
container_name
Defines the name to use for the container.
ports
Defines port mappings between host and container. In this case port 80 on the host is being mapped to the same port on the container. This allows me to run the site on the default HTTP port in both development and production.
volumes
Defines directory mappings between host and container. In this case the config tells the container where on the host it can expect to find the WordPress files and the Apache vhost config file.
links
Allows the WordPress container to access the MySQL container.
env_file
Points to a plain-text file that defines environment variables that will be accessible within the container. In this case there are two such files: one for environment variables that are common to environments and one for environment variables that are specific to an environment, e.g., WP_SITEURL, WP_HOME.

Building the services

With this configuration in place it becomes trivial to build the services for development and production.

To build for development I can simply update my repo on my local machine and enter the following command: docker-compose up --build -d. This command will combine the config from common-services.yml and docker-compose.yml and use the result.

To build for production I can simply update my repo on my remote machine and enter the following command: docker-compose -f docker-compose.production.yml --build -d. This command will combine the config from common-services.yml and docker-compose.production.yml and use the result.

Leave a Reply

Your email address will not be published. Required fields are marked *