들어가며
안녕하세요 여러분,
이번 포스팅은 CloudNet@ 커뮤니티에서 주최하는 CI/CD 스터디 3주 차 주제인 "Jenkins CI/ArgoCD + K8S"에 대해서 정리한 내용입니다.
실습환경 구성
이번 주차 스터디에서는 mac OS 기반 docker 환경에서 레포지토리인 Gogs, CI/CD 파이프라인 도구인 Jenkins, 그리고 kind 기반 kubernetes 클러스터를 구성하여 실습을 진행했습니다.
실습 컨테이너 설정
# 작업 디렉토리 생성 후 이동
mkdir cicd-labs
cd cicd-labs
#
cat <<EOT > docker-compose.yaml
services:
jenkins:
container_name: jenkins
image: jenkins/jenkins
restart: unless-stopped
networks:
- cicd-network
ports:
- "8080:8080"
- "50000:50000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- jenkins_home:/var/jenkins_home
gogs:
container_name: gogs
image: gogs/gogs
restart: unless-stopped
networks:
- cicd-network
ports:
- "10022:22"
- "3000:3000"
volumes:
- gogs-data:/data
volumes:
jenkins_home:
gogs-data:
networks:
cicd-network:
driver: bridge
EOT
# 배포
docker compose up -d
docker compose ps
# 기본 정보 확인
for i in gogs jenkins ; do echo ">> container : $i <<"; docker compose exec $i sh -c "whoami && pwd"; echo; done
# 도커를 이용하여 각 컨테이너로 접속
docker compose exec jenkins bash
exit
docker compose exec gogs bash
exit
다음으로 Jenkins 컨테이너 초기 설정을 수행합니다.
# Jenkins 초기 암호 확인
docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
09a21116f3ce4f27a0ede79372febfb1
# Jenkins 웹 접속 주소 확인 : 계정 / 암호 입력 >> admin / qwe123
open "http://127.0.0.1:8080" # macOS
웹 브라우저에서 http://127.0.0.1:8080 접속 # Windows
# (참고) 로그 확인 : 플러그인 설치 과정 확인
docker compose logs jenkins -f
마지막으로 1주 차 실습때와 같이 Jenkins 컨테이너에서 호스트 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 yq -y
docker info
docker ps
which docker
# Jenkins 컨테이너 내부에서 root가 아닌 jenkins 유저도 docker를 실행할 수 있도록 권한을 부여
groupadd -g 2000 -f docker # macOS(Container)
groupadd -g 1001 -f docker # Windows WSL2(Container) >> cat /etc/group 에서 docker 그룹ID를 지정
chgrp docker /var/run/docker.sock
ls -l /var/run/docker.sock
usermod -aG docker jenkins
cat /etc/group | grep docker
exit
--------------------------------------------
# jenkins item 실행 시 docker 명령 실행 권한 에러 발생 : Jenkins 컨테이너 재기동으로 위 설정 내용을 Jenkins app 에도 적용 필요
docker compose restart jenkins
sudo docker compose restart jenkins # Windows 경우 이후부터 sudo 붙여서 실행하자
# jenkins user로 docker 명령 실행 확인
docker compose exec jenkins id
docker compose exec jenkins docker info
docker compose exec jenkins docker ps
Gogs 세부 설정
Gogs 초기설정은 http://127.0.0.1:3000/install 로 로그인하여 설정합니다.
로그인 후 Your Settings > Applications > Generate New Token > devops 토큰을 생성합니다.
토큰이 생성완료된 모습입니다.
다음으로는 실습을 위해 애플리케이션 코드를 업로드하는 레포지토리와 배포를 위한 helm chart를 저장하는 레포지토리를 생성합니다.
Docker hub 토큰 발급
계정 > Account settings > Security > Personal access tokens > Generate new token
Kind 싱글 클러스터 생성 테스트
가벼운 쿠버네티스 클러스터를 구성할 수 있는 Kind를 설치합니다.
도움이 되는 툴을 먼저 설치합니다.
brew install krew
brew install kube-ps1
brew install kubectx
# kubectl 출력 시 하이라이트 처리
brew install kubecolor
echo "alias kubectl=kubecolor" >> ~/.zshrc
echo "compdef kubecolor=kubectl" >> ~/.zshrc
# krew 플러그인 설치
kubectl krew install neat stren
Kind 클러스터를 설치해 봅니다.
# 클러스터 배포 전 확인
docker ps
# Create a cluster with kind
kind create cluster
# 클러스터 배포 확인
kind get clusters
kind get nodes
kubectl cluster-info
# 노드 정보 확인
kubectl get node -o wide
# 파드 정보 확인
kubectl get pod -A
kubectl get componentstatuses
# 컨트롤플레인 (컨테이너) 노드 1대가 실행
docker ps
docker images
# kube config 파일 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시
# nginx 파드 배포 및 확인 : 컨트롤플레인 노드인데 파드가 배포 될까요?
kubectl run nginx --image=nginx:alpine
kubectl get pod -owide
# 노드에 Taints 정보 확인
kubectl describe node | grep Taints
Taints: <none>
# 클러스터 삭제
kind delete cluster
# kube config 삭제 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시
API Server address를 잡아놓기 때문에 외부 호스트에서도 클러스터 접근이 가능합니다.
실습 클러스터 설치
이제 본격적으로 실습을 위한 kind 클러스터를 설치합니다. 클러스터는 control-plane 한대와 worker 두대로 구성됩니다.
# 클러스터 배포 전 확인
docker ps
# 방안1 : 환경변수 지정
export KUBECONFIG=$PWD/kubeconfig
# Create a cluster with kind
MyIP=<각자 자신의 PC IP>
MyIP=192.168.254.106
cd ..
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
# 확인
kind get nodes --name myk8s
kubens default
# kind 는 별도 도커 네트워크 생성 후 사용 : 기본값 172.18.0.0/16
docker network ls
docker inspect kind | jq
# k8s api 주소 확인 : 어떻게 로컬에서 접속이 되는 걸까?
kubectl cluster-info
# 노드 정보 확인 : CRI 는 containerd 사용
kubectl get node -o wide
# 파드 정보 확인 : CNI 는 kindnet 사용
kubectl get pod -A -o wide
# 네임스페이스 확인 >> 도커 컨테이너에서 배운 네임스페이스와 다릅니다!
kubectl get namespaces
# 컨트롤플레인/워커 노드(컨테이너) 확인 : 도커 컨테이너 이름은 myk8s-control-plane , myk8s-worker/worker-2 임을 확인
docker ps
docker images
# 디버그용 내용 출력에 ~/.kube/config 권한 인증 로드
kubectl get pod -v6
# kube config 파일 확인
cat $KUBECONFIG
ls -l $KUBECONFIG
파드 정보를 보면 kubeconfig 정보를 저장되어 있는 디렉터리로부터 불러 읽어서 자격 증명이 가능합니다.
kube-ops-view 설치
노드와 pod의 상황을 비주얼하게 확인할 수 있는 kube-ops-view를 설치합니다.
# kube-ops-view
# helm show values geek-cookbook/kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30001 --set env.TZ="Asia/Seoul" --namespace kube-system
# 설치 확인
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view
# kube-ops-view 접속 URL 확인 (1.5 , 2 배율)
open "http://127.0.0.1:30001/#scale=1.5"
참고: Mac OS M계열 사용시 해당 문제가 발생하면 다음과 같이 해결합니다.
rosetta error: Rosetta is only intended to run on Apple Silicon with a macOS host using Virtualization.framework with Rosetta mode enabled
1. rosetta 설치
softwareupdate --install-rosetta
2. docker for mac에서 rosetta 사용 해제
출처 - https://romanzipp.com/blog/maocs-sequoia-docker-resetta-is-only-intended-to-run-silicon
젠킨스 설정
젠킨스로 파이프라인을 구성하기 위한 설정을 수행합니다.
사전 확인한 패스워드로 로그인 합니다.
젠킨스 플러그인 설치
Pipeline Stage View, Docker pipeline, Gogs를 설치합니다.
다음으로 Jenkins의 자격증명 설정합니다.
Gogs Repo, Docker hub, k8s에 접근하기 위한 자격증명을 생성합니다.
k8s 같은 경우는 secret file 종류를 선택하고 kubeconfig파일을 업로드하여 구성합니다.
자격증명을 모두 등록하면 다음과 같은 모습이 됩니다.
설치 후 파이프라인 동작이 되는지 간단히 확인합니다.
pipeline {
agent any
environment {
DOCKER_IMAGE = '<자신의 도커 허브 계정>/dev-app' // Docker 이미지 이름
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'http://192.168.254.124:3000/devops/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."
}
}
}
파이프라인이 잘 작동하여 이미지가 생성된 모습을 확인할 수 있습니다.
k8s 애플리케이션 배포
다음으로 kind로 구축한 k8s 클러스터에 방금 jenkins 파이프라인으로 빌드한 이미지를 배포해 봅니다.
배포를 하면 ImagePullBackOff 로인해 애플리케이션이 정상적으로 배포되지 않는 상황을 확인할 수 있습니다.
이러한 상황은 컨테이너 이미지 정보가 잘못되었거나, 이미지를 가져오는 자격증명에 문제가 있을 때 발생하게 됩니다.
이를 해결하기 위해 k8s에서 docker hub에 접근하기 위한 자격정보를 secret으로 설정하고, 배포 스크립트에 imagePullSecrets를 설정합니다.
# k8s secret : 도커 자격증명 설정
kubectl get secret -A # 생성 시 타입 지정
DHUSER=<도커 허브 계정>
DHPASS=<도커 허브 암호 혹은 토큰>
echo $DHUSER $DHPASS
DHUSER=devlos0322
DHPASS=dckr_pat_KWx-xxxx
echo $DHUSER $DHPASS
kubectl create secret docker-registry dockerhub-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=$DHUSER \
--docker-password=$DHPASS
# 확인
kubectl get secret
kubectl describe secret
kubectl get secrets -o yaml | kubectl neat # base64 인코딩 확인
SECRET=eyJdddddd
echo "$SECRET" | base64 -d ; echo
# 디플로이먼트 오브젝트 업데이트 : 시크릿 적용 >> 아래 도커 계정 부분만 변경해서 배포해보자
cat <<EOF | kubectl apply -f -
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:0.0.1
imagePullSecrets:
- name: dockerhub-secret
EOF
watch -d kubectl get deploy,pod -o wide
# 확인
kubectl get deploy,pod
# 접속을 위한 curl 파드 생성
kubectl run curl-pod --image=curlimages/curl:latest --command -- sh -c "while true; do sleep 3600; done"
kubectl get pod -owide
# timeserver 파드 IP 1개 확인 후 접속 확인
PODIP1=<timeserver-Y 파드 IP>
PODIP1=10.244.1.3
kubectl exec -it curl-pod -- curl $PODIP1
kubectl exec -it curl-pod -- curl $PODIP1
# 로그 확인
kubectl logs deploy/timeserver
kubectl logs deploy/timeserver -f
kubectl stern deploy/timeserver
kubectl stern -l pod=timeserver-pod
Deployment 개념 간략 실습
Deployment와 Pod의 관계에 대해서 확인하는 실습도 간단하게 진행했습니다. 다음과 같이 Pod를 삭제하더라도 Deployment의 replica개수에 의해 새로운 Pod가 생성되고 새로운 IP가 할당되게 됩니다.
POD1NAME=<파드 1개 이름>
POD1NAME=timeserver-7954b8f6df-l25wx
kubectl get pod -owide
kubectl delete pod $POD1NAME && kubectl get pod -w
# 셀프 힐링 , 파드 IP 변경 -> 고정 진입점(고정 IP/도메인네임) 필요 => Service
kubectl get deploy,rs,pod -owide
다음으로는 service를 생성하여 각각의 Pod에 접속이 되는지 확인해 봅니다.
# 서비스 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: timeserver
spec:
selector:
pod: timeserver-pod
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 30000
type: NodePort
EOF
#
kubectl get service,ep timeserver -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/timeserver NodePort 10.96.236.37 <none> 80:30000/TCP 25s pod=timeserver-pod
NAME ENDPOINTS AGE
endpoints/timeserver 10.244.1.2:80,10.244.2.2:80,10.244.3.2:80 25s
# Service(ClusterIP)로 접속 확인 : 도메인네임, ClusterIP
kubectl exec -it curl-pod -- curl timeserver
kubectl exec -it curl-pod -- curl $(kubectl get svc timeserver -o jsonpath={.spec.clusterIP})
# Service(NodePort)로 접속 확인 "노드IP:NodePort"
curl http://127.0.0.1:30000
curl http://127.0.0.1:30000
# 반복 접속 해두기 : 부하분산 확인
while true; do curl -s --connect-timeout 1 http://127.0.0.1:30000 | grep name ; sleep 1 ; done
for i in {1..100}; do curl -s http://127.0.0.1:30000 | grep name; done | sort | uniq -c | sort -nr
# 파드 복제복 증가 : service endpoint 대상에 자동 추가
kubectl scale deployment timeserver --replicas 4
kubectl get service,ep timeserver -owide
# 반복 접속 해두기 : 부하분산 확인
while true; do curl -s --connect-timeout 1 http://127.0.0.1:30000 | grep name ; sleep 1 ; done
for i in {1..100}; do curl -s http://127.0.0.1:30000 | grep name; done | sort | uniq -c | sort -nr
도메인 네임 또는 클러스터 IP로 접근이 가능합니다. Node Port로 설정해 뒀기 때문에 호스트에도 접근 가능합니다. 또한 서비스를 통한 로드밸런싱이 되어 있어 Replica 개수를 조정하여도 거의 동일하게 접속 요청이 분배됩니다.
애플리케이션 롤링업데이트 실습
다음으로 애플리케이션 업데이트를 하여 클러스터에 배포할 때 롤링 업데이트가 잘 일어나는지 확인해 봅니다. 파드 복제본 4개를 만들어 놓은 상황에서 새로운 이미지를 배포해 봅니다.
애플리케이션 버전을 0.0.1 -> 0.0.2로 변경하여 신규 이미지를 생성합니다.
# VERSION 변경 : 0.0.2
# server.py 변경 : 0.0.2
git add . && git commit -m "VERSION $(cat VERSION) Changed" && git push -u origin main
파이프라인 실행 후 새로운 이미지가 생성되었습니다.
업데이트를 통해 4개의 컨테이너가 정상적으로 배포되는 것을 확인할 수 있습니다.
다음으로 Gogs webhook 설정을 수행합니다.
# gogs container / files / data / gogs / conf / app.ini 수정
[security]
INSTALL_LOCK = true
SECRET_KEY = j2xaUPQcbAEwpIu
LOCAL_NETWORK_ALLOWLIST = 192.168.219.112 # 각자 자신의 PC IP
# 컨테이너 재기동
docker compose restart gogs
다음으로 웹훅을 생성합니다.
- Payload URL : http://[자신의 IP]:8080/gogs-webhook/?job=**SCM-Pipeline**/
- Content Type : application/json
- Secret : qwe123
gogs webhook을 적용할 새로운 파이프라인을 생성합니다.
- GitHub project : http://***<mac IP>***:3000/***<Gogs 계정명>***/dev-app ← .git 은 제거
- Use Gogs secret : qwe123
- Build Triggers : Build when a change is pushed to Gogs 체크
- Pipeline script from SCM
- SCM : Git
- Repo URL(http://***<mac IP>***:3000/***<Gogs 계정명>***/dev-app)
- Credentials(devops/***)
- Branch(*/main)
- Script Path : Jenkinsfile
- SCM : Git
파이프라인을 설정하면 다음과 같이 정상적으로 배포가 되는 모습을 확인할 수 있습니다.
Jenkins CI/CD + k8s(Kind)
드디어 이제부터 jenkins와 연동하여 helm을 통해 k8s에 서비스를 배포해 보는 실습을 진행합니다.
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
설치가 완료되면 다음과 같이 외부에서 Jenkins 컨테이너 내부의 kuberetes관련 명령어를 실행되는 것으로 정상 동작을 확인합니다.
Jenkins k8s 자격증명 테스트
다음으로 파이프라인에서 k8s 자격증명을 삽입하는 파이프라인 구조를 테스트해봅니다.
참고 - 만약 실습 과정 중 kind cluster를 재실행하게 되면 kubeconfig 파일의 정보가 변경될 수 있으므로 k8s-crd를 업데이트해야 합니다. (ㅠ . ㅠ)
Jenkins를 이용한 블루그린 배포
echo 서버를 이용하여 배포 테스트를 해봅니다.
#
cd dev-app
#
mkdir deploy
#
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
블루 그린 배포를 수동으로 테스트해봅니다.
cd deploy
kubectl delete deploy,svc --all
kubectl apply -f .
#
kubectl get deploy,svc,ep -owide
curl -s http://127.0.0.1:30000
#
kubectl patch svc echo-server-service -p '{"spec": {"selector": {"version": "green"}}}'
kubectl get deploy,svc,ep -owide
curl -s http://127.0.0.1:30000
#
kubectl patch svc echo-server-service -p '{"spec": {"selector": {"version": "blue"}}}'
kubectl get deploy,svc,ep -owide
curl -s http://127.0.0.1:30000
# 삭제
kubectl delete -f .
cd ..
삭제하고 나서, 이제는 파이프라인을 통해 수행해 봅니다.
젠킨스 를이용한 배포가 불편하고, 개발팀과 운영팀에 동시에 레포지토리를 관리하기 때문에 불편한 상황입니다. 이를 Argo CD를 이용하여 해결해 보겠습니다.
Jenkins CI + Argo CD + K8S(Kind)
Argo CD
Argo CD는 Kubernetes에 특화된 GitOps 기반의 지속적 배포(CD) 도구입니다. Git에 선언적으로 정의된 애플리케이션 상태를 Kubernetes 클러스터에 동기화하고 관리하는 데 사용.
- GitOps 기반: Git을 단일 진실의 원천(Single Source of Truth)으로 활용하여 애플리케이션 배포를 선언적으로 관리합니다.
- 자동화 및 동기화: Git 상태와 Kubernetes 클러스터 상태를 비교하여 불일치를 감지하고, 필요시 자동으로 동기화합니다.
- 멀티 클러스터 지원: 여러 Kubernetes 클러스터를 한 곳에서 관리할 수 있습니다.
- UI 및 CLI 제공: 사용자 친화적인 대시보드와 강력한 CLI 도구를 통해 배포 상태를 확인하고 제어할 수 있습니다.
- RBAC 및 보안: 사용자 및 애플리케이션에 대한 세부적인 역할 기반 접근 제어(RBAC)를 제공합니다.
Argo CD는 선언적 배포 방식을 통해 안정적이고 일관된 Kubernetes 애플리케이션 관리를 가능하게 하여, DevOps 및 GitOps 워크플로우에 적합합니다.
우리가 구성하려는 환경은 git에 명시된 리소스 스펙을 기반으로 k8s 클러스터로 배포하는 것입니다.
출처 - https://argo-cd.readthedocs.io/en/stable/operator-manual/architecture/
Argo CD 설치
# 네임스페이스 생성 및 파라미터 파일 작성
kubectl create ns argocd
cat <<EOF > 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 get pod,svc,ep -n argocd
kubectl get crd | grep argo
applications.argoproj.io 2024-04-14T08:12:16Z
applicationsets.argoproj.io 2024-04-14T08:12:17Z
appprojects.argoproj.io 2024-04-14T08:12:16Z
# 최초 접속 암호 확인
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
## Windows OS경우 직접 웹 브라우저에서 https://127.0.0.1:30002 접속
레포지토리를 연결합니다.
Setting / Repositories / connect repo /
Helm 실습
#
mkdir nginx-chart
cd nginx-chart
mkdir templates
cat > templates/configmap.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}
data:
index.html: |
{{ .Values.indexHtml | indent 4 }}
EOF
cat > templates/deployment.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: nginx
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
ports:
- containerPort: 80
volumeMounts:
- name: index-html
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: index-html
configMap:
name: {{ .Release.Name }}
EOF
cat > templates/service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}
spec:
selector:
app: {{ .Release.Name }}
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30000
type: NodePort
EOF
cat > values.yaml <<EOF
indexHtml: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Hello, Kubernetes!</h1>
<p>Nginx version 1.26.1</p>
</body>
</html>
image:
repository: nginx
tag: 1.26.1
replicaCount: 1
EOF
cat > Chart.yaml <<EOF
apiVersion: v2
name: nginx-chart
description: A Helm chart for deploying Nginx with custom index.html
type: application
version: 1.0.0
appVersion: "1.26.1"
EOF
# 이전 timeserver/service(nodeport) 삭제
kubectl delete deploy,svc --all
# 직접 배포 해보기
helm install dev-nginx . -f values.yaml
helm list
kubectl get deploy,svc,ep,cm dev-nginx -owide
#
curl http://127.0.0.1:30000
curl -s http://127.0.0.1:30000 | grep version
이번에는 value 값을 변경하여 적용해 봅니다. 변경되는 정보는 tag의 버전정보와 replica 수입니다.
# value 값 변경 후 적용 해보기 : version/tag, replicaCount
cat > values.yaml <<EOF
indexHtml: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Hello, Kubernetes!</h1>
<p>Nginx version 1.26.2</p>
</body>
</html>
image:
repository: nginx
tag: 1.26.2
replicaCount: 2
EOF
# helm chart 업그레이드 적용
helm upgrade dev-nginx . -f values.yaml
# 확인
helm list
kubectl get deploy,svc,ep,cm dev-nginx -owide
curl http://127.0.0.1:30000
curl -s http://127.0.0.1:30000 | grep version
open http://127.0.0.1:30000
# 확인 후 삭제
helm uninstall dev-nginx
Repo(ops-deploy) 에 nginx helm chart 를 Argo CD를 통한 배포 1
운영과 배포를 각각 관리하기 위해 두 개의 value 파일로 구분하였습니다.
create 버튼을 클릭합니다.
배포를 위해 sync를 클릭합니다.
Sync를 누르면 다음과 같이 helm chart로 만든 애플리케이션이 배포됩니다.
다음으로 코드를 변경하여 변경사항을 적용시켜 봅니다.
#
VERSION=1.26.2
cat > nginx-chart/VERSION <<EOF
$VERSION
EOF
cat > nginx-chart/values-dev.yaml <<EOF
indexHtml: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Hello, Kubernetes!</h1>
<p>DEV : Nginx version $VERSION</p>
</body>
</html>
image:
repository: nginx
tag: $VERSION
replicaCount: 2
EOF
cat > nginx-chart/values-prd.yaml <<EOF
indexHtml: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Hello, Kubernetes!</h1>
<p>PRD : Nginx version $VERSION</p>
</body>
</html>
image:
repository: nginx
tag: $VERSION
replicaCount: 2
EOF
#
git status && git add . && git commit -m "Update nginx version $(cat nginx-chart/VERSION)" && git push -u origin main
3분마다 싱크를 맞춰주기 때문에 싱크가 안 맞을 수 있습니다. 그래서 새로고침해야지만 최신으로 확인할 수 있습니다. 이러한 처리는 argocd에 github 웹훅을 통해서 동기화시켜줄 수 있습니다.
Repo(ops-deploy) 에 nginx helm chart 를 Argo CD를 통한 배포 2
ArgoCD Declarative Setup - ArgoCD 애플리케이션 자체를 yaml로 생성할 수 있습니다. 이때 자동으로 배포하도록 설정도 가능합니다.
#
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prd-nginx
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
namespace: prd-nginx
server: https://kubernetes.default.svc
project: default
source:
helm:
valueFiles:
- values-prd.yaml
path: nginx-chart
repoURL: http://192.168.219.112:3000/devops/ops-deploy
targetRevision: HEAD
syncPolicy:
automated:
prune: true
syncOptions:
- CreateNamespace=true
EOF
#
kubectl get applications -n argocd prd-nginx
kubectl describe applications -n argocd prd-nginx
kubectl get pod,svc,ep,cm -n prd-nginx
#
curl http://127.0.0.1:30000
open http://127.0.0.1:30000
# Argo CD App 삭제
kubectl delete applications -n argocd prd-nginx
소스코드 변경 시 바로 배포가 됩니다.
Argo Rollout + K8S(Kind)
Argo CD를 이용하여 고급 배포전략을 지원하는 방법에 대해 배웠습니다.
다음과 같은 배포 전략들을 제공합니다.
Blue-Green
Canary
이제 공식 실습예제를 통해 Argo Rollout 사용법을 확인해 봅니다.
# 네임스페이스 생성 및 파라미터 파일 작성
cd $PWD
kubectl create ns argo-rollouts
cat <<EOT > argorollouts-values.yaml
dashboard:
enabled: true
service:
type: NodePort
nodePort: 30003
EOT
# 설치
helm install argo-rollouts argo/argo-rollouts --version 2.35.1 -f argorollouts-values.yaml --namespace argo-rollouts
# 확인
kubectl get all -n argo-rollouts
kubectl get crds
# Argo rollouts 대시보드 접속 주소 확인
echo "http://127.0.0.1:30003"
설치하면 다음과 같이 argo rollouts으로 접속이 됩니다.
kubectl edit rollouts rollouts-demo
..
- image: argoproj/rollouts-demo:yellow
...
# 파드 label 정보 확인
watch -d kubectl get pod -l app=rollouts-demo -owide --show-labels
GUI 환경을 통해 스텝을 조절하면 순차적으로 배포됩니다.
이 외에도 다양한 툴들과 연동되어 traffic management 가 가능합니다.
출처 - https://argo-rollouts.readthedocs.io/en/stable/features/traffic-management/
마치며
이번 시간에는 Jenkins와 gogs, argocd를 통해 CI/CD 파이프라인을 구축하는 방법에 대해 스터디했습니다. 이번 주차에서는 argo rollout에 대해 배우고, helm을 통해 argocd를 구성하는 방법에 대해서 배운 것이 새로웠습니다. 현재 회사에서는 argocd와 kustomize를 사용하고 있기 때문에, 새로운 패턴을 알게 되어 많은 도움이 되었습니다.
또한 이번 스터디를 통해 Jenkins와 argocd를 연동하는 방법을 배우게 되어, 차년도 사업에서 많이 활용하게 될 것 같습니다!
역시 스터디를 참여하기 잘한 것 같아요.. 짧은 3주였지만 스터디를 준비하시고 이끌어주신 가시다 님께 진심으로 감사의 마음을 전합니다. 또한 긴 스터디를 끝까지 완주한 저의 동반자 피터님과 다른 스터디 분들 모두 고생 많으셨어요!!
긴 글 읽어주셔서 감사합니다 :)
'클라우드 컴퓨팅 & NoSQL > [CICD] CICD 맛보기 스터디' 카테고리의 다른 글
[2주차 - Github Action] CI/CD 스터디 (24.12.08) (3) | 2024.12.15 |
---|---|
[1주차] CI/CD 스터디 (24.12.01) (2) | 2024.12.08 |