๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“š ์‹œ๋ฆฌ์ฆˆ/- Jenkins์™€ Webhook์„ ์ด์šฉํ•œ CICD

[Webhook์„ ์ด์šฉํ•˜์—ฌ CI CD ๊ตฌ์„ฑํ•˜๊ธฐ] - pipeline์œผ๋กœ ๋ฐฐํฌํ•˜๊ธฐ

by Wonit 2021. 8. 31.

ํ•ด๋‹น ๊ธ€์€ Jenkins์™€ Github Webhook์„ ์ด์šฉํ•œ CICD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑํ•˜๊ธฐ ์‹œ๋ฆฌ์ฆˆ ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์‚ฌํ•ญ์€ ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!

 

๋งŒ์•ฝ ํ•ด๋‹น ์‹ค์Šต ๋‚ด์šฉ์˜ ์ฝ”๋“œ๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ ๊นƒํ—ˆ๋ธŒ ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ด์ œ ์ด Jenkins์˜ ๋งˆ์ง€๋ง‰ ์‹œ๊ฐ„์ด ๋˜์—ˆ๋‹ค.

 

์ง€๋‚œ ์‹œ๊ฐ„๊นŒ์ง€ Continous Integration ์„ ์ˆ˜ํ–‰ํ–ˆ์œผ๋‹ˆ ์ด์ œ๋Š” Continous Deploy๋ฅผ ์ˆ˜ํ–‰ํ•ด๋ณด์ž!

 

๋ชฉ์ฐจ

  • jenkins์— pipeline ์ƒ์„ฑํ•˜๊ธฐ
    • item ์ถ”๊ฐ€
    • ์„ค์ • ๋ฐ script ์ž‘์„ฑ
  • ํ…Œ์ŠคํŠธ

 

1. Jenkins์— Pipeline ์ƒ์„ฑํ•˜๊ธฐ

 

์  ํ‚จ์Šค์˜ Pipeline ์€ ์—ฐ์†์ ์ธ ์ด๋ฒคํŠธ & Job ๊ทธ๋ฃน์„ ์˜๋ฏธํ•œ๋‹ค.

 

์šฐ๋ฆฌ๊ฐ€ ๋งŒ์•ฝ ๋ฐฐํฌํ•ด์•ผํ•  ์—ฌ๋Ÿฌ Application ์ด๋‚˜ ๊ด€๋ฆฌํ•ด์•ผํ•  ์ž์›์ด ์žˆ๋‹ค๋ฉด Pipeline Script๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ ๊ธฐ๋Œ€ํ•œ ๋ชฉ์ ์„ ์ด๋ฃฌ๋‹ค.

 

์ฆ‰, ์šฐ๋ฆฌ๊ฐ€ Code Commit ์„ ํ•œ๋‹ค๋ฉด Pipeline ์ด์šฉํ•ด์„œ Webhooks ๋ฅผ ๊ฐ์‹œํ•˜๊ณ  ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

 

Pipeline Script ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ํ•  ๊ฒƒ๋“ค์„ ๋ช…์‹œํ•ด์ฃผ๋Š”๋ฐ, ์ด๋Š” ํ‰๋ฒ”ํ•œ Groovy ํ˜•ํƒœ์˜ ์ฝ”๋“œ ๋ธ”๋Ÿญ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด๋„ ๋œ๋‹ค.

 

Pipeline ์„ ์„ ์–ธํ•  ๋•Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด pipeline ๋ธ”๋ก ๋‚ด๋ถ€์—์„œ ์ •์˜ํ•œ๋‹ค.

 

pipeline {
  // Declarative ์ถ”๊ฐ€
}

 

์ด๋Š” ํ•ญ์ƒ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ ๋‹ค๋ฅธ ๋ธ”๋ก๋“ค์„ ๊ฐ์‹ธ์•ผ ํ•˜๊ณ , ์•„๋ž˜์˜ ๋ธ”๋ก์ด ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

 

  • agent
    • pipeline ์ตœ์ƒ๋‹จ์— ์œ„์น˜ํ•˜์—ฌ, ํŠน์ • job ๋“ค์„ ์ˆ˜ํ–‰ํ•  agent ๋ฅผ ์˜๋ฏธํ•œ๋‹ค
    • ๋Œ€ํ‘œ์ ์œผ๋กœ๋Š” node, docker, kubernetes ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค.
  • stages
    • ํ•˜๋‚˜ ์ด์ƒ์˜ stage๋ฅผ ์ •์˜ํ•˜๋Š”๋ฐ, stage๋Š” ํ•ด๋‹น pipeline ์ด ๋™์ž‘ํ•  ๋•Œ, ์‹คํ–‰๋˜๋Š” ๋‹จ๊ณ„๋ฅผ ์˜๋ฏธํ•œ๋‹ค
    • ๋‚ด๋ถ€์ ์œผ๋กœ steps ๋ฅผ ์ •์˜ํ•ด์ค˜์•ผ ํ•œ๋‹ค
  • environment
    • pipeline ๋‚ด๋ถ€์—์„œ key-value ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜์ด๋‹ค.
  • parameters
    • pipeline ๋‚ด๋ถ€์—์„œ ํŠน์ • ๋…ธ๋“œ, ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ๋•Œ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ณตํ•ด์•ผํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

 

์ด ๊ฐœ๋…๋“ค์„ ๊ฐ€์ง€๊ณ  pipeline ์„ ๊ตฌ์„ฑํ•ด๋ณด์ž!

 

Pipeline Item ์ถ”๊ฐ€ํ•˜๊ธฐ

 

Jenkins ๋Œ€์‹œ๋ณด๋“œ๋กœ ๋“ค์–ด๊ฐ€์„œ ๋‹ค์‹œ ์ƒˆ๋กœ์šด Item ์„ ๋งŒ๋“ค๊ณ  ์ด๋ฒˆ์—๋Š” Pipeline Item์„ ์ถ”๊ฐ€ํ•˜์ž.

 

 

์—ญ์‹œ Github ํ”„๋กœ์ ํŠธ๋ฅผ ์„ ํƒํ•œ ๋’ค, Github Repository์˜ URL์„ ์ ์–ด์ฃผ์ž.

 

๊ทธ๋ฆฌ๊ณ  Pipeline speed/durability ์—์„œ๋Š” Performance-optimized ๋กœ ์„ค์ •ํ•ด์ฃผ๊ณ  Build Trigger๋ฅผ Github hook trigger for GitScm Polling ์œผ๋กœ ์ฒดํฌํ•˜์ž

 

 

Pipeline Script ์ž‘์„ฑํ•˜๊ธฐ

 

jenkins pipeline ์„ ์ถ”๊ฐ€ํ•  ๋•Œ, ์•„๋ž˜์˜ pipeline script ํ•ญ๋ชฉ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜์ž

 

pipeline {
    agent any
    options {
        timeout(time: 1, unit: 'HOURS')
    }
    environment {
        SOURCECODE_JENKINS_CREDENTIAL_ID = 'jenking-github-wh'
        SOURCE_CODE_URL = 'https://github.com/my-research/todo-with-cicd.git'
        RELEASE_BRANCH = 'master'
    }
    stages {
        stage('Init') {
            steps {
                echo 'clear'
                sh 'docker stop $(docker ps -aq)'
                sh 'docker rm $(docker ps -aq)'
                deleteDir()
            }
        }

        stage('clone') {
            steps {
                git url: "$SOURCE_CODE_URL",
                    branch: "$RELEASE_BRANCH",
                    credentialsId: "$SOURCECODE_JENKINS_CREDENTIAL_ID"
                sh "ls -al"
            }
        }

        stage('frontend dockerizing') {
            steps {
                sh "docker build -t todo/frontend ./frontend"
            }
        }

        stage('backend dockerizing') {
            steps {
                sh "pwd"
                dir("./backend"){
                    sh "pwd"

                    sh "gradle clean"
                    sh "gradle bootJar"

                    sh "docker build -t todo/backend ."
                }
            }
        }

        stage('deploy') {
            steps {
                sh '''
                  docker run -d -p 5000:5000 todo/frontend

                  docker run -d -p 8080:8080 todo/backend
                '''
            }
        }
    }
}

 

์ด๋ฅผ ํ•ด์„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

์ตœ์ดˆ์˜ agent ๋Š” any๋กœ ์„ค์ •ํ•ด์„œ ๋ชจ๋“  ์ž‘์—…์„ ์ปค๋ฒ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ , environment ์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ git clone ์„ ํ•  ๋•Œ, ํ•„์š”ํ•œ ์—ฌ๋Ÿฌ ์ •๋ณด๋“ค์„ ์œ„ํ•ด ์ •์˜ํ•ด์คฌ๋‹ค.

 

Init ๋‹จ๊ณ„์—์„œ๋Š” ๊ธฐ์กด์— docker ๊ฐ€ ๋„์›Œ์ ธ ์žˆ๋‹ค๋ฉด ๋ชจ๋“  ๋„์ปค๋ฅผ ๊บผ์ค€๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  Frontend Dockerizing ์ด๋ผ๋Š” stage ์—์„œ clone ํ•œ ๋””๋ ‰ํ† ๋ฆฌ์— ์œ„์น˜ํ•œ Dockerfile ๋“ค์„ ์ด์šฉํ•ด Docker build ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

 

๊ทธ ๋‹ค์Œ Backend Dockerizing ์ด๋ผ๋Š” stage ์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ clone ํ•œ spring boot project ๋ฅผ build ํ•˜๋Š”๋ฐ, ๋นŒ๋“œ์— ์„ฑ๊ณตํ•˜๋ฉด dockerizing ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  deploy ๋ผ๋Š” stage ์—์„œ ์šฐ๋ฆฌ์˜ ๋„์ปค ์ด๋ฏธ์ง€๋“ค์„ ๊ฐ๊ฐ์˜ port ์— ๋งž๊ฒŒ ํฌ์›Œ๋”ฉ ํ•œ ํ›„ run ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด์„œ ์‹คํ–‰์„ ํ•˜๊ฒŒ ๋œ๋‹ค.

 

ํ•ด๋‹น ๋‚ด์šฉ์„ ์ €์žฅํ•˜๊ณ  ๋‚˜์™€์„œ Build Now ๋ฅผ ํด๋ฆญํ•˜์ž!

 

 

๊ทธ๋Ÿผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด Build์— ์„ฑ๊ณตํ•˜๊ณ  ์šฐ๋ฆฌ๊ฐ€ Pipeline ์— ๋ช…์‹œํ•ด๋†“์€ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ์„ฑ๊ณต์ ์œผ๋กœ Job์„ ์‹คํ–‰ํ•˜์˜€๋‹ค.

 

 

์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•ด๋ณด์ž!

 

2. ํ…Œ์ŠคํŠธ

 

์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์ „์— ์ค€๋น„ํ•ด๋†“์€ Nginx๋ฅผ ํ†ตํ•ด์„œ EC2 ์˜ 80 ํฌํŠธ๋กœ ์ ‘์†ํ•˜๋ฉด 5000ํฌํŠธ์˜ ๋„์ปค๋กœ ์ ‘์†ํ•˜๊ฒŒ ๋˜์–ด์„œ ์•„๋ž˜์˜ ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค๊ฐ€ ์ž˜ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

ํ•˜์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค!

 

์šฐ๋ฆฌ๊ฐ€ ํ”„๋ก ํŠธ์—”๋“œ์— ์ ‘์†ํ•˜๋ฉด ์ง€๋‚œ ์‹œ๊ฐ„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋†“์€ import.sql ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฑ์—”๋“œ๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„์™€์•ผ ํ•œ๋‹ค

 

ํ•˜์ง€๋งŒ ๋ณด์ด๋Š”๊ฒƒ ์ฒ˜๋Ÿผ ๋ฐ›์•„์˜ค์ง€ ์•Š๋Š”๋‹ค.

 

ํ˜„์žฌ ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ API ํ˜ธ์ถœ์„ ๋ณด๋‚ด๋Š” ๊ณณ์„ ํ™•์ธํ•ด๋ณด์ž

 

 

ํ˜„์žฌ ํ”„๋ก ํŠธ์—”๋“œ๋Š” 127.0.0.1 ์˜ api/todos๋กœ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

 

์šฐ๋ฆฌ๋Š” ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์ธ Local ์—์„œ๋‚˜ 127.0.0.1๋กœ ๋ช…์‹œํ–ˆ์ง€, ์‹ค ์„œ๋น„์Šค๊ฐ€ ์šด์˜์ค‘์ธ ์„œ๋ฒ„์˜ Backend๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค.

 

์ด ๋ฌธ์ œ๋ฅผ CICD ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ตํ•ด์„œ ํ•ด๊ฒฐํ•ด๋ณด์ž!!

 

frontend ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ํ•ด์„œ SERVER.js ์— ์žˆ๋Š” API ํ˜ธ์ถœ ์ŠคํŽ™์„ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  EC2 ์ธ์Šคํ„ด์Šค์˜ IP๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์ž

 

import axios from "axios";

export const SERVER = axios.create({
  baseURL: "http://3.38.95.48",
  headers: {
    "Content-Type": "application/json",
  },
});

 

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  github๋กœ code push๋ฅผ ํ•œ๋‹ค๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ด์ „์— ์ž‘์„ฑํ•ด๋†“์€ webhooks๊ณผ pipeline script์— ์˜ํ•ด์„œ ์ƒˆ๋กœ์šด ๋ฒ„์ „์ด ์ฆ‰์‹œ ๋ฐฐํฌ๋  ๊ฒƒ์ด๋‹ค!

 

 

์จ˜~

๋Œ“๊ธ€