Docker와 Jenkins로 NodeJs 프로젝트의 CI/CD Pipeline 구축하기 (with AWS EC2 Ubuntu) - (2)

Seung Hyeon ·2023년 10월 23일
0

백엔드

목록 보기
7/14
post-thumbnail

Jenkins CI/CD 파이프라인 구축에서 핵심은 pipeline 스크립트를 효과적으로 작성하는 데 있다.
이번 포스트는 Jenkins로 도커 이미지 Build & Push 자동화하는 방법을 적어볼 것이다.

Pipeline script 구성


Sections 로 구성된다.

  • Agent section
    젠킨스는 많은 일들을 해야하기 때문에 혼자하기 버겁다.
    그래서 여러 slave node를 두고 일을 시킬 수 있는데, 이처럼 어떤 젠킨스가 일을 하게할 것인지를 지정한다.
    젠킨스 노드 관리에서 새로 노드를 띄우거나 혹은 docker 이미지 등을 통해서 처리할 수 있다.
  • Post section
    스테이지. 즉, 각 단계가 끝난 이후의 결과에 따라서 후속 조치를 취할 수 있다.
    success, failure, always, cleanup 등
  • Stages section
    어떤 일들을 처리할 것인지 일련의 stage를 정의한다.
    • Declartives:
      각 stage 안에서 어떤 일을 할건지 정의하는 것
    • Environment:
      어떤 파이프라인이나 stage scope의 환경변수를 설정한다.
    • Parameter:
      파이프라인 실행시 파라미터를 받는다.
    • Triggers:
      어떤 형태로 트리거되는지. 즉, 실행 주기 설정. git 소스코드 3분마다 긁어오기.
    • When:
      언제 실행되는가
  • Steps section
    한 stage 안에서의 단계

Build & Push 자동화 설계 흐름도


Start✨

본격적인 pipeline script 작성에 앞서, 만약 연동하려는 Github가 private인 경우는 홈 > Jenkins 관리 > System > GitHub > Name적고 API URL은 냅둠 > credentials add 클릭 > kind: secret text > secret에 본인 Github의 settings에서 생성한 엑세스 키 토큰을 입력 > id는 아무거나 을 차례로 입력해 credentials에 본인 깃헙 계정을 연결시킨다.
반대로 public repo일 경우, 이 과정은 생략한다.

  1. 새로운 Item > Pipeline에 들어간다.

  2. General의 Github project에 연동할 깃허브 repo주소를 입력한다.

  3. Build Triggers에 GitHub hook trigger for GITScm polling을 체크한다.

    Build Triggers 항목들 간단 설명

    • Build after other projects are built : 다른 프로젝트의 빌드가 완료된 후 현재 프로젝트의 빌드를 자동으로 트리거한다. 예를 들어, 프로젝트 A가 빌드되면 프로젝트 B를 자동으로 시작하도록 설정할 수 있다.
    • Build periodically : 일정한 주기로 빌드를 실행 (cron 사용)
    • GitHub hook trigger for GITScm polling : GitHub 웹훅을 통해 코드 저장소(Git)의 변경 사항을 감지하고, 변경이 있을 때 빌드를 트리거한다. 이 옵션은 GitHub와의 통합을 통해 코드가 푸시될 때 자동으로 빌드하고 배포하는 데 사용된다.
    • Poll SCM : 지정된 시간 간격으로 코드 저장소를 폴링하여 변경 사항을 검색하고 변경이 감지되면 빌드를 트리거한다. 이것은 코드 저장소에 자동으로 푸시되지 않는 경우 사용할 수 있는 백업 방법이다.
    • Quiet period : 빌드가 트리거되기 전에 대기하는 시간을 설정. 예를 들어, "Quiet period"을 30으로 설정하면 빌드가 트리거된 후 30초 동안 대기한 다음 빌드를 시작. 코드 푸시 후 안정성을 확보하거나 충돌을 방지하는 데 사용됨
  4. Pipeline script에 pipeline 작성

Pipeline 작성

1. environment옵션

먼저 프로젝트에서 사용된 환경변수를 입력해야한다.
기존 Node.js프로젝트에서는 front와 back폴더 각각에 .env파일을 생성하여 각종 엑세스키, 포트번호, URL등을 입력하였는데 이번에는 .env파일을 생성하는 대신 environment옵션에 환경변수를 넣어주겠다.
https://www.educative.io/answers/how-to-set-environment-variables-in-jenkins
위 링크를 참고했다.

홈 > Jenkins 관리 > system > Global properties에 다음과 같이 환경변수들 모두 작성

비번, 키 같은 공개하기 어려운 값들은
홈 > Jenkins 관리 > credentials > Stores scoped to Jenkins > Global credentials (unrestricted) > Add > secret text 선택한 다음 작성하면 된다.


그런 다음 아래와 같이 작성해준다.

pipeline{
    agent any
    
    environment {
        GOOGLE_CLIENT_ID = credentials('google_client_id')  # Global credentials
        SMTP_PASSWORD = credentials('smtp_password')
        SMTP_SERVICE = 'gmail'  # Global properties
        ...
    }
}

2. stages

첫번째 stage는 git clone이다.
맨 아래 pipeline syntax > Sample step > checkout: Checkout from version control 선택 > repository URL에 연동할 github repo url을 입력 > (optional) private repo인 경우 credentials 추가 > branches to build에 클론할 브랜치 입력 > generate pipeline script클릭하면 아래와 같이 깃 클론해줄 명령어 script가 나온다.

복사해서 아래와 같이 추가해준다.

pipeline{
    agent any
    
    environment {
        GOOGLE_CLIENT_ID = credentials('google_client_id')  # Global credentials
        SMTP_PASSWORD = credentials('smtp_password')
        SMTP_SERVICE = 'gmail'  # Global properties
        
    }
    stages{
        stage('clone') {
            steps{
                checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/snghyun331/elice-damchae-upgrade']])
            }
        }
    }
}

 
두번째 stage는 도커 빌드이다.
도커 컴포즈로 빌드하기 위해 아래와 같이 작성했다.

(위 코드 생략)
...

stage('Build Docker images') {
            steps{
                echo "Building docker images............."
                script{
                    // elice-damchae-upgrade 폴더로 이동
                    dir('elice-damchae-upgrade') { 
                        // 도커 컴포즈 빌드
                        sh 'docker-compose build' 
                    }

                }
            }
        }

깃 클론을 해서 elice-damchae-upgrade폴더가 생겼고, 그 폴더 안에 바로 docker-compose.yml파일이 있다. 이 docker-compose.yml파일을 빌드하면 한번에 4개의 서비스(이미지)가 빌드된다.

 
세번째 stage는 빌드한 이미지를 도커 허브에 푸쉬하는 것이다.
본인의 도커 허브에 푸쉬하기 위해서는 먼저 도커 로그인을 해야한다.
pipeline syntax > Sample Step > withCredentials: Bind credentials to variables선택 > Bindings의 Add에서 Secret Text 선택 > Variable에 pipeline script에 쓸 pwd명 아무거나 쓰고 add credentials 클릭 > secret text > Secret에는 도커 허브 비밀번호, ID는 새로 지정할 credentials명 아무거나 입력 > Add 클릭 > credentials에서 방금 지정한 credential선택 > Generate Pipeline Script 클릭 후 복사

복사한 script을 아래와 같이 붙여넣기

// 맨 처음에 빌드할 서비스명 정의
def services = [
    'backapp',
    'frontapp'
]

....
....

stage('Tag and Push to Hub') {
            steps{
                echo "Tagging and pushing to hub.................."
                script{
                    services.each { service ->
                      stage ("${service} Push") {
                          echo "${service} Pushing..."
                          withCredentials([string(credentialsId: 'docker_pwd', variable: 'docker_hub_pwd')]) {
                              def imageName = "damchae1_${service.toLowerCase()}:latest"
                              def imageTag = "snghyun/damchae_pipeline_${service.toLowerCase()}:${BUILD_NUMBER}"
                              
                              // 이미지 태깅
                              sh "docker tag ${imageName} ${imageTag}"
                              
                              // Hub에 로그인
                              sh "docker login -u 도커허브 아이디 -p ${docker_hub_pwd}"
                              
                              // 이미지를 허브로 푸쉬
                              sh "docker push ${imageTag}"
                            }
                        }
                    }              
                }   
            }
        }
  • 빌드된 각각의 이미지를 순회하면서 이미지를 새로 태깅하고 도커 허브에 푸쉬한다.
  • 빌드된 이미지명을 알고 싶을 때는 linux창에 docker images입력하면 알 수 있다.
  • BUILD_NUMBER 변수는 Jenkinsfile에서 기본으로 제공되는 환경변수이다. 빌드 순서용으로 쓰인다.

 
결과↓

마지막 단계

지금까지는 Pipeline script에 Pipeline을 작성하고 ▷지금 빌드 버튼을 누르면서 테스트해보았다면, 이제는 이런식으로 하지 않고 소스코드폴더에 Jenkinsfile 파일을 생성하고 그 안에 파이프라인을 옮겨 적을 것이다.

▲ Jenkinsfile 작성

GitHub Webhook 설정

  • Github Repository > Settings > Webhooks > Add webhook
  • Payload URL : http:// {Server IP}:{Jenkins Port}/github-webhook/
  • Content type : application/json
  • Acitve 활성화

Definition을 Pipeline Script → Pipeline Script from SCM으로 변경

확인

master로 푸쉬하기 전, 깃허브의 webhooks에 들어가더니 아래와 같은 에러 메시지가 나왔다. 몇분 전 다른 브래치로 푸쉬한 적이 있는데 webhooks에 입력한 호스트 주소와의 연결이 실패했다는 에러 메시지였다.

원인은 AWS EC2 보안 인바운드 규칙에 Jenkins 접속 포트를 내 IP주소로만 접속하도록 설정해서 생긴 오류였다!

이제 master로 푸쉬해봤더니 ▷지금 빌드버튼을 누르지 않아도 자동으로 빌드/푸쉬가 되었다.

성공~

 

※ 참고:
[Jenkins 파일 작성법]

[Jenkins를 github에 연동하기] https://dev2-jay.tistory.com/47 👍

[How to set environment variables in Jenkins?] https://www.educative.io/answers/how-to-set-environment-variables-in-jenkins

[Jenkins 로 도커 이미지 Build & Push 자동화하기]

유튜브 - Build & Push Docker Image using Jenkins Pipeline

profile
안되어도 될 때까지

0개의 댓글