Jenkins Pipeline (기초부터 Blue/Green까지)

appti·2024년 4월 10일
0

쿠버네티스 인강

목록 보기
12/15

서론

해당 글은 일프로 님의 인프런 강의 쿠버네티스 어나더 클래스 (지상편) - Sprint 1, 2의 내용을 정리한 글입니다.

해당 글에 사용된 내용, 사진 및 그림은 모두 강의와 강의 자료에 포함된 내용입니다.

젠킨스 파이프라인 기본 구성 및 배포 세분화

step1

  • 파이프라인 생성
pipeline {
    agent any

    // 전역적으로 JDK 및 gradle 설정
    tools {
        gradle 'gradle-7.6.1'
        jdk 'jdk-17'
    }

    // 환경 변수
    environment {
        DOCKERHUB_USERNAME = '<username>'
        GITHUB_URL = 'https://github.com/<username>/kubernetes-anotherclass-sprint2.git'
        // deployment.yaml -> image: 1pro/api-tester:v1.0.0        

        // 실습 넘버링 - (수정x)
        CLASS_NUM = '2211'
    }

    stages {
        stage('Source Build') {
            steps {
                // 소스파일 체크아웃
                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"
                script{
                    if (DOCKERHUB_USERNAME == "1pro") {
                        echo "docker push ${DOCKERHUB_USERNAME}/api-tester:v1.0.0"
                    } else {
                        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"
            }
        }
    }
}
  • 스크립트 작성
    • Pipeline Syntax를 참고하며 진행

  • 빌드 확인

구조 이해

  • 젠킨스 파이프라인의 경우 agent 형태로 기능 제공
    • 필수 값
    • 현재 agent any를 통해 파이프라인에 모든 agent 허용

  • 젠킨스를 마스터-슬레이브 구조로 했을 때 사용할 수 있는 방식
    • 지정한 노드(slave)에서 스크립트를 실행시키겠다는 의미
    • 한 번에 여러 스크립트를 실행해야 할 때 부하를 분산하기 위해 사용

step2

  • 파이프라인 생성

  • github project 입력

  • Pipeline script from SCM 설정

  • 빌드 확인

블루/그린 수동 배포

실습

  • 기존 파이프라인 복사

  • 2212에서 2213으로 변경
while true; do curl http://192.168.56.30:32213/version; sleep 1; echo '';  done;
  • 마스터 노드에서 버전 조회 시작

  • 지금 빌드 후 수동배포 시작 yes 선택
    • 버전 1(블루)이 동작하는 상황

  • Green 전환 yes 선택
    • 트래픽 전환
    • 버전 2(그린)가 동작하는 상황
    • 블루 서버 삭제

  • 블루에서 그린으로 트래픽을 변경하면서 그린 기준으로 트래픽이 갑자기 몰리게 되었으므로 모니터링을 통해 상태 확인 필요
    • 그린의 상태에 따라 롤백을 할지 배포를 종료할지 선택

필요한 요소

  1. Blue-Green배포를 고려한 Deployment 네이밍 필요
    1-1. 배포를 수행할 때 마다 새로운 Deployment가 생성되기 때문에 이를 관리할 네이밍 필요
    1-2. 그림에서는 간단하게 시퀀스 번호를 통해 표현
  2. Blue-Green 배포를 위한 추가 레이블 및 셀렉터 필요
    2-1. 배포를 수행할 때 마다 새로운 파드가 생성되며 Blue 서버에서 Green 서버가 동작하면 트래픽을 변경하기 위해 셀렉터를 지정해줘야 하기 때문

  1. Green Deployment 생성 & 테스트를 위한 서비스 생성
    1-1. 서비스는 Green 파드와 연결
    1-2. ConfigMap과 Secret은 공통으로 사용
  2. 서비스의 셀렉터 blue-green-no를 2로 변경해 트래픽을 Green 파드로 변경
  3. Green 파드의 기동 결과에 따라 후처리 진행
    3-1. Green 파드가 정상적으로 기동되었다면 Blue Deployment, Green Service 삭제 및 관련 모든 리소스의 레이블 정보 변경
    3-2. Green 파드에 문제가 발생했다면 배포 롤백

젠킨스 스크립트 확인

pipeline {
    agent any

    environment {
        // 본인의 username으로 하실 분은 수정해주세요.
        GITHUB_URL = 'https://github.com/k8s-1pro/kubernetes-anotherclass-sprint2.git'

        // 실습 넘버링
        CLASS_NUM = '2213'
    }

    stages {
        stage('릴리즈파일 체크아웃') {
            steps {
                checkout scmGit(branches: [[name: '*/main']],
                        extensions: [[$class: 'SparseCheckoutPaths',
                                      sparseCheckoutPaths: [[path: "/${CLASS_NUM}"]]]],
                        userRemoteConfigs: [[url: "${GITHUB_URL}"]])
            }
        }

        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"
            }
        }

        stage('배포 시작') {
            steps {
                input message: '수동배포 시작', ok: "Yes"
            }
        }

        stage('쿠버네티스 Green배포') {
            steps {
	        	sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/green/deployment.yaml"
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/green/service.yaml"
            }
        }

        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\"}}}'"
                    }
                }
            }
        }

        stage('롤백 확인') {
            steps {
                script {
                    returnValue = input message: 'Blue 롤백?', parameters: [choice(choices: ['done', 'rollback'], name: 'IS_ROLLBACk')]
                    if (returnValue == "done") {
                        sh "kubectl delete -f ./${CLASS_NUM}/deploy/k8s/blue/deployment.yaml"
                        sh "kubectl delete -f ./${CLASS_NUM}/deploy/k8s/green/service.yaml"
                        sh "kubectl patch -n anotherclass-221 svc api-tester -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
                        sh "kubectl patch -n anotherclass-221 cm api-tester-properties -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
                        sh "kubectl patch -n anotherclass-221 secret api-tester-postgresql -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
                    }
                    if (returnValue == "rollback") {
                        sh "kubectl patch -n anotherclass-221 svc api-tester -p '{\"spec\": {\"selector\": {\"blue-green-no\": \"1\"}}}'"
                    }
                }
            }
        }
    }

}
  • 쿠버네티스 배포 시
    • create : 기존 리소스가 있을 때 실패
    • apply : 리소스가 없다면 생성, 있다면 리소스 업데이트
    • 주로 apply 명령어 사용
  • 배포 시작
    • input을 통해 파이프라인 진행을 막음
  • 스크립트 변경
    • patch 명령어 사용
    • -f : 지정한 스크립트 자체를 변경하는 옵션
    • -p : 특정 속성만 변경하는 옵션

블루/그린 자동 배포

  • 기존 파이프라인 복사

  • 2213에서 2214로 변경
while true; do curl http://192.168.56.30:32214/version; sleep 1; echo '';  done;
  • 마스터 노드에서 버전 조회 시작

  • 빌드 시작
    • 버전 1이 트래픽 처리

  • 자동 배포 시작
    • 배포 성공 후 Green 파드가 모두 기동되면 버전 2가 트래픽 처리
    • 이후 Blue에 해당하는 리소스 삭제

리소스 리뷰

  1. Green Deployment 생성
  2. 파드를 조회해서 ready 상태인지 확인
  3. 서비스의 셀렉터를 2로 변경해 트래픽을 Green 파드로 변경
  4. Blue Deployment 삭제 & 관련 모든 리소스 레이블 변경

젠킨스 스크립트 확인

pipeline {
    agent any
    
    environment {
        // 본인의 username으로 하실 분은 수정해주세요.
        GITHUB_URL = 'https://github.com/k8s-1pro/kubernetes-anotherclass-sprint2.git'

        // 실습 넘버링
        CLASS_NUM = '2214'
    }

    stages {
        stage('릴리즈파일 체크아웃') {
            steps {
                checkout scmGit(branches: [[name: '*/main']],
                        extensions: [[$class: 'SparseCheckoutPaths',
                                      sparseCheckoutPaths: [[path: "/${CLASS_NUM}"]]]],
                        userRemoteConfigs: [[url: "${GITHUB_URL}"]])
            }
        }

        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"
            }
        }

        stage('자동배포 시작') {
            steps {
                input message: '자동배포 시작', ok: "Yes"
            }
        }

        stage('쿠버네티스 Green배포') {
            steps {
                sh "kubectl apply -f ./${CLASS_NUM}/deploy/k8s/green/deployment.yaml"
            }
        }

        stage('Green 배포 확인중') {
            steps {
                script {
                    def returnValue
                    while (returnValue != "true true"){
                        returnValue = sh(returnStdout: true, encoding: 'UTF-8', script: "kubectl get -n anotherclass-221 pods -l instance='api-tester-2214',blue-green-no='2' -o jsonpath='{.items[*].status.containerStatuses[*].ready}'")
                        echo "${returnValue}"
                        sleep 5
                    }
                }
            }
        }

        stage('Green 전환 완료') {
            steps {
                sh "kubectl patch -n anotherclass-221 svc api-tester-2214 -p '{\"spec\": {\"selector\": {\"blue-green-no\": \"2\"}}}'"
            }
        }

        stage('Blue 삭제') {
            steps {
                sh "kubectl delete -f ./${CLASS_NUM}/deploy/k8s/blue/deployment.yaml"
                sh "kubectl patch -n anotherclass-221 svc api-tester-2214 -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
                sh "kubectl patch -n anotherclass-221 cm api-tester-2214-properties -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
                sh "kubectl patch -n anotherclass-221 secret api-tester-2214-postgresql -p '{\"metadata\": {\"labels\": {\"version\": \"2.0.0\"}}}'"
            }
        }
    }
}
  • Green 배포 확인
    • steps에 scripts를 통해 반복문(while) 사용
    • sleep을 통해 일정 주기마다 해당하는 파드가 동작하는지 확인하는 식으로 배포 확인
      • instance='api-tester-2214',blue-green-no='2' : Green으로 배포한 파드
      • -o 옵션을 통해 파드 내부 상태 조회
        • .items[*].status.containerStatuses[*].ready}를 통해 파드 기동 확인
  • 주의 사항
    • 현재 배포 방식은 교육용일 뿐 현업에서 사용하기에는 무리가 있음
    • 현업에서는 별도의 배포 툴을 사용하며, 강의에서는 ArgoCD 사용
profile
안녕하세요

0개의 댓글