A robust and highly-scalable implementation of WordPress in Docker using the Autopilot Pattern
This project uses the Autopilot Pattern to automate operations, including discovery and configuration, for easy scaling to any size. All component containers use ContainerPilot and Consul to configure themselves. This also allows each service to be scaled independently to handle incoming traffic and as more services are added, the containers that consume these services will reconfigure themselves accordingly.
A running cluster includes the following components:
- ContainerPilot: included in our MySQL containers to orchestrate bootstrap behavior and coordinate replication using keys and checks stored in Consul in the
preStart
,health
, andonChange
handlers. - MySQL: we're using the Autopilot Pattern implementation of MySQL for automatic backups and self-clustering so that we can deploy and scale easily
- HyperDB: an "advanced database class that replaces a few of the WordPress built-in database functions" to support the MySQL cluster that's necessary for scaling WordPress; everything is automatically configured so running a scalable WordPress site is no more complex than running without the scaling features
- Memcached: improves performance by keeping frequently accessed data in memory so WordPress doesn't have to query the database for every request; the images include tollmanz's Memcached plugin pre-installed, and ContainerPilot automatically configures it as we scale
- Nginx: the front-end load balancer for the WordPress environment; passes traffic from users to the WordPress containers on the back-end
- NFS: stores user uploaded files so these files can be shared between many WordPress containers
- Consul: used to coordinate replication and failover
- Manta: the Joyent object store, for securely and durably storing our MySQL snapshots
- Prometheus: an optional, open source monitoring tool that tracks the performance of each component and demonstrates ContainerPilot telemetry
- WP-CLI: to make managing WordPress easier
Pick the answer that fits:
- For the hello world experience: follow the directions below for configuration, then
docker-compose up -d
and you're done. - For building your own WordPress in Docker: clone this repository and place the WordPress theme you want to use into the
var/www/html/content/themes
directory. Develop locally using thelocal-compose.yml
file, then build your Docker image and run those in the cloud with your owndocker-compose.yml
file that specifies your custom image.
The instructions below will get you set up to run containers on Triton, or anywhere that supports the Autopilot Pattern.
- Get a Joyent account and add your SSH key.
- Install the Docker Toolbox (including
docker
anddocker-compose
) on your laptop or other environment, as well as the Joyent Triton CLI - Configure Docker and Docker Compose for use with Joyent:
curl -O https://raw.githubusercontent.com/joyent/sdc-docker/master/tools/sdc-docker-setup.sh && chmod +x sdc-docker-setup.sh
./sdc-docker-setup.sh -k us-east-1.api.joyent.com <ACCOUNT> ~/.ssh/<PRIVATE_KEY_FILE>
Check that everything is configured correctly by running ./setup.sh
. You'll need an SSH key that has access to Manta, the object store where the MySQL backups are stored. Pass the path of that SSH key as ./setup.sh ~/path/to/MANTA_SSH_KEY
. The script will create an _env
file that names the variables that you will need to run your WordPress environment.
The script will set defaults for almost every config variable, but the Manta config is required and must be set manually. The two most important variables there are:
MANTA_BUCKET=/<username>/stor/<bucketname> # an existing Manta bucket
MANTA_USER=<username> # a user with access to that bucket
The MySQL container will take a backup during its preStart
handler and periodically while running. Configure these Manta settings to specify how and where this backup is stored. Here you need to specify the MANTA_USER
, and also the MANTA_BUCKET
where the backups will be stored.
The setup script will set working defaults for the entire WordPress configuration. The defaults will work for a quick "hello world" experience, but you'll probably want to set your own values for many fields.
# Environment variables for for WordPress site
WORDPRESS_URL=http://my-site.example.org/
WORDPRESS_SITE_TITLE=My Blog
WORDPRESS_ADMIN_EMAIL=user@example.net
WORDPRESS_ADMIN_USER=admin
WORDPRESS_ADMIN_PASSWORD=<random string>
WORDPRESS_ACTIVE_THEME=twentysixteen
WORDPRESS_CACHE_KEY_SALT=<random string>
#WORDPRESS_TEST_DATA=true # uncomment to import a collection of test content on start
This block is the typical information you must provide when installing WordPress. The URL of the site, the site title and admin user information are all straightforward. WORDPRESS_ACTIVE_THEME
is the theme that will be activated automatically when the container starts. This will typically be theme that you are developing in this repo, or one of the default themes. WORDPRESS_CACHE_KEY_SALT
should be set to a unique string, the object caching in WordPress will use this salt to determine the cache keys for information it sets on the Memcached container.
If you are not bringing your own theme in this repo, you can choose from these default themes for the WORDPRESS_ACTIVE_THEME
variable:
twentyfifteen
twentyfourteen
twentysixteen
The script will set a WORDPRESS_URL
value for Triton users using Container Name Service that will make it easy to test the containers without setting any DNS information. You can CNAME
your site DNS to that to make it easy to scale and replace the Nginx containers at the front of your site without ever needing to update the DNS configuration.
Setting WORDPRESS_TEST_DATA
will download the manovotny/wptest content library when the WordPress container starts.
The setup script will set default values for the MySQL configuration, including randomly generated passwords.
# Environment variables for MySQL service
# WordPress database/WPDB information
MYSQL_USER=wpdbuser
MYSQL_PASSWORD=<random string>
MYSQL_DATABASE=wp
# MySQL replication user, should be different from above
MYSQL_REPL_USER=repluser
MYSQL_REPL_PASSWORD=<random string>
These values will be automatically set in the wp-config.php
. The last two options are used by the Autopilot Pattern MySQL container to set up its replication when scaled up to more than a single container. You can keep repluser
, but set a unique password for your environment.
As with most of the other configuration blocks, the setup script will set reasonable defaults for these values.
# Wordpress security salts
# These must be unique for your install to ensure the security of the site
WORDPRESS_AUTH_KEY=<random string>
WORDPRESS_SECURE_AUTH_KEY=<random string>
WORDPRESS_LOGGED_IN_KEY=<random string>
WORDPRESS_NONCE_KEY=<random string>
WORDPRESS_AUTH_SALT=<random string>
WORDPRESS_SECURE_AUTH_SALT=<random string>
WORDPRESS_LOGGED_IN_SALT=<random string>
WORDPRESS_NONCE_SALT=<random string>
These variables are how WordPress secures your logins and other secret info. These should be unique for your site. You can set your own values, or use this WordPress tool to generate a new set of random values.
Finally we need to configure an environment variable with the location of our Consul service. The setup script will pre-set this for Triton users.
CONSUL=<IP or DNS to Consul>
For local development, we use Docker links and simply set this to CONSUL=consul
, but on Triton we use Container Name Service so that we can have a raft of Consul instances operating as a highly available service (see example).
This project also builds it's own Nginx container that is based on the AutoPilot Pattern Nginx. We build a custom Nginx container to more easily inject our custom configurations. The configs located in the /nginx
directory should work well for most use cases of this project, but they can be customized and baked into the Nginx image if the need arises.
After configuring everything, we are now ready to start the containers. To do that simply execute docker-compose up -d
to spin everything up on Triton. Open your browser to the WORDPRESS_URL
and enjoy your new site!
For local development, use docker-compose -f local-compose.yml up -d
.
To scale, use docker-compose scale...
. For example, the following will set the scale of the WordPress, Memcached, Nginx, and MySQL services to three instances each:
docker-compose scale wordpress=3 memcached=3 nginx=3 mysql=3
If there are few instances running for any of those services, more will be added to meet the specified count. As you scale, the application will automatically reconfigure itself so that everything is connected. All the Nginx instances will connect to all the WordPress instances, and those will connect to all the Memcached and MySQL instances. If an instance should unexpectedly crash, the other instances will automatically reconfigure to re-route requests around the failed instance.
To scale back down, simply run docker-compose scale...
and specify a smaller number of instances.
This project has been fully tested and documented to run in Docker in local development environments and on Joyent Triton, however it has been demonstrated on, or is believe compatible with container environments including:
- Mantl
- DC/OS
- Docker Swarm
- Kubernetes
- Others
- Please report bugs in Github (and check the bug list for known bugs)
- It's open source, pull requests welcome!
Initial development of this project was sponsored by Joyent and 10up.