<!-- TITLE: Parallel Deploy To Swarm --> <!-- SUBTITLE: The art of parallel deploy to SWARM --> # Parallel Deploy to SWARM. Pipeline The following pipeline example allows to deploy SWARM services in parallel which saves a lot of time comparing to ```groovy node { def repo = "$env.backend_repo"; def configs = "$env.deploy_repo"; def creds = "github-ssh"; def branch = (env.gitlabMergeRequestLastCommit) ? env.gitlabMergeRequestLastCommit : "${env.BRANCH}"; def project = "$env.project"; def project_hub = "$env.docker_hub"; def image_tag = (env.environment == 'staging') ? "latest" : "prod"; def envs = []; stage ("Get app code") { dir ("build") { checkout scm: [$class: 'GitSCM', userRemoteConfigs: [[url: "${repo}", credentialsId: "github-ssh"]], branches: [[name: "${branch}"]]], changelog: false, poll: false } } stage("Get configs") { dir("deploy") { checkout scm: [$class: 'GitSCM', userRemoteConfigs: [[url: "${configs}", credentialsId: "github-ssh"]], branches: [[name: "master"]]], changelog: false, poll: false } dir('build') { //Get .env file configFileProvider( [configFile(fileId: "${env.environment}-docker-env", variable: 'envs')]) { sh 'cp ${envs} ./.env'; } for (String i : readFile('.env').split("\r?\n")) { if(i != "") { envs.push(i); } } sh "cp ../deploy/dockerfiles/Backend.Dockerfile ./Backend.Dockerfile"; sh "cp ../deploy/configs/default_nginx.conf ./config/default_nginx.conf"; sh "cp ../deploy/dockerfiles/Proxy.Dockerfile ./Proxy.Dockerfile" sh "cp ../deploy/dockerfiles/Test.Dockerfile ./Test.Dockerfile"; sh "cp ../deploy/configs/database.yml ./config/database.yml"; sh "cp ../deploy/configs/entrypoint.sh ./entrypoint.sh"; sh "cp ../deploy/docker-compose.docs.yml ./docker-compose.docs.yml"; sh "cp ../deploy/dockerfiles/Static.Dockerfile ./Static.Dockerfile"; } } //build container if(env.BUILD_DOCS == 'yes') { stage ("Generate Docs"){ dir ("build") { def customImage = docker.build("backend:docs", "-f Test.Dockerfile ."); def current_dir = pwd(); configFileProvider( [configFile(fileId: 'test-docker-env', variable: 'envs')]) { sh 'cp ${envs} ./.env'; sh "docker-compose -f docker-compose.docs.yml up -d"; def test_container = docker.image('backend:docs'); test_container.inside("--env-file=${current_dir}/.env --network=build_docs") { sh "bundle exec rails db:drop db:create RAILS_ENV=test"; sh "bundle exec rake docs:generate SIMPLECOV=false"; } sh "docker-compose -f docker-compose.docs.yml stop"; } } } } stage ("Build App") { dir ("build") { withCredentials([file(credentialsId: 'cloudfront-key', variable: 'FILE')]) { sh "rm -f ./.cfk"; sh 'cp $FILE ./.cfk'; sh "chmod 644 .cfk"; } configFileProvider( [configFile(fileId: "${env.environment}-docker-env", variable: 'envs')]) { sh 'cp ${envs} ./.env'; def customImage = docker.build ("${project_hub}/${project}/backend:${image_tag}", "-f Backend.Dockerfile ."); sh "docker push ${project_hub}/${project}/backend:${image_tag}"; def staticImage = docker.build ("${project_hub}/${project}/backend_static:${image_tag}", "-f Static.Dockerfile ."); sh "docker push ${project_hub}/${project}/backend_static:${image_tag}"; } } } stage("Deploy app") { shCommand("sudo docker pull ${project_hub}/${project}/backend:${image_tag}"); shCommand("sudo docker pull ${project_hub}/${project}/backend_static:${image_tag}"); def jenvs = envs.join(" --env-add "); def services = ["backend", "sidekiq", "rpc", "ws"] parallel rolling_update(services, jenvs, image_tag) } dir("build") { GIT_COMMIT = sh ( script: 'git rev-parse --short HEAD', returnStdout: true ).trim() wrap([$class: 'BuildUser']) { sh """curl https://api.rollbar.com/api/1/deploy/ \ -F access_token=${env.ROLLBAR_KEY} \ -F environment=${env.environment} \ -F revision=${GIT_COMMIT} \ -F local_username=${BUILD_USER}""" sh 'echo "${BUILD_USER}"' } } } def rolling_update(services, jenvs, image_tag) { def buildParallelMap = [:] for (name in services) { buildParallelMap.put(name, update(name, jenvs, image_tag)) } buildParallelMap.put("static", update_static(image_tag)) return buildParallelMap } def update(name, jenvs, image_tag) { return { shCommand("sudo docker service update --env-add ${jenvs} --force --image ${env.docker_hub}/${env.project}/backend:${image_tag} ${env.project}_${name}"); } } def update_static(image_tag) { return { shCommand("sudo docker service update --force --image ${env.docker_hub}/${env.project}/backend_static:${image_tag} ${env.project}_static"); } } def shCommand(command) { sshagent (credentials: ['ssh-key']) { def ip = (env.environment == 'staging') ? env.dev_ip : env.prod_ip sh "ssh -o StrictHostKeyChecking=no -l $env.user $ip $command" } } ```