
Пример деплоя в Docker Swarm с Jenkins'а используя 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
Для использования Nginx'а в качестве Load Balancer'а, его нужно добавить в namespace с остальными контейнерами. Для связности в файл конфигурации nginx.conf в блок "http" добавить следующее:
upstream production {
server artem-api_production;
}
upstream staging {
server artem-api_staging;
}
И проксировать уже по именам апстримов.