Jenkins – Deploy in Docker Swarm using Stack Deploy

An example deployment in Docker Swarm from Jenkins using stack deploy.

Jenkinsfile:

pipeline {
    agent any
    environment {
        PROJECT_NAME = 'artem-api'
        SLACK_CHANNEL = 'maintenance-artem-api'
        SWARM_MANAGER_IP = '8.8.8.8'
        SWARM_WORKER_1_IP = '1.1.1.1'
        SWARM_WORKER_2_IP = '2.2.2.2'
        TLS_CA = '/var/lib/jenkins/TLS/swarm/ca.pem'
        TLS_CERT = '/var/lib/jenkins/TLS/swarm/cert.pem'
        TLS_KEY = '/var/lib/jenkins/TLS/swarm/key.pem'
        ECR = '111111111111.dkr.ecr.us-west-1.amazonaws.com/artem'
        PROFILE = 'artem'
    }
    stages {
        stage ('Auth to AWS ECR.') {
            steps {
                sh "echo 'Auth to image repo'"
                sh "eval \$(aws ecr get-login --profile ${PROFILE} --no-include-email) &>/dev/null"
            }
        }
        stage ('Build image'){
            steps{
                script{
                    withDockerServer([uri:'tcp://127.0.0.1:4243']) {
                        sh "cp ./.jenkins/Dockerfile ./Dockerfile"
                        echo "Debug: Building  with ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}"
                        def image = docker.build ("${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}")
                        image.push ()
                        echo "Debug: After push to registry"
                    }
                }
            }
        }
        stage ('Update API on Staging') {
            when { branch 'staging' }
            steps {
                sh 'envsubst < ".jenkins/Staging.yml" > "Staging.yml"'
                sh "ssh ubuntu@${SWARM_WORKER_1_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "ssh ubuntu@${SWARM_WORKER_2_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "docker -H tcp://${SWARM_MANAGER_IP}:2376 --tlsverify --tlscacert=${TLS_CA} --tlscert=${TLS_CERT} --tlskey=${TLS_KEY} stack deploy --compose-file Staging.yml artem-api"
            }
        }
        stage ('Update API on Production') {
            when { branch 'production' }
            steps {
                sh 'envsubst < ".jenkins/Production.yml" > "Production.yml"'
                sh "ssh ubuntu@${SWARM_WORKER_1_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "ssh ubuntu@${SWARM_WORKER_2_IP} 'sudo docker pull ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}'"
                sh "docker -H tcp://${SWARM_MANAGER_IP}:2376 --tlsverify --tlscacert=${TLS_CA} --tlscert=${TLS_CERT} --tlskey=${TLS_KEY} stack deploy --compose-file Production.yml artem-api"
            }
        }
    }
    post {
        success {
            slackSend channel: "${SLACK_CHANNEL}", color: 'good', message: "Job: ${JOB_NAME}${BUILD_NUMBER} build was successful."
        }
        failure {
            slackSend channel: "${SLACK_CHANNEL}", color: 'danger', message: "Job: ${JOB_NAME}${BUILD_NUMBER} was finished with some error. It may occurs because of the build was rollbacked by docker swarm, or because of other error (watch the Jenkins Console Output): ${JOB_URL}${BUILD_ID}/consoleFull"
        }
        unstable {
            slackSend channel: "${SLACK_CHANNEL}", color: 'warning', message: "Job: ${JOB_NAME}${BUILD_NUMBER} was finished with some error. Please watch the Jenkins Console Output: ${JOB_URL}${BUILD_ID}/console."
        }
    }
}

Production.yml

version: '3.7'

services:
  production:
    image: ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}
    deploy:
      replicas: 2
        update_config:
          parallelism: 1
          delay: 30s
      placement:
        constraints:
          - node.labels.env == production
    volumes:
      - "/var/docker/api/production:/usr/src/app/storage"
    environment:
      SERVER_URL: "api.artem.service"
    ports:
      - 8080:80

 

Staging.yml

version: '3.7'

services:
  staging:
    image: ${ECR}:${PROJECT_NAME}-${JOB_BASE_NAME}-${BUILD_NUMBER}
    deploy:
      replicas: 2
        update_config:
          parallelism: 1
          delay: 30s
      placement:
        constraints:
          - node.labels.env == staging
    volumes:
      - "/var/docker/api/staging:/usr/src/app/storage"
    environment:
      SERVER_URL: "stg.api.artem.service"
    ports:
      - 8081:80

 

To use Nginx as a Load Balancer, you need to add it to the namespace with the other containers. For connectivity, add the following to the “http” block in the nginx.conf configuration file:

    upstream production {
        server artem-api_production;
    }

    upstream staging {
    	server artem-api_staging;
    }

And proxy already by the names of upstream.

Tagged: Tags

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments