-
이전 포스팅에서 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 설정
이전 포스팅으로 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/configurekubectl 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 구축은 끝이다.
'DevOps > Jenkins' 카테고리의 다른 글
Jenkins와 GitLab webhook 연결 (0) 2026.05.27 NCP(Naver Cloud Platform) 에서 쿠버네티스 Jenkins 구축 - NCP Container Registry 연동 (0) 2026.05.27 댓글

