169 lines
6.4 KiB
Django/Jinja
169 lines
6.4 KiB
Django/Jinja
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:-<none>} 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:-<none>} 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()
|
|
}
|
|
}
|
|
}
|