• NCP(Naver Cloud Platform) 에서 쿠버네티스 Jenkins gitlab 연동과 설정

    2026. 5. 27.

    by. Daramu

    이전 포스팅에서 Jenkins를 설치하여 접속했다.

    기본적인 세팅은 모두 되어 있으므로, 이제는 내부 설정 차례다.

     

    크게 두가지를 준비했다.

     

    첫번째는 Build로, gitlab(혹은 github)에서 코드를 clone으로 가져와 어플리케이션을 build하고, 이미지를 build해서 push한다. 이 과정에서 manifest 파일의 update도 포함이다.

     

    당연히 manifest 파일이 update되므로 argoCD와 사용해도 좋다.

     

    두번째는 deploy다. 

    CD부분으로, 업데이트된 이미지와 manifest 파일을 통해 쿠버네티스에 직접 리소스를 배포하는 작업이다.

     

    이 작업은 pipeline을 생성하고 직접 적어도 되지만, 

    본 포스팅에서는 대부분 코드로 처리할 것이므로 pipeline또한 코드로 처리할 것이다.

     

    우선 gitlab에 jenkins 프로젝트를 생성한다.

    github여도 상관 없다. 연동 부분에서 URL만 수정하면 된다.

     

    이어서 하자면 gitlab에서 프로젝트(repo)를 생성한다.

    테스트 용이기에 cicd-demo-jenkins로 생성했다.

     

    생성시 git 연동과 pull, push등이 있지만, 자세한 내역은 아래 포스팅 참고 바란다.

    GitLab: Git 설정 :: Daramu

     

    GitLab: Git 설정

    이전 포스팅으로 GitLab을 설치했다면,이제는 Git 설정을 통해 실제 코드를 올릴 차례이다. 코드를 올리기 전 연결을 먼저 해야하는데, GitLab또한 Git기반이기에 Git이 설치가 되어 있어야한다.터미

    daramu.tistory.com

     

    연동까지 다 되었다면 이제 코드를 push 한다.

    jenkins의 파이프라인은 100명의 사람이 한다면 100개의 형식이 나오므로, 한개에 종속되는게 아니다.

    아래 코드는 어디까지나 예시임을 명심하며 세개의 파일을 생성하여 jenkins gitlab에 push 한다.

     

    Jenkinsfile.build

    pipeline {
        agent {
            kubernetes {
                yamlFile 'agent-pod.yaml'
                defaultContainer 'jnlp'
            }
        }
    
        parameters {
            string(
                name: 'BRANCH',
                defaultValue: 'main',
                description: '빌드할 브랜치'
            )
        }
    
        options {
            timeout(time: 30, unit: 'MINUTES')
            buildDiscarder(logRotator(numToKeepStr: '30'))
            timestamps()
            disableConcurrentBuilds()
        }
    
        environment {
            REGISTRY      = 'registry_endpoint'
            IMAGE_NAME    = 'cicd-demo-backend'
            REPO_URL      = 'repo주소(ex. http://172.16.211.6/root/cicd-demo-backend.git)'
            MANIFEST_REPO = 'http://172.16.211.6/root/cicd-demo-k8s.git'
            MANIFEST_PATH = 'cicd-demo-backend/deployment.yaml'
        }
    
        stages {
            stage('Checkout') {
                steps {
                    checkout([
                        $class           : 'GitSCM',
                        branches         : [[name: params.BRANCH]],
                        userRemoteConfigs: [[
                            url          : env.REPO_URL,
                            credentialsId: 'gitlab-credentials'
                        ]]
                    ])
                }
            }
    
            stage('Build & Push') {
                steps {
                    script {
                        def imageTag   = "${GIT_COMMIT[0..6]}-${BUILD_NUMBER}"
                        env.IMAGE_TAG  = imageTag
                        echo "빌드 이미지: ${REGISTRY}/${IMAGE_NAME}:${imageTag}"
                    }
                    container('kaniko') {
                        sh """
                            /kaniko/executor \\
                              --context=\${WORKSPACE} \\
                              --dockerfile=\${WORKSPACE}/Dockerfile \\
                              --destination=\${REGISTRY}/\${IMAGE_NAME}:\${IMAGE_TAG} \\
                              --verbosity=info
                        """
                    }
                }
            }
    
            stage('Update Manifest') {
                steps {
                    dir('cicd-demo-k8s') {
                        git(
                            url          : env.MANIFEST_REPO,
                            branch       : 'main',
                            credentialsId: 'gitlab-credentials'
                        )
                        sh """
                            sed -i "s|image: .*/${IMAGE_NAME}:.*|image: ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}|g" ${MANIFEST_PATH}
                        """
    
                        withCredentials([usernamePassword(
                            credentialsId: 'gitlab-credentials',
                            usernameVariable: 'GIT_USER',
                            passwordVariable: 'GIT_TOKEN'
                        )]) {
                            sh """
                                git config user.email "jenkins@cicd.com"
                                git config user.name "Jenkins"
                                git add ${MANIFEST_PATH}
                                git commit -m "[Jenkins] update ${IMAGE_NAME} image to ${IMAGE_TAG}"
                                git -c credential.helper='!f() { echo username=\${GIT_USER}; echo password=\${GIT_TOKEN}; }; f' push \${MANIFEST_REPO} main
                            """
                        }
                    }
                }
            }
        }
    
        post {
            success {
                echo "✅ 완료: ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} 배포 요청됨"
            }
            failure {
                echo "❌ 빌드 실패"
            }
            always {
                cleanWs()
            }
        }
    }

     

     

    Jenkinsfile.deploy

    pipeline {
        agent {
            kubernetes {
                yamlFile 'agent-pod.yaml'
                defaultContainer 'jnlp'
            }
        }
    
        parameters {
            string(name: 'BRANCH',    defaultValue: 'main',  description: 'manifest 브랜치')
            string(name: 'NAMESPACE', defaultValue: 'default', description: '배포 네임스페이스')
        }
    
        options {
            timeout(time: 15, unit: 'MINUTES')
            buildDiscarder(logRotator(numToKeepStr: '30'))
            timestamps()
        }
    
        environment {
            IMAGE_NAME    = 'cicd-demo-backend'
            MANIFEST_REPO = 'http://172.16.211.6/root/cicd-demo-k8s.git'
            MANIFEST_PATH = 'cicd-demo-backend'
        }
    
        stages {
            stage('Checkout Manifest') {
                steps {
                    withCredentials([usernamePassword(
                        credentialsId: 'gitlab-credentials',
                        usernameVariable: 'GIT_USER',
                        passwordVariable: 'GIT_TOKEN'
                    )]) {
                        sh """
                            git -c credential.helper='!f() { echo username=\${GIT_USER}; echo password=\${GIT_TOKEN}; }; f' \
                              clone -b ${params.BRANCH} \${MANIFEST_REPO} cicd-demo-k8s
                        """
                    }
                }
            }
    
            stage('Deploy') {
                steps {
                    sh "kubectl apply -f cicd-demo-k8s/${MANIFEST_PATH}/ -n ${params.NAMESPACE}"
                }
            }
    
            stage('Verify Rollout') {
                steps {
                    sh """
                        kubectl rollout status deployment/${IMAGE_NAME} \
                          -n ${params.NAMESPACE} \
                          --timeout=300s
                    """
                }
            }
        }
    
        post {
            success { echo "✅ 배포 완료: ${IMAGE_NAME}" }
            failure {
                sh "kubectl rollout undo deployment/${IMAGE_NAME} -n ${params.NAMESPACE} || true"
                echo "❌ 배포 실패 - 롤백 시도됨"
            }
            always { cleanWs() }
        }
    }

     

    그리고 build에 있는 "kaniko"동작을 위해 "agent-pod.yaml"을 생성한다.

    apiVersion: v1
    kind: Pod
    metadata:
      generateName: jenkins-agent-
      labels:
        jenkins/agent: standard-builder
    spec:
      serviceAccountName: jenkins
      imagePullSecrets:
      - name: regcred
      containers:
        - name: jnlp
          image: {container_endpoint}/jenkins-agent:0.1
          imagePullPolicy: Always
          env:
            - name: HOME
              value: /home/jenkins/agent
          volumeMounts:
            - name: ncloud-config
              mountPath: /home/jenkins/agent/.ncloud
              readOnly: true
          resources:
            requests:
              cpu: 200m
              memory: 256Mi
            limits:
              cpu: 1000m
              memory: 1Gi
    
        - name: kaniko
          image: {container_endpoint}/jenkins-kaniko:0.1
          imagePullPolicy: IfNotPresent
          command:
            - /busybox/cat
          tty: true
          volumeMounts:
            - name: kaniko-docker-config
              mountPath: /kaniko/.docker
          resources:
            requests:
              cpu: 1000m
              memory: 2Gi
            limits:
              cpu: 4000m
              memory: 6Gi
    
      volumes:
        - name: ncloud-config
          secret:
            secretName: ncloud-credentials
        - name: kaniko-docker-config
          secret:
            secretName: registry-credentials
            items:
              - key: .dockerconfigjson
                path: config.json

     

    여기서 두개의 Jenkins파일에서 "environment" 부분을 수정해준다.

    본 포스팅에서는 별도의 k8s문서를 정의 해놓은 프로젝트(repo)가 있고, 그 repo구성이 다음과 같이 되어있기 때문이다.

     

     

    즉, 별도의 k8s 레포지토리가 있고, 그 레포 안에 각 서비스별 폴더가 있고,

    다시 그 폴더 안에 manifest파일이 있는 구조이기 때문이다.

    결과적으로 cicd-demo-backend라는 서비스의 매니페스트 파일은 cicd-demo-k8s/cicd-demo-backend/deployment.yaml 파일에 있게 된다.

     

    구성한 환경이 다르다면 build와 deploy 폴더 구조를 다르게 하면 된다.

     

    다음으로 secret을 생성해준다.

     

    ncloud-credentials은 nks(naver kubernetes)에 접근하기 위한 설정 파일이며, 이는 deploy에 사용된다. 반대로 CI로만 사용할려면 필요 없다는 의미이기도 하다.

     

    registry-credentials은 container registry에 접근하기 위한 secret으로, CI에 필요하니 이 부분은 필수다.

     

    각각 생성해준다.

    cat <<EOF > /tmp/configure
    [DEFAULT]
    ncloud_access_key_id = ACCESSKEY입력
    ncloud_secret_access_key = SECRETKEY입력
    ncloud_api_url = https://ncloud.apigw.ntruss.com
    EOF
    
    kubectl create secret generic ncloud-credentials \
      --from-file=configure=/tmp/configure \
        -n jenkins
        
    rm /tmp/configure

     

    kubectl create secret docker-registry registry-credentials \
      --docker-server=registryendpoint입력 \
      --docker-username=ACCESSKEY입력 \
      --docker-password=SECRET입력 \
      -n jenkins

     

    그럼 총 4개의 secret을 사용하고 있다.

     

    순서대로 구축때 사용하였던 admin 계정, nks접근을 위한 설정파일, container registry에 접근하기 위한 secret, 마지막으로 동일하게 container registry에 접근하기 위한 secret이다. 

     

    준비가 되었다면 3개의 파일을 push한다.

     

    그 이후 jenkins 웹페이지에서 설정은 마무리 한다.

    Jenkins 우측 상단 톱니바퀴 -> Credentials -> Add Credentials 로 새로운 자격증명을 생성한다.

     

    kind는 username/password이다.이름(ID)은 "gitlab-credentials" 로 생성해야한다.build와 deploy에서 이 이름으로 자격증명을 요청하기 때문이다.

     

     

    웹페이지 좌측 새로운 Item -> name:아무거나(ex. build), type: pipeline 

     

    사진처럼 생성해준다.

    본 포스팅에서 jenkinsfile은 git 방식을 사용하는 gitlab(gitgub도 동일하다)에 있으므로 URL을 입력하고, push한 jenkins파일이 있는 URL을 집어 넣는다. 그리고 자격증명으로 방금 생성했던 "gitlab-credentials"를 선택한다.

    마지막으로 브런치는 각 상황에 맞게 넣고(대부분 main이다), 제일 하단의 Script path는 push한대로 "Jenkinsfile.build"이다.

     

    그리고 build를 실행시켜보면 동작을 확인할 수 있다.

     

    출력된 consoleoutput을 보면, 이미지 태그를 1c6546f-2 로 하여 push 한걸 알 수 있다.

     

    이제 container registry와 gitlab의 프로젝트에 정상적으로 push되었는지 눈으로 확인하면 된다.

     

    gitlab을 보면 상단에 Jenkins가 update한걸 알 수 있다.

     

     

    마지막으로 Deploy 부분이다.

     

    동일하게 생성하되 마지막 Path부분은 "Jenkins.deploy" 만 수정하면 된다.

     

    그 후 kubectl edit pod 로 현재 떠 있는 pod의 image를 확인해보면, 앞선 build로 생성했던 1c6546f-2 로 이미지 태그가 변경되어 동작중인걸 확인할 수 있다.

     

     

    물론 Jenkins의 console output을 보더라도 정상적으로 apply 한걸 알 수 있다.

     

    이렇게 되면 CasC 기반의 Jenkins 구축은 끝이다.

    댓글