Deploy your Stateful Web Applications in Docker Swarm using Traefik Sticky Sessions
The shift away from monolithic legacy applications to microservices has been long coming. The benefits of deploying your application as a microservice far outweigh any additional complexity or costs. High availability, redundancy, robustness, cost, and ease of development are only a few of the advantages.
Docker has significantly sped up this process. With Docker, you can package your applications in lightweight containers and run them on any system with a Docker Engine. When Docker Swarm was released, they brought native orchestration to our production clusters. Stateless applications fit perfectly into this deployment model; however, what about stateful services?
Configuring your stateful application to work with load balancers in high availability mode used to require a significant amount of effort. You needed to point your load balancers at a set of reverse proxies. These proxies needed to cache cookies or other metadata to determine how to route traffic from the web connections to containers providing your services. All of this was fairly complicated and costly, until Traefik and Docker Swarm came along.
Traefik is a modern reverse proxy / load balancer that is designed for use with microservices. It supports a large number of technologies. In this post, we'll go over how to use Traefik with Docker Swarm to serve a WordPress blog in high availability mode with sticky sessions. Sticky sessions basically means the reverse proxy will remember which connections are associated with each server / container, and continue to route those HTTP messages.This is extremely useful for applications that require you to sign in.
WordPress is one of the most popular content management systems in use today. By default, it contains stateful components such as session management. Let's explore how to setup WordPress in High Availability mode on Docker Swarm using sticky session in Traefik so that these stateful components work out of the box.
Deploying WordPress with Docker Swarm
The first thing we'll do is deploy WordPress using Docker Swarm in high availability mode. To start, go to play-with-docker. This is a fantastic website to play around with Docker. After you verify that you're a human, you will have access to a server instance with Docker installed. Once the GUI loads, click the wrench icon to the right of “Instances” on the left side of the screen.
Then click 3 Managers and 2 Workers.
Play-with-docker is provisioning a Docker Swarm with 5 machines. 3 of the machines are managers, and 2 are workers. We will deploy WordPress using this Docker Swarm.
Go to one of your managers (blue person icon)
Now, execute the following:
docker network create -d overlay net. Next, using your text editor of choice, create a file called
wordpress.yml and paste in the following content. Remember, if you are using vim, execute
:set paste and then make sure to enter interactive mode, otherwise “versi” will be cut off in the pasted file.
version: '3' services: db: image: mysql:5.7 deploy: replicas: 1 restart_policy: condition: on-failure max_attempts: 3 volumes: - db_data:/var/lib/mysql networks: - net environment: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest deploy: replicas: 3 restart_policy: condition: on-failure max_attempts: 3 volumes: - wordpress_data:/var/www/html networks: - net ports: - "8001:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_PASSWORD: wordpress volumes: db_data: wordpress_data: networks: net: external: true
What you just pasted is a Docker Compose file. This file specifies the configuration for a set of containers that you will deploy as a microservice. The main thing to look at is the “replicas” section under “wordpress.” In this configuration file, we define that the WordPress frontend will have a total of 3 replicas — that is 3 different containers will serve the PHP code that powers WordPress.
docker stack deploy --compose-file=wordpress.yml wordpress. This is how we deploy our application to the Docker Swarm we just created.
After a minute or so, you will see port 8001 appear at the top of the page. Click on port 8001, and go through the WordPress installation steps (pick a language, blog title, login, etc). When you start clicking around the interface, you will have to keep logging in. This is because your browser is not logged in to the container servicing your request.
Specifically, Docker Swarm is using round robin routing every time you access the blog. Because of this, your browser uses a different container for every request. After you login to the first container, your traffic is routed to the second — which you aren't logged in to. And then the third, which you aren't logged in to. After you've logged into all 3 of them, then everything works fine. Extremely useful for applications where you don't login, but really annoying if you need to.
docker stack rm wordpress. This will bring down WordPress. We'll now deploy WordPress but use Traefik to serve as a reverse proxy, and configure sticky sessions. Create a file called
traefik.yml and paste in the following content:
version: '3.0' services: loadbalancer: image: traefik command: --docker \ --docker.swarmmode \ --docker.watch \ --web \ --loglevel=DEBUG ports: - 80:80 - 9090:8080 volumes: - /var/run/docker.sock:/var/run/docker.sock deploy: restart_policy: condition: any mode: replicated replicas: 1 update_config: delay: 2s placement: constraints: [node.role == manager] networks: - net networks: net: external: true
docker stack deploy --compose-file=traefik.yml traefik. After 2 or 3 minutes, the Traefik reverse proxy will be running. Click on port 9090 to see the current status.
Now that we've deployed Traefik, we will deploy WordPress with a slightly modified configuration. Create another file,
wordpress-sticky.yml and paste in the following contents:
version: "3.1" services: db: image: mysql:5.7 deploy: replicas: 1 restart_policy: condition: on-failure max_attempts: 3 volumes: - db_data:/var/lib/mysql networks: - net environment: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest deploy: mode: replicated replicas: 3 restart_policy: condition: on-failure max_attempts: 3 placement: constraints: [node.role == worker] update_config: delay: 2s labels: - "traefik.docker.network=net" - "traefik.port=80" - "traefik.frontend.rule=PathPrefix:/" - "traefik.backend.loadbalancer.sticky=true" volumes: - wordpress_data:/var/www/html networks: - net ports: - "80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_PASSWORD: wordpress networks: net: external: true volumes: db_data: wordpress_data:
There are a few key differences between this version of the WordPress Docker Compose file, and the previous ones. The main differences are that this one defines labels in the deploy step, and forces the WordPress containers to run on worker nodes.
docker stack deploy --compose-file=wordpress-sticky.yml wordpress-sticky. After a minute or so, click on port 80.
Now you can login and use WordPress as normal. At this point, we have deployed WordPress in high availability mode with sticky sessions enabled. This allows you to deliver a stateful web application to your users, using a high availability microservice setup. This enables you to deploy your applications that require logins as Docker containers in a high availability setup using Docker Swarm.