Overview
지난 글에서 학습한 Jenkins CI 파이프라인을 확장하여 쿠버네티스 CI&CD를 Jenkins와 ArgoCD, Gogs를 통해 구성하겠습니다.
환경 구성
실습 쿠버네티스 환경은 Kind로 구성하였습니다.
Kind는 테스트 목적으로 로컬 환경에서 쿠버네티스를 구성시키는 도구입니다.
# Install Kind
brew install kind
kind --version
# Install kubectl
brew install kubernetes-cli
kubectl version --client=true
## kubectl -> k 단축키 설정
echo "alias kubectl=kubecolor" >> ~/.zshrc
# Install Helm
brew install helm
helm version
- apiserverAddress : 쿠버네티스 API 서버 접근 허용을 위한 IP 지정이 필요합니다. 자신의 IP를 등록해야 합니다.
- nodes.extraPortMappings : 클러스터 내부의 포트를 로컬호스트와 동일한 호스트로 매핑시킵니다. 외부 접근을 위해 사용합니다.
# 자신의 IP
# ifconfig en0.inet
MyIP=192.168.1.5
cat > kind-3node.yaml <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
apiServerAddress: "$MyIP"
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001
hostPort: 30001
- containerPort: 30002
hostPort: 30002
- containerPort: 30003
hostPort: 30003
- role: worker
- role: worker
EOF
kind create cluster --config kind-3node.yaml --name myk8s --image kindest/node:v1.30.6
# 도커 구성 확인
docker ps
docker network ls
# kind 네트워크로 내부 172.18.0.0/16 사용
docker inspect kind
# 쿠버네티스 정보 확인
kubectl get pods -o wide -v6
kubectl get nodes -o wide
Gogs와 Jenkins는 도커로 구성하였습니다.
구성방법과 설정은 필자의 글을 참고해주세요.
체크리스트는 다음과 같습니다.
- Jenkins 구성 플러그인 설정 (Docker Pipeline, Gogs, Pipeline Stage)
- 자격증명 설정 : Jenkins 관리 → Credentials → Globals → Add Credentials
- Gogs Repo 자격증명 설정 : gogs-crd
- Kind : Username with password
- Username : devops
- Password : 접근 키 발급 : Your Setting > Application > Generate New Token
- ID : gogs-crd
- 도커 허브 자격증명 설정 : dockerhub-crd
- Kind : Username with password
- Username : <도커 계정명>
- Password : <도커 계정 암호 혹은 토큰>
- ID : dockerhub-crd
- k8s(kind) 자격증명 설정 : k8s-crd
- Kind : Secret file
- File : <kubeconfig 파일 업로드> ~/.kube/config
- ID : k8s-crd
- Gogs Repo 자격증명 설정 : gogs-crd
필자의 경우 이전에 구성한 Jenkins를 사용하였으나 속도가 느려 젠킨스 볼륨을 삭제하고 다시 생성하였습니다.
Jenkins URL 이 변경되어 그런 것으로 확인 중입니다.
Jenkins 을 새로 구성하였다면 Docker-out-of-Docker 설정이 필요합니다.
Gogs 에서 개발용, Devops용 Repo 를 생성합니다.
- New Repository
- Repository Name : dev-app
- Visibility : (Check) This repository is Private
- .gitignore : Python
- Readme : Default → (Check) initialize this repository with selected files and template
- New Repository
- Repository Name : ops-deploy
- Visibility : (Check) This repository is Private
- Readme : Default → (Check) initialize this repository with selected files and template
Jenkins 파이프라인 테스트
pipeline {
agent any
environment {
DOCKER_IMAGE = 'tmdgh663/dev-app' // Docker 이미지 이름
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'http://192.168.1.5:3000/hanhorang/dev-app.git', // Git에서 코드 체크아웃
credentialsId: 'gogs-crd' // Credentials ID
}
}
stage('Read VERSION') {
steps {
script {
// VERSION 파일 읽기
def version = readFile('VERSION').trim()
echo "Version found: ${version}"
// 환경 변수 설정
env.DOCKER_TAG = version
}
}
}
stage('Docker Build and Push') {
steps {
script {
docker.withRegistry('https://index.docker.io/v1/', 'dockerhub-crd') {
// DOCKER_TAG 사용
def appImage = docker.build("${DOCKER_IMAGE}:${DOCKER_TAG}")
appImage.push()
appImage.push("latest")
}
}
}
}
}
post {
success {
echo "Docker image ${DOCKER_IMAGE}:${DOCKER_TAG} has been built and pushed successfully!"
}
failure {
echo "Pipeline failed. Please check the logs."
}
}
}
필자의 경우 Jenkins 내 docker 미설치로 오류가 발생하였습니다.
다음의 스크립트를 통해 docker 설치 후 다시 빌드해주세요
# Jenkins 컨테이너 내부에 도커 실행 파일 설치
docker compose exec --privileged -u root jenkins bash
-----------------------------------------------------
id
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update && apt install docker-ce-cli curl tree jq -y
docker info
docker ps
which docker
# Jenkins 유저도 docker를 실행할 수 있도록 권한을 부여
groupadd -g 2000 -f daemon
chgrp daemon /var/run/docker.sock
ls -l /var/run/docker.sock
usermod -aG daemon jenkins
cat /etc/group | grep daemon
Kind를 통해 쿠버네티스 클러스터 구성 후 생성한 이미지를 기반으로 애플리케이션을 구성합니다.
- 쿠버네티스에서 도커 허브 접근을 위해 사전 Secert 생성이 필요합니다.
DHUSER=<도커 허브 계정>
DHPASS=<도커 허브 암호 혹은 토큰>
kubectl create secret docker-registry dockerhub-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=$DHUSER \
--docker-password=$DHPASS
cat <
Jenkins CI/CD
Jenkins를 통해 생성한 이미지를 통해 쿠버네티스 배포를 진행하도록 하겠습니다.
Jenkins 에서 쿠버네티스 객체 관리를 위해 kubectl, helm 툴을 설치하겠습니다.
# Install kubectl, helm
docker compose exec --privileged -u root jenkins bash
--------------------------------------------
#curl -LO "https://dl.k8s.io/release/v1.31.0/bin/linux/amd64/kubectl"
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/arm64/kubectl" # macOS
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" # WindowOS
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client=true
#
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version
exit
--------------------------------------------
docker compose exec jenkins kubectl version --client=true
docker compose exec jenkins helm version
dev-app Repo 에 쿠버네티스 객체를 생성합니다.
git clone http://192.168.1.5:3000/hanhorang/dev-app.git
cd dev-app
cat > deploy/echo-server-blue.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-server-blue
spec:
replicas: 2
selector:
matchLabels:
app: echo-server
version: blue
template:
metadata:
labels:
app: echo-server
version: blue
spec:
containers:
- name: echo-server
image: hashicorp/http-echo
args:
- "-text=Hello from Blue"
ports:
- containerPort: 5678
EOF
cat > deploy/echo-server-service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: echo-server-service
spec:
selector:
app: echo-server
version: blue
ports:
- protocol: TCP
port: 80
targetPort: 5678
nodePort: 30000
type: NodePort
EOF
cat > deploy/echo-server-green.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-server-green
spec:
replicas: 2
selector:
matchLabels:
app: echo-server
version: green
template:
metadata:
labels:
app: echo-server
version: green
spec:
containers:
- name: echo-server
image: hashicorp/http-echo
args:
- "-text=Hello from Green"
ports:
- containerPort: 5678
EOF
#
git add . && git commit -m "Add echo server yaml" && git push -u origin main
Jenkins 파이프라인을 다음과 같이 구성하여 빌드하면 젠킨스를 통해 쿠버네티스 배포 관리를 할 수 있습니다.
- returnValue 분기를 통해 젠킨스에서 배포 rollback 및 버전 스위칭을 관리할 수 있게 됩니다.
pipeline {
agent any
environment {
KUBECONFIG = credentials('k8s-crd')
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'http://192.168.1.5:3000/hanhorang/dev-app.git', // Git에서 코드 체크아웃
credentialsId: 'gogs-crd' // Credentials ID
}
}
stage('container image build') {
steps {
echo "container image build"
}
}
stage('container image upload') {
steps {
echo "container image upload"
}
}
stage('k8s deployment blue version') {
steps {
sh "kubectl apply -f ./deploy/echo-server-blue.yaml --kubeconfig $KUBECONFIG"
sh "kubectl apply -f ./deploy/echo-server-service.yaml --kubeconfig $KUBECONFIG"
}
}
stage('approve green version') {
steps {
input message: 'approve green version', ok: "Yes"
}
}
stage('k8s deployment green version') {
steps {
sh "kubectl apply -f ./deploy/echo-server-green.yaml --kubeconfig $KUBECONFIG"
}
}
stage('approve version switching') {
steps {
script {
returnValue = input message: 'Green switching?', ok: "Yes", parameters: [booleanParam(defaultValue: true, name: 'IS_SWITCHED')]
if (returnValue) {
sh "kubectl patch svc echo-server-service -p '{\"spec\": {\"selector\": {\"version\": \"green\"}}}' --kubeconfig $KUBECONFIG"
}
}
}
}
stage('Blue Rollback') {
steps {
script {
returnValue = input message: 'Blue Rollback?', parameters: [choice(choices: ['done', 'rollback'], name: 'IS_ROLLBACk')]
if (returnValue == "done") {
sh "kubectl delete -f ./deploy/echo-server-blue.yaml --kubeconfig $KUBECONFIG"
}
if (returnValue == "rollback") {
sh "kubectl patch svc echo-server-service -p '{\"spec\": {\"selector\": {\"version\": \"blue\"}}}' --kubeconfig $KUBECONFIG"
}
}
}
}
}
}
위 Jenkins 내부 스크립트를 확인하면 명령어 스크립트를 통해 자동으로 실행하는 도구임을 확인할 수 있습니다.
Jenkins로 쿠버네티스 CD를 구성할 수 있지만, 시각화 대시보드 및 배포 전략 고급화를 손 쉽게 할 수 없어 다른 툴인 ArgoCD를 통해 CD를 구성하겠습니다.
Argo CD
ArgoCD는 쿠버네티를 위한 CD 툴입니다.
쿠버네티스 객체 모니터링을 통해 대상 클러스터에 배포 및 시각화 기능을 제공합니다.
kubectl create ns argocd
cat < argocd-values.yaml
dex:
enabled: false
server:
service:
type: NodePort
nodePortHttps: 30002
EOF
# 설치
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 7.7.10 -f argocd-values.yaml --namespace argocd
# 최초 접속 암호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
PCdOlwZT8c4naBWK
# Argo CD 웹 접속 주소 확인 : 초기 암호 입력 (admin 계정)
open "https://127.0.0.1:30002" # macOS
ArgoCD 웹 접속 후 코드 관리 대상 클러스터 확인과 코드 저장소 연결이 필요합니다.
- 클러스터는 기본 Default로 https://kubernetes.default.svc 를 사용합니다.
- Settings → Repositories → CONNECT REPO에서 다음과 같이 기입 (Repo, 접근키 각자 등록)
Repo, Ops-deploy 에 쿠버네티스 yaml를 구성하여 ArgoCD를 통해 배포하겠습니다.
git clone http://192.168.1.5:3000/hanhorang/ops-deploy.git
cd ops-deploy
mkdir dev-app
VERSION=0.0.1
cat > dev-app/VERSION <<EOF
$VERSION
EOF
cat > dev-app/timeserver.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: timeserver
spec:
replicas: 2
selector:
matchLabels:
pod: timeserver-pod
template:
metadata:
labels:
pod: timeserver-pod
spec:
containers:
- name: timeserver-container
image: docker.io/$DHUSER/dev-app:$VERSION
imagePullSecrets:
- name: dockerhub-secret
EOF
cat > dev-app/service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: timeserver
spec:
selector:
pod: timeserver-pod
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 30000
type: NodePort
EOF
#
git status && git add . && git commit -m "Add dev-app deployment yaml" && git push -u origin main
ArgoCD CRD application yaml를 정의하여 ArgoCD에서 원본 Repo 에 있는 yaml를 기반으로 대상 클러스터에 배포하도록 설정하겠습니다.
cat <https://kubernetes.default.svc
EOF
- argocd-application-controller-0 파드가 Repo를 3분 간격으로 모니터링하여 Sync를 확인합니다.
Jenkins CI + Argo CD 구성
이제 Jenkins 에서 ArgoCD를 통해 쿠버네티스 객체가 관리되도록 설정하겠습니다.
핵심은 Jenkins가 ArgoCD가 바라보는 원본 Repo에 버전 정보가 수정되도록 파이프라인을 추가하는 것입니다.아래 ops-deploy Checkout Stage 에서 argoCD가 바라보는 REPO에 버전 수정이 되도록 추가하면 쿠버네티스 배포까지 한번에 진행됩니다.
pipeline {
agent any
environment {
DOCKER_IMAGE = 'tmdgh663/dev-app' // Docker 이미지 이름
GOGSCRD = credentials('gogs-crd')
}
stages {
stage('dev-app Checkout') {
steps {
git branch: 'main',
url: 'http://192.168.1.5:3000/hanhorang/dev-app.git', // Git에서 코드 체크아웃
credentialsId: 'gogs-crd' // Credentials ID
}
}
stage('Read VERSION') {
steps {
script {
// VERSION 파일 읽기
def version = readFile('VERSION').trim()
echo "Version found: ${version}"
// 환경 변수 설정
env.DOCKER_TAG = version
}
}
}
stage('Docker Build and Push') {
steps {
script {
docker.withRegistry('https://index.docker.io/v1/', 'dockerhub-crd') {
// DOCKER_TAG 사용
def appImage = docker.build("${DOCKER_IMAGE}:${DOCKER_TAG}")
appImage.push()
appImage.push("latest")
}
}
}
}
stage('ops-deploy Checkout') {
steps {
git branch: 'main',
url: 'http://192.168.1.5:3000/hanhorang/ops-deploy.git', // Git에서 코드 체크아웃
credentialsId: 'gogs-crd' // Credentials ID
}
}
stage('ops-deploy version update push') {
steps {
sh '''
OLDVER=$(cat dev-app/VERSION)
NEWVER=$(echo ${DOCKER_TAG})
sed -i -e "s/$OLDVER/$NEWVER/" dev-app/timeserver.yaml
sed -i -e "s/$OLDVER/$NEWVER/" dev-app/VERSION
git add ./dev-app
git config user.name "devops"
git config user.email "a@a.com"
git commit -m "version update ${DOCKER_TAG}"
git push http://${GOGSCRD_USR}:${GOGSCRD_PSW}@192.168.1.5:3000/hanhorang/ops-deploy.git
'''
}
}
}
post {
success {
echo "Docker image ${DOCKER_IMAGE}:${DOCKER_TAG} has been built and pushed successfully!"
}
failure {
echo "Pipeline failed. Please check the logs."
}
}
}
- 태그가 변경됨에 따라 파드가 변경됨을 확인
'Cloud Tech' 카테고리의 다른 글
Github Action CI/CD (1) | 2024.12.15 |
---|---|
도커 기반 애플리케이션 CI/CD 구성 (0) | 2024.12.08 |
DownTime Zero를 통한 EKS 운영 안정성 높이기 (1) | 2024.11.02 |
Cilium Service Mesh on EKS (1) | 2024.10.26 |
EKS VPC CNI 네트워크 최적화 설정과 Kubeflow에서의 istio 구성 (2) | 2024.10.20 |