1) Kaoni Cloud/CI CD

10. Jenkins와 ArgoCD 연동

러시안블루 크레아 의 집 2024. 6. 10. 15:01

이제 CI/CD 마지막 chapter 이다.

이번 chapter에서는 Jenkins와 ArgoCD 연동하여 CI/CD를 완성시킬 것이다.

앞선 지시대로 이행하며 잘 따라왔다면, 이번 chapter 에서는 특별히 할 게 없다. 

각 모듈(Jenkinsfile, GitOps, ArgoCD) 을 잘 연결해서 올바르게 동작하는 지 확인할 것이다.

 

 

아래의 CI/CD flow를 참고하면 Jenkinsfile을 이해하는데 도움이 될 것이다.

 

 

 


1. Jenkinsfile에 stage 추가

 1) Jenkinsfile 작성

import java.text.SimpleDateFormat;
import java.util.Date;

def microServiceName = "ezapprovalg"
def packageName = "ezApprovalG"
def imgRegistry  = "10.0.50.10:31110"   // Kaoni Cloud NEXUS
def sonarqube = "http://10.0.50.10:31373"
def gitops = "gitlab-msa2.kaoni.com/msa1.0/gitops/ezApprovalG.git"
def today = new SimpleDateFormat("yyyyMMdd").format(new Date())


podTemplate(
    containers: [
        containerTemplate(name: 'jnlp', image: 'jenkins/inbound-agent:latest', resourceRequestMemory: '512Mi', resourceRequestCpu: '500m', workingDir: '/home/jenkins/agent'),
        containerTemplate(name: 'docker', image: 'docker:24-dind', resourceRequestMemory: '2Gi',  resourceRequestCpu: '500m', ttyEnabled: true, command: 'dockerd-entrypoint.sh', privileged: true),
        containerTemplate(name: 'maven', image: 'maven:3.8.8-ibmjava-8', resourceRequestMemory: '256Mi', resourceRequestCpu: '500m', ttyEnabled: true, command: 'cat'),
        containerTemplate(name: 'kustomize', image: 'alpine/git', resourceRequestMemory: '256Mi', resourceRequestCpu: '200m', ttyEnabled: true, command: 'cat'),
        containerTemplate(name: 'sonarqube-scanner', image: 'sonarsource/sonar-scanner-cli:latest', resourceRequestMemory: '256Mi', resourceRequestCpu: '200m', ttyEnabled: true, command: 'cat')
    ],
    volumes: [
        persistentVolumeClaim(mountPath: '/root', claimName: 'maven-jenkins-pvc'),
        secretVolume(secretName: 'docker-config', mountPath: '/etc/docker')
    ]
) {
    node(POD_LABEL) {
        stage("1. Checkout") {
            checkout scm
        }

        stage("2. Maven build") {
            container('maven') {
                script {
                        sh "cd ${packageName} && mvn clean package -DskipTests=true"
                        sh "mkdir ROOT && cd ROOT && jar xvf ../${packageName}/output/ezFlow.war"
                        echo "Maven build completed"
                }
            }
        }

        stage("3. SonarQube Analysis and Quality Gate Check") {
            container('sonarqube-scanner') {
                script {
                    withSonarQubeEnv('SonarQube') {
                        withCredentials([string(credentialsId: 'sonarqubeToken', variable: 'SONARQUBE_TOKEN')]) {
                            sh """
                                sonar-scanner \
                                -Dsonar.projectKey=${microServiceName} \
                                -Dsonar.sources=${packageName} \
                                -Dsonar.host.url=${sonarqube} \
                                -Dsonar.token=${SONARQUBE_TOKEN} \
                                -Dsonar.java.binaries=${packageName}/output/classes \
                                -Dsonar.java.libraries=ROOT/WEB-INF/lib \
                                -Dsonar.sourceEncoding=UTF-8
                            """
                        }
                    }

                    def qualityGate = waitForQualityGate()
                    echo "Status: ${qualityGate.status}"
                    if (qualityGate.status != 'OK') {
                        error "Pipeline aborted due to Quality Gate failure: ${qualityGate.status}"
                    } else {
                        echo "Quality Gate passed: ${qualityGate.status}"
                    }
                }
            }
        }

        stage("4. Docker build") {
            container('docker') {
                script {
                    sh "docker build -t ${microServiceName}:${today}bn${env.BUILD_NUMBER} ."
                    echo "Docker build completed"
                }
            }
        }

        stage("5. Push Docker Image to Kaoni Cloud Nexus") {
            container('docker') {
                script {
                    withCredentials([[$class: 'UsernamePasswordMultiBinding',
                        credentialsId: 'kcr-credential',
                        usernameVariable: 'USERNAME',
                        passwordVariable: 'PASSWORD'
                    ]]) {
                        sh "docker login ${imgRegistry} -u ${USERNAME} -p ${PASSWORD}"
                        sh "docker tag ${microServiceName}:${today}bn${env.BUILD_NUMBER} ${imgRegistry}/ktg-${microServiceName}:${today}bn${env.BUILD_NUMBER}"
                        sh "docker push ${imgRegistry}/ktg-${microServiceName}:${today}bn${env.BUILD_NUMBER}"
                        echo "push to Kaoni Cloud Nexus completed"
                    }
                }
            }
        }

        stage("6. Update Manifest and Push to GitOps") {
            container('kustomize') {
                script {
                    withCredentials([[$class: 'UsernamePasswordMultiBinding',
                        credentialsId: 'gitlab-credentials',
                        usernameVariable: 'GIT_USERNAME',
                        passwordVariable: 'GIT_PASSWORD'
                    ]]) {
                        sh "apk add --no-cache kustomize"
                        sh 'git config --global user.email "jenkins@kaoniDevops.com"'
                        sh 'git config --global user.name "Jenkins"'
                        sh "git clone http://${GIT_USERNAME}:${GIT_PASSWORD}@${gitops} gitops"
                        sh "cd gitops/overlays/staging && \
                            kustomize edit set image registry.nexus.com/ktg-${microServiceName}:${today}bn${env.BUILD_NUMBER} && \
                            git add . && \
                            git commit -m \"Update ${microServiceName} image to ${today}bn${env.BUILD_NUMBER}\" && \
                            git push http://${GIT_USERNAME}:${GIT_PASSWORD}@${gitops}"
                        echo "Update Manifest and push to GitOps completed"
                    }
                }
            }
        }
    }
}

 stage("6. Update Manifest and Push to GitOps"

를 추가했다.

 

개발자가 Git 에 App 소스코드를 push하면 Jenkins pipeline이 CI를 진행한다.

Jenkins가 Docker Image build를 완료하면, 해당 Image로 적용해서 새롭게 Deploy를 해야할 것이다. 즉, deploy 하려는 Image의  name:tag 를 해당 Image의 것으로 변경해주어야 함을 의미한다.

 

따라서 Stage("6. Update Menifest and Push to GitOps")가 의미하는 바는 다음과 같다.

1. menifest repo 인 gitOps에서 menifest를 clone 받는다.

2. ./overlays/staging/kustomize.yaml 파일에서 image 의 name:tag 를  registry.nexus.com/ktg-${microServiceName}:${today}bn${env.BUILD_NUMBER}

로 수정(update) 한다.

3. update 된 menifest 를 GitOps에 push 한다.

4. GitOps의 menifest를 기반으로 ArgoCD는 deploy한다.

 

 


#GitOps 구성은 아래에서 확인할 수 있다.

https://crea-russianblue.tistory.com/entry/CI-CD-09-Kubernetes%EC%97%90-ArgoCD-%EB%A1%9C-%EB%B0%B0%ED%8F%AC

 

[CI CD] 09. Kubernetes에 ArgoCD 로 App 배포

지난 chapter에서 Kubernetes에 ArgoCD를 설치하였다.이번 chapter에서는 GitOps menifest Repo를 구성하고,  ArgoCD server Web UI 를 통해 Kubernetes cluster에 App을 배포 할 것이다. 바로 본론으로 들어가자.   1. GitOp

crea-russianblue.tistory.com

 


 

 

 

 2) Jenkins에 Credentials 추가

Jenkins 접속, 로그인

 

 

 

 

Jenkins 관리 클릭

 

 

 

 

 

credential 클릭

 

 

 

 

system 클릭

 

 

 

 

Global credentials 클릭

 

 

 

 

Add Credentials 클릭

 

 

 

kind = username with password 선택

username = [GitLab ID]

passowrd = [Gitlab Password]

ID = gitlab-credentials 입력 

 

아래 Create 클릭

 

 

 

Credential : gitlab-credentials 등록 완료

 

 

 

 

 

 


 

 

 

이로서 모든 준비가 끝났다.

CI CD 10개의 chapter에 걸쳐 Jenkins, ArgoCD, SonarQube 를 이용하여  CI/CD security 까지 구현해냈다.

GitLab에 application 소스코드를 push해서 CI/CD pipeline이  정상적으로 동작하는지 확인해 보자.

 

 

 

 


2.  CI/CD for DevsOps

 1) Jenkins

stage 3. SonarQube의 코드품질 검사

stage 6. GitOps repo에 Image tag를 변경시킨 menifest를 push

 

 

 

 2) SonarQube

SonarQube 서버에서 '코드 품질 분석 결과' 확인

Quality Gate Status = passed    

이므로 Jenkins pipeline - stage 3에서 CI/CD 를 계속 진행해도 된다는 응답을 보낸다.

 

 

 

 3) ArgoCD

Jenkins pipeline - stage 6에서  GitOps의 menifest를 update 했으므로,  ArgoCD는 변화를 감지하고 deploy를 새롭게 진행한다.

성공적으로 deploy 된 모습을 볼 수 있다.

 

 

 

 


 

 

여기까지 따라오느라 고생 많았다.

당신도 이제 DevsOps 엔지니어다.

건투를 빈다.

 

'1) Kaoni Cloud > CI CD' 카테고리의 다른 글

09. Kubernetes에 ArgoCD 로 App 배포  (0) 2024.06.10
08. Kubernetes에 ArgoCD 설치  (0) 2024.06.08
07. Jenkins와 SonarQube 연동  (0) 2024.06.08
06. Kubernetes에 SonarQube 설치  (1) 2024.06.08
05. Jenkins Pipeline 구축  (0) 2024.06.07