내맘대로 개발일지

[AWS] Jenkins 로 배포하기 [Spring] 본문

IT

[AWS] Jenkins 로 배포하기 [Spring]

eulBlue 2025. 11. 25. 11:22

 

 

[AWS] Jenkins 로 배포하기 [Node]

[Jenkins] EC2 안에서 설치하고 실행하기[EC2] 안에서 nginx 사용하기[AWS] 아무것도 모르는데 EC2 + Docker + MariaDB + nginx진짜 아무것도 모른다.개발만 해봤지 인프라 처음해본다.곁눈질도 안해봤고 해주는

8735.tistory.com

드디어 여기까지왔다....

마지막으로 Spring 서버를 무중단으로 해볼 예정이다.

기본적인 설정은 프론트를 배포하면서 다 해놓은 상태이다.

서버도 프론트와 동일하게 Pipeline 으로 만들고

스크립트를 작성해준다.

pipeline {
    agent any
    options { timestamps() }

    environment {
        PROJECT_NAME   = "PROJECT_NAME"
        GIT_URL        = "GIT_URL"
        GIT_BRANCH     = "GIT_BRANCH"
        CREDENTIALS_ID = "github_ssh"

        DOCKER_IMAGE   = "DOCKER_IMAGE:latest"

        BLUE_PORT      = "8080"
        GREEN_PORT     = "8082"

        NGINX_CONF     = "/etc/nginx/conf.d/default.conf"

        // sudo 비번 없이 실행 (sudoers 에 ec2-user NOPASSWD 설정 필요)
        SUDO           = "sudo -n"
    }

    stages {

        stage('Clone Repository') {
            steps {
                sh "git --version"
                git branch: "${GIT_BRANCH}",
                    credentialsId: "${CREDENTIALS_ID}",
                    url: "${GIT_URL}"
            }
        }

        stage('Build JAR') {
            steps {
                sh 'chmod +x ./gradlew'
                sh './gradlew clean build -x test'
            }
        }

        stage('Build Docker Image') {
            steps {
                sh """
                  echo "🐳 build image: ${DOCKER_IMAGE}"
                  docker build -t ${DOCKER_IMAGE} .
                """
            }
        }

        stage('Blue-Green Deploy') {
            steps {
                script {
                    // 1) nginx 에서 현재 LIVE 포트(8080 or 8082) 확인
                    def currentPort = sh(
                        script: "grep -o '127.0.0.1:808[0-9]' ${NGINX_CONF} | head -n1 | sed 's/127.0.0.1://' || echo ''",
                        returnStdout: true
                    ).trim()

                    if (!currentPort) {
                        // 처음 셋업 시에는 8080 기준
                        currentPort = BLUE_PORT
                    }

                    echo "현재 LIVE PORT = ${currentPort}"

                    def bluePort  = currentPort
                    def greenPort = (currentPort == BLUE_PORT) ? GREEN_PORT : BLUE_PORT

                    def blueName  = "${PROJECT_NAME}-${bluePort}"
                    def greenName = "${PROJECT_NAME}-${greenPort}"

                    echo "BLUE  (현재 LIVE) : ${blueName} / ${bluePort}"
                    echo "GREEN(새 버전)   : ${greenName} / ${greenPort}"

                    // 2) 기존 GREEN 컨테이너 정리
                    sh """
                      echo "🧹 기존 GREEN 컨테이너 정리: ${greenName}"
                      docker stop ${greenName} || true
                      docker rm   ${greenName} || true

                      # 예전에 쓰던 이름이 있으면 같이 정리
                      docker stop backend || true
                      docker rm   backend || true
                    """

                    // 3) 새 버전을 GREEN 포트로 먼저 기동
                    sh """
                      echo "🚀 새 버전(${greenPort}) 기동: ${greenName}"
                      docker run -d \\
                        --name ${greenName} \\
                        --network host \\
                        -e SPRING_PROFILES_ACTIVE=prod \\
                        -e SERVER_PORT=${greenPort} \\
                        ${DOCKER_IMAGE}
                    """

                    // 4) GREEN 헬스체크 (/api 사용)
                    sh """
                      echo "🩺 새 버전(포트 ${greenPort}) 헬스체크 시작"

                      for i in {1..30}; do
                        if curl -sf http://127.0.0.1:${greenPort}/api > /dev/null; then
                          echo "✅ 새 버전(포트 ${greenPort}) 헬스체크 통과"
                          exit 0
                        fi
                        echo "⏳ 대기중 (\$i)..."
                        sleep 2
                      done

                      echo "❌ 새 버전(포트 ${greenPort}) 헬스체크 실패"
                      echo "------ 컨테이너 로그 (${greenName}) ------"
                      docker logs ${greenName} || true
                      exit 1
                    """

                    // 5) nginx proxy_pass 808X → GREEN 포트로 변경
                    sh """
                      echo "🔁 Nginx proxy_pass ${bluePort} → ${greenPort} 변경"

                      ${SUDO} sed -i 's/127.0.0.1:${bluePort}/127.0.0.1:${greenPort}/' ${NGINX_CONF}

                      echo "🔎 nginx 설정 테스트"
                      ${SUDO} nginx -t

                      echo "🔄 nginx reload"
                      ${SUDO} systemctl reload nginx
                    """

                    // 6) 옛날 BLUE 컨테이너 종료/삭제
                    sh """
                      echo "🛑 기존 BLUE 컨테이너 정리: ${blueName}"
                      docker stop ${blueName} || true
                      docker rm   ${blueName} || true
                    """

                    echo "🎉 blue-green 배포 완료 (LIVE PORT = ${greenPort})"
                }
            }
        }
    }
}

스크립트가 길어서 어려운데 간단하게 보면

포트를 8080 과 8082 를 번갈아가면서 새로운게 올라올때까지

기다렸다가 헬스체크가 끝나고나면 포트를 변경해 연결해주는 것으로 해서

실제 웹에서는 무중단처럼 느낄 수 있게끔 해주는 방식이다.

스크립트를 작성하고 다음은 nginx 를 수정해줘야한다.

server {
    listen 80;
    server_name _;

    root /var/www/frontend;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8082/;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_connect_timeout 5s;
        proxy_send_timeout    60s;
        proxy_read_timeout    60s;
    }

    gzip on;
    gzip_types text/plain text/css application/json application/javascript application/xml+rss;
    gzip_min_length 256;
}
ps aux | grep jenkins | head

jenkins ...

해당 명령어를 통해 Jenkins 가 어떤 계정으로 돌아가는지 확인하고

맨앞에 나오는 이름이 유저이름이다 나같은경우는 jenkins 였고

// 파일 열고
sudo visudo -f /etc/sudoers.d/jenkins

// 입력 하고
jenkins ALL=(ALL) NOPASSWD: /usr/bin/sed, /usr/sbin/nginx, /usr/bin/systemctl

// 문법 체크
sudo visudo -c

// 결과
/etc/sudoers.d/jenkins: OK

// 적용 테스트
sudo -n echo "sudo works"

// 결과
sudo works

해당 파일로 들어가서 해당 명령을 입력해준다.

이를 통해서 Jenkins 가 서버권한을 갖고 설정 파일을 건드릴 수 있게 된다.

이렇게해서 젠킨스가서 빌드를 실행해보면 무중단처럼 배포를 진행할 수 있게된다.