[식구하자_MSA] Jenkins+Docker+MSA+Spring Boot CI/CD 적용

이민우·2024년 2월 5일
5

🍀 식구하자_MSA

목록 보기
2/21

CI/CD 설계도

지난 포스팅 에 이어 MSA 적용을 하면서, CI/CD 파이프라인을 구축하려 한다.
기존에는 Github Actions을 사용했지만, 프로젝트 규모가 커지다 보면 속도 측면에 Jenkins보다 느리기 때문에 Jenkins로 변경하기로 했습니다.

1️⃣ 구성 요소

  • Jenkins Server : AWS EC2 Ubuntu 18.04
  • Spring Boot Server : AWS EC2 Ubuntu 18.04
  • Github Repository
  • Docker Hub Repository

인스턴스 2개를 팔 예정이다(Jenkins용 , Spring 서버용)
인스턴스 생성하는 과정은 생략할 예정입니다!!

2️⃣ 진행 순서

- Jenkins Server에 Docker 설치
- Jenkins Server에 Docker를 이용하여 Jenkins 실행
- Jenkins 접속
- Jenkins와 Github 연동
- Jenkins와 Docker Hub 연결
- Jenkins Server와 Spring Boot Server SSH 연결 설정
- Jenkins와 Slack 연동
- Jenkins Pipeline 구성
  - Spring Boot Project Github Repository Clone
  - application.yml Jenkins로 관리
  - Gradle Build
  - Docker Build
  - Docker Push
  - Spring Boot Server SSH 연결
     - Docker Pull
     - Docker Run
- Slack Notification

  사전에 Jenkins Server, Spring Boot Server를 위한 AWS EC2 
  인스턴스 2개와 Spring Boot Project가 올라가있는 Github Repository와
  Docker Hub Repository가 생성되어 있어야 한다. 
  대부분의 설정은 Jenkins Server에 접속하여 진행한다. 
  Spring Boot Server는 SSH 연결 설정 시 public key를 등록할 때만 접속한다.

💻 Jenkins Server EC2 구축

1️⃣ EC2 초기 설정 (ubuntu 기준)

sudo apt update
sudo apt upgrade
sudo apt install build-essential

2️⃣ Docker install

1. 기본 설정, 사전 설치

sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common

2. 자동 설치 스크립트 활용

sudo wget -qO- https://get.docker.com/ | sh

3. Docker 서비스 실행 및 부팅 시 자동 실행

sudo systemctl start docker
sudo systemctl enable docker

4. Docker 그룹에 현재 계정 추가

sudo usermod -aG docker ${USER}
sudo systemctl restart docker

3️⃣ Docker로 Jenkins 설치하기

1. Jenkins 이미지 파일 내려받기(lts 버전)

docker pull jenkins/jenkins:lts

2. 내려받아진 이미지 확인

docker images

3. Jenkins 이미지를 Container로 실행

docker run -d -p 8080:8080 -p 50000:50000 -v /jenkins:/var/jenkins -v /home/ubuntu/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock --name jenkins -u root jenkins/jenkins:lts

4. 돌아가고 있는 Container 확인

docker ps

✅ ec2 swap 메모리 설정(선택 사항)

sudo dd if=/dev/zero of=/swapfile bs=128M count=16
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo swapon -s
sudo vi /etc/fstab
/swapfile swap swap defaults 0 0

🤷‍♂️ Jenkins

1️⃣ Jenkins 접속

  1. [ec2 instance URL]:[포트번호(default 8080)]
  2. password 입력
// Container 접속
$ docker exec -it jenkins bash

// 암호 파일 확인
$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword
  1. Install suggested plugins로 플러그인 설치
  2. Jenkins 계정 생성
    Jenkins 메인 대시보드 페이지가 나오면 성공

2️⃣ Jenkins, Github 연동

1. ssh키 생성
Jenkins Container를 생성할 때 "/home/ubuntu/.ssh:/root/.ssh"로 .ssh 디텍도리를 마운트 해놓았기 때문에 Container 밖에서 ssh 키를 생성하면 Jenkins Container와 연결된다.

ssh-keygen

// 아래 사진과 같이 나머지 값들 그냥 전부 enter를 입력해 default로 만든다.

2. Github Deploy Key 등록
만들어 놓은 Github Repository > Settings > Deploy Keys > Add deploy key로 접속한다.

상단 사진 빨간색 박스 표시 참고!

Title은 Jenkins로 지어 주고(임의의 이름), Key 부분에 id_rsa.pub에 들어있는 public key 값을 넣어준다. 아래 명령어로 확인 가능하다.

cd /home/ubuntu/.ssh
cat id_rsa.pub

3. Jenkins Credentials 등록

Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다.

Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다.
왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다.

👉👉global 클릭

  • Kind
    SSH Username with private key
  • ID
    github -> 임의로 지어도 된다. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자
  • Username
    root (default)
  • Private Key
    Enter directly 체크 -> private key 입력
    여기서 private key는 Jenkins Server에서 생성한 id_rsa이다. 아래 명령어로 확인 가능하다.
cd /home/ubuntu/.ssh
cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
...
... 이와 같은 형태의 key가 private key 입니다 ...
...
-----END OPENSSH PRIVATE KEY-----

-----BEGIN OPENSSH PRIVATE KEY-----, -----END OPENSSH PRIVATE KEY----- 이부분도 포함해야한다!

3️⃣ Jenkins, Docker Hub 연결

1. Docker Plugin 설치

Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Docker 검색 > Docker, Docker Pipeline 플러그인 설치 및 재실행

하단 사진 참고

2. Docker Hub Credentials 등록
Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다. (상단 Jenkins Credentials 등록과 같은 방식)
Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다.
왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다.

  • Kind
    Username with password
  • Username
    본인의 Docker Hub ID
  • Password
    본인의 Docker Hub Password
  • ID
    docker-hub -> 임의로 생성. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자.

OK를 눌러 키를 생성

3. Jenkins Container 내부에 Docker 설치
Jenkins Pipeline에서 Docker 명령어를 사용할 수 있도록 Jenkins Container 내부에 Docker를 설치해야 한다.

  • Jenkins Container에 접속
docker exec -it jenkins bash
  • Docker 설치
docker run -d -p 8080:8080 -p 50000:50000 -v 
/jenkins:/var/jenkins -v /home/ubuntu/.ssh:/root/.ssh -v 
/var/run/docker.sock:/var/run/docker.sock --name jenkins -u root 
jenkins/jenkins:lts

Jenkins Container를 가동할 때 위에 처럼 외부 Docker volume을 연결해놓아서 아래처럼 docker.sock 권한 변경만 하면 Container 내부에서 docker 명령어가 사용 가능하다고 하는데 Pipeline Script를 작성하고 Build했더니 docker 명령어 사용 부분에서 command not found 에러가 발생하여 그냥 Container 내부에도 Docker를 설치하였다.
Docker 설치 방법은 위에서 EC2 내에 Docker를 설치한 방법과 동일하다. 다만 Container 내부에 sudo, vi, wget이 설치되어 있지 않아 차례대로 설치 후 Docker를 설치해야 한다.

  • docker.sock 권한 변경
    sudo chmod 666 /var/run/docker.sock

✅ Jenkins Container 내부에 Docker를 설치하는 것에 대하여

  • Docker가 설치되어 있는 Jenkins 이미지 파일을 사용한다.

  • docker exec 명령어로 Jenkins Container 내부로 접속한 다음 내부에 Docker를 설치한다.

  • docker 경로와 docker.sock 파일 경로를 도커 볼륨에 추가해 사용한다.

    • 이 방법을 사용하더라도 Container 내부에 docker-cil는 설치해야 한다는 글을 보았다.

    • 실험 필요.

4️⃣ Jenkins, Spring Boot Server SSH 연결

Jenkins로 Gradle 빌드하고 Dockerfile로 도커 이미지를 빌드해서 Docker Hub에 Push하고 Spring Boot Server에서 도커 이미지를 Pull해서 실행하게 하기 위해 필요하다. Jenkins Pipeline Script에서 SSH를 사용하여 Spring Boot Server의 명령어 실행을 할 수 있도로 하는 것이다.

1. SSH Agent Plugin 설치

Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > SSH Agent 플러그인을 검색하고 설치 및 재실행

2. Spring Boot Server Instance 접속

3. Spring Boot Server의 .ssh/authorized_keys 파일에 Jenkins Server의 public key를 추가

// Jenkins Server에서 public key 확인
$ cat /home/ubuntu/.ssh/id_rsa.pub

// Spring Boot Server에 Jenkins Server public key 추가
$ vi /home/ubuntu/.ssh/authorized_keys

🔎 id_rsa.pub 출력하면 맨 뒤에 유저네임과 ip주소가 나올수도 있다. 상관없이 다 포함해서 Spring Boot Instance에 추가해준다!! 아래 사진과 같이 그리고 Spring Boot Instance authorized_keys 파일에 pem키에 대한 정보가 있을텐데, 그 정보 마지막 줄에서 한 칸 뛰고 id_rsa.pub 키를 추가해주면 된다.

4. Jenkins Credentials 등록

Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다.
Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다.
왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다.

  • Kind
    SSH Username with private key
  • ID
    ssh -> 마음대로 지어도 된다. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자.
  • Username
    root (default)
  • Private Key
    Enter directly 체크 -> private key 입력
    여기서 private key는 Jenkins Server에서 생성한 id_rsa이다. 아래 명령어로 확인 가능하다.
cd /home/ubuntu/.ssh
cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
...
... 이와 같은 형태의 key가 private key 입니다 ...
...
-----END OPENSSH PRIVATE KEY-----
  • OK를 눌러 키를 생성
    사실상 위의 Jenkins와 Github 연동 시 생성한 Jenkins Credentials과 동일하다. 하지만 ID를 구분하여 사용하고자 SSH Credentials을 별도로 생성하였다.

5️⃣ Publish Over SSH 플러그인 설정

Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Publish Over SSH 플러그인을 검색하고 설치 및 재실행

1. Publish Over SSH 플러그인 설정

Jenkins 대시보드 > Jenkins 관리 > System에서 Publish Over SSH 영역의 고급 버튼을 눌러 설정

  • Path to key는 private key의 경로를 입력한다.
    지금까지는 Jenkins Server에서 jenkins 컨테이너에 접속하지 않고 key들을 접근했지만 jenkins는 컨테이너로 실행중이니까 Jenkins Server의 key 경로를 모른다. 즉 /home/ubuntu/.ssh/id_rsa를 입력하면 안된다. 우리는 다행이 Jenkins Server에서 컨테이너를 실행할 때 /home/ubuntu/.ssh를 /root/.ssh와 연결해 놓았기 때문에 /root/.ssh/id_rsa를 입력하면 된다.
  • Key는 private key 값을 넣어주면 된다.
    id_rsa 파일 내용을 복사해서 넣어준다.
  • Name은 접속할 ssh 서버의 이름을 입력한다.(마음대로 지어주세요)
  • Hostname은 접속할 서버의 주소를 넣어주세요.
    Spring Boot Server EC2 인스턴스 URL을 넣어준다.
  • Username은 접속할 유저명을 넣어준다.
    기본 유저인 ubuntu를 입력한다.
  • Test Configuration 버튼을 눌러 정상적으로 연결 되는지 확인한다.
아래 사진 참고

5️⃣ Jenkins, Slack 연동(24년 2월 기준)

  1. Slack Notification Plugin 설치
    Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Slack Notification 플러그인을 검색하고 설치 및 재실행

  2. Slack에 Jenkins 앱 추가
    Slack 앱에서 Slack 찾아보기 > 앱 >jenkins 검색 > jenkins 선택 후 연동을 하면 연동 가이드 웹페이지에 하위 도메인과 토큰이 출력된다. 이를 이용하여 Slack Credentials을 등록한다.

3. Slack Credentials 등록

Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다.
Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다.
왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다
  • Kind
    Secret text
  • Scope
    Global
  • Secret
    Slack에서 jenkins 앱 연동 시 출력된 토큰
  • ID
    slack -> 마음대로 지어도 된다. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자.
  • OK를 눌러 키를 생성

🤷‍♂️ Jenkins Pipeline

이제 드디어 Pipeline을 작성하면 된다. Jenkins 대시보드 > 새로운 Item에서 item name을 입력하고 Pipeline을 선택, OK 버튼을 누른다.

1️⃣ Jenkins, Github Webhook 연동

Github Repository에 push event가 발생했을 때 자동으로 Build가 실행되게 하기 위해 Pipeline과 Github Webhook을 연동해야 한다.

1. Github Integration Plugin 설치
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Github Integration 플러그인을 검색하고 설치 및 재실행

2. Jenkins Pipeline 설정

  • Github project 설정
    Pipeline 구성(톱니바퀴 버튼) > General 영역에서 Github project를 선택한다. Project url에 본인의 Github Repository Url을 입력한다. 이 때 Repository Url은 Clone 시 사용하는 HTTPS Url(.git으로 끝남)을 입력한다.
  • Build Triggers 설정
    Pipeline 구성(톱니바퀴 버튼) > Build Triggers 영역에서 GitHub hook trigger for GITScm polling을 선택한다.

3. Github Webhook 추가
Github Repository에서 Settings > Webhooks > Add Webhook 을 눌러 Webhook을 추가한다.

  • Payload URL
    [Jenkins Server URL]:[Jenkins Server 포트]/github-webhook/
  • Content type
    application/x-www-form-urlencoded
  • 나머지는 모두 default 설정 유지
    -Add webhook 버튼을 눌러 Webhook을 추가 -> 목록에서 녹색 체크 아이콘이 생성되면 성공

2️⃣ Pipeline Script 작성

📌 저는 msa로 진행하여 하나의 브랜치에서 여러개의 마이크로 서비스 폴더를 올렸습니다. 그래서 하나의 프로젝트만 올렸을 때 파이프라인 하나의 브랜치에서 여러 프로젝트를 올렸을 떄 버전 두개를 공유하겠습니다!

👨🏻‍💻 하나의 프로젝트 파이프라인

pipeline {
    agent any

    environment {
        imagename = "docker build로 만들 이미지 이름"
        registryCredential = '위에서 만든 Docker Hub Credential ID'
        dockerImage = ''
    }

    stages {
        stage('Clonning Repository') {
          steps {
            echo 'Clonning Repository'
            git url: 'Github Repository SSH Url(git@github.com로 시작)',
              branch: 'Clone 받아올 Branch 이름',
              credentialsId: '위에서 만든 Github Credential ID -> github'
            }
            post {
             success { 
               echo 'Successfully Cloned Repository'
             }
           	 failure {
               error 'This pipeline stops here...'
             }
          }
        }

        stage('Bulid Gradle') {
          steps {
            echo 'Bulid Gradle'
            dir('.'){
                sh './gradlew build '
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
        
        stage('Bulid Docker') {
          steps {
            echo 'Bulid Docker'
            script {
                dockerImage = docker.build imagename
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }

        stage('Push Docker') {
          steps {
            echo 'Push Docker'
            script {
                docker.withRegistry( '', registryCredential) {
                    dockerImage.push() 
                }
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
        
        stage('Docker Run') {
            steps {
                echo 'Pull Docker Image & Docker Image Run'
                sshagent (credentials: ['SSH Credential ID -> ssh']) {
                    sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker rm -f [컨테이너 이름] || true'"
                     sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker ps -q --filter name=[컨테이너 이름] | grep -q . && docker rm -f \$(docker ps -aq --filter name=[컨테이너 이름])'"
                    sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker run -d --name [컨테이너 이름] -p 8080:8080 [도커이미지 이름]'"
                }
            }
        }
    }
    post {
        success {
            slackSend (channel: '#채널명', color: '#00FF00', message: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
        failure {
            slackSend (channel: '#채널명', color: '#FF0000', message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
    }
}

👨🏻‍💻 하나의 브랜치에서 여러 프로젝트를 올렸을 때

pipeline {
    agent any

    environment {
        imagename = "docker build로 만들 이미지 이름"
        registryCredential = 'Docker Hub Credential ID'
        dockerImage = ''
        sshCredential = 'SSH Credential ID'
    }

  stages {
        stage('Prepare') {
            steps {
                echo 'Cloning Repository'
                script {
                        deleteDir()
                        git branch: 'branch 이름',
                        credentialsId: 'Github Credential ID ',
                        url: 'Github Repository SSH Url(git@github.com로 시작)',
                        changelog: true,
                        poll: false,
                        script: {
                            dir('branch/가져올 프로젝트 폴더 이름') {
                                // Additional steps specific to the folder, if needed
                                echo 'Cloning specific folder: branch/가져올 프로젝트 폴더 이름'
                            }
                        }
                }
            }
            post {
                success {
                    echo 'Successfully Cloned Repository'
                }
                failure {
                    error 'This pipeline stops here...'
                }
            }
        }
     
       stage('Bulid Gradle') {
          steps {
            echo 'Bulid Gradle'
            dir('가져올 프로젝트 폴더 이름/'){
                sh './gradlew build'
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
        
        stage('Bulid Docker') {
          steps {
            echo 'Bulid Docker'
            dir('가져올 프로젝트 폴더 이름/'){
            script {
                dockerImage = docker.build imagename
            }
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }

        stage('Push Docker') {
          steps {
            echo 'Push Docker'
            dir('가져올 프로젝트 폴더 이름/'){
            script {
                docker.withRegistry( '', registryCredential) {
                    dockerImage.push() 
                }
            }
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
        
        stage('Docker Run') {
            steps {
                echo 'Pull Docker Image & Docker Image Run'
                sshagent (credentials: [sshCredential]) {
                       sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker rm -f [컨테이너 이름] || true'"
                       sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker ps -q --filter name=[컨테이너 이름] | grep -q . && docker rm -f \$(docker ps -aq --filter name=[컨테이너 이름])'"
                       sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker run -d --name [컨테이너 이름] -p 8080:8080 [도커이미지 이름]'"
                }
            }
            post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
    }
 post {
        success {
            slackSend (channel: '#채널명', color: '#00FF00', message: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
        failure {
            slackSend (channel: '#채널명', color: '#FF0000', message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
    }
}

✅ 추가 application.yml 같은 비밀정보를 .gitignore 하였을 때, Jenkins를 통한 관리 및 파이프라인

yml파일을 따로 .gitignore 하지 않은분들은 위에 내용까지 진행하시면 됩니다!!

보통 프로젝트를 github에 올리게 된다면, 비밀정보가 들어있는 yml,properties 파일을 .gitignore 시켜서 올립니다. 그런 상황에서 jenkins를 통해 관리하고 파이프라인을 알아보도록 하겠습니다!

1. application.yml Credentials 등록
Jenkins 대시보드 > Jenkins 관리 > Manage Credentials > Credentials에 접속한다.

Store Jenkins에 Domain이 (global)인 화살표를 눌러 Global credentials (unrestricted)로 이동한다. 왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가한다.

  • Kind
    Secret File
  • File
    File 업로드
  • ID
    application.yml -> 마음대로 지어도 된다. 다만 Pipeline Script 작성 시 credentialsId로 사용되니 식별할 수 있도록 하자.
    OK를 눌러 키를 생성

application.yml 추가 Pipeline

pipeline {
    agent any

    environment {
        imagename = "docker build로 만들 이미지 이름"
        registryCredential = 'Docker Hub Credential ID'
        dockerImage = ''
        sshCredential = 'SSH Credential ID'
    }

  stages {
        stage('Prepare') {
            steps {
                echo 'Cloning Repository'
                script {
                        deleteDir()
                        git branch: 'branch 이름',
                        credentialsId: 'Github Credential ID ',
                        url: 'Github Repository SSH Url(git@github.com로 시작)',
                        changelog: true,
                        poll: false,
                        script: {
                            dir('branch/가져올 프로젝트 폴더 이름') {
                                // Additional steps specific to the folder, if needed
                                echo 'Cloning specific folder: branch/가져올 프로젝트 폴더 이름'
                            }
                        }
                }
            }
            post {
                success {
                    echo 'Successfully Cloned Repository'
                }
                failure {
                    error 'This pipeline stops here...'
                }
            }
        }
         stage('secret.yml download') {
            steps {
                withCredentials([file(credentialsId: 'Secret File Credential Id ', variable: 'application')]) {
                    dir('가져올 프로젝트 폴더 이름/') {
                        script {
                            if (!fileExists("src/main/resources/") || !isDirectory("src/main/resources/")) {
                                sh "mkdir -p src/main/resources/"
                            }
                            sh "cp \$application src/main/resources/"
                        }
                    }
                }
            }
        }
     
       stage('Bulid Gradle') {
          steps {
            echo 'Bulid Gradle'
            dir('가져올 프로젝트 폴더 이름/'){
                sh './gradlew clean build -x test'
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
        
        stage('Bulid Docker') {
          steps {
            echo 'Bulid Docker'
            dir('가져올 프로젝트 폴더 이름/'){
            script {
                dockerImage = docker.build imagename
            }
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }

        stage('Push Docker') {
          steps {
            echo 'Push Docker'
            dir('가져올 프로젝트 폴더 이름/'){
            script {
                docker.withRegistry( '', registryCredential) {
                    dockerImage.push() 
                }
            }
            }
          }
          post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
        
        stage('Docker Run') {
            steps {
                echo 'Pull Docker Image & Docker Image Run'
                sshagent (credentials: [sshCredential]) {
                       sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker rm -f [컨테이너 이름] || true'"
                       sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker ps -q --filter name=[컨테이너 이름] | grep -q . && docker rm -f \$(docker ps -aq --filter name=[컨테이너 이름])'"
                       sh "ssh -o StrictHostKeyChecking=no [Spring Boot Server username]@[Spring Boot Server IP 주소] 'docker run -d --name [컨테이너 이름] -p 8080:8080 [도커이미지 이름]'"
                }
            }
            post {
            failure {
              error 'This pipeline stops here...'
            }
          }
        }
    }
 post {
        success {
            slackSend (channel: '#채널명', color: '#00FF00', message: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
        failure {
            slackSend (channel: '#채널명', color: '#FF0000', message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
    }
}

개선할 점

✅ 특정 폴더 push event에만 동작하도록 설정 필요

위와 같은 파이프라인 설정으로는 하나의 프로젝트 폴더만 변경되더라도 다른 모든 모든 프로젝트 폴더에 push event에 Pipeline이 동작하게 된다. 변경사항이 있는 프로젝트만 동작해야하는데, 나머지 프로젝트들도 동작하면 굉장히 리소스 낭비고 비효율적이다. 이 부분에 대해서는 조금 더 공부하고 수정해서 공유해보도록 하겠습니다!

참고

https://hyeinisfree.tistory.com/23
https://jmlim.github.io/docker/2019/02/25/docker-jenkins-setup/
https://kanoos-stu.tistory.com/55?category=1024343
https://repost.aws/ko/knowledge-center/ec2-memory-swap-file

profile
백엔드 공부중입니다!

5개의 댓글

comment-user-thumbnail
2024년 10월 16일

안녕하세요. 혹시 SSH Username with private key Credentials을 Jenkins에 등록할 때 private key는 젠킨스 컨테이너가 실행중인 VM에 ssh 원격 접속을 할 때 사용하는 key로 등록하는 걸까요?

1개의 답글

관련 채용 정보