Zero Down Time Deployment!

First Step

let’s consider we have one nginx and one php node and we want to deploy on php node without down time
Our structure is like this

.
├── app
│   └── index.php
├── docker-compose.yml
├── nginx.Dockerfile
├── nginx.conf
└── php.Doc…


This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Mohammad Reza

First Step

let's consider we have one nginx and one php node and we want to deploy on php node without down time
Our structure is like this

.
├── app
│   └── index.php
├── docker-compose.yml
├── nginx.Dockerfile
├── nginx.conf
└── php.Dockerfile

That is our docker-compose.yml

version: "3.7"

services:
    cicd-nginx:
        build:
          context: .
          dockerfile: nginx.Dockerfile
        ports:
            - "88:80"
        volumes:
            - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro

    cicd-php:
        build:
          context: .
          dockerfile: php.Dockerfile

That is our nginx.Dockerfile

FROM nginx:1.17-alpine

WORKDIR /app
COPY ./app ./

That is our nginx.conf

server {
    listen 80;
    index index.php index.html;

    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;

    root /app;
    server_name localhost;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass cicd-php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

    }
}

That is our simple php.Dockerfile

FROM php:fpm
RUN docker-php-ext-install pdo pdo_mysql mysqli

RUN curl -sS https://getcomposer.org/installer | \
    php -- --install-dir=/usr/bin/ --filename=composer

RUN apt-get update && apt-get install -y \
    git \
    unzip

RUN apt-get update -y && apt-get install -y sendmail libpng-dev
RUN docker-php-ext-install gd

WORKDIR /app
COPY ./app ./

And at the end that is our simple index.php

<?php

echo "hi"

?>

Let's go to the next interesting part

Image description

First we change build with image because we want to first build the image and then just replace the new one with the old one, so our docker-compose.yml will become like this:

version: "3.7"

services:
    cicd-nginx:
        image: ${NGINX_IMAGE_TAG}
        ports:
            - "88:80"
        volumes:
            - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro

    cicd-php:
        image: ${PHP_IMAGE_TAG}

First set the variables and the need to build the images

export PHP_IMAGE_TAG=phptest:1
export NGINX_IMAGE_TAG=nginxtest:1

docker build -f php.Dockerfile -t $PHP_IMAGE_TAG .
docker build -f nginx.Dockerfile -t $NGINX_IMAGE_TAG .

Then we just run up -d

Now I want to show you what will happen if you just want to deploy the new code

First we prepare a bash script for it (./script.sh):

#!/bin/bash
while :
do
    echo "Your response : "
    curl 127.0.0.1:88
    echo " "
    date
    sleep 2
done

Now we just change the php file to sth like

<?php

echo "hi hi :)"

?>

And then we try to build it with new name

export PHP_IMAGE_TAG=phptest:2
docker build -f php.Dockerfile -t $PHP_IMAGE_TAG .

Now we want run the script and then run these commands to update the php container

sh ./script.sh

And

docker-compose down
docker-compose up -d

Result

You will see sth like this and that is the problem

...
Your response : 
hi 
Mon Oct 31 00:31:23 UTC 2022
Your response : 
hi 
Mon Oct 31 00:31:25 UTC 2022
Your response : 
hi 
Mon Oct 31 00:31:27 UTC 2022
Your response : 
hi 
Mon Oct 31 00:31:30 UTC 2022
Your response : 
curl: (7) Failed to connect to localhost port 88: Connection refused

Mon Oct 31 00:31:32 UTC 2022
Your response : 
curl: (7) Failed to connect to localhost port 88: Connection refused

Mon Oct 31 00:31:34 UTC 2022
Your response : 
curl: (7) Failed to connect to localhost port 88: Connection refused

Mon Oct 31 00:31:36 UTC 2022
Your response : 
curl: (7) Failed to connect to localhost port 88: Connection refused

Mon Oct 31 00:31:38 UTC 2022
Your response : 
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.17.10</center>
</body>
</html>

Mon Oct 31 00:31:40 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:31:42 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:31:44 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:31:46 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:31:48 UTC 2022
...

You can feel what is the problem right now so let's try to fix it

Image description

We want to use docker swarm

First init it

docker swarm init

Then update your docker-compose.yml like this:

version: "3.7"

services:
    cicd-nginx:
        image: ${NGINX_IMAGE_TAG}
        ports:
            - "88:80"
        volumes:
            - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
        deploy:
          mode: replicated
          replicas: 2
          update_config:
            order: start-first
            failure_action: rollback
            delay: 5s

    cicd-php:
        image: ${PHP_IMAGE_TAG}
        deploy:
          mode: replicated
          replicas: 2
          update_config:
            order: start-first
            failure_action: rollback
            delay: 5s

Then run this command and now you are up

docker stack deploy -c docker-compose.yml <stack_name>

Let's look at containers

CONTAINER ID   IMAGE                   COMMAND                  CREATED              STATUS              PORTS                                       NAMES
6cc2b3516a3a   phptest:2               "docker-php-entrypoi…"   About a minute ago   Up About a minute   9000/tcp                                    website_cicd-php.1.ijd0lpj995318hpffx6gx5t44
7cffa4115598   phptest:2               "docker-php-entrypoi…"   About a minute ago   Up About a minute   9000/tcp                                    website_cicd-php.2.jbd2sg2qm6ounji76q99fk2ql
fcedfb42b44a   nginxtest:1             "nginx -g 'daemon of…"   About a minute ago   Up About a minute   80/tcp                                      website_cicd-nginx.2.8z4spuco9rtdxcpc8y0fux79p
99e1642cf461   nginxtest:1             "nginx -g 'daemon of…"   About a minute ago   Up About a minute   80/tcp                                      website_cicd-nginx.1.eo6erxose7asze8ref2poracc

We have 2 php node and 2 nginx node :)
Let's update the php node and see the result
Change the php file and add one hi

<?php

echo "hi hi hi :)"

?>

And then we try to build php node it with new name

export PHP_IMAGE_TAG=phptest:3
docker build -f php.Dockerfile -t $PHP_IMAGE_TAG .

Now we want run the script and then run the command to update the php container

sh ./script.sh

And

docker stack deploy -c docker-compose.yml <stack_name>

Result

...
Your response : 
hi hi :) 
Mon Oct 31 00:53:53 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:53:55 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:53:57 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:53:59 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:54:01 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:03 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:54:05 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:07 UTC 2022
Your response : 
hi hi :) 
Mon Oct 31 00:54:09 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:11 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:13 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:15 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:17 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:19 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:21 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:23 UTC 2022
Your response : 
hi hi hi:) 
Mon Oct 31 00:54:25 UTC 2022
...

Wow And that is the magic
We do not have any down time and docker swarm completely handle it for us

let's make .gitlab-ci.yml for it

Step one create a project in gitlab
Step two add project to the git and then push it

git init
git add .
git commit -m "init"
git remote add origin git@gitlab.com:azibom/cicd.git

Step three add .gitlab-ci.yml to the project

image: docker:20.10.16

stages:
  - publish
  - deploy

variables:
  PHP_TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:php-$CI_COMMIT_SHORT_SHA
  NGINX_TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:nginx-$CI_COMMIT_SHORT_SHA
  DOCKER_TLS_CERTDIR: "/certs"

services:
  - docker:20.10.16-dind

before_script:
  - 'command -v ssh-agent >/dev/null || ( apk add --update openssh )' 
  - eval $(ssh-agent -s)
  - echo "${SSH_PRIVATE_KEY}" | tr -d '\r' | ssh-add -
  - mkdir -p ~/.ssh
  - chmod 700 ~/.ssh

publish:
  stage: publish
  script:
    - docker build -f php.Dockerfile -t $PHP_TAG_COMMIT .
    - docker build -f nginx.Dockerfile -t $NGINX_TAG_COMMIT .
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker push $PHP_TAG_COMMIT
    - docker push $NGINX_TAG_COMMIT

deploy:
  image: alpine:latest
  stage: deploy
  script:
    - ssh -o StrictHostKeyChecking=no ubuntu@130.185.120.185 "cd /opt/cicd/docker-compose-lemp ; docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY ;echo $NGINX_TAG_COMMIT; docker pull $NGINX_TAG_COMMIT"
    - ssh -o StrictHostKeyChecking=no ubuntu@130.185.120.185 "cd /opt/cicd/docker-compose-lemp && docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY && docker pull $PHP_TAG_COMMIT"
    - ssh -o StrictHostKeyChecking=no ubuntu@130.185.120.185 "cd /opt/cicd/docker-compose-lemp && export PHP_IMAGE_TAG=$PHP_TAG_COMMIT && export NGINX_IMAGE_TAG=$NGINX_TAG_COMMIT && docker stack deploy -c docker-compose.yml website"
  only:
    - master

Step Four add a variable to the gitlab ci from setting

SSH_PRIVATE_KEY

You can find SSH_PRIVATE_KEY with run this command

cat ~/.ssh/id_rsa

Also run this on server

cat ~/.ssh/id_rsa.pub > ~/.ssh/authorized_keys

Step five define your own runner

curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh > script.deb.sh
sudo bash script.deb.sh
sudo apt install gitlab-runner
systemctl status gitlab-runner
sudo gitlab-runner register -n \
  --url https://gitlab.com/ \
  --registration-token REGISTRATION_TOKEN \
  --executor docker \
  --description "My Docker Runner" \
  --docker-image "docker:20.10.16" \
  --docker-privileged \
  --docker-volumes "/certs/client"

(bring REGISTRATION_TOKEN from gitlab.com)
Step six push to your server and look at pipline


This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Mohammad Reza


Print Share Comment Cite Upload Translate Updates
APA

Mohammad Reza | Sciencx (2022-10-31T04:24:47+00:00) Zero Down Time Deployment!. Retrieved from https://www.scien.cx/2022/10/31/zero-down-time-deployment/

MLA
" » Zero Down Time Deployment!." Mohammad Reza | Sciencx - Monday October 31, 2022, https://www.scien.cx/2022/10/31/zero-down-time-deployment/
HARVARD
Mohammad Reza | Sciencx Monday October 31, 2022 » Zero Down Time Deployment!., viewed ,<https://www.scien.cx/2022/10/31/zero-down-time-deployment/>
VANCOUVER
Mohammad Reza | Sciencx - » Zero Down Time Deployment!. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/10/31/zero-down-time-deployment/
CHICAGO
" » Zero Down Time Deployment!." Mohammad Reza | Sciencx - Accessed . https://www.scien.cx/2022/10/31/zero-down-time-deployment/
IEEE
" » Zero Down Time Deployment!." Mohammad Reza | Sciencx [Online]. Available: https://www.scien.cx/2022/10/31/zero-down-time-deployment/. [Accessed: ]
rf:citation
» Zero Down Time Deployment! | Mohammad Reza | Sciencx | https://www.scien.cx/2022/10/31/zero-down-time-deployment/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.