[CI/CD] Jenkins - 개발 서버를 위한 배포 환경 만들기 (Pipeline)

Soover·2021년 10월 27일
0

CI/CD 이야기

목록 보기
2/2

📌들어가기

Local 환경에서 개발한 소스를 바로 운영 서버로 배포한다면 어떤 문제가 발생할까요..?
예기치 못한 버그나 에러가 우수수 발생할 경우 난처한 상황을 겪게 될 것입니다😱
이와 같은 상황을 방지하기 위해 일반적으로 운영 서버의 환경과 거의 유사한 환경을 가진 개발 서버(또는 테스트 서버)를 만들어 테스트를 거치게 되죠.
그리고 문제가 없다면 최종적으로 운영 서버로 배포하는 아름다운 과정을 그리게 됩니다 :)

이번 글에서는 개발 서버에서 활용 가능한 배포 환경을 만들어보겠습니다.
Jenkins가 설치되어 있지 않으시다면 이전 글 [CI/CD] Jenkins - 설치하기 (Docker 기반)을 참고해주시면 감사하겠습니다.




🚀시작하기

진행할 배포 시나리오를 간단히 살펴보겠습니다.

  1. Gitlab 원격 저장소로 최신 커밋을 master 브랜치로 업데이트 합니다.
  2. master 브랜치로 push 이벤트가 발생하면 webhook이 발동되어 Jenkins로 신호를 보냅니다.
  3. Jenkins에서 webhook 신호를 감지하게 되면 Pipeline에서 작성한 스크립트를 실행합니다.
  4. git clone으로 소스코드를 가져와 zip 파일로 압축합니다.
  5. Publish Over SSH 플러그인을 통해 원격 서버로 접근하여 zip 파일의 압축을 해제하여 배포를 완료합니다.

기술스택과 시스템 구성에 따라 배포 구성의 차이가 있을 수 있습니다. 본 글에서는 원격 서버로 최신 소스코드가 제대로 업데이트 되는지를 확인할 수준으로 구성했습니다.

그럼 지금부터 본격적으로 하나씩 살펴보도록 합시다!


(준비단계) 인증 수단과 플러그인 설정

배포 절차를 담고 있는 Pipeline 작업을 생성하기에 앞서 기본적으로 필요한 설정사항들이 있습니다.

Gitlab 플러그인 설치

Git으로 버전관리를 하고 원격 저장소는 Gitlab을 사용한다고 가정하겠습니다. 소스코드를 Gitlab으로부터 가져올 것이기 때문에 연동을 위해 Jenkins 관리플러그인 관리로 이동 후, Gitlab 플러그인을 설치합니다.

Credentials 생성

Gitlab과 해당 프로젝트에 접근 가능한 인증 수단을 만들어보겠습니다.
대시보드 화면에서 Jenkins 관리Manage Credentials로 들어갑니다.

Credentials 화면이 나오게 되는데요. 아직 아무것도 등록되지 않은 상태입니다.
등록을 위해 globalAdd Credntials로 갑니다.

입력란을 채워 Credentials를 생성합니다.

  • kind : Gitlab 계정으로 접근할 것이기 때문에 Username with password을 선택합니다.
  • Scope : Global로 선택합니다.
  • username : Gitlab 계정의 ID 입니다.
  • password : Gitlab 계정의 PW 입니다.
  • ID : Credentials를 식별하는 값입니다.

[OK] 버튼을 클릭하면 목록에 생성한 Credentials를 확인할 수 있습니다.

Publish Over SSH 설정

마지막 준비단계로 배포 대상 서버에 SSH 방식으로 접근하여 소스를 배포하기 위해 Publish Over SSH를 설정해야 합니다.
Jenkins 관리 -> 시스템 설정 으로 이동하여 Publish over SSH 구간으로 이동합니다.

배포 대상 서버에 접근하기 위한 Name, Hostname, Username, Remote Directory, Proxy password 값을 기입합니다.

Pipeline 작업 생성

Gitlab과 연동

Credentials를 만들고 Publish Over SSH 세팅도 되었으니 이제 작업을 생성할 준비가 되었습니다.
작업을 만들기 위해 대시보드에서 새로운 Item을 선택합니다.

그리고 생성할 작업 명을 기입하고, Pipeline을 선택한 뒤 OK 버튼을 클릭하면,
본격적으로 세팅해야 할 Pipeline 작업 설정 단계로 진입하게 됩니다. 신나게 작성해봅시다.

먼저, Build Triggers를 설정해야 합니다. Gitlab에서 해당 브랜치에 이벤트가 발생하면 webhook으로 pipeline에 신호를 보내게 됩니다. Bulid Truggers는 대기 중에 신호를 감지하면 Pipeline을 실행합니다.

Gitlab에서 연동을 위해 필요로 하는 값은 2가지 입니다.
먼저 1) Gitlab webhook URL을 복사합니다. Build when a change is pushed to GitLab 체크박스를 선택하여 하위 항목들은 default 값으로 진행하겠습니다.
그리고 고급 버튼을 클릭하여 활성화 된 하위 항목들 중 아래쪽에 2) Generate 버튼을 클릭하여 Secret token을 갱신 후 복사합니다.

연동하기 위한 Gitlab 브랜치의 설정연동으로 이동하여, 앞서 복사한 Gitlab webhook URLSecret token 정보를 기입합니다.
본 테스트에서는 master 브랜치로 push 이벤트가 발생했을 때 webhook이 실행되도록 설정했습니다.

Pipeline - 매개변수 설정

작업의 편리성을 위해 아래에서 수행할 매개변수를 기입해줍니다.

  1. GIT_CREDENTIALS_ID
  2. ZIP_NAME
  3. BUILD_PATH
  4. WORKING_PATH
  5. GIT_URL
  6. SSH_CONFIG_NAME

Pipeline - 스크립트 작성

다시 Jenkins Pipeline 작업으로 돌아와서 Pipeline script에 실행할 내용을 작성합니다.

Pipeline의 절차는 다음과 같습니다.

  1. Git Clone
    - 해당 git url로부터 소스 코드를 가져와 Jenkins의 workspace에 저장합니다.
  2. Create Zip File
    - 해당 workspace의 전체 폴더 및 파일을 zip으로 압축합니다. (deploy-entrypoint.sh 제외)
  3. Copy Zip File & Deploy
    - Publish Over SSH를 통해 소스를 넘겨주도록 합니다.
    - 압축한 zip 파일과 deploy-entrypoint.sh 파일을 전달한 뒤, deploy-entrypoint.sh를 실행합니다.
  4. Delete Zip File
    - 배포가 끝난 후에 Jenkins 서버에 존재하는 zip 파일은 삭제하도록 하겠습니다.
pipeline {
    agent any
    
    stages {
        stage('Git Clone') {
            steps {
                script {
                    try {
                        git url: "$GIT_URL", branch: "master", credentialsId:"$GIT_CREDENTIALS_ID" 
                        sh "sudo rm -rf ./.git"
                        env.cloneResult=true
                    } catch (error) {
                        print(error)
                        env.cloneResult=false
                        currentBuild.result='FAILURE'
                    }
                } 
            }
        }
        stage('Create Zip File') {
            when {
                expression {
                    return env.cloneResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/
                }
            }
            steps {
                script {
                    try {
                        sh "zip -9 -r $ZIP_NAME . -x deploy-entrypoint.sh"
                        env.createZipResult=true
                    } catch (error) {
                        print(error)
                        env.createZipResult=false
                        currentBuild.result='FAILURE'
                    }
                    
                }
            }
        }
        stage('Copy Zip File & Deploy') {
            when {
                expression {
                    return env.createZipResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/
                }
            }
            steps([$class: 'BapSshPromotionPublisherPlugin']) {
                sshPublisher(
                    continueOnError: false, failOnError: true,
                    publishers: [
                        sshPublisherDesc(
                            configName: "$SSH_CONFIG_NAME",
                            verbose: true,
                            transfers: [
                                sshTransfer(
                                    sourceFiles: "**/$ZIP_NAME, **/deploy-entrypoint.sh",
                                    removePrefix: "",
                                    remoteDirectory: "$BUILD_PATH",
                                    execCommand:"cd $BUILD_PATH; \
                                    chmod +x deploy-entrypoint.sh; \
                                    ./deploy-entrypoint.sh $ZIP_NAME $WORKING_PATH dev"
                                )
                            ]
                        )
                    ]
                )
            }
        }
        stage('Delete Zip File') {
            steps {
                script {
                    sh "sudo rm -rf $ZIP_NAME"
                }
            }
        }
    }
}



감사합니다.

profile
자동화가 우리를 자유케 하리라

1개의 댓글

comment-user-thumbnail
2022년 6월 14일

도움이 됐습니다. 감사합니다.

답글 달기