CICD 맛보기 Study

[3주차] - Jenkins CI/ArgoCD + K8S - #2

haru224 2024. 12. 21. 22:32

CloudNet@ 가시다님이 진행하는 CI/CD 맛보기 스터디 내용 참고.

 

 

3. Jenkins CI + Argo CD + K8S(Kind)


 

☞ Argo CD 소개 : Argo CD는 Kubernetes를 위한 선언적 GitOps 지속적 전달 도구입니다.

 

  • 애플리케이션 정의, 설정, 환경은 선언적이고 버전 관리되어야 합니다.
  • 애플리케이션 배포와 라이프사이클 관리는 자동화되고, 감사 가능하며, 이해하기 쉬워야 합니다.
  • 작동 방식: Argo CD는 GitOps 패턴을 따라 Git 리포지토리를 원하는 애플리케이션 상태를 정의하는 기준(source of truth)으로 사용합니다.
    Kubernetes 매니페스트는 여러 가지 방식으로 지정할 수 있습니다
    • kustomize applications
    • helm charts
    • jsonnet files
    • Plain directory of YAML/json manifests
    • Any custom config management tool configured as a config management plugin
  • Architecture - Docs

출처: https://argo-cd.readthedocs.io/en/stable/

 

 

  • API Server : Web UI 대시보드, k8s api 처럼 API 서버 역할
    • API 서버는 Web UI, CLI, CI/CD 시스템에서 사용하는 API를 제공하는 gRPC/REST 서버입니다. API 서버의 주요 역할은 다음과 같습니다:
    • 애플리케이션 관리 및 상태 보고
    • 애플리케이션 작업 호출 (예: 동기화(sync), 롤백(rollback), 사용자 정의 작업)
    • 저장소 및 클러스터 자격 증명 관리 (Kubernetes Secrets로 저장)
    • 외부 ID 공급자에 대한 인증 및 인증 위임
    • RBAC(역할 기반 접근 제어) 적용
    • Git 웹훅 이벤트의 리스너/포워더 역할
 
  • Repository Server : Git 연결 및 배포할 yaml 생성 
    • 저장소 서버는 애플리케이션 매니페스트를 보유한 Git 저장소의 로컬 캐시를 유지하는 내부 서비스입니다. 다음 입력값이 제공되었을 때 Kubernetes 매니페스트를 생성하고 반환하는 역할을 합니다:
    • 저장소 URL
    • 리비전(커밋, 태그, 브랜치)
    • 애플리케이션 경로
    • 템플릿별 설정: 매개변수, Helm values.yaml
  • Application Controller : k8s 리소스 모니터링, Git과 비교
    • 애플리케이션 컨트롤러는 Kubernetes 컨트롤러로, 실행 중인 애플리케이션을 지속적으로 모니터링하며 현재의 실시간 상태를 저장소에 지정된 원하는 목표 상태와 비교합니다. 이 컨트롤러는 애플리케이션 상태가 OutOfSync(동기화되지 않음)인 것을 감지하고, 선택적으로 이를 수정하는 작업을 수행합니다. 또한 PreSync, Sync, PostSync와 같은 라이프사이클 이벤트에 대해 사용자 정의 훅을 호출하는 역할을 합니다. 
  • Redis : k8s api와 git 요청을 줄이기 위한 캐싱
  • Notification : 이벤트 알림, 트리거
  • Dex : 외부 인증 관리
  • ApplicationSet Controller : 멀티 클러스터를 위한 App 패키징 관리
  • 기능
    • 지정된 대상 환경에 애플리케이션 자동 배포
    • 다양한 구성 관리 및 템플릿 도구 지원 (Kustomize, Helm, Jsonnet, plain-YAML)
    • 여러 클러스터에 대한 관리 및 배포 기능
    • SSO 통합 지원 (OIDC, OAuth2, LDAP, SAML 2.0, GitHub, GitLab, Microsoft, LinkedIn)
    • 멀티 테넌시 및 RBAC(역할 기반 접근 제어) 정책을 통한 권한 관리
    • Git 저장소에 커밋된 애플리케이션 구성으로 롤백 또는 특정 지점으로의 롤아웃
    • 애플리케이션 리소스의 상태 분석
    • 구성 드리프트 자동 감지 및 시각화
    • 애플리케이션을 원하는 상태로 자동 또는 수동 동기화
    • 실시간 애플리케이션 활동을 보여주는 웹 UI
    • 자동화 및 CI 통합을 위한 CLI
    • 웹훅 통합 (GitHub, BitBucket, GitLab)
    • 자동화를 위한 액세스 토큰
    • PreSync, Sync, PostSync 훅을 통해 블루/그린 또는 카나리 업그레이드와 같은 복잡한 애플리케이션 롤아웃 지원
    • 애플리케이션 이벤트 및 API 호출에 대한 감사 기록
    • Prometheus 메트릭 지원
    • Git에서 Helm 매개변수를 덮어쓸 수 있는 매개변수 오버라이드 기능
  • Core Concepts - Docs
    • Application (애플리케이션): 매니페스트로 정의된 Kubernetes 리소스의 그룹. 이는 커스텀 리소스 정의(CRD)입니다.
    • Application source type (애플리케이션 소스 유형): 애플리케이션을 빌드하는 데 사용되는 도구.
    • Target state (목표 상태): Git 저장소의 파일로 표현된 애플리케이션의 원하는 상태.
    • Live state (실시간 상태): 해당 애플리케이션의 실시간 상태. 배포된 파드 등 현재 클러스터의 상태.
    • Sync status (동기화 상태): 실시간 상태가 목표 상태와 일치하는지 여부. 배포된 애플리케이션이 Git에 정의된 상태와 동일한지 확인.
    • Sync (동기화): 애플리케이션을 목표 상태로 이동시키는 과정. 예: Kubernetes 클러스터에 변경 사항 적용.
    • Sync operation status (동기화 작업 상태): 동기화가 성공했는지 여부.
    • Refresh (새로 고침): Git의 최신 코드와 실시간 상태를 비교하여 차이점을 파악.
    • Health (상태): 애플리케이션의 상태, 올바르게 실행되고 요청을 처리할 수 있는지 여부.
    • Tool (도구): 파일 디렉토리에서 매니페스트를 생성하는 도구. 예: Kustomize. Application Source Type 참조.
    • Configuration management tool (구성 관리 도구): Tool 참조.
    • Configuration management plugin (구성 관리 플러그인): 사용자 정의 도구.

 

☞ Argo CD 설치 및 기본 설정 - helm_chart

  • 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 접속

 

 

 

  • Argo CD 웹 접속 확인
    • User info → UPDATE PASSWORD 로 admin 계정 암호 변경 (qwe12345)
  • 기본 정보 확인 (Settings) : Clusters, Projects, Accounts

  • ops-deploy Repo 등록 : Settings → Repositories → CONNECT REPO 클릭

⇒ 입력 후 CONNECT 클릭

 

☞ (기초) helm chart 를 통한 배포 실습

#
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
open http://127.0.0.1:30000


# 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

 

upgrade 후 버전 확인

 

☞ Repo(ops-deploy) 에 nginx helm chart 를 Argo CD를 통한 배포 1

  • git 작업
#
cd ~/cicd-labs
git clone http://192.168.68.12:3000/devops/ops-deploy.git
cd ops-deploy

#
git config user.name "devops"
git config user.email "a@a.com"
git config init.defaultBranch main
git config credential.helper store

#
VERSION=1.26.1
mkdir nginx-chart
mkdir nginx-chart/templates

cat > nginx-chart/VERSION <<EOF
$VERSION
EOF

cat > nginx-chart/templates/configmap.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}
data:
  index.html: |
{{ .Values.indexHtml | indent 4 }}
EOF

cat > nginx-chart/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 > nginx-chart/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 > 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: 1
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

cat > nginx-chart/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: "$VERSION"
EOF

tree nginx-chart
nginx-chart
├── Chart.yaml
├── VERSION
├── templates
│   ├── configmap.yaml
│   ├── deployment.yaml
│   └── service.yaml
├── values-dev.yaml
└── values-prd.yaml

#
git status && git add . && git commit -m "Add nginx helm chart" && git push -u origin main

 

  • Argo CD에 App 등록 : Application → NEW APP
    • GENERAL
      • App Name : dev-nginx
      • Project Name : default
      • SYNC POLICY : Manual
      • SYNC OPTIONS : AUTO-CREATE NAMESPACE(Check)
    • Source
      • Repo URL : 설정되어 있는 것 선택
      • Revision : HEAD
      • PATH : nginx-chart
    • DESTINATION
      • Cluster URL : <기본값>
      • NAMESPACE : dev-nginx
    • HELM
      • Values files : values-dev.yaml
    ⇒ 작성 후 상단 CREATE 클릭

 

  • dev-nginx App 클릭 후 상세 정보 확인 → DIFF 클릭 확인

 

#
kubectl get applications -n argocd
NAME        SYNC STATUS   HEALTH STATUS
dev-nginx   OutOfSync     Missing

kubectl describe applications -n argocd dev-nginx

# 반복 접속 시도
while true; do curl -s --connect-timeout 1 http://127.0.0.1:30000 ; date ; echo "------------" ; sleep 1 ; done

  • SYNC 클릭 으로 반영 확인
# 아래 처럼 yaml 로 APP 생성 가능
kubectl get applications -n argocd
kubectl get applications -n argocd -o yaml | kubectl neat

# 배포 확인
kubectl get all -n dev-nginx -o wide

 

  • 코드 수정 후 반영 확인
#
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

  • Argo CD 웹 확인 → REFRESH 클릭 - Interval

 

Argo CD는 Git 또는 Helm 저장소의 변경 사항을 얼마나 자주 확인하나요?
기본 폴링 간격은 3분(180초)입니다. 이 설정은 argocd-cm 설정 맵(ConfigMap)에서 timeout.reconciliation 값을 업데이트하여 변경할 수 있습니다.

 

  • SYNC 클릭 → SYNCHRONIZE 클릭
# 배포 확인
kubectl get all -n dev-nginx -o wide

 

 

  • Argo CD 웹에서 App 삭제
watch -d kubectl get all -n dev-nginx -o wide

 

 

☞ Repo(ops-deploy) 에 nginx helm chart 를 Argo CD를 통한 배포 2 : ArgoCD Declarative Setup - ArgoCD 애플리케이션 자체를 yaml로 생성

  • ArgoCD Declarative Setup - Project, applications, ArgoCD Settings - Docs
  • dev-nginx App 생성 및 Auto SYNC
#
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: dev-nginx
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    helm:
      valueFiles:
      - values-dev.yaml
    path: nginx-chart
    repoURL: http://192.168.68.12:3000/devops/ops-deploy
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: dev-nginx
    server: https://kubernetes.default.svc
EOF

#
kubectl get applications -n argocd dev-nginx
kubectl get applications -n argocd dev-nginx -o yaml | kubectl neat
kubectl describe applications -n argocd dev-nginx
kubectl get pod,svc,ep,cm -n dev-nginx

#
curl http://127.0.0.1:30000
open http://127.0.0.1:30000

# Argo CD App 삭제
kubectl delete applications -n argocd dev-nginx

 

 

  • prd-nginx App 생성 및 Auto SYNC
#
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.68.12: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

 

 

 

Full CI/CD 구성도

 

☞ ops-deploy Repo 코드 작업

#
cd ops-deploy
mkdir dev-app

# 도커 계정 정보
DHUSER=<도커 허브 계정>
DHUSER=gasida

# 버전 정보 
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

 

☞ Argo CD app 생성

#
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: timeserver
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    path: dev-app
    repoURL: http://192.168.68.12:3000/devops/ops-deploy
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: default
    server: https://kubernetes.default.svc
EOF

#
kubectl get applications -n argocd timeserver
kubectl get applications -n argocd timeserver -o yaml | kubectl neat
kubectl describe applications -n argocd timeserver
kubectl get deploy,rs,pod
kubectl get svc,ep timeserver

#
curl http://127.0.0.1:30000
open http://127.0.0.1:30000

☞ dev-app Repo 코드 작업

  • dev-app Repo에 VERSION 업데이트 시 → ops-deploy Repo 에 dev-app 에 파일에 버전 정보 업데이트 작업 추가
    1. 기존 버전 정보는 VERSION 파일 내에 정보를 가져와서 변수 지정 : OLDVER=$(cat dev-app/VERSION)
    2. 신규 버전 정보는 environment 도커 태그 정보를 가져와서 변수 지정 : NEWVER=$(echo ${DOCKER_TAG})
    3. 이후 sed 로 ops-deploy Repo 에 dev-app/VERSION, timeserver.yaml 2개 파일에 ‘기존 버전’ → ‘신규 버전’으로 값 변경
    4. 이후 ops-deploy Repo 에 git push ⇒ Argo CD app 가 최대 3분 사이에 변경 확인 후 AutoSync 로 신규 버전 업데이트 진행

  • 아래는 dev-app 에 위치한 Jenkinsfile 로 젠킨스에 SCM-Pipeline(SCM:git) 으로 사용되고 있는 파일을 수정해서 실습에 사용
pipeline {
    agent any
    environment {
        DOCKER_IMAGE = 'sspp30578/dev-app' // Docker 이미지 이름
        GOGSCRD = credentials('gogs-crd')
    }
    stages {
        stage('dev-app Checkout') {
            steps {
                 git branch: 'main',
                 url: 'http://192.168.68.12: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")
                    }
                }
            }
        }
        stage('ops-deploy Checkout') {
            steps {
                 git branch: 'main',
                 url: 'http://192.168.68.12:3000/devops/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.68.12:3000/devops/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."
        }
    }
}

 

  • 아래는 dev-app (Repo) 에서 git push 수행
# VERSION 파일 수정 : 0.0.3
# server.py 파일 수정 : 0.0.3

# git push : VERSION, server.py, Jenkinsfile
git add . && git commit -m "VERSION $(cat VERSION) Changed" && git push -u origin main

 

 

☞ 동작 확인

  • Argo CD app 가 최대 3분 사이에 변경 확인 후 AutoSync 로 신규 버전 업데이트 진행 → Argo CD WebHook 설정 시 즉시 반영 가능

 

☞ dev-app Repo 에서 한번 더 버전 업데이트 수행

# VERSION 파일 수정 : 0.0.4
# server.py 파일 수정 : 0.0.4

# git push : VERSION, server.py, Jenkinsfile
git add . && git commit -m "VERSION $(cat VERSION) Changed" && git push -u origin main
# VERSION 파일 수정 : 0.0.5
# server.py 파일 수정 : 0.0.5

# git push : VERSION, server.py, Jenkinsfile
git add . && git commit -m "VERSION $(cat VERSION) Changed" && git push -u origin main
즉, 개발팀 dev-app Repo 에서만 코드 업데이트 작업 시, jenkins pipeline 에서 ops-deploy Repo 에 버전 정보 업데이트를 하고,
이후 Argo CD가 자동으로 신규 버전 정보로 배포를 하게 된다.

 

 

4. Argo Rollout + K8S(Kind)


 

☞ Argo Rollouts 소개 : Kubernetes 단계적 배포 컨트롤러  - Docs

  • Argo Rollouts는 Kubernetes 컨트롤러와 CRD(Custom Resource Definition) 세트로, Kubernetes에 블루-그린, 카나리 배포, 카나리 분석, 실험적 배포, 단계적 배포와 같은 고급 배포 기능을 제공합니다.
    • Argo Rollouts는 (선택적으로) Ingress 컨트롤러서비스 메쉬와 통합하여 트래픽 분배 기능을 활용하며, 업데이트 동안 트래픽을 새로운 버전으로 점진적으로 전환할 수 있습니다. 또한 Rollouts는 다양한 메트릭 제공자로부터 데이터를 조회하고 이를 해석하여, 업데이트 중 주요 KPI를 검증하고 자동으로 승격(promote)하거나 롤백(rollback)을 수행할 수 있습니다.
  • 왜 Argo Rollouts인가?
    • 기본 Kubernetes Deployment 객체는 RollingUpdate 전략을 지원하며, 업데이트 중에 준비 상태 프로브(readiness probes)를 통해 기본적인 안전성을 보장합니다. 그러나 롤링 업데이트 전략에는 다음과 같은 여러 한계가 있습니다: 
    • 배포 속도를 세밀하게 제어할 수 있는 기능이 제한적입니다.
    • 새로운 버전으로의 트래픽 흐름을 제어할 수 없습니다.
    • 준비 상태 프로브는 심층 테스트, 스트레스 테스트 또는 일회성 검증에 적합하지 않습니다.
    • 업데이트를 검증하기 위해 외부 메트릭을 조회하거나 이를 활용할 수 있는 기능이 없습니다.
    • 진행을 중단할 수는 있지만, 문제 발생 시 자동으로 중단하고 롤백하는 기능은 없습니다.
  • 컨트롤러 기능
    • 블루-그린 업데이트 전략

출처: https://argoproj.github.io/argo-rollouts/concepts/

  • 카나리 업데이트 전략

출처: https://argoproj.github.io/argo-rollouts/concepts/

 

  • 세밀하고 가중치 기반의 트래픽 전환
  • 자동 롤백 및 승격(promotion)
  • 수동 승인(Manual Judgement)
  • 비즈니스 KPI에 대한 사용자 정의 메트릭 쿼리 및 분석
  • Ingress 컨트롤러 통합: NGINX, ALB, Apache APISIX
  • 서비스 메쉬 통합: Istio, Linkerd, SMI
  • 다중 제공자 동시 사용: SMI + NGINX, Istio + ALB 등
  • 메트릭 제공자 통합: Prometheus, Wavefront, Kayenta, Web, Kubernetes Jobs, Datadog, New Relic, Graphite, InfluxDB

 

  • 아키텍처 - Docs

출처: https://argoproj.github.io/argo-rollouts/architecture/

  • Argo Rollouts 컨트롤러
    • Rollout 타입의 리소스를 감시하고 변경 사항이 있을 때 클러스터 상태를 Rollout 정의와 일치하도록 조정.
    • 일반 Deployment 리소스에는 영향을 주지 않으므로 기존 Deployment와 병행 사용 가능.
    • Progressive Delivery를 시작하려면 설치 필요.
  • Rollout 리소스
    • Argo Rollouts가 관리하는 커스텀 Kubernetes 리소스.
    • Kubernetes Deployment와 호환되지만, 단계, 임계값, 배포 방식(Canary, Blue/Green 등)을 제어하는 추가 필드 포함.
    • Rollouts로 관리하려면 기존 Deployment를 Rollout으로 마이그레이션 필요.
  • ReplicaSets 관리
    • 표준 Kubernetes ReplicaSet에 메타데이터 추가로 버전 추적.
    • 컨트롤러가 자동으로 관리하며 외부에서 수정 금지.
  • Ingress/Service
    • 트래픽 관리를 위해 Kubernetes Service 리소스를 사용하며, 새로운/이전 버전에 따른 서비스 구성이 가능.
    • Canary 배포의 경우 서비스 메쉬와 Ingress를 통해 트래픽 비율 기반 분할 지원.
  • AnalysisTemplate 및 AnalysisRun
    • 분석 기능: 메트릭 제공자와 연결하여 특정 메트릭 임계값을 설정해 업데이트 성공 여부 판단.
    • AnalysisTemplate: 메트릭 쿼리 정의.
    • AnalysisRun: Rollout에 연결된 결과 리소스.
    • 메트릭 솔루션 없이도 수동 제어 가능하며 자동화 및 수동 단계를 혼합 가능.
  • 메트릭 제공자
    • Prometheus, Datadog 등 다양한 메트릭 제공자와 네이티브 통합 가능.
  • CLI 및 UI
    • Rollout 관리를 위한 CLI 및 UI 제공 (선택적 사용).

 

☞ Argo Rollouts 설치 및 Sample 테스트 - Docs

  • Argo Rollouts 설치
# 네임스페이스 생성 및 파라미터 파일 작성
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"
open "http://127.0.0.1:30003"

 

  • Deploying a Rollout
spec:
  replicas: 5
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause: {}
      - setWeight: 40
      - pause: {duration: 10}
      - setWeight: 60
      - pause: {duration: 10}
      - setWeight: 80
      - pause: {duration: 10}
# Run the following command to deploy the initial Rollout and Service:
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/rollout.yaml
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/service.yaml

# 확인
kubectl get rollout
kubectl describe rollout

kubectl get pod -l app=rollouts-demo
kubectl get svc,ep rollouts-demo
kubectl get rollouts rollouts-demo -o json | grep rollouts-demo
...
   "image": "argoproj/rollouts-demo:blue"
...

 

 

 

 

  • Updating a Rollout
# Run the following command to update the rollouts-demo Rollout with the "yellow" version of the container:
kubectl edit rollouts rollouts-demo
..
     - image: argoproj/rollouts-demo:yellow
...

# 파드 label 정보 확인
watch -d kubectl get pod -l app=rollouts-demo -owide --show-labels

  • Promoting a Rollout

promote 를 승인해야 진행
시간이 지나면 자동으로 진행

 

순차적으로 pod 가 전환됨

# 정보 확인
kubectl get rollouts rollouts-demo -o json | grep rollouts-demo
watch -d kubectl get pod -l app=rollouts-demo -owide --show-labels

"image": "argoproj/rollouts-demo:yellow" 로 변경됨