[DevOps] GitOps 기반의 프로젝트 CI/CD 구축하기

2해승·2024년 12월 29일

쿠버네티스?!

목록 보기
14/16

지난 글에 이어서 GitOps를 기반으로 쿠버네티스 클러스터를 구축하고 Jenkins CI와 ArgoCD를 이용하여 배포 자동화를 구현하는 과정을 정리해보려고 한다.

진행 순서

1. 소스 코드 변경사항 Push

2. Jenkins CI 파이프라인 동작
Webhook을 통해 Jenkins가 자동으로 CI 작업을 실행하며 주요 단계는 다음과 같다.

- Docker Image Build
- Docker Registry Push
- K8S Manifests Update: 별도의 Manifest Repository에서 Kustomize 관련 .yaml 파일을 업데이트하고 Push 한다.
    
3. ArgoCD를 통한 배포
ArgoCD가 Manifest Repository의 변경 사항을 감지하고 이를 바탕으로 쿠버네티스 클러스터에 자동으로 배포한다.

Jenkins CI Pipeline

쿠버네티스를 도입하기 이전의 파이프라인과 비교하면 Jenkins CI에 새로운 과정이 추가되었다. 바로 'K8S Manifest Update'이다.

이 과정은 쿠버네티스 클러스터에서 애플리케이션의 상태를 최신으로 유지하기 위해 매우 중요한 역할을 한다.


K8S Manifest Update

쿠버네티스의 배포 방식은 YAML 형식의 매니페스트 파일과 Helm 차트가 있는데 나의 경우 매니페스트 파일을 통해 애플리케이션의 배포 상태를 정의하였다.

Deployment 객체에 지정된 컨테이너 이미지 태그를 기준으로 애플리케이션 버전을 관리하고 이를 최신 상태로 반영하기 위해 Jenkins 파이프라인에 이 단계를 추가했다.

Manifest Repo: https://github.com/haeseung123/k8s_cicd_prac

쿠버네티스의 Kustomize를 이용한 배포 방식에 대해서는 다른 게시글을 통해 더 자세히 다룰 예정이니 설정 파일이 궁금하시다면 레포지토리를 참고해주세용


Pipeline 동작 과정

젠킨스 파이프라인의 동작과정을 단계별로 정리하면 다음과 같다.

1. Git Clone

stage('git clone') {
    steps {
        git branch: 'develop', changelog: false, credentialsId: 'GitHub-Token', url: "https://github.com/haeseung123/kanbanBoard.git"
    }
}

사전에 등록한 GitHub-Token 크리덴셜을 이용하여 지정된 브랜치에서 소스 코드를 가져온다.

2. Docker Image Build

		stage('Docker Image Build') {
            steps {
                script {
                    sh '/usr/local/bin/docker-compose --env-file .development.env build'
                }
            }
        }

프로젝트의 도커 이미지를 생성한다.

3. Docker Image Push

stage('Docker Image Push') {
    steps {
        script {
            sh "docker tag haeseung/kanban-server haeseung/kanban-server:${VERSION_TAG}"
                    
            withDockerRegistry(credentialsId: 'DockerHub-Token') {
                  sh "docker push haeseung/kanban-server:${VERSION_TAG}"
                  sh 'docker push haeseung/kanban-server:latest'
            }
        }
    }
}

사전에 등록한 DockerHub-Token 크리덴셜을 이용하여 Docker Hub에 이미지를 업로드한다.

이미지를 특정 태그(v1.0.x)로 태깅하고 :latest 태그도 항상 함께 업로드하여 최신 이미지를 유지하도록 했다.

파이프라인 넘버에 맞는 버전으로 허브에 저장된 것을 확인할 수 있다.

4. K8S Manifest Update

stage('K8S Manifest Update'){
    steps {
        script {
            def repoPath = 'k8s_cicd_prac'
            
            // 기존 디렉토리 삭제
            if (fileExists(repoPath)) {
               sh "rm -rf ${repoPath}"
            }
                    
            sh "mkdir ${repoPath}"
            
            dir(repoPath) {
                git branch: 'main', changelog: false, credentialsId: 'GitHub-Token', poll: false, url: 'https://github.com/haeseung123/k8s_cicd_prac.git'
                        
                // deployment-patches.yaml 파일에서 이미지 태그를 최신 빌드 태그로 변경
                sh "sed -i 's|haeseung/kanban-server:.*|haeseung/kanban-server:${VERSION_TAG}|g' overlays/development/deployment-patches.yaml"
                        
                // kustomize.yaml에서 이미지 태그를 동적으로 업데이트
                sh "sed -i 's|newTag: .*|newTag: ${VERSION_TAG}|g' overlays/development/kustomization.yaml"
             
                //
                sh 'git add overlays/development/.'
                sh "git -c user.name='haeseung123' -c user.email='showui96@gmail.com' commit -m 'update image tag to ${VERSION_TAG}'"
                        
                withCredentials([gitUsernamePassword(credentialsId: 'GitHub-Token', gitToolName: 'git-tool')]) {
                sh "git remote set-url origin https://github.com/haeseung123/k8s_cicd_prac.git"
                sh "git push -u origin main"
                }            
            }
        }
    }
}

나는 최신 Docker 이미지 태그를 매니페스트에 반영하기 위해 Manifest Repository를 클론하고 관련 Kustomize yaml 파일의 이미지 태그를 최신 태그로 수정했다.

이후 변경사항에 대하여 Git에 커밋하고 Push 하기까지가 CI 과정이다.


ArgoCD를 이용한 배포

Jenkins 파이프라인에서 최신 버전의 이미지 태그로 업데이트된 Manifest 파일이 Git 저장소에 푸시되면 ArgoCD가 이를 감지하여 클러스터에 배포하도록 구축할 것이다.

이번 과정에서는 Push-Based 전략을 통해 Git 저장소의 변경 사항에 따라 ArgoCD가 배포를 실행하도록 설정하는 방법을 다뤄보겠다.


ArgoCD 구성 준비

ArgoCD 설치

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

설치 확인

초기 패스워드 확인

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

패스워드 변경

파드에 접속하여 초기 비밀번호를 변경할 것인데 로그인시 'admin:초기 패스워드'를 통해 로그인 후 account 명령어를 통해 변경해주면 된다.

$ kubectl exec -it -n argocd deployment/argocd-server -- /bin/bash
$ argocd login localhost:8080
WARNING: server certificate had error: x509: certificate signed by unknown authority. Proceed insecurely (y/n)? y
Username: admin
Password:
'admin:login' logged in successfully

$ argocd account update-password
*** Enter password of currently logged in user (admin):  // 초기 비밀번호
*** Enter new password for user admin:  	 // 변경 비밀번호
*** Confirm new password for user admin:     // 변경 비밀번호
Password updated

ArgoCD 대시보드 접속

ArgoCD의 경우 외부 IP로 노출되지 않기 때문에 별도의 방법을 통해 서버에 엑세스 할 수 있는데, 우선은 port-forward를 통해 접속을 할 수 있도록 해보자.

kubectl port-forward --address=0.0.0.0 svc/argocd-server -n argocd 8080:443

저장소 등록 및 애플리케이션 배포

Git Repository 등록

우선 매니페스트 파일을 관리하는 깃 저장소를 등록해주자.

[Settings] > [Repositories] 페이지로가서 [+CONNECT REPO]를 눌러 등록하기 위한 창을 확인한다.

ArgoCD는 GitOps 방식으로 동작하기 때문에 Git 저장소의 매니페스트 파일을 기준으로 애플리케이션의 배포 상태를 관리한다.

때문에 관련 Git Repository와 연결을 설정하면 ArgoCD는 해당 저장소를 스캔하여 변경사항을 동기화 하기때문에 등록을 필수로 해야만한다.

성공적으로 연결된 것을 확인할 수 있다. 이를 통해 애플리케이션의 선언적 배포와 자동화된 관리가 가능하게 되었다.


애플리케이션 배포

그럼 이제 [Applications] > [+ NEW APP]을 눌러 배포할 프로젝트를 등록해주자.

기본 애플리케이션 정보와 매니페스트 파일이 저장된 Git 저장소의 URL을 입력해준다. Path의 경우 배포에 사용할 Kustomize 디렉토리 경로를 설정하면 된다.

[DESTINATION] 설정은 대상 클러스터와 네임스페이스를 설정하는 곳이다. 애플리케이션을 배포할 대상 쿠버네티스 클러스터를 선택하면 되는데 ArgoCD가 설치된 클러스터를 선택하고 네임스페이스 또한 ArgoCD가 설치된 네임스페이스를 입력하여 배포 설정을 마무리하였다.

ArgoCD와 애플리케이션 모두 동일한 네임스페이스에 배포하도록 설정한 이유는 현재 같은 네임스페이스를 사용하는 것으로 배포를 간단히 마치기 위해서였다. 실제 운영 환경에서는 별도의 네임스페이스를 생성하여 격리된 환경을 구성해봐야겠다.


생성된 애플리케이션의 [SYNC] 버튼을 누르게 되면 Git 저장소의 내용을 바탕으로 Kubernetes에 배포를 시작하게 된다.


Auto-SYNC

이후 저장소의 변경사항을 자동으로 감지하고 반영하기 위해서는 설정을 추가해주어야 한다.

애플리케이션의 [DETAILS] 창에서 [ENABLE AUTO-SYNC] 버튼을 누르면 자동 동기화가 활성화 되어 수정사항이 자동으로 반영된다.


배포 확인하기

마지막으로 배포가 잘 되었는지 스웨거 화면을 조회해보는 것으로 마무리하겠다!

Deployment 및 Pod 확인

$ kubectl get deployment -n argocd
kanban-deploy                      3/3     3            3           3d

$ kubectl get pods -n argocd
kanban-deploy-6cf5d766f-8jflz                       1/1     Running   0          3d
kanban-deploy-6cf5d766f-rfh45                       1/1     Running   0          3d
kanban-deploy-6cf5d766f-vzz4z                       1/1     Running   0          3d

세개의 파드를 생성하도록 설정한 deployment가 잘 올라온 것으로 확인되었다. 그렇다면 내가 마지막으로 빌드한 v1.0.23 버전의 이미지를 이용한지 한번 보자!

Service 확인

$ kubectl get service -n argocd
NAME                                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
kanban-service                            ClusterIP   10.96.128.246   <none>        3030/TCP                     3d

deployment를 통해 생성한 세개의 파드가 잘 묶여있는 것을 확인했다.


API 서버 확인

마지막으로 서버가 정상적으로 동작중인지 확인하려면 클러스터에 직접 접근하여 curl로 조회하는 방법이 있다.

$ docker exec -it kind-test-today-cluster-worker2 /bin/bash

쿠버네티스 Service의 ClusterIP로 조회한 결과 정상적으로 스웨거 페이지가 조회되는 것을 확인할 수 있다.


쿠버네티스를 위한 CI/CD 구축 과정은 처음 시도해보는 작업이라 시간이 예상보다 훨씬 오래 걸렸다. 특히 시작하기 전에 필요한 개념들을 이해하고 익히는 데 많은 시간을 투자해야 했다. 익숙하지 않은 도구들과의 씨름은 쉽지 않았지만 그만큼 성취감을 얻을 수 있었던 시간이되었다.

이번 시간에는 CI/CD 구축과정에 대한 기본적인 배포 과정을 다뤘지만 Kustomize, Helm, ArgoCD의 심화 사용법까지 상세히 다뤄보려고 한다. 그러면서 공부하는거지 뭐.... 암튼 바이...!


[참고자료]
https://velog.io/@wlgns5376/GitOps-ArgoCD%EC%99%80-Kustomize%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-kubernetes%EC%97%90-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0
https://medium.com/@minina1868/kubernetes-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%EC%9D%98-ci-cd-%EA%B0%9C%EC%84%A0%EA%B8%B0-82872154570e
https://cwal.tistory.com/22

profile
Node 백엔드 개발자 / 데브옵스 취준생

0개의 댓글