이번에 Kubernetes를 다루면서 코드형 인프라(Infrastructure as Code, IaC)의 장점을 더 살리기 위해 GitOps를 채택했는데요.
GitOps는 DevOps의 확장 개념으로, 배포와 운영에 관련된 코드들을 Git에서 관리하는 것을 의미합니다.
이 GitOps의 CI / CD 파이프라인에서 CI 파이프라인은 Jenkins를 통해 구축해 보기로 했습니다.
Jenkins 배포
우선 Jenkins를 클러스터 내에 구동해야 합니다.
그러나 Jenkins와 관련된 Pod, Service, Ingress 등을 수동으로 배포하고 관리하기는 힘들다고 생각했습니다.
그래서 Helm을 사용하기로 했는데요.
각 벤더(Vendor)에서 만들어준 Helm 차트를 기반으로 values.yaml만 잘 수정해서 배포하기만 하면 됩니다.
> helm repo add jenkins https://charts.jenkins.io"jenkins" has been added to your repositories> helm repo updateHang tight while we grab the latest from your chart repositories......Successfully got an update from the "jenkinsci" chart repository...Successfully got an update from the "jenkins" chart repositoryUpdate Complete. ⎈Happy Helming!⎈
Jenkins 차트를 가져오기 위해 차트 레포지토리를 추가합니다.
> helm show values jenkins/jenkins > jenkins-values.yaml
그 다음, Jenkins 차트에 설정할 jenkins-values.yaml을 가져옵니다.jenkins-values.yaml
그리고 jenkins-values.yaml에서 권한이나 볼륨 등 설정하고자 하는 부분을 수정했는데요.
추가로 /jenkins를 Prefix로 가지는 Ingress를 생성할 것이므로, 이에 맞게 jenkinsUriPrefix도 수정했습니다.
이렇게 설정된 Ingress는 제가 사전에 배포한 NodePort 타입의 Nginx Ingress Controller를 통해 구현됩니다.persistent-volume.yaml
제가 사용하는 Kubernetes는 AWS EKS(Elastic Kubernetes Service) 등의 Managed Kubernetes가 아니므로 AWS EBS(Elastic Block Storage) 등의 스토리지(Storage)를 프로비저닝할 Storage Class를 사용하기는 어렵습니다.
그래서 우선은 임시적으로 hostPath 타입의 Persistence Volume을 생성했습니다.
이후에 워커 노드가 많아진다면 NFS(Network File System) 등의 대안을 선택해야 합니다.
> helm install jenkins jenkins/jenkins -f jenkins-values.yaml -n jenkinsNAME: jenkinsLAST DEPLOYED: Tue Mar 5 01:52:04 2024NAMESPACE: jenkinsSTATUS: deployedREVISION: 1NOTES:1. Get your 'admin' user password by running: kubectl exec --namespace jenkins -it svc/jenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo2. Get the Jenkins URL to visit by running these commands in the same shell: echo http://127.0.0.1:8080/jenkins kubectl --namespace jenkins port-forward svc/jenkins 8080:80803. Login with the password from step 1 and the username: admin4. Configure security realm and authorization strategy5. Use Jenkins Configuration as Code by specifying configScripts in your values.yaml file, see documentation: http://127.0.0.1:8080/jenkins/configuration-as-code and examples: https://github.com/jenkinsci/configuration-as-code-plugin/tree/master/demosFor more information on running Jenkins on Kubernetes, visit:https://cloud.google.com/solutions/jenkins-on-container-engineFor more information about Jenkins Configuration as Code, visit:https://jenkins.io/projects/jcasc/NOTE: Consider using a custom image with pre-installed plugins
이제 jenkins-values.yaml와 함께 Jenkins 차트를 배포합니다.
> kubectl get all -n jenkinsNAME READY STATUS RESTARTS AGEpod/jenkins-0 2/2 Running 0 12hNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/jenkins ClusterIP 10.101.229.50 <none> 8080/TCP 12hservice/jenkins-agent ClusterIP 10.106.246.55 <none> 50000/TCP 12hNAME READY AGEstatefulset.apps/jenkins 1/1 12h
> kubectl get ingresses -n jenkinsNAME CLASS HOSTS ADDRESS PORTS AGEjenkins nginx * 172.16.1.101 80 12h
위와 같이 Jenkins와 관련된 리소스들이 자동으로 생성된 것을 볼 수 있습니다.
Jenkins 접속
사전에 배포된 Ingress Controller는 NodePort 타입이므로 <NodeIP>:<NodePort>/jenkins를 통해 Jenkins에 접속할 수 있습니다.
Jenkins에서는 GitHub나 DockerHub 등의 원격 저장소에 접근해야하는 경우가 있는데, 이때 사용하는 자격 증명이 필요하므로 따로 설정을 해줘야 합니다.
위와 같이 username에는 계정 이름을, password에는 발급 받은 토큰을 입력한 후 Credential을 생성합니다.
같은 방식으로 GitHub와 DockerHub 모두 Credential을 생성해줍니다.
플러그인
또한 CI 파이프라인은 GitHub 레포지토리에 커밋이 발생한 이후에 수행되도록 할 것이므로 WebHook이 필요합니다.
그래서 사용할 GitHub Webhook과 괸련된 플러그인들을 설치합니다.
Job
CI 파이프라인을 수행할 Job을 구성해야 하는데요.
GitHub 레포지토리의 변경 사항을 감지하고 Job을 수행하도록 하기 위해 Build Trigger로 GitHub Hook Trigger를 선택합니다.
그 다음 레포지토리 URL, GitHub Credential, 브랜치를 설정합니다.
이렇게 되면 Pipeline Script로 레포지토리 내부에 있는 Jenkinsfile을 사용하게 됩니다.
Job에서 수행되는 파이프라인은 레포지토리 내의 Jenkinsfile에 정의하면 됩니다.
애플리케이션 설정
이전에 SW 마에스트로에서 GitOps를 구축할 때는 이미지 빌드 및 배포를 루트 권한 없이 할 수 있는 Kaniko를 사용했었습니다.
그러나 이번에는 좀 더 간단하게 Jib를 통해서 Docker나 Kaniko 등의 도구 없이 이미지를 빌드해서 컨테이너 레지스트리에 배포하는 방식을 사용해보겠습니다.
Jenkins가 새로운 이미지를 배포한 후에 클러스터에 변경 사항을 반영해야 합니다.
해당 프로젝트에서는 CD 도구로 ArgoCD를 사용할 것이므로 Jenkins가 이미지 태그를 수정할 Helm 차트가 있어야 합니다.
참고로 GitOps에서 Helm 차트는 Git을 통해 관리하게 됩니다.
values.yaml에는 templates 내의 매니페스트들에 설정될 값들을 정의하면 됩니다.
이렇게 되면 Jenkins가 이미지를 업데이트한 후 values.yaml에 있는 이미지 태그들만 변경해주면 됩니다.
이후, 차트를 기반으로 애플리케이션을 배포하는 것은 Jenkins가 아닌 ArgoCD의 역할입니다.
CI 파이프라인
이제 모든 준비가 끝났으니 Jenkinsfile에 지금까지의 CI 파이프라인을 작성할 차례입니다.