Ssoon

3주차 - Jenkins CI/ArgoCD + K8S : Full CI/CD 구성 본문

CICD 맛보기

3주차 - Jenkins CI/ArgoCD + K8S : Full CI/CD 구성

구구달스 2024. 12. 17. 23:33
CloudNet@ 가시다님이 진행하는 CI/CD 맛보기 스터디

Full CI/CD

🧿 ops-deploy Repo 코드 작업

  • dev-app 디렉터리를 생성합니다.
  • VERSION=0.0.1 값을 환경 변수로 설정합니다.
  • dev-app/VERSION 파일을 생성하고 그 안에 버전 정보(0.0.1)를 저장합니다.
[ssoon@localhost ops-deploy]$ mkdir dev-app
[ssoon@localhost ops-deploy]$ DHUSER=kschoi728
[ssoon@localhost ops-deploy]$ VERSION=0.0.1
[ssoon@localhost ops-deploy]$ cat > dev-app/VERSION <<EOF
$VERSION
EOF
  • Docker Hub 사용자 정보(DHUSER, DHPASS)를 환경 변수로 설정.
  • Kubernetes Secret을 생성하여 Docker Hub에 접근할 수 있는 인증 정보를 저장.
  • Secret은 이후 Kubernetes에서 이미지(Pod 생성 시)에 접근할 때 사용됩니다.
[ssoon@localhost dev-app]$ DHUSER=kschoi728
[ssoon@localhost dev-app]$ DHPASS=dckr_pat_qAvtuYOW9U4OEDevuW81CuluDk0
[ssoon@localhost dev-app]$ echo $DHUSER $DHPASS
kschoi728 dckr_pat_qAvtuYOW9U4OEDevuW81CuluDk0
[ssoon@localhost dev-app]$ kubectl get secret
No resources found in default namespace.
[ssoon@localhost dev-app]$ kubectl create secret docker-registry dockerhub-secret \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=$DHUSER \
  --docker-password=$DHPASS
secret/dockerhub-secret created
[ssoon@localhost dev-app]$ kubectl get secret
NAME               TYPE                             DATA   AGE
dockerhub-secret   kubernetes.io/dockerconfigjson   1      3s
  • 이 YAML 파일은 Kubernetes 클러스터에서 timeserver라는 Deployment를 정의합니다.
  • 이 Deployment는:
    • docker.io/kschoi728/dev-app:0.0.1 이미지를 사용하여 Pod를 생성.
    • dockerhub-secret 을 사용하여 Docker Hub에서 이미지를 다운로드.
    • 동일한 Pod를 2개 생성하여 관리.
[ssoon@localhost ops-deploy]$ 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
  • 이 파일은 Kubernetes 클러스터에서 NodePort Service를 생성하여 외부에서 Deployment의 Pod에 접근할 수 있게 합니다.
  • Service 이름: timeserver.
  • 외부 요청 → 노드 IP + 포트(30000) → Pod의 컨테이너 포트(80번)으로 전달.
[ssoon@localhost ops-deploy]$ 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을 사용하여 현재 작업 내용을 커밋하고 원격 저장소(main 브랜치)에 푸시
[ssoon@localhost ops-deploy]$ git status && git add . && git commit -m "Add dev-app deployment yaml" && git push -u origin main
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.

추적하지 않는 파일:
  (커밋할 사항에 포함하려면 "git add <파일>..."을 사용하십시오)
        dev-app/

커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다 (추적하려면 "git
add"를 사용하십시오)
[main fad2437] Add dev-app deployment yaml
 3 files changed, 33 insertions(+)
 create mode 100644 dev-app/VERSION
 create mode 100644 dev-app/service.yaml
 create mode 100644 dev-app/timeserver.yaml
오브젝트 나열하는 중: 7, 완료.
오브젝트 개수 세는 중: 100% (7/7), 완료.
Delta compression using up to 4 threads
오브젝트 압축하는 중: 100% (5/5), 완료.
오브젝트 쓰는 중: 100% (6/6), 785 bytes | 785.00 KiB/s, 완료.
Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
To http://192.168.56.105:3000/devops/ops-deploy.git
   4e431c2..fad2437  main -> main
branch 'main' set up to track 'origin/main'.
  • gogs 대시보드에서 내용을 확인합니다.


🧿Argo CD app 생성

finalizers: 리소스 삭제 시 추가 작업을 지정.

  • 여기서 resources-finalizer.argocd.argoproj.io는 ArgoCD에서 리소스를 정리하는 데 사용됩니다.

  • syncPolicy: 애플리케이션 동기화 정책을 정의.
    • automated: 동기화 작업을 자동으로 수행.
      • prune: true: Git 저장소에 없는 리소스를 자동으로 삭제.
    • syncOptions:
      • CreateNamespace=true: 네임스페이스가 없으면 자동으로 생성.

ArgoCD에 새로운 애플리케이션(timeserver)을 등록하여 GitOps 방식으로 Kubernetes 클러스터에 배포를 관리합니다.

[ssoon@localhost ops-deploy]$ 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.56.105:3000/devops/ops-deploy
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: default
    server: https://kubernetes.default.svc
EOF
Warning: metadata.finalizers: "resources-finalizer.argocd.argoproj.io": prefer a domain-qualified finalizer name to avoid accidental conflicts with other finalizer writers
application.argoproj.io/timeserver created
  • ArgoCD 애플리케이션의 상태를 확인합니다.
[ssoon@localhost dev-app]$ kubectl get applications -n argocd timeserver
NAME         SYNC STATUS   HEALTH STATUS
timeserver   Synced        Healthy
[ssoon@localhost dev-app]$ kubectl get deploy,rs,pod
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/timeserver   2/2     2            2           56s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/timeserver-7fcbc89ff9   2         2         2       56s

NAME                              READY   STATUS    RESTARTS   AGE
pod/timeserver-7fcbc89ff9-hd266   1/1     Running   0          56s
pod/timeserver-7fcbc89ff9-tbxck   1/1     Running   0          56s
[ssoon@localhost dev-app]$ kubectl get svc,ep timeserver
NAME                 TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/timeserver   NodePort   10.96.150.246   <none>        80:30000/TCP   61s

NAME                   ENDPOINTS                       AGE
endpoints/timeserver   10.244.1.17:80,10.244.2.18:80   61s
  • 애플리케이션이 정상적으로 배포되고 작동 중임을 확인합니다.
[ssoon@localhost dev-app]$ curl http://127.0.0.1:30000
The time is 2:55:06 PM, VERSION 0.0.1
Server hostname: timeserver-7fcbc89ff9-hd266


🧿 dev-app Repo 코드 작업

  • Jenkinsfile 내용을 변경합니다.
pipeline {
    agent any
    environment {
        DOCKER_IMAGE = 'kschoi728/dev-app' // Docker 이미지 이름
        GOGSCRD = credentials('gogs-crd')
    }
    stages {
        stage('dev-app Checkout') {
            steps {
                 git branch: 'main',
                 url: 'http://192.168.56.105: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.56.105: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.56.105: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."
        }
    }
}
  • VERSION 파일과 server.py 파일을 수정하고 repo 에 배포합니다.
git add . && git commit -m "VERSION $(cat VERSION) Changed" && git push -u origin main
  • Jenkins 에서 pipeline 을 확인합니다.


🧿 동작 확인

  • ops-deploy repo에서 변경된 내용을 확인합니다.

  • ArgoCD 에서도 Sync 을 실행하여 업데이트 내용을 확인합니다.

Comments