In our previous tutorial we demonstrated how to deploy simple application packaged as Docker container to production environment using Kontena. If you are doing some serious business and need to serve visitors at massive scale, you'll need to avoid single-point-of-failure and create scalable high availability solution. With Kontena, it is easy. Before diving in to our solution, let's talk a bit about Kontena and what is happening under the hood.
Kontena includes advanced scheduler that will automatically orchestrate Docker containers into different host nodes. There is also built-in network overlay powered by Weave. This technology is used to create a virtual LAN between application services. The network overlay enables connections between containers no matter on what host nodes they are deployed.
Kontena is also gathering logs and stats from all running containers and aggregates them to service level log and stats streams. This allows easy viewing of logs and statistics for your application CPU, memory, disk and network usage.
To demonstrate Kontena in action, in this tutorial we will build high availability WordPress site using Docker that is scaled up to three instances and backed up by database cluster. To avoid single point of failure, all WordPress instances and database cluster nodes are running on a different hosts.
High Availability WordPress with Docker
In this tutorial we will be building a WordPress setup that is running on three hosts. All the requests are handled by a set of load balancers (HA Proxy). The load balancers will then forward the traffic to WordPress instances. We will also use MySQL database cluster to serve the WordPress site. This database cluster is also behind a set of load balancers.
All the WordPress media files like photos are by default uploaded and stored on local file system of single machine. Naturally, this is not going to work for us since we have three instances of WordPress running. One solution is to turn-off the local storage and upload media files to CDN. While this is a great solution, it's adding requirement to have CDN service available. Therefore, we are using another solution: synchronizing filesystem with BitTorrent Sync (btsync).
BitTorrent Sync service is used to synchronize uploaded files between WordPress containers. When a new file is uploaded into some WordPress instance, BitTorrent Sync will transfer it automatically to all WordPress instances and it's visible to all users instantly no matter what WordPress instance is serving the file.
Let's get started! First, we'll need to define our application.
Prerequisites: You'll need to have Kontena CLI installed and access to Kontena infrastructure. See Kontena quick start guide.
The difference is that docker-compose.yml defines your application in container level so you will have one container for each defined service.
In kontena.yml application is defined in service level and you can define how many containers you want to deploy for each service. Additionally there can be also defined where and how containers will be deployed.
At first, a stateful seed database service is defined for our MySQL cluster:
galera-seed: image: jakolehm/galera-mariadb-10.0-xtrabackup:latest stateful: true command: seed env_file: galera-seed.env
Environment variables are stored in galera-seed.env env_file in the same directory:
Then a MySQL cluster will be defined. We want to have three stateful instances of MySQL databases in our cluster.
galera: image: jakolehm/galera-mariadb-10.0-xtrabackup:latest stateful: true instances: 3 command: "node wordpress-cluster-galera-seed-1.kontena.local,wordpress-cluster-galera.kontena.local" env_file: galera.env
In galera.env file is defined the same XTRABACKUP_PASSWORD variable than in seed database.
Now we have described a MySQL cluster, but some load balancer is needed on the front of it. To do this HAProxy service is defined. It will be scaled up to three instances and our galera service will be linked to it:
galera-ha: image: kontena/haproxy:latest instances: 3 links: - galera:wordpress-cluster-galera environment: - BACKEND_PORT=3306 - FRONTEND_PORT=3306 - MODE=tcp
MySQL cluster and it will start listen to port
Now we can define a WordPress service that will use MySQL cluster as a database. We want it to be stateful service, so uploaded files don’t get lost every time the service is re-deployed. Also it is scaled up to three instances, one for each host node:
wordpress: image: wordpress:4.1 stateful: true instances: 3 env_file: wordpress.env
WordPress config parameters are stored in a separate
WORDPRESS_DB_HOST=wordpress-cluster-galera-ha.kontena.local WORDPRESS_DB_PASSWORD=secret WORDPRESS_AUTH_KEY=secret WORDPRESS_SECURE_AUTH_KEY=secret WORDPRESS_LOGGED_IN_KEY=secret WORDPRESS_NONCE_KEY=secret WORDPRESS_AUTH_SALT=secret WORDPRESS_SECURE_AUTH_SALT=secret WORDPRESS_LOGGED_IN_SALT=secret WORDPRESS_NONCE_SALT=secret
Next, we'll define BitTorrent Sync service. But first, we'll need to create a secret key that is shared between out btsync clients. You can create the secret key from your command line like this:
$ docker run -i --rm --entrypoint=/usr/bin/btsync jakolehm/btsync:latest --generate-secret
This will generate you with the secret key you can use with your btsync setup. Now, let's define the btsync service:
wordpress-btsync: image: jakolehm/btsync:latest volumes_from: - "wordpress-cluster-wordpress-%%s" environment: - SYNC_DIR=/var/www/html/wp-content instances: 3 command: "YOUR_SECRET_KEY_HERE"
What is defined here is that we want three instances of btsync service so that each container instance will follow one of the WordPress containers. This is done by setting
volumes_from option to
So far we have defined WordPress service, but in order to route traffic correctly, some load balancing is still needed. Let’s add another haproxy service here and scale it up to three instances and link our WordPress service to it. Also port
80 is exposed so our haproxy service will listen standard
http port on a host node:
wordpress-ha: image: kontena/haproxy:latest instances: 3 ports: - 80:80 links: - wordpress:wordpress-cluster-wordpress environment: - BALANCE=source
This completes our high availablity WordPress site setup. See the final kontena.yml file.
You can deploy your whole application with just single command:
$ kontena deploy
After the application is deployed we can reach it with a web browser:
You might want to configure a domain name and point it to all host nodes.
Checking Stats and Logs
When application is deployed, stats and logs can be seen by following commands:
$ kontena service stats wordpress-cluster-wordpress $ kontena service logs wordpress-cluster-wordpress
Get this example project from Github.