Rolling update with docker-compose

Share on:

This article covers simple steps to perform rolling update with docker-compose with an example. If you are using docker-compose file in combination with docker swarm, you will probably get rolling update feature out of the box. Otherwise to perform rolling-update with only docker-compose is bit tricky.

Assumptions/ Prerequisites

  1. You have golang installed on your machine. (If you are using the example from this page for testing)
  2. You have Docker cli, runtime installed on your machine.
  3. You have docker-compose cli installed on your machine.
  4. Your machine is connected to internet.

Steps to follow

If you alredy have docker-compose file and application directly jump to step 4. Otherwise follow from step 1.

1. Creating 2 docker images of a sample golang application.

Follow this article to create docker image with golang app inside it. Create 2 images, for simplicity lets name them testgoapp:old and testgoapp:new. You can change the text printed by helloworld function to differentiate between 2 images.

2. Creating a docker image with nginx as reverse proxy

Now we will create a docker image which can run nginx as reverse proxy. We will hardcode nginx's config to use goapp from above step as backend server.

For this follow below steps.

a. Create a file nginx.conf and save following text in it.

 1server {
 2	// To listen on port 8080
 3    	listen 8080;
 4    	root /data/up1;
 5
 6    location / {
 7	//Configuring backend server as goapp.
 8	// goapp will later be resolved to goapp container ip(s) by docker's dns
 9        set $backend_servers goapp;
10        proxy_pass http://$backend_servers:8080;
11    }
12}
13// Docker's embedded dns server
14resolver 127.0.0.11 valid=5s;

b. Create a file DockerfileNginx and save following text in it.

1FROM nginx:1.19
2COPY nginx.conf /etc/nginx/conf.d/site.conf
3CMD ["nginx", "-g", "daemon off;"]

c. Run the following command to create docker image for nginx.

1docker build -t testnginx -f DockerfileNginx .

3. Running the nginx and goapp together using docker-compose

a. Create a file docker-compose.yml and save following text in it.

 1version: "3.3"
 2  
 3services:
 4 nginx:
 5   image: testnginx
 6   depends_on:
 7     - goapp
 8   ports:
 9     - "8000:8080"
10 goapp:
11   image: testgoapp:old

b. Bring up the applications by running following command

1cd /path/where/docker/compose/file/is
2docker-compose up -d

If every thing worked you should be able to reach helloworld endpoint in web browser with http://localhost:8000/helloworld

4. Performing rolling update

Now comes the intersting part where you will update the goapp to newer version, without having downtime. Follow below steps.

a. Update docker-compose.yml file to use testgoapp:new image.

 1version: "3.3"
 2  
 3services:
 4 nginx:
 5   image: testnginx
 6   depends_on:
 7     - goapp
 8   ports:
 9     - "8000:8080"
10 goapp:
11   image: testgoapp:new

b. Scale the goapp to 2 instance using below command

1docker-compose up -d --scale goapp=2 --scale nginx=1 --no-recreate

This step makes sure that your old go application is not removed but the new golang application is added. If every thing worked you should be able to reach http://localhost:8000/helloworld

c. Remove the old golang app manually running below command

1docker container ls
2#copy the old container id
3docker container rm -f <old-container-id>

If every thing worked you should be able to reach http://localhost:8000/helloworld, and will see the message from new application.

d. Clean up docker-compose state by running the following command

1docker-compose up -d --scale goapp=1 --scale nginx=1 --no-recreate

If every thing worked you should be able to reach http://localhost:8000/helloworld, and will see the message from new application.

In Conclusion, rolling update with docker-compose is possible but not very clean. You need to modify the above commands to match your setup if you are not using the example setup.