Разведены Builder и Deploy: сборка освобождает DinD до старта деплоя.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Vendored
+124
-113
@@ -1,20 +1,22 @@
|
|||||||
// Wrapped — CI: multi-arch push (Harbor + Docker Hub) + Helm deploy
|
// Wrapped — CI: multi-arch push (Harbor + Docker Hub), затем асинхронный Deploy
|
||||||
//
|
//
|
||||||
// Триггер: push в main (webhook Gitea → Jenkins Multibranch).
|
// Ресурсы k3s: Builder и Deploy не должны держать два DinD-пода сразу.
|
||||||
// Версия образа = файл VERSION из коммита (без авто-bump в CI).
|
// 1) стадии сборки на agent label 'docker' (DinD)
|
||||||
// Bump: make bump-patch / make push локально — что запушили, то и уйдёт в релиз.
|
// 2) при успехе — trigger Deploy с wait:false и agent none → Builder-под умирает
|
||||||
|
// 3) Deploy стартует отдельно уже без Builder
|
||||||
//
|
//
|
||||||
// Credentials (Manage Jenkins → Credentials → Global):
|
// Версия образа = VERSION из коммита. Bump: make bump-patch / make push.
|
||||||
|
//
|
||||||
|
// Credentials (Global):
|
||||||
// harbor-devops-tools-push-pull-access — Harbor devops-tools (robot)
|
// harbor-devops-tools-push-pull-access — Harbor devops-tools (robot)
|
||||||
// docker-hub — Docker Hub (inecs)
|
// docker-hub — Docker Hub (inecs)
|
||||||
// ssh-gitea-key — SCM checkout Gitea
|
// ssh-gitea-key — SCM checkout Gitea
|
||||||
// k3s-kubeconfig — в job Deploy (Jenkinsfile.deploy)
|
// k3s-kubeconfig — в job Deploy (Jenkinsfile.deploy)
|
||||||
//
|
//
|
||||||
// Теги образа: :<semver из VERSION>, :<sha>, :latest
|
// Deploy job: devops-tools/wrapped/wrapped-deploy/main
|
||||||
// Deploy: devops-tools/wrapped/wrapped-deploy/main
|
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'docker' }
|
agent none
|
||||||
|
|
||||||
options {
|
options {
|
||||||
buildDiscarder(logRotator(numToKeepStr: '20'))
|
buildDiscarder(logRotator(numToKeepStr: '20'))
|
||||||
@@ -34,104 +36,123 @@ pipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
stage('Checkout') {
|
stage('Build image') {
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Version') {
|
|
||||||
when {
|
when {
|
||||||
anyOf {
|
anyOf {
|
||||||
branch 'main'
|
branch 'main'
|
||||||
branch 'master'
|
branch 'master'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
steps {
|
agent { label 'docker' }
|
||||||
container('docker') {
|
stages {
|
||||||
script {
|
stage('Checkout') {
|
||||||
env.IMAGE_VERSION = sh(
|
steps {
|
||||||
script: "tr -d '[:space:]' < VERSION",
|
checkout scm
|
||||||
returnStdout: true
|
}
|
||||||
).trim()
|
}
|
||||||
if (!env.IMAGE_VERSION) {
|
|
||||||
error('VERSION file is empty')
|
stage('Version') {
|
||||||
|
steps {
|
||||||
|
container('docker') {
|
||||||
|
script {
|
||||||
|
env.IMAGE_VERSION = sh(
|
||||||
|
script: "tr -d '[:space:]' < VERSION",
|
||||||
|
returnStdout: true
|
||||||
|
).trim()
|
||||||
|
if (!env.IMAGE_VERSION) {
|
||||||
|
error('VERSION file is empty')
|
||||||
|
}
|
||||||
|
echo "IMAGE_VERSION from VERSION → ${env.IMAGE_VERSION}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
echo "IMAGE_VERSION from VERSION → ${env.IMAGE_VERSION}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Build & push') {
|
|
||||||
when {
|
|
||||||
anyOf {
|
|
||||||
branch 'main'
|
|
||||||
branch 'master'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
withCredentials([
|
|
||||||
usernamePassword(
|
|
||||||
credentialsId: 'harbor-devops-tools-push-pull-access',
|
|
||||||
usernameVariable: 'HARBOR_USER',
|
|
||||||
passwordVariable: 'HARBOR_PASS'
|
|
||||||
),
|
|
||||||
usernamePassword(
|
|
||||||
credentialsId: 'docker-hub',
|
|
||||||
usernameVariable: 'DOCKERHUB_USER',
|
|
||||||
passwordVariable: 'DOCKERHUB_PASS'
|
|
||||||
)
|
|
||||||
]) {
|
|
||||||
container('docker') {
|
|
||||||
sh '''
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
test -n "${IMAGE_VERSION}"
|
|
||||||
echo "Building tags: ${IMAGE_VERSION}, ${RELEASE_TAG}, latest"
|
|
||||||
|
|
||||||
echo "$HARBOR_PASS" | docker login "$HARBOR_REGISTRY" -u "$HARBOR_USER" --password-stdin
|
|
||||||
echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin
|
|
||||||
|
|
||||||
docker buildx rm "$BUILDX_BUILDER" 2>/dev/null || true
|
|
||||||
docker buildx create --name "$BUILDX_BUILDER" --driver docker-container --use
|
|
||||||
docker buildx inspect --bootstrap >/dev/null
|
|
||||||
|
|
||||||
docker buildx build \
|
|
||||||
--platform linux/amd64 \
|
|
||||||
--provenance=false --sbom=false --push \
|
|
||||||
-t "${HARBOR_IMAGE}:${RELEASE_TAG}-amd64" \
|
|
||||||
-t "${DOCKERHUB_IMAGE}:${RELEASE_TAG}-amd64" \
|
|
||||||
-f Dockerfile .
|
|
||||||
|
|
||||||
docker buildx build \
|
|
||||||
--platform linux/arm64 \
|
|
||||||
--provenance=false --sbom=false --push \
|
|
||||||
-t "${HARBOR_IMAGE}:${RELEASE_TAG}-arm64" \
|
|
||||||
-t "${DOCKERHUB_IMAGE}:${RELEASE_TAG}-arm64" \
|
|
||||||
-f Dockerfile .
|
|
||||||
|
|
||||||
for IMAGE in "$HARBOR_IMAGE" "$DOCKERHUB_IMAGE"; do
|
|
||||||
docker buildx imagetools create \
|
|
||||||
-t "${IMAGE}:${RELEASE_TAG}" \
|
|
||||||
-t "${IMAGE}:${IMAGE_VERSION}" \
|
|
||||||
-t "${IMAGE}:latest" \
|
|
||||||
"${IMAGE}:${RELEASE_TAG}-amd64" \
|
|
||||||
"${IMAGE}:${RELEASE_TAG}-arm64"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "--- Harbor ---"
|
|
||||||
docker buildx imagetools inspect "${HARBOR_IMAGE}:${IMAGE_VERSION}" | sed -n '1,40p'
|
|
||||||
echo "--- Docker Hub ---"
|
|
||||||
docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:${IMAGE_VERSION}" | sed -n '1,40p'
|
|
||||||
|
|
||||||
docker buildx rm "$BUILDX_BUILDER" || true
|
|
||||||
'''
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stage('Build & push') {
|
||||||
|
steps {
|
||||||
|
withCredentials([
|
||||||
|
usernamePassword(
|
||||||
|
credentialsId: 'harbor-devops-tools-push-pull-access',
|
||||||
|
usernameVariable: 'HARBOR_USER',
|
||||||
|
passwordVariable: 'HARBOR_PASS'
|
||||||
|
),
|
||||||
|
usernamePassword(
|
||||||
|
credentialsId: 'docker-hub',
|
||||||
|
usernameVariable: 'DOCKERHUB_USER',
|
||||||
|
passwordVariable: 'DOCKERHUB_PASS'
|
||||||
|
)
|
||||||
|
]) {
|
||||||
|
container('docker') {
|
||||||
|
sh '''
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
test -n "${IMAGE_VERSION}"
|
||||||
|
echo "Building tags: ${IMAGE_VERSION}, ${RELEASE_TAG}, latest"
|
||||||
|
|
||||||
|
echo "$HARBOR_PASS" | docker login "$HARBOR_REGISTRY" -u "$HARBOR_USER" --password-stdin
|
||||||
|
echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin
|
||||||
|
|
||||||
|
docker buildx rm "$BUILDX_BUILDER" 2>/dev/null || true
|
||||||
|
docker buildx create --name "$BUILDX_BUILDER" --driver docker-container --use
|
||||||
|
docker buildx inspect --bootstrap >/dev/null
|
||||||
|
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64 \
|
||||||
|
--provenance=false --sbom=false --push \
|
||||||
|
-t "${HARBOR_IMAGE}:${RELEASE_TAG}-amd64" \
|
||||||
|
-t "${DOCKERHUB_IMAGE}:${RELEASE_TAG}-amd64" \
|
||||||
|
-f Dockerfile .
|
||||||
|
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/arm64 \
|
||||||
|
--provenance=false --sbom=false --push \
|
||||||
|
-t "${HARBOR_IMAGE}:${RELEASE_TAG}-arm64" \
|
||||||
|
-t "${DOCKERHUB_IMAGE}:${RELEASE_TAG}-arm64" \
|
||||||
|
-f Dockerfile .
|
||||||
|
|
||||||
|
for IMAGE in "$HARBOR_IMAGE" "$DOCKERHUB_IMAGE"; do
|
||||||
|
docker buildx imagetools create \
|
||||||
|
-t "${IMAGE}:${RELEASE_TAG}" \
|
||||||
|
-t "${IMAGE}:${IMAGE_VERSION}" \
|
||||||
|
-t "${IMAGE}:latest" \
|
||||||
|
"${IMAGE}:${RELEASE_TAG}-amd64" \
|
||||||
|
"${IMAGE}:${RELEASE_TAG}-arm64"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "--- Harbor ---"
|
||||||
|
docker buildx imagetools inspect "${HARBOR_IMAGE}:${IMAGE_VERSION}" | sed -n '1,40p'
|
||||||
|
echo "--- Docker Hub ---"
|
||||||
|
docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:${IMAGE_VERSION}" | sed -n '1,40p'
|
||||||
|
|
||||||
|
docker buildx rm "$BUILDX_BUILDER" || true
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
script {
|
||||||
|
try {
|
||||||
|
container('docker') {
|
||||||
|
sh 'docker buildx rm "$BUILDX_BUILDER" 2>/dev/null || true'
|
||||||
|
}
|
||||||
|
} catch (Ignored) {
|
||||||
|
// pod may already be gone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success {
|
||||||
|
echo "✓ Build OK: ${DOCKERHUB_IMAGE}:{${RELEASE_TAG},${IMAGE_VERSION},latest}"
|
||||||
|
}
|
||||||
|
failure {
|
||||||
|
echo "✗ Build/push не удались — Deploy не запускается"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Без DinD: только очередь Deploy, Builder-под уже освобождён
|
||||||
stage('Trigger deploy') {
|
stage('Trigger deploy') {
|
||||||
when {
|
when {
|
||||||
anyOf {
|
anyOf {
|
||||||
@@ -139,19 +160,21 @@ pipeline {
|
|||||||
branch 'master'
|
branch 'master'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
agent none
|
||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
echo "Triggering ${DEPLOY_JOB} → ${DOCKERHUB_IMAGE}:${IMAGE_VERSION}"
|
echo "Build finished — triggering ${DEPLOY_JOB} → ${DOCKERHUB_IMAGE}:${IMAGE_VERSION} (wait: false)"
|
||||||
build(
|
build(
|
||||||
job: env.DEPLOY_JOB,
|
job: env.DEPLOY_JOB,
|
||||||
wait: true,
|
wait: false,
|
||||||
propagate: true,
|
propagate: false,
|
||||||
parameters: [
|
parameters: [
|
||||||
string(name: 'IMAGE_REPOSITORY', value: env.DOCKERHUB_IMAGE),
|
string(name: 'IMAGE_REPOSITORY', value: env.DOCKERHUB_IMAGE),
|
||||||
string(name: 'IMAGE_TAG', value: env.IMAGE_VERSION),
|
string(name: 'IMAGE_TAG', value: env.IMAGE_VERSION),
|
||||||
string(name: 'IMAGE_PULL_POLICY', value: 'Always'),
|
string(name: 'IMAGE_PULL_POLICY', value: 'Always'),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
echo "Deploy queued; Builder pipeline exits and releases cluster resources."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,24 +182,12 @@ pipeline {
|
|||||||
|
|
||||||
post {
|
post {
|
||||||
success {
|
success {
|
||||||
echo "✓ Version: ${IMAGE_VERSION}"
|
echo "✓ Version: ${IMAGE_VERSION}"
|
||||||
echo "✓ Harbor: ${HARBOR_IMAGE}:{${RELEASE_TAG},${IMAGE_VERSION},latest}"
|
echo "✓ Image: ${DOCKERHUB_IMAGE}:{${RELEASE_TAG},${IMAGE_VERSION},latest}"
|
||||||
echo "✓ Docker Hub: ${DOCKERHUB_IMAGE}:{${RELEASE_TAG},${IMAGE_VERSION},latest}"
|
echo "✓ Deploy: ${DEPLOY_JOB} triggered (async)"
|
||||||
echo "✓ Deploy: ${DEPLOY_JOB} (${DOCKERHUB_IMAGE}:${IMAGE_VERSION})"
|
|
||||||
}
|
}
|
||||||
failure {
|
failure {
|
||||||
echo "✗ Version / build / push / deploy — см. лог стадий"
|
echo "✗ Сборка не удалась — см. лог Build image"
|
||||||
}
|
|
||||||
always {
|
|
||||||
script {
|
|
||||||
try {
|
|
||||||
container('docker') {
|
|
||||||
sh 'docker buildx rm "$BUILDX_BUILDER" 2>/dev/null || true'
|
|
||||||
}
|
|
||||||
} catch (Ignored) {
|
|
||||||
// agent may already be gone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ kubectl -n wrapped rollout status deployment/wrapped
|
|||||||
|
|
||||||
Credential: `k3s-kubeconfig` (Secret file) — kubeconfig к K3S.
|
Credential: `k3s-kubeconfig` (Secret file) — kubeconfig к K3S.
|
||||||
|
|
||||||
Рекомендуемая связка job’ов уже в [`Jenkinsfile`](Jenkinsfile): после **Version** (чтение `VERSION`) + **Build & push** стадия **Trigger deploy** вызывает `devops-tools/wrapped/wrapped-deploy/main` с тем же SemVer (`wait: true`).
|
Рекомендуемая связка job’ов уже в [`Jenkinsfile`](Jenkinsfile): после успешного **Build image** (DinD) стадия **Trigger deploy** с `wait: false` и `agent none` — под Builder освобождается, затем отдельно стартует Deploy. Так на кластере не нужны два DinD одновременно.
|
||||||
|
|
||||||
Ручной запуск Deploy: **Build with Parameters** (пустой `IMAGE_TAG` → `cat VERSION`).
|
Ручной запуск Deploy: **Build with Parameters** (пустой `IMAGE_TAG` → `cat VERSION`).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user