반응형

들어가기 전

  • 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 설정

원격 서버 설정

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

+ Recent posts