๐ŸŒฑ ์ธํ”„๋Ÿฐ/โš“ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์–ด๋‚˜๋” ํด๋ž˜์Šค (์ง€์ƒํŽธ)

(12) Jenkins Pipeline (๊ธฐ์ดˆ๋ถ€ํ„ฐ Blue/Green ๊นŒ์ง€)

mallin 2025. 6. 14. 22:56

โš“ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์–ด๋‚˜๋” ํด๋ž˜์Šค (์ง€์ƒํŽธ) - Spring 1, 2 ์„ ๋“ฃ๊ณ  ์ž‘์„ฑํ•˜๋Š” ๋ณต์Šต ๋ธ”๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค.

 

(1) ์  ํ‚จ์Šค ํŒŒ์ดํ”„๋ผ์ธ ๊ธฐ๋ณธ ๊ตฌ์„ฑ ๋ฐ ๋ฐฐํฌ ์„ธ๋ถ„ํ™”

Step 1. Jenkins Pipeline ๊ธฐ๋ณธ ๊ตฌ์„ฑ ๋งŒ๋“ค๊ธฐ

1-1. ์ƒˆ๋กœ์šด item ๋งŒ๋“ค๊ธฐ

  • item name ์ž…๋ ฅ ๋ฐ Pipeline ์„ ํƒ

 

1-2. Pipeline Script

๋”๋ณด๊ธฐ
pipeline {
    agent any
    tools {
	        gradle 'gradle-7.6.1'
        jdk 'jdk-17'
    }

    environment {
        DOCKERHUB_USERNAME = "soyeon207"
        GITHUB_USERNAME = "soyeon207"

        // ์•„๋ž˜ ๋ถ€๋ถ„ ์ˆ˜์ •(x)
        GITHUB_URL = "https://github.com/${GITHUB_USERNAME}/kubernetes-anotherclass-sprint2.git"
        CLASS_NUM = '2211'
    }

    stages {
        stage('Source Build') {
            steps {
                // ์†Œ์ŠคํŒŒ์ผ ์ฒดํฌ์•„์›ƒ (Source Repo๋Š” ๋ณ€๊ฒฝ์—†์ด ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ)
                git branch: 'main', url: 'https://github.com/k8s-1pro/kubernetes-anotherclass-api-tester.git'

                // ์†Œ์Šค ๋นŒ๋“œ
                // 755๊ถŒํ•œ ํ•„์š” (์œˆ๋„์šฐ์—์„œ Git์œผ๋กœ ์†Œ์Šค ์—…๋กœ๋“œ์‹œ ๊ถŒํ•œ์€ 644)
                sh "chmod +x ./gradlew"
                sh "gradle clean build"
            }
        }

        stage('Container Build') {
            steps {	
                // ๋ฆด๋ฆฌ์ฆˆํŒŒ์ผ ์ฒดํฌ์•„์›ƒ
                checkout scmGit(branches: [[name: '*/main']], 
                extensions: [[$class: 'SparseCheckoutPaths', 
                sparseCheckoutPaths: [[path: "/${CLASS_NUM}"]]]], 
                userRemoteConfigs: [[url: "${GITHUB_URL}"]])

                // jar ํŒŒ์ผ ๋ณต์‚ฌ
                sh "cp ./build/libs/app-0.0.1-SNAPSHOT.jar ./${CLASS_NUM}/build/docker/app-0.0.1-SNAPSHOT.jar"

                // ์ปจํ…Œ์ด๋„ˆ ๋นŒ๋“œ ๋ฐ ์—…๋กœ๋“œ
                sh "docker build -t ${DOCKERHUB_USERNAME}/api-tester:v1.0.0 ./${CLASS_NUM}/build/docker"
                // ์˜์ƒ๊ณผ ๋‹ฌ๋ฆฌ if๋ฌธ์ด ์—†์–ด์ง€๊ณ  ํ•ญ์ƒ ๋ณธ์ธ์˜ Docker Hub์—์„œ ๋นŒ๋“œ๊ฐ€ ๋˜๋„๋ก ์ˆ˜์ • ๋จ
                sh "docker push ${DOCKERHUB_USERNAME}/api-tester:v1.0.0"
            }
        }

        stage('K8S Deploy') {
            steps {
                // ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฐฐํฌ 
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/namespace.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/configmap.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/secret.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/service.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/deployment.yaml"
            }
        }
    }
}

 

1-3. [์ง€๊ธˆ ๋นŒ๋“œ] ์‹คํ–‰ ํ›„ Stage View ๊ฒฐ๊ณผ ํ™•์ธ

 

1-4. Jenkins Pipeline ๊ตฌ์กฐ ์ดํ•ด

 

  • stage ๊ฐ€ ๊ฐ๊ฐ์˜ ํŒŒ์ดํ”„๋ผ์ธ
  • agent any
    • ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰, Dockerfile ๋นŒ๋“œ, Yaml ๋ฐฐํฌ ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๊ฐ๊ฐ Agent ํ˜•ํƒœ๋กœ ์ œ๊ณต
    • ์ด ํŒŒ์ดํ”„๋ผ์ธ์— ์–ด๋–ค Agent ๋ฅผ ๋„ฃ์–ด๋„ ๋œ๋‹ค๋ผ๊ณ  ์„ค์ •

 

  • ์œ„์™€ ๊ฐ™์€ ํ˜•์‹์€ ์  ํ‚จ์Šค๋ฅผ master, slave ๋กœ ๋‚˜๋ˆ ์„œ ์„ค์น˜ํ–ˆ์„ ๋•Œ slave ์—์„œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋Œ๋ฆฌ๊ฒ ๋‹ค๋Š” ์˜๋ฏธ
  • ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ script ๋ฅผ ๋Œ๋ฆด๋ ค๊ณ  ํ•  ๋•Œ node ๋ฅผ ๋ถ„์‚ฐ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ

Step 2. Github ์—ฐ๊ฒฐ ๋ฐ ํŒŒ์ดํ”„๋ผ์ธ ์„ธ๋ถ„ํ™”

2-1. item name ์ž…๋ ฅ ๋ฐ Pipeline ์„ ํƒ

 

2-2. Pipeline ์„ค์ •

General > GitHub project

 

Advanced Project Options > Pipeline

 

  • SCM : Source Code Management

 

  • Path : 2212 : 2212 ํด๋”๋ฅผ ์‚ฌ์šฉ
  • 2212/Jenkinsfile : 2212 ํด๋”์˜ Jenkinsfile ํŒŒ์ผ์„ ์‚ฌ์šฉ

 

2-3. ์ง€๊ธˆ ๋นŒ๋“œ ์‹คํ–‰

 

ERROR: [ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ํ•จ๊ป˜ ๋นŒ๋“œ]์— GITHUB_USERNAME๋ฅผ ๋ณธ์ธ์˜ username์œผ๋กœ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”! ๋งค๋ฒˆ ์ž…๋ ฅ์ด ๋ฒˆ๊ฑฐ๋กญ๋‹ค๋ฉด Jenkinsfile์—์„œ parameters์— ์ž…๋ ฅ ํ•ญ๋ชฉ์„ ์‚ญ์ œ ํ•˜์‹œ๊ณ  environment์— ์ „์—ญ๊ฐ’์„ ๋„ฃ์€ ํ›„ ํ•ด๋‹น ์กฐ๊ฑด๋ฌธ์€ ์‚ญ์ œํ•ด ์ฃผ์„ธ์š”. Finished: FAILURE

 

https://github.com/soyeon207/kubernetes-anotherclass-sprint2/blob/main/2212/Jenkinsfile

 

kubernetes-anotherclass-sprint2/2212/Jenkinsfile at main · soyeon207/kubernetes-anotherclass-sprint2

[โš“์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์–ด๋‚˜๋” ํด๋ž˜์Šค (์ง€์ƒํŽธ) - ๐Ÿ“—Sprint2]. Contribute to soyeon207/kubernetes-anotherclass-sprint2 development by creating an account on GitHub.

github.com

 

→ Jenkinsfile ์—์„œ Username ํ™•์ธ stage ์—์„œ DOCKERHUB_USERNAME ์ด๋‚˜ GITHUB_USERNAME๊ฐ€ ์—†์œผ๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒํ•˜๋„๋ก ๋˜์–ด ์žˆ์Œ

 

2-4. ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ํ•จ๊ป˜ ๋นŒ๋“œ

 

 


Step 3. Blue/Green ๋ฐฐํฌ ๋งŒ๋“ค๊ธฐ ๋ฐ ํŠน์ง• ์‹ค์Šต

3-1. item name ์ž…๋ ฅ ๋ฐ Pipeline ์„ ํƒ

  • item name : 2213-jenkins_pipeline-step3
  • Copy from : 2212-jenkins_pipeline-step2

 

3-2. Additional Behaviours ๋ฐ Script Path ์ˆ˜์ •

 

3-3. ์•ฑ ๋นŒ๋“œ

Blue ๋ฐฐํฌ ์‹œ [App Version] : Api Tester v1.0.0

๋ฐฐํฌ ์‹œ์ž‘์— ๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ฆฌ๋ฉด ์ˆ˜๋™๋ฐฐํฌ ์‹œ์ž‘ ๊ฐ€๋Šฅ

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค Green ๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์ƒˆ๋กœ์šด ํŒŒ๋“œ๊ฐ€ ๋œจ๊ณ  V2 Service ํ˜ธ์ถœ ๊ฐ€๋Šฅ

Green ์ „ํ™˜ → ํŠธ๋ž˜ํ”ฝ์ด ๋ฐ”๋กœ v2.0.0 ์œผ๋กœ ๋ณ€๊ฒฝ

 

 

๋ชจ๋‹ˆํ„ฐ๋ง ํ›„ ๋กค๋ฐฑ๋ฒ„ํŠผ์œผ๋กœ v1 ์œผ๋กœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ


4. Blue/Green ์ž๋™ ๋ฐฐํฌ script ๋งŒ๋“ค๊ธฐ

4-1. item name ์ž…๋ ฅ ๋ฐ Pipeline ์„ ํƒ

  • item name : 2213-jenkins_pipeline-step4
  • Copy from : 2212-jenkins_pipeline-step3

4-2. Additional Behaviours ๋ฐ Script Path ์ˆ˜์ •

  • 2214
  • 2214/Jenkinsfile

 

4-3. ์ž๋™๋ฐฐํฌ ์‹œ์ž‘

  • Pod ๊ฐ€ Ready ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ํŠธ๋ž˜ํ”ฝ์ด ์ „ํ™˜๋œ๋‹ค

(2) Blue/Green ๋ฐฐํฌ์‹œ ๊ณ ๋ คํ•ด์•ผํ•  ์š”์†Œ

  1. Blue-Green ๋ฐฐํฌ๋ฅผ ๊ณ ๋ คํ•œ Deployment ๋„ค์ด๋ฐ ํ•„์š”
  2. Blue-Green ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€ ๋ ˆ์ด๋ธ” ๋ฐ ์…€๋ ‰ํ„ฐ ํ•„์š”

 

  1. Green Deployment ์ƒ์„ฑ
    1. ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ Service ์ƒ์„ฑ
    2. ์ƒˆ ์„œ๋น„์Šค๋Š” Green Pod ์— ์—ฐ๊ฒฐ๋˜๋„๋ก ์„ค์ •
  2. Service ์˜ Selector (blue-green-no) ๋ฅผ 2๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ํŠธ๋ž˜ํ”ฝ์„ Green ์œผ๋กœ ์ „ํ™˜
    1. Selector ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํŠธ๋ž˜ํ”ฝ์ด ์ „ํ™˜๋œ๋‹ค
    2. Green ๋ฐฐํฌ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค๊ณ  ํŒ๋‹จ๋˜๋ฉด → 3
  3. Blue Deployment, Green Service ์‚ญ์ œ ๋ฐ ๊ด€๋ จ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค์˜ ๋ ˆ์ด๋ธ” ์ •๋ณด ๋ณ€๊ฒฝ (version)
    1. ๊ณตํ†ต ๋ฆฌ์†Œ์Šค์—๋„ ๋ฒ„์ „ ์ •๋ณด ๋ณ€๊ฒฝ
    2. ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๋ฅผ ์ฑ™๊ธฐ๊ธฐ์—” ์–ด๋ ค์›€ → Helm ์‚ฌ์šฉ
  4. Rollback
    1. blue-green-no ๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋œ๋‹ค

 

stage('์ฟ ๋ฒ„๋„คํ‹ฐ์Šค Blue๋ฐฐํฌ') {
            steps {
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/namespace.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/configmap.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/secret.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/service.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/blue/deployment.yaml"
            }
}
  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— Blue ๋ฐฐํฌ๋ฅผ ์„ค์ •ํ•ด ๋†“๋Š” ๋ถ€๋ถ„
  • apply ๋กœ ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ
    • create ๋„ ์žˆ์ง€๋งŒ create ๋Š” ๋ช…๋ น์–ด๋ฅผ ๋‚ ๋ฆฌ๊ณ  ๊ธฐ์กด์— ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ์œผ๋ฉด ์‹คํŒจ๋ฅผ ํ•œ๋‹ค
    • apply ๋Š” ์žˆ์œผ๋ฉด ์—…๋ฐ์ดํŠธ

 

  stage('๋ฐฐํฌ ์‹œ์ž‘') {
      steps {
          input message: '์ˆ˜๋™๋ฐฐํฌ ์‹œ์ž‘', ok: "Yes"
      }
  }
  • ์ˆ˜๋™ ๋ฐฐํฌ๋ฅผ ํ•  ์ง€ ๋ฉ”์„ธ์ง€ ๋ฐ•์Šค๋ฅผ ๋งŒ๋“œ๋Š” ์ฝ”๋“œ
  • ๋‹ค์Œ์Šคํ…์œผ๋กœ ๋„˜์–ด๊ฐ€๋Š” ์—ญํ• 

 

stage('์ „ํ™˜์—ฌ๋ถ€ ํ™•์ธ') {
    steps {
        script {
            returnValue = input message: 'Green ์ „ํ™˜?', ok: "Yes", parameters: [booleanParam(defaultValue: true, name: 'IS_SWITCHED')]
            if (returnValue) {
                sh "kubectl patch -n anotherclass-221 svc api-tester -p '{\"spec\": {\"selector\": {\"blue-green-no\": \"2\"}}}'"
            }
        }
    }
}
  • patch ๋Š” ์ˆ˜์ •ํ•˜๋ผ๋Š” ๋ช…๋ น์–ด
  • -p ์†์„ฑ์„ ์ค˜์„œ ํŠน์ • ์†์„ฑ๋งŒ ๋ณ€๊ฒฝํ•ด์•ผํ•  ๋•Œ ์‚ฌ์šฉ

 


์ด๋ฏธ์ง€ ์ถœ์ฒ˜ URL : 
https://inf.run/k7mF