지금까지 우리는 도커가 설치된 리눅스 호스트나 도커 실행환경에 젠킨스를 설치한 후 파이프라인을 이용하여 git 레포지토리에서 소스 파일을 체크아웃하고 Dockerfile을 도커 이미지로 빌드한 후 별도의 레지스트리로 push 한 후, 아르고를 이용하여 쿠버네티스 클러스터에 해당 도커 이미지를 배포하였습니다. (길다...)
정석적인 방법이기는 하지만 쿠버네티스 배포를 위해 별도의 환경에 의존해야 하는 점, 젠킨스의 호스트 도커 의존성 등이 한계로 남아있습니다. 쿠버네티스 관리 클러스터에서 컨테이너의 배포와 관리를 자동화하는 것을 목표로 보면 개선이 필요한 상황입니다.
문제 해결을 위해 일단 젠킨스를 관리 클러스터의 쿠버네티스 환경에 설치하고 에이전트의 호스트 의존을 최소화 하도록 에이전트를 동적으로 생성하고 에이전트 내에 사이드 컨테이너로 dind 컨테이너(도커 유틸리티가 기본 설치되어 있는 도커에서 공식지원하는 이미지의 태그인 dind로 생성하는 컨테이너)를 통해 젠킨스 파이프라인 상에서 dind 컨테이너의 도커를 사용하도록 합니다.
k8s는 1.20 버전부터 docker의 컨테이너 런타임 기본 지원을 중단하였습니다. 따라서 젠킨스 파드에서 직접 도커 런타임을 사용하였던 기존 방식과 다르게, 1.20 버전부터는 젠킨스 컨테이너에서 도커를 사용하려면 다른 방식을 적용해야 합니다. 여러가지 방식이 있지만 최근 공부한 DinD 방식을 적용하여 보기로 합시다.
k config get-clusers # 컨텍스트 확인
k config use-contexts <컨텍스트명>
# Mac
brew install kubernetes-helm
# Linux
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \
chmod 700 get_helm.sh && ./get_helm.sh
helm repo add jenkins https://charts.jenkins.io
helm repo update
# 원본 (계속 업데이트)
curl -LO https://raw.githubusercontent.com/jenkinsci/helm-charts/main/charts/jenkins/values.yaml
# 수정본 (Jenkins Ver.2.426.3)
https://github.com/codelab-kr/microservices-starter/blob/feature/infra/mgmt/jenkins/values.yaml
❯ helm install jenkins jenkins/jenkins --namespace jenkins --create-namespace -f values.yaml
Release "jenkins" does not exist. Installing it now.
NAME: jenkins
LAST DEPLOYED: Thu Jan 18 14:36:56 2024
NAMESPACE: jenkins
STATUS: deployed
REVISION: 1
NOTES:
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 && echo
2. Get the Jenkins URL to visit by running these commands in the same shell:
echo http://127.0.0.1:8080
kubectl --namespace jenkins port-forward svc/myjenkins 8080:8080
3. Login with the password from step 1 and the username: admin
4. Configure security realm and authorization strategy
5. Use Jenkins Configuration as Code by specifying configScripts in your values.yaml file, see documentation: http://127.0.0.1:8080/configuration-as-code and examples: https://github.com/jenkinsci/configuration-as-code-plugin/tree/master/demos
For more information on running Jenkins on Kubernetes, visit:
https://cloud.google.com/solutions/jenkins-on-container-engine
For more information about Jenkins Configuration as Code, visit:
https://jenkins.io/projects/jcasc/
NOTE: Consider using a custom image with pre-installed plugins
❯ k get all -n jenkins
NAME READY STATUS RESTARTS AGE
pod/jenkins-0 2/2 Running 0 2m8s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/jenkins ClusterIP 10.96.234.211 <none> 8080/TCP 2m8s
service/jenkins-agent ClusterIP 10.96.76.209 <none> 50000/TCP 2m8s
NAME READY AGE
statefulset.apps/jenkins 1/1 2m8s
echo http://127.0.0.1:8080
kubectl --namespace jenkins port-forward svc/jenkins 8080:8080
5번까지만 해도 일단 사용은 가능하지만 로컬호스트로 연결하는 것은 왠지 프로답지 않습니다. :)
ssl을 적용하고 도메인을 연결해 봅시다.
여기서부터는 NLB 설치 및 nginx-ingress, cert-manager 등이 설치되어 있고 상용 도메인을 소유하고 있다는 가정하여 진행됩니다.
상세 사항은 관련 포스팅을 참고하시기 바랍니다.
https://velog.io/@codelab/multi-cluster-2-Ingress-Nginx
해당내용을 스킵하실 분은 바로 10번으로 건너가시기 바랍니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins-prod
namespace: jenkins
annotations:
acme.cert-manager.io/http01-ingress-class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: 999m
spec:
ingressClassName: nginx
tls:
- hosts:
- jenkins.code-lab.kr
secretName: jenkins-prod-tls
rules:
- host: jenkins.code-lab.kr
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: jenkins
port:
number: 8080
❯ k apply -f ingress-jenkins-prod.yaml -n jenkins
❯ k get certificate -n jenkins
NAME READY SECRET AGE
jenkins-prod-tls True jenkins-prod-tls 5m46s
❯ k get ingress -n jenkins
NAME CLASS HOSTS ADDRESS PORTS AGE
jenkins-prod nginx jenkins.code-lab.kr 10.0.20.108,146.56.188.188 80, 443 6m52s
# 비번 확인
❯ kubectl exec --namespace jenkins -it svc/jenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo
이런 화면이 뜨면 성공입니다.
node {
stage('Build UI Docker Image') {
container('dind') {
sh "docker --version"
}
}
}
도커 버전을 올바르게 출력하고 결과도 성공으로 나옵니다.
좀 더 상세한 로그는 아래와 같이 확인할 수 있습니다.
❯ k logs -f pod/jenkins-0 -n jenkins