본문 바로가기
Cloud

[ArgoCD] FE 배포 Helm 구성기

by VENUSIM 2024. 12. 27.

구성 및 동작 과정

  1. Helm 을 통해 Job을 생성한다.
  2. Job은 빌드 번호에 해당하는 디렉터리의 파일을 배포 폴더로 Sync 를 맞춰준다.

Helm 구성

  • Front 소스 배포용 Helm 차트 구조

  • Helm 상세 내용
    • job.yaml
      apiVersion: batch/v1
      kind: Job
      metadata:
        name: {{ .Release.Name }}
        namespace: {{ .Values.namespace }}
      spec:
        ttlSecondsAfterFinished: 0 // 1회성 실행을 위한 설정
        template:
          spec:
            containers:
            - name: {{ .Release.Name }}-container
              image: {{ .Values.image }}
              command: {{ .Values.command }}
              envFrom:
                - secretRef:
                    name: {{ .Values.envSecretName }}
              args:
                - "--endpoint-url=https://{{ .Values.storage.endpoint }}"
            restartPolicy: {{ .Values.restartPolicy }}
            imagePullSecrets:
              - name: {{ .Values.imagePullSecretName }}
        backoffLimit: {{ .Values.backoffLimit }}

    • index.yaml
      apiVersion: v1
      entries:
        fastapi:
        - apiVersion: v2
          appVersion: "1.0"
          created: "2023-11-21T16:39:53.6250541+09:00"
          description: A Helm chart for deploying project
          digest: b212cc1ff670a1e2b2d50a03b7703afc21031655564e2090e1b74066336ccc7d
          name: fastapi
          type: application
          urls:
            - https://storage.com/bucket-name/front-chart/fastapi-0.1.0.tgz
          version: 0.1.0
      generated: "2023-11-21T16:39:53.6244422+09:00"
       

HelmBuild

 

 

Releases · helm/helm

The Kubernetes Package Manager. Contribute to helm/helm development by creating an account on GitHub.

github.com

 

  • Helm 환경 변수 추가

 

Helm Package
fastapi 디렉터리가 위치한 경로로 이동 후 helm package . 명령어 실행

 

Helm upload
index.yaml 에 추가한 entries.fastapi.urls 경로에 package를 통해 생성된
fastapi-0.1.0.tgz 업로드

 

ArgoCD Manifest 구성

    • Base kustomize & values
      Jenkins pipeline Check Manifest stage 에서 생성 됩니다.

    • 환경 별 kustomize & image-patch.yaml
      • kustomization.yaml
        helmCharts:
        - name: fastapi
          repo: https://storage.com/bucket-name/front-chart
          version: 0.1.0
          releaseName: object-storage-deploy-test
          namespace: default
          valuesFile: values.yaml
      • values.yaml
        image: container-registry/aws-cli-1.15.58
        
        namespace: example
        
        storage:
          endpoint: storage-endpoint.org
        
        command: 
          
        restartPolicy: OnFailure
        
        imagePullSecretName: ncpsecret
        
        backoffLimit: 4
        
        envSecretName: awscli


      • 환경 별 kustomize & image-patch.yaml
        • kustomization.yaml
          resources:
            - ../base
          
          commonLabels:
            app: object-storage-deploy-test
          
          namespace: example
                
          generatorOptions:
            disableNameSuffixHash: true
            
          patches:
            - path: image-patch.yaml
              target:
                kind: Job
        • image-patch.yaml
           -op: replace
            path: /spec/template/spec/containers/0/image
            value: container-registry/aws-cli-1.15.58
          - op: replace
            path: /spec/template/spec/containers/0/command
            value: ["aws", "s3", "sync", "s3://contents/test/#166/dist", "s3://contents/test/dist"]
           
          • image
            커스텀한 aws-cli image로 s3 command line 을 이용하여 정적 리소스를 동기화 합니다.
          • command
            sync 를 맞추는 역할로 from bucket/path 와 to bucket/path를 설정 할 수 있도록 구성했습니다
 

K8S Secret 추가

kind: Secret
apiVersion: v1
metadata:
  name: awscli
  namespace: example
stringData:
  AWS_ACCESS_KEY_ID: access_key
  AWS_SECRET_ACCESS_KEY: secert_key
type: Opaque

Jenkins Pipeline

@Library('shared-library-teams') _ // Shared Library (Jenkins > System > Global Pipeline)

pipeline {
    agent any

	tools {
        nodejs 'nodejs-21.2.0'
    }

    environment {
        
        PATH = "/usr/local/bin:$HOME/.local/bin:$PATH"  // 환경 변수 설정
        ENDPOINT = "container-registry"
        ENDPOINT_URL = "https://${ENDPOINT}"  // 객체 스토리지 엔드포인트 URL
        BUCKET_NAME = "bucket"  // 버킷 이름
        BUILD_NUMBER = "#${currentBuild.number}"
        ROOT_DIRECTORY = "version"  // Root 폴더 이름
        DIRECTORY_PATH = "dist"  // 업로드할 디렉토리 경로
        DEPLOY_DIRECTORY = "deploy"
        
        GIT_URL = "http://gitlab.com/project.git"
        GIT_BRANCH = "main"
        APP_DIR = "dev"
		
		APP_NAME = "app-test"
		LIBRARY_NAME = "aws-cli-1.15.58"
		
		// ArgoCD Init
		APP_NAMESPACE="namespace"
		CONFIG_FILE_CONTENT = ""
		BASE_KUSTOMIZE = ""
		PROD_KUSTOMIZE = ""
		ARGOCD_CREATE = ""
		ARGOCD_UPDATE = ""
		
		PROD_ENV = " "
       
		KEY_BASE_PATH = "${ROOT_DIRECTORY}/${BUILD_NUMBER}" 
		STORAGE_FROM_PATH= "${KEY_BASE_PATH}"
	    STORAGE_TO_PATH="${DEPLOY_DIRECTORY}"
		
		BASE_VALUE="""
image: 	image-endpoint/${LIBRARY_NAME}

namespace: ${APP_NAMESPACE}

storage:
  endpoint: ${ENDPOINT}

command: 
  
restartPolicy: OnFailure

imagePullSecretName: ncpsecret

backoffLimit: 4

envSecretName: awscli
"""
    }

    stages {
        stage('Nodejs Version Check') {
            steps {
                sh 'node --version'
            }
        }
        stage('Read Config File') {
            steps {
			// Jenkins Dashboard -> Jenkins 관리 -> Managed Files 에서 파일로 관리
				configFileProvider([configFile(fileId: 'base_yaml', variable: 'CONFIG_FILE')]) {script {BASE_KUSTOMIZE = readFile("${CONFIG_FILE}")}}
				configFileProvider([configFile(fileId: 'kustomize_front_yaml', variable: 'CONFIG_FILE')]) {script {MATH_KUSTOMIZE = readFile("${CONFIG_FILE}")}}
				configFileProvider([configFile(fileId: 'argo_create_cdn', variable: 'CONFIG_FILE')]) {script {ARGOCD_CREATE = readFile("${CONFIG_FILE}")}}
				configFileProvider([configFile(fileId: 'argo_front_update_curl_dev', variable: 'CONFIG_FILE')]) {script {ARGOCD_UPDATE = readFile("${CONFIG_FILE}")}}
				script {
					
					BASE_KUSTOMIZE = BASE_KUSTOMIZE
									.replaceAll("__HELM_CHART_URL__", "${HELM_CHART_FRONT_URL}")
									.replaceAll("__APP_NAME__", "${APP_NAME}")
							
					MATH_KUSTOMIZE = MATH_KUSTOMIZE
									.replaceAll('__APP_NAME__', "${APP_NAME}")
									.replaceAll('__APP_NAMESPACE__', "${APP_NAMESPACE}")
									
				    ENGL_KUSTOMIZE = MATH_KUSTOMIZE
				    DEV_KUSTOMIZE = MATH_KUSTOMIZE
				    STG_KUSTOMIZE = MATH_KUSTOMIZE

					ARGOCD_CREATE = ARGOCD_CREATE
										.replaceAll("__ARGOCD_GIT_URL__", "${ARGOCD_GIT_URL}")
										.replaceAll("__ARGOCD_GIT_TOKEN__", "${ARGOCD_GIT_TOKEN}")
										.replaceAll("__ARGOCD_GIT_BRANCH__", "${ARGOCD_GIT_BRANCH}")
										.replaceAll("__APP_NAME__", "${APP_NAME}")
                                        .replaceAll("__BASE_KUSTOMIZE__", "${BASE_KUSTOMIZE}")
                                        .replaceAll("__DEV_KUSTOMIZE__", "${DEV_KUSTOMIZE}")
                                        .replaceAll("__STG_KUSTOMIZE__", "${STG_KUSTOMIZE}")
                                        .replaceAll("__MATH_KUSTOMIZE__", "${MATH_KUSTOMIZE}")
                                        .replaceAll("__ENGL_KUSTOMIZE__", "${ENGL_KUSTOMIZE}")
                                        .replaceAll("__BASE_VALUE__", "${BASE_VALUE}")
				  
					ARGOCD_UPDATE = ARGOCD_UPDATE
										.replaceAll("__ARGOCD_GIT_URL__", "${ARGOCD_GIT_URL}")
										.replaceAll("__ARGOCD_GIT_TOKEN__", "${ARGOCD_GIT_TOKEN}")
										.replaceAll("__ARGOCD_GIT_BRANCH__", "${ARGOCD_GIT_BRANCH}")
										.replaceAll("__APP_NAME__", "${APP_NAME}")
                                        .replaceAll("__APP_DIR__", "${APP_DIR}")
										.replaceAll("__IMAGE_NAME__", "${LIBRARY_NAME}")
										.replaceAll("__NCP_REGISTRY_ENDPOINT__", "${DEV_NCP_REGISTRY_ENDPOINT}")
										.replaceAll("__STORAGE_FROM_BUCKET__", "${BUCKET_NAME}")
										.replaceAll("__STORAGE_FROM_PATH__", "${STORAGE_FROM_PATH}")
										.replaceAll("__STORAGE_TO_BUCKET__", "${BUCKET_NAME}")
										.replaceAll("__STORAGE_TO_PATH__", "${STORAGE_TO_PATH}")
					
				}
            }
        }
        stage('Checkout') {
            steps {
                script{
                    checkout([
    					$class: 'GitSCM',
                        branches: [[name: "${GIT_BRANCH}"]],
                        userRemoteConfigs: [[credentialsId: 'gitlab-access-token', url: "${GIT_URL}"]]
                    ])
                }
            }
            
            post {
                failure {
                    echo 'Repository clone failure'
                }
                success {
                    echo 'Repository clone success'
                    echo "${env.gitlabBranch}"
                }
            }
        }
        
        // python3 pip3 가 설치 되어야함
        // AWS CLI 설치 여부 확인
        stage('Check AWS CLI') {
            steps {
                script {
                    // AWS CLI 설치 여부 확인
                    def awsCLIInstallStatus = sh(script: 'command -v aws', returnStatus: true)
                    if (awsCLIInstallStatus == 0) {
                        echo "AWS CLI is already installed."
                    } else {
                        // AWS CLI 설치
                        echo "AWS CLI is not installed. Installing..."
                        sh 'pip3 install awscli==1.15.85 --user --no-cache-dir'
                        echo "AWS CLI installed successfully."
                    }
                }
            }
        }
        
        stage('Build') {
			steps {
				script {
					sh """
						npm install
						npm run build
					"""
				}
			}
		}
        
        // 빌드 번호로 관리 하기 및 업로드 aws cli 이용
        stage('Sync') {
            steps {
                script {
                    sh "aws --profile ncp-gov --endpoint-url=${ENDPOINT_URL} s3 sync ${DIRECTORY_PATH} s3://${BUCKET_NAME}/${KEY_BASE_PATH}"
                }
            }
        }
        
        stage("Check Manifest") {
            steps {
                script {
                    def check_repo_response = sh(
                        returnStdout: true,
                        script: """
                            curl --header "PRIVATE-TOKEN: ${ARGOCD_GIT_TOKEN}" ${ARGOCD_GIT_URL}/repository/tree?path=${APP_NAME}
                        """
                    )
					
					echo "check_repo_response result: ${check_repo_response}"
                    
                    if ( check_repo_response == "[]" ) {
                        echo "Repository is empty."
                        check_repo_response = sh(
                            returnStatus: true,
                            script: """
                                ${ARGOCD_CREATE}
                            """
                        )
                    } else {
                        echo "Repository is not empty."
                    }
                      
                    echo "check_repo_response = ${check_repo_response}"
                }
            }
        }
		
		stage("Update Manifest") {
            steps {
                script {
                    
					def check_repo_response = sh(
						returnStatus: true,
						script: """
							${ARGOCD_UPDATE}
						"""
					)
					
					echo "check_repo_response = ${check_repo_response}"
                }
            }
        }
    }
    post {
        success {
            script {
                sendBuildMsg(1, APP_NAME)
            }
        }
    } 
}




ArgoCD 연동 결과

Job을 생성하며 빌드 번호에 해당하는 directory의 파일을 복사하여 배포 전용 디렉터리로 덮어 씁니다.
완료 후 job과 pod는 자동으로 삭제 됩니다.

 

'Cloud' 카테고리의 다른 글

[CSAP] K8S Node Init Script  (1) 2024.12.27
[ArgoCD] 계정 생성  (1) 2024.12.27
[Tempo] Grafana Tempo 적용기 (2)  (0) 2024.11.19
[Tempo] Grafana Tempo 도입 (1)  (0) 2024.11.18
[Kafka] CDC 도입기 (1)  (0) 2024.11.18

댓글