반응형
들어가기 전
- jenkins pipeline을 활용하여 spring api 새 컨테이너를 띄우고 nginx을 새로 띄워진 spring container port로 바라보도록 하여 무중단 배포하는 예제
- docker registry 주소는 192.168.56.12, 배포할 원격 서버 주소는 192.168.56.14
- 아래 두 예제를 선행하여 환경을 구성한 상태에서 해당 예제를 이어 진행
- git 프로젝트 빌드 설정 : https://sg-choi.tistory.com/212
- docker image 빌드 설정 : https://sg-choi.tistory.com/627
jenkins 설정
- jenkins item 생성
- name : demo-api-deploy
- 구성 > Pipeline > Script Path : .jenkins/deploy.groovy
- jenkins credential 설정
- ssh key 생성
- 생성된 id_rsa 파일의 내용을 credential에 등록
- ID : demo-api-server-sshkey
원격 서버 설정
- docker 설치
- 설치 참고 : https://sg-choi.tistory.com/235
- registry 서버 활용을 위한 daemon.json 설정
- deamon.json 설정 참고 : https://sg-choi.tistory.com/625
- jenkins와 통신을 위한 ssh key 설정
- jenkins credential 설정 과정에서 생성된 id_rsa.pub 파일 내용을 원격 서버의 ~/.ssh/authorized_keys에 id_rsa.pub 추가
- 참고 : https://sg-choi.tistory.com/214
deploy.groovy
경로 : ~/.jenkins/deploy.groovy
context = [:]
pipeline {
agent any
stages {
stage("select image tag") {
steps {
script {
def json = sh(script: "docker run --rm -i alpine/curl http://192.168.56.12:5000/v2/demo-api/tags/list", returnStdout: true)
def body = readJSON(text: json) // Pipeline Utility Steps 플러그인 필요
def tags = body.tags.sort().reverse()
def tag = input(message: 'TAG', parameters: [choice(description: "TAG", name: "TAG", choices: tags)])
context.tag = tag
}
}
}
stage("check blue container") {
steps {
script {
sshagent(credentials: ["demo-api-server-sshkey"]) {
sh "ssh -o StrictHostKeyChecking=no ubuntu@192.168.56.14 > /dev/null"
def blueId = sh(script: "ssh ubuntu@192.168.56.14 \"docker ps --filter 'label=app_name=demo-api' -q\"", returnStdout: true).trim()
context.blueId = blueId
}
}
}
}
stage("run green container") {
steps {
script {
sshagent(credentials: ["demo-api-server-sshkey"]) {
def greenId = sh(script: "ssh ubuntu@192.168.56.14 \"docker run --rm -dit -P 192.168.56.12:5000/demo-api:${context.tag}\"", returnStdout: true).trim()
def greenPort = sh(script: "ssh ubuntu@192.168.56.14 \"docker inspect -f '{{(index (index .NetworkSettings.Ports \\\"9090/tcp\\\") 0).HostPort}}' ${greenId}\"", returnStdout: true).trim()
sh "docker run --rm -i alpine/curl --retry-all-errors --max-time 5 --retry-delay 3 --retry 10 http://192.168.56.14:${greenPort}/api/health"
context.greenPort = greenPort
}
}
}
}
stage("change load balancer") {
steps {
script {
sshagent(credentials: ["demo-api-server-sshkey"]) {
sh "sed 's/{{greenPort}}/${context.greenPort}/g' .jenkins/nginx.conf.template > .jenkins/nginx.conf"
sh "scp -r .jenkins/nginx.conf ubuntu@192.168.56.14:/home/ubuntu"
def nginxId = sh(script: "ssh ubuntu@192.168.56.14 \"docker ps --filter 'name=demo-nginx' -q\"", returnStdout: true).trim()
if (nginxId) {
sh "ssh ubuntu@192.168.56.14 \"docker exec ${nginxId} nginx -s reload\""
} else {
sh "ssh ubuntu@192.168.56.14 \"docker run --rm -dit -p 80:80 -v /home/ubuntu/nginx.conf:/etc/nginx/nginx.conf --add-host host.docker.internal:host-gateway --name demo-nginx nginx\""
}
sh "docker run --rm -i alpine/curl --retry-all-errors --max-time 5 --retry-delay 3 --retry 10 http://192.168.56.14/api/health"
}
}
}
}
stage("stop blue container") {
steps {
script {
sshagent(credentials: ["demo-api-server-sshkey"]) {
if (context.blueId) {
sh "ssh ubuntu@192.168.56.14 \"docker stop ${context.blueId}\""
}
}
}
}
}
}
}
nginx.conf.template
경로 : ~/.jenkins/nginx.conf.template
user root;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '[$remote_addr][$remote_user][$time_local][$request][$status][$body_bytes_sent][$http_referer][$http_user_agent][$http_x_forwarded_for]';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
upstream demo-api-url {
server host.docker.internal:{{greenPort}};
}
# Proxy
server {
listen 80;
location / {
proxy_pass http://demo-api-url;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
반응형
'Development > Jenkins' 카테고리의 다른 글
[Jenkins] docker image 빌드 설정 (0) | 2023.01.18 |
---|---|
[Jenkins] Ansible 연동 (0) | 2020.12.28 |
[Jenkins] Jenkins Pipeline (0) | 2020.12.28 |
[Jenkins] Jenkinsfile (0) | 2020.12.28 |
[Jenkins] Selenium 테스트 설정 (0) | 2019.11.24 |