기타/인프라 구축과정

[Infra] 4. Jenkins Back 빌드 & 배포 - HelloWorld Project

배발자 2023. 5. 24.
반응형

 

브랜치 전략

 

 

필자가 진행한 프로젝트의 브랜치 전략은 Feature, Develop-BE, Develop-FE, Develop, Master이다.

먼저, 백엔드, 프론트 담당을 나누고 각 팀원마다 Feature 브랜치를 생성하여 자신의 담당 브랜치로 Merge를 진행한다. 예를들면, 필자는 Feature 개인 브랜치를 만들어 작업을 진행하고 백엔드 담당이기에 Develop-BE에 Merge, Pull을 진행한다.

프론트와의 통신을 하기위해 EC2 서버에 우선 Back 애플리케이션 컨테이너를 구동을 진행하였다. 물론, local에서 Back 소스 코드, Front 소스 코드를 실행하여 통신을 진행해도 되지만, 프론트가 디자인을 진행하는동안 Back은 어느정도 API 설계 및 구현이 완료되었다. 그렇기때문에, back 애플리케이션 컨테이너 3개 (알림, 스토리, 메인) 를 EC2 서버에 미리 띄워둔다. 그리고 프론트는 API 통신을 위해 서버 도메인에게 요청을 하고 서버에서는 요청 자원이 존재하는 컨테이너 서버로 포트포워딩을 진행한다.

 

 

Jenkins 흐름

 

 

 

앞선 언급했듯이 back 애플리케이션 서버를 먼저 띄워야하기 때문에 젠킨스에서 back_build 프로젝트를 생성하여 back 프로젝트 파일들을 빌드를 진행한다.

 

기본적으로 형상관리 툴은 GitLab을 활용하였고, 젠킨스와 WebHook 설정을 통해 Develop-BE의 변경 사항이 있다면, 자동으로 젠킨스에서 해당 프로젝트들로 빌드를 진행한다. 그 빌드를 진행하는 곳이 위의 사진에서 back_build 프로젝트이며, 빌드로 생성된 파일 (.jar 파일) 을 가지고 배포를 진행하는 파이프라인이 “back_build_pipeline”이다.

 

 

1. back_build 구성

 

[Jenkins] 

Dashboard > back_build > Configuration > Build Steps > Execute shell

 

  • back 애플리케이션 서버는 RestAPI 통신을 위한 WebMVC 서버 빌드 작업 진행
  • notify 애플리케이션 서버는 알림 데이터를 통신하기 위한 Webflux 서버 빌드 작업 진행
  • storyModule 애플리케이션 서버는 스토리 데이터를 통신하기 위한 WebMVC서버 빌드 작업 진행

cd /var/jenkins_home/workspace/back_build
cp /var/jenkins_home/workspace/yml/application-db.yml back/src/main/resources/
cd /var/jenkins_home/workspace/back_build/back
chmod +x gradlew
./gradlew clean build
cp /var/jenkins_home/workspace/back_build/back/build/libs/helloworld-0.0.1-SNAPSHOT.jar /var/jenkins_home/workspace/deploy_test/back

cd /var/jenkins_home/workspace/back_build
cp /var/jenkins_home/workspace/nyml/application-db.yml notify/src/main/resources/
cd /var/jenkins_home/workspace/back_build/notify
chmod +x gradlew
./gradlew clean build
cp /var/jenkins_home/workspace/back_build/notify/build/libs/notify-0.0.1-SNAPSHOT.jar /var/jenkins_home/workspace/deploy_test/notify

cd /var/jenkins_home/workspace/back_build
cp /var/jenkins_home/workspace/yml_story/application-db.yml StoryModule/src/main/resources/ 
cd /var/jenkins_home/workspace/back_build/StoryModule 
chmod +x gradlew 
./gradlew clean build 
cp /var/jenkins_home/workspace/back_build/StoryModule/build/libs/StoryModule-0.0.1-SNAPSHOT.jar /var/jenkins_home/workspace/deploy_test/StoryModule

 

  1. 애플리케이션에 필요한 application-db.yml 설정 파일을 소스 코드의 적절한 위치로 복사한다. application.yml은 깃랩에 올라가지만 **application-db.yml**은 DB 보안 정보나 S3 Key 값 등을 포함하기 때문에 공개하면 안된다. 그러므로, EC2 서버 내부에 **application-db.yml** 을 저장하여 프로젝트를 빌드하기 전에 복사해간다.
  2. 각 애플리케이션 디렉토리로 이동한다.
  3. Gradle Wrapper (gradlew)의 실행 권한을 설정한다. Gradle Wrapper는 Gradle 빌드 도구를 프로젝트에 포함시키는 방법으로, 이를 통해 빌드를 수행하는 시스템에 Gradle이 미리 설치되어 있지 않아도 빌드를 실행할 수 있다.
  4. gradlew clean build 명령을 실행하여 애플리케이션을 빌드한다. clean 작업은 이전 빌드 결과를 삭제하고, build 작업은 애플리케이션을 새로 빌드한다.
  5. 빌드 결과물인 JAR 파일을 배포 디렉토리로 복사한다. 이 JAR 파일은 Spring Boot 애플리케이션의 실행 가능한 아카이브 파일이다.

 

각 애플리케이션에 대해 위의 작업을 수행하므로, 이 스크립트를 실행하면 3개의 애플리케이션 모두를 빌드하고 각 애플리케이션의 JAR 파일을 배포 디렉토리로 복사할 수 있다.

 

 

 

2. back_build_pipeline

 

 

[Jenkins]

Dashboard > back_build_pipeline > Configuration > Pipeline

 

위의 작업을 통해 JAR 파일을 배포 디렉토리로 옮겼고, 해당 파일을 가지고 컨테이너로 띄워주는 작업을 진행하면 된다.

 

pipeline{
    environment {
        PATH = "/usr/local/bin:$PATH"
        dockerImage = ''
    }

    agent any 
    stages{
      

        stage('Building back image'){
            steps{
                script {
                  dockerImage = docker.build("bae3007/back-zero-downtime", "/var/jenkins_home/workspace/deploy_test/back")
                  withCredentials([usernamePassword(credentialsId: 'bae3007', usernameVariable: 'DOCKER_HUB_USERNAME', passwordVariable: 'DOCKER_HUB_PASSWORD')]) {
                     sh 'docker login -u $DOCKER_HUB_USERNAME -p $DOCKER_HUB_PASSWORD'
                     sh 'docker push bae3007/back-zero-downtime'
                  }
                }
            }
        }
       stage('Run docker back image') {
          steps {
              dir('/var/jenkins_home/workspace/deploy_test/back'){
                  sh 'chmod +x deploy.sh'
                  sh './deploy.sh'
               }
            }
        }
        
        stage('Building notify image'){
            steps{
                script {
                  dockerImage = docker.build("bae3007/notify-zero-downtime", "/var/jenkins_home/workspace/deploy_test/notify")
                  withCredentials([usernamePassword(credentialsId: 'bae3007', usernameVariable: 'DOCKER_HUB_USERNAME', passwordVariable: 'DOCKER_HUB_PASSWORD')]) {
                     sh 'docker login -u $DOCKER_HUB_USERNAME -p $DOCKER_HUB_PASSWORD'
                     sh 'docker push bae3007/notify-zero-downtime'
                  }
                }
            }
        }
       stage('Run docker notify image') {
          steps {
              dir('/var/jenkins_home/workspace/deploy_test/notify'){
                  sh 'chmod +x deploy.sh'
                  sh './deploy.sh'
               }
            }
        }
        
        stage('Building story image'){
            steps{
                script {
                  dockerImage = docker.build("bae3007/story-zero-downtime", "/var/jenkins_home/workspace/deploy_test/StoryModule")
                  withCredentials([usernamePassword(credentialsId: 'bae3007', usernameVariable: 'DOCKER_HUB_USERNAME', passwordVariable: 'DOCKER_HUB_PASSWORD')]) {
                     sh 'docker login -u $DOCKER_HUB_USERNAME -p $DOCKER_HUB_PASSWORD'
                     sh 'docker push bae3007/story-zero-downtime'
                  }
                }
            }
        }
       stage('Run docker story image') {
          steps {
              dir('/var/jenkins_home/workspace/deploy_test/StoryModule'){
                  sh 'chmod +x deploy.sh'
                  sh './deploy.sh'
               }
            }
        }
        
        stage('not using images&containers delete '){
            steps{
                sh "docker image prune -a -f"
            }
        }
    }
}

 

이 스크립트는 Jenkins의 Declarative Pipeline이며, 각 스테이지에서 특정 도커 이미지를 빌드하고 실행하는 일련의 단계를 정의한다.

 

  1. Building back image 스테이지: **back-zero-downtime**라는 Docker 이미지를 빌드하고 Docker Hub에 푸시한다.
  2. Run docker back image 스테이지: 빌드한 back-zero-downtime 이미지를 실행하기 위해 deploy.sh 스크립트를 실행한다.
  3. Building notify image 스테이지: **notify-zero-downtime**라는 Docker 이미지를 빌드하고 Docker Hub에 푸시한다.
  4. Run docker notify image 스테이지: 빌드한 notify-zero-downtime 이미지를 실행하기 위해 deploy.sh 스크립트를 실행한다.
  5. Building story image 스테이지: **story-zero-downtime**라는 Docker 이미지를 빌드하고 Docker Hub에 푸시한다.
  6. Run docker story image 스테이지: 빌드한 story-zero-downtime 이미지를 실행하기 위해 deploy.sh 스크립트를 실행한다.
  7. not using images&containers delete 스테이지: 더 이상 사용되지 않는 Docker 이미지를 시스템에서 삭제한다. docker image prune -a -f 명령은 사용되지 않는 모든 Docker 이미지를 강제로 삭제한다.

 

Jenkins credential plugin을 사용하여 Docker Hub 계정 정보를 안전하게 저장하고, **docker login**을 사용하여 Docker Hub에 로그인 후, **docker push**를 사용하여 이미지를 푸시한다. Docker Hub 클라우드 저장소에 저장하는 이유는 로컬이나 서브 서버에서 해당 이미지를 pull 받아와 작업을 할 수 있기때문에, 공유 저장소에 기록한다.

이런 식으로, 이 Jenkins pipeline은 여러 Docker 이미지를 빌드하고 실행하는 과정을 자동화하게된다.

 

deploy.sh 관련된 내용은 "[Infra] 4. 무중단 배포 - HelloWorld Project" 글에서 정리할 예정이다. 

 

반응형

댓글