pipeline { agent { label 'py-kaniko' } // JCasC 파드 템플릿: jnlp / ci-python / tooling / kaniko options { timestamps() } parameters { string(name: 'BRANCH_NAME', defaultValue: '', description: '빌드할 브랜치명(비우면 main)') string(name: 'GIT_COMMIT_HASH', defaultValue: '', description: '빌드할 커밋 해시(비우면 최신 커밋 기준)') } environment { // 고정 값(노드 생성 시점에 Jinja로 박힘) NODE_ID = '{{ node_id }}' NODE_TYPE = '{{ node_type }}' NAMESPACE = '{{ namespace }}' REGISTRY = '{{ regi }}' platform_namespace = '{{ platform_namespace }}' // ✅ imagePullSecret 이름도 "메소드에서 전달"되도록 Jinja로 박힘 // (create_node_project_files(extra_context={"image_pull_secret":"..."}) 로 전달) IMAGE_PULL_SECRET = '{{ image_pull_secret | default("acr-pull") }}' } stages { stage('Checkout') { steps { container('jnlp') { sh ''' set -e git fetch --all || true ''' script { def checkoutBranch = params.BRANCH_NAME?.trim() ? params.BRANCH_NAME.trim() : 'main' def commitHash = params.GIT_COMMIT_HASH?.trim() if (commitHash) { sh """ git fetch origin ${checkoutBranch} git checkout ${checkoutBranch} git checkout ${commitHash} """ } else { sh """ git fetch origin ${checkoutBranch} git checkout ${checkoutBranch} """ commitHash = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() } env.BRANCH_NAME = checkoutBranch env.GIT_COMMIT_HASH = commitHash env.RELEASE_NAME = "node-${NODE_ID}-${env.BRANCH_NAME}" env.IMAGE_REPO = "${REGISTRY}/node.${NODE_ID}.${env.BRANCH_NAME}" env.IMAGE_TAG = env.GIT_COMMIT_HASH env.FULL_IMAGE = "${env.IMAGE_REPO}:${env.IMAGE_TAG}" echo "RELEASE_NAME=${env.RELEASE_NAME}" echo "FULL_IMAGE=${env.FULL_IMAGE}" echo "IMAGE_PULL_SECRET=${env.IMAGE_PULL_SECRET}" } } } } stage('Build Image (Kaniko)') { steps { container('kaniko') { retry(3) { sh ''' set -e /kaniko/executor \ --context=$WORKSPACE \ --dockerfile=Dockerfile \ --destination=$FULL_IMAGE \ --cache=true \ --snapshot-mode=time ''' } } } } stage('Deploy (Manifests)') { steps { container('tooling') { sh ''' set -euo pipefail # ✅ B) imagePullSecret 복제 (platform -> ${NAMESPACE}) # secret 이름도 IMAGE_PULL_SECRET로 통일 if [ -n "${IMAGE_PULL_SECRET}" ] && ! kubectl -n "${NAMESPACE}" get secret "${IMAGE_PULL_SECRET}" >/dev/null 2>&1; then echo "[INFO] Copying imagePullSecret '${IMAGE_PULL_SECRET}' platform -> ${NAMESPACE} ..." {% raw %} kubectl -n "${platform_namespace}" get secret "${IMAGE_PULL_SECRET}" -o go-template='{{ index .data ".dockerconfigjson" }}' > .dockercfg.b64 {% endraw %} base64 -d .dockercfg.b64 > .dockerconfigjson kubectl -n "${NAMESPACE}" create secret generic "${IMAGE_PULL_SECRET}" \ --type=kubernetes.io/dockerconfigjson \ --from-file=.dockerconfigjson rm -f .dockercfg.b64 .dockerconfigjson fi # ✅ C) 배포 전 Deployment generation 저장 PREV_GEN="" if kubectl -n "${NAMESPACE}" get deploy "${RELEASE_NAME}" >/dev/null 2>&1; then PREV_GEN="$(kubectl -n "${NAMESPACE}" get deploy "${RELEASE_NAME}" -o jsonpath='{.metadata.generation}' 2>/dev/null || true)" fi echo "[INFO] PREV_GEN=${PREV_GEN:-} deploy=${RELEASE_NAME}" # ✅ D) repo의 manifests 템플릿을 렌더링 후 apply # - k8s/*.yaml 은 Jinja로 이미 한번 렌더된 상태(노드 생성 시점) # - 여기서는 배포마다 바뀌는 값(RELASE_NAME, FULL_IMAGE, BRANCH_NAME)만 envsubst로 주입 rm -rf .rendered && mkdir -p .rendered # envsubst 치환 대상 화이트리스트 export RELEASE_NAME FULL_IMAGE BRANCH_NAME for f in k8s/*.yaml; do echo "[INFO] render $f" envsubst '${RELEASE_NAME} ${FULL_IMAGE} ${BRANCH_NAME}' < "$f" > ".rendered/$(basename "$f")" done echo "---- Rendered files ----" ls -al .rendered kubectl -n "${NAMESPACE}" apply -f .rendered/ # ✅ E) 롤아웃 대기(Deployment가 이 이름으로 생성된다는 전제) kubectl -n "${NAMESPACE}" rollout status deploy "${RELEASE_NAME}" --timeout=10m # ✅ F) generation 비교 → 안 바뀌면 rollout restart POST_GEN="$(kubectl -n "${NAMESPACE}" get deploy "${RELEASE_NAME}" -o jsonpath='{.metadata.generation}' 2>/dev/null || true)" echo "[INFO] POST_GEN=${POST_GEN:-} deploy=${RELEASE_NAME}" if [ -n "${PREV_GEN}" ] && [ -n "${POST_GEN}" ] && [ "${PREV_GEN}" = "${POST_GEN}" ]; then echo "[INFO] Deployment spec unchanged (generation=${POST_GEN}). Running rollout restart..." kubectl -n "${NAMESPACE}" rollout restart deploy "${RELEASE_NAME}" kubectl -n "${NAMESPACE}" rollout status deploy "${RELEASE_NAME}" --timeout=10m else echo "[INFO] Deployment spec changed (or first install). Skip rollout restart." fi echo '--- STATUS ---' kubectl -n "${NAMESPACE}" get deploy,po,svc -l watcher.nodeId="${NODE_ID}",watcher.role="${NODE_TYPE}" || true ''' } } } } post { always { container('tooling') { sh ''' set +e echo '--- FINAL SUMMARY ---' kubectl -n "${NAMESPACE}" get deploy "${RELEASE_NAME}" -o wide || true kubectl -n "${NAMESPACE}" get po -l app.kubernetes.io/name="${RELEASE_NAME}" -o wide || true kubectl -n "${NAMESPACE}" get svc "${RELEASE_NAME}" -o wide || true ''' } cleanWs() } } }