1. Overviews
Kubernetes에서 CI/CD를 테스트 한 내용을 기록합니다. 기존 작성한 Kubernetes CI/CD 글의 경우 Jenkins만 이용하였지만, 이번 테스트에서는 일반적으로 많이 사용하는 Jenkins-ArgoCD 조합을 사용하여 파이프라인을 구성하고 Docker build를 위해 Kaniko를 이용합니다. 또한 Github에서 webhook을 설정해 push가 발생하였을 때 trigger가 발생해 자동화가 되도록 설정하였습니다. 전체적인 플로우는 다음과 같습니다.
효율적인 관리를 위해 Source Repo 와 Manifest Repo를 나누어서 관리하였지만 일반적인 경우 charts, 나 mainfests 파일을 만들어 동일한 repository에서 사용하기도 합니다. Jenkins, ArgoCD, Harbor 모두 Kubernetes 안에서 배포되어 동작합니다.
2. Jenkins 설치
Jenkins 설치를 위해 아래 파일을 실행했습니다. Jenkins는 공식 Helm을 지원하여 헬름을 통해 쉽게 배포할 수 도 있습니다.
#ServiceAccount설치
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jenkins-admin
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-admin
namespace: devops-tools
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jenkins-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins-admin
subjects:
- kind: ServiceAccount
name: jenkins-admin
namespace: devops-tools
이후 Deployment를 생성합니다. Jenkins 데이터를 유지하기 위해 PV를 사용하는데 따로 임시로 사용하기 위해 local-Stroage를 사용하였습니다. 문서를 참조해 jenkins-pv-claim
을 생성한 후 Deployment를 생성합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: devops-tools
spec:
replicas: 1
selector:
matchLabels:
app: jenkins-server
template:
metadata:
labels:
app: jenkins-server
spec:
securityContext:
fsGroup: 1000
runAsUser: 1000
serviceAccountName: jenkins-admin
containers:
- name: jenkins
image: jenkins/jenkins:lts
resources:
limits:
memory: "2Gi"
cpu: "1000m"
requests:
memory: "500Mi"
cpu: "500m"
ports:
- name: httpport
containerPort: 8080
- name: jnlpport
containerPort: 50000
livenessProbe:
httpGet:
path: "/login"
port: 8080
initialDelaySeconds: 90
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
readinessProbe:
httpGet:
path: "/login"
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumeMounts:
- name: jenkins-data
mountPath: /var/jenkins_home
volumes:
- name: jenkins-data
persistentVolumeClaim:
claimName: jenkins-pv-claim
Deployment가 정상적으로 생성되었다면 Jenkins에 접속하기 위해 Service를 생성합니다. kubectl expose deploy jenkins -n devops-tools —type=NodePort
이후 생성된 포트로 접속시 jenkins로 접속되는 것을 확인할 수 있습니다. 기본 설정을 통해 default로 설치되는 Plugin 제외하고 Kubernetes Plugin을 추가로 설치합니다.
3. Jenkins Pipeline 구성
우선 Private Repository를 Clone 하기 위해 Github Credentials을 생성합니다. jenkins 관리
→ Manage Credentials
→ jenkins
→ add Credentials
github에서 push 하면 Pipeline이 실행될 수 있도록 repository에서 webhook을 설정합니다. repository 설정에서 Paload URL 부분에 Jenkins주소/github-webhook/
을 설정합니다. 해당 주소에 POST로 요청합니다.
Jenkins에서 새로운 Item에서 Pipeline을 선택해 파이프라인을 생성합니다.
Build Triggers에서 GitHub hook trigger for GITScm polling
를 설정합니다.
Pipeline Script에서 CI Script를 작성합니다.
podTemplate(yaml: '''
kind: Pod
metadata:
name: kaniko-image-build-pod
spec:
containers:
- name: yq
image: [harbor-repo]/docker-local/yq
imagePullPolicy: Always
tty : true
command:
- sleep
args:
- 99d
- name: kaniko
image: gcr.io/kaniko-project/executor:v1.6.0-debug
imagePullPolicy: Always
command:
- sleep
args:
- 99d
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker
tty: true
volumes:
- name: docker-config
configMap:
name: docker-config-harbor
'''
) {
node(POD_LABEL) {
stage('Build with Kaniko') {
//git tag를 가져오기 위한 clone
git branch: 'main',
credentialsId: 'github-credential',
url: 'https://github.com/matildalab-private/gcmp-api.git'
script(){
GIT_TAG = sh (
script: 'git describe --always',
returnStdout: true
).trim()
}
//Image build
container('kaniko') {
//kaniko 에서 빌드하기 위해 소스코드 clone
git branch: 'main',
credentialsId: 'github-credential',
url: 'https://github.com/matildalab-private/gcmp-api.git'
sh 'mkdir manifests'
sh 'chmod 777 -R manifests'
dir("manifests"){
//dockerfile이 포함된 repository clone
git branch: 'main',
credentialsId: 'github-credential',
url: 'https://github.com/matildalab-private/matilda-helm-for-CD'
}
// kaniko 실행
sh '/kaniko/executor -f `pwd`/manifests/gcmp-api/Dockerfile -c `pwd` --insecure --skip-tls-verify --cache=true --destination=[harbor-repo]/docker-local/gcmp-api:' + GIT_TAG
}
}
}
}
이후 파이프라인을 실행하면 다음과 같이 Kaniko를 통해 이미지가 빌드되고 harbor로 Push 된 것을 확인할 수 있습니다.
4. Argo CD 구성
위의 과정을 통해 빌드된 이미지를 바탕으로 Kubernetes에 배포하기 위해 Argo CD를 설치합니다.
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
설치 된 Argo UI에 접속해 로그인 후 NEW APP을 선택해 새로운 애플리케이션을 생성합니다. SYNC POLICY
는 Manual은 수동으로 배포하고 Automatic은 Sync를 감지해 자동으로 배포합니다.
이후 Git repository를 설정하고 Manifests가 저장된 경로를 지정합니다. gcmp-api 경로 아래에 Helm 차트를 만들어 저장했습니다. ( Manifests 파일도 동일하게 적용됩니다). 이후 Destination에 배포할 위치를 정합니다. Kubernetes Cluster와 Namespace를 지정합니다.
이후 테스트로 Sync를 눌러 배포를 하면 다음과 같이 배포된 화면을 볼 수 있습니다. 이후 실제 쿠버네티스에서도 배포된 것을 확인할 수 있습니다.
5. Jenkins-Argo CD 연결
위에서 테스트한 Argo를 Jenkins Pipeline 통해 배포 할 수 있도록 파이프라인을 추가합니다.
stage('Deploy dev') {
container('yq') {
dir("~/"){
git branch: 'main',
credentialsId: 'github-credential',
url: 'https://github.com/matildalab-private/matilda-helm-for-CD'
sh('yq -i \'.imagetag="'+ GIT_TAG + '"\' ./gcmp-api/values_dev.yaml')
sh('ls')
sh('cat ./gcmp-api/values_dev.yaml')
sh('git add --all')
sh('git commit -a -m \"updated the image tag to ' + GIT_TAG + '\" || true')
sh('git remote set-url origin https://sgithub.com/matildalab-private/matilda-helm-for-CD.git')
sh('git push -u origin --all')
sh('argocd login [Argo 주소] --username admin --password password --insecure')
sh('argocd app get gcmp-api --hard-refresh')
}
}
}
위의 파이프 라인은 yq 컨테이너를 생성해 helm이 저장된 리포지토리의 values.yaml의 image tag를 변경하고 Push 합니다. 이후 변경된 사항을 argo에서 변경할 수 있도록 refresh를 진행합니다. 현재 ID/PW는 수동으로 입력하였지만 이 부분 또한 Credentials로 생성해 넣도록 합니다. 이후 전체 파이프 라인을 실행시키면 아래와 같이 정상적으로 동작하는 것을 볼 수 있습니다.
6. 마무리
위와 같은 방법뿐 아니라 GitOps를 통해서 CI/CD Flow를 구성할 수도 있고 이전 글과 같이 Jenkins로만으로도 CD까지 구성할 수 있습니다. 다음과 같이 jenkins-ArgoCD를 통해서 구성할 경우 사용자 입장에서는 두 가지 UI를 관리해야 돼서 불편함이 있을 수 있습니다만 Jenkins와 ArgoCD의 기능을 모두 사용할 수 있습니다(Argo 가 UI가 잘되어있음..). 전체 흐름을 보면 복잡하고 어려울 수 있지만 실제 개발자가 쿠버네티스를 잘 알지 못하는 경우가 많기 때문에 배포에 어려움을 겪을 수 있기 때문에 한번 구성하면 매우 편하게 사용할 수 있습니다.
'Kubernetes' 카테고리의 다른 글
EFK Stack을 이용한 쿠버네티스 로깅 스택 구축#1 (0) | 2023.10.12 |
---|---|
Thanos를 이용한 Prometheus HA 구성 (1) | 2023.10.12 |
Kubernetes HA 구성을 위한 Pod Scheduling (0) | 2023.10.12 |
쿠버네티스 멀티클러스터 관리하기(Feat. Teleport) (1) | 2023.10.12 |
Kubernetes에서 학습용 Job 생성하기 (0) | 2023.10.12 |