From 332c6357e06d58cd3a2b485933b990e3cc385432 Mon Sep 17 00:00:00 2001 From: Sergey Antropoff Date: Mon, 27 Jul 2026 15:02:57 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20Jenkinsfile.deploy=20=D0=B4=D0=BB=D1=8F=20Helm=20upgra?= =?UTF-8?q?de=20wrapped=20=D0=B2=20k3s;=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D1=91=D0=BD=20README.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile.deploy | 144 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 49 ++++++++++++--- 2 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 Jenkinsfile.deploy diff --git a/Jenkinsfile.deploy b/Jenkinsfile.deploy new file mode 100644 index 0000000..4ab839c --- /dev/null +++ b/Jenkinsfile.deploy @@ -0,0 +1,144 @@ +// Wrapped — CD: helm upgrade в k3s (как make addon-wrapped, только смена образа) +// +// Первый install — только через DevOpsTools/K3S: make addon-wrapped +// (секреты, Ingress, Postgres, MinIO). Этот pipeline лишь обновляет image.* +// через helm --reuse-values, не затирая values с кластера. +// +// Job: отдельный Pipeline / Multibranch, Script Path = Jenkinsfile.deploy +// Credentials: +// k3s-kubeconfig — Secret file (kubeconfig), как у devops.org.ru +// +// Agent: cloud kubernetes, label docker (pod template с container docker) +// +// Эквивалент addon: +// helm upgrade --install wrapped … -n wrapped --atomic --wait +// kubectl -n wrapped rollout status deployment/wrapped + +pipeline { + agent { label 'docker' } + + options { + buildDiscarder(logRotator(numToKeepStr: '20')) + disableConcurrentBuilds() + timeout(time: 20, unit: 'MINUTES') + timestamps() + } + + parameters { + string( + name: 'IMAGE_REPOSITORY', + defaultValue: 'inecs/wrapped', + description: 'Как wrapped_image_repository в k3s addon (Hub или Harbor)' + ) + string( + name: 'IMAGE_TAG', + defaultValue: '0.1.0', + description: 'Тег образа (0.1.0 / latest / short-sha после CI build)' + ) + choice( + name: 'IMAGE_PULL_POLICY', + choices: ['Always', 'IfNotPresent'], + description: 'Always — как в addon (mutable tag подтягивается заново)' + ) + } + + environment { + HELM_RELEASE = 'wrapped' + HELM_NAMESPACE = 'wrapped' + HELM_CHART = './helm/wrapped' + HELM_TIMEOUT = '600s' + DEPLOYMENT = 'wrapped' + TZ = 'Europe/Moscow' + } + + stages { + stage('Checkout') { + steps { + checkout scm + } + } + + stage('Helm upgrade') { + when { + anyOf { + branch 'main' + branch 'master' + } + } + steps { + withCredentials([ + file(credentialsId: 'k3s-kubeconfig', variable: 'KUBECONFIG') + ]) { + container('docker') { + sh ''' + set -eux + + # helm + kubectl (alpine docker:*-cli) + if ! command -v helm >/dev/null 2>&1; then + apk add --no-cache curl tar openssl bash >/dev/null + ARCH="$(uname -m)" + case "$ARCH" in + x86_64) ARCH=amd64 ;; + aarch64|arm64) ARCH=arm64 ;; + *) echo "unsupported arch: $ARCH" >&2; exit 1 ;; + esac + HELM_VERSION=v3.16.4 + curl -fsSL "https://get.helm.sh/helm-${HELM_VERSION}-linux-${ARCH}.tar.gz" \ + | tar -xz -C /tmp + install -m 0755 "/tmp/linux-${ARCH}/helm" /usr/local/bin/helm + fi + if ! command -v kubectl >/dev/null 2>&1; then + apk add --no-cache curl >/dev/null + ARCH="$(uname -m)" + case "$ARCH" in + x86_64) ARCH=amd64 ;; + aarch64|arm64) ARCH=arm64 ;; + esac + KVER="$(curl -fsSL https://dl.k8s.io/release/stable.txt)" + curl -fsSLo /usr/local/bin/kubectl \ + "https://dl.k8s.io/release/${KVER}/bin/linux/${ARCH}/kubectl" + chmod +x /usr/local/bin/kubectl + fi + + helm version --short + kubectl version --client --short || kubectl version --client + + # Релиз должен уже существовать (первый install — make addon-wrapped) + if ! helm status "$HELM_RELEASE" -n "$HELM_NAMESPACE" >/dev/null 2>&1; then + echo "Release ${HELM_RELEASE} not found in ns ${HELM_NAMESPACE}." >&2 + echo "Сначала: make addon-wrapped в DevOpsTools/K3S." >&2 + exit 1 + fi + + echo "Upgrading ${HELM_RELEASE}: ${IMAGE_REPOSITORY}:${IMAGE_TAG} (${IMAGE_PULL_POLICY})" + + # Как addon: helm upgrade --install … --atomic --wait + # --reuse-values сохраняет Ingress/секреты/DB/S3 с кластера + helm upgrade "$HELM_RELEASE" "$HELM_CHART" \ + --namespace "$HELM_NAMESPACE" \ + --reuse-values \ + --set "image.repository=${IMAGE_REPOSITORY}" \ + --set "image.tag=${IMAGE_TAG}" \ + --set "image.pullPolicy=${IMAGE_PULL_POLICY}" \ + --atomic \ + --wait \ + --timeout "$HELM_TIMEOUT" + + kubectl -n "$HELM_NAMESPACE" rollout status "deployment/${DEPLOYMENT}" --timeout=300s + kubectl -n "$HELM_NAMESPACE" get deploy,po,ing -o wide + ''' + } + } + } + } + } + + post { + success { + echo "✓ Helm ${HELM_RELEASE}/${HELM_NAMESPACE}: ${params.IMAGE_REPOSITORY}:${params.IMAGE_TAG}" + } + failure { + echo "✗ Helm upgrade не удался — см. лог. Первый install только через make addon-wrapped." + } + } +} diff --git a/README.md b/README.md index 06e4e3a..bc310c1 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ | **Расшифровка** | Прокрутка превью текста по вертикали и горизонтали; кнопка **Копировать** рядом со скачиванием | | **Пароль** | Argon2-проверка *до* выдачи ciphertext; лимит попыток; пустой пароль попытку не тратит; структурированные ошибки в UI | | **Админка** | Стартовая **Статистика** (MinIO, wraps, audit); очистка audit с подтверждением; пагинация журнала | -| **Релиз** | `make release` / Jenkins CI: **multi-arch** `linux/amd64` + `linux/arm64` → Harbor `devops-tools/wrapped` и Docker Hub `inecs/wrapped` (`:sha`, `:0.1.0`, `:latest`) | +| **Релиз** | `make release` / Jenkins CI+CD: multi-arch → Harbor и Docker Hub; Helm upgrade в k3s (`Jenkinsfile.deploy`, как addon-wrapped) | Подробности — в разделах ниже (безопасность, админка, сборка образа). @@ -425,23 +425,58 @@ docker buildx build \ ### Jenkins CI (Harbor + Docker Hub) -После push в ветку **`main`** Jenkins собирает multi-arch образ (`linux/amd64` + `linux/arm64`) и пушит в оба реестра: +После push в ветку **`main`** job со Script Path [`Jenkinsfile`](Jenkinsfile) собирает multi-arch образ (`linux/amd64` + `linux/arm64`) и пушит в оба реестра: | Реестр | Образ | |--------|--------| | Harbor | `hub.antropoff.ru/devops-tools/wrapped` | | Docker Hub | `inecs/wrapped` | -Теги на каждый реестр: `:`, `:0.1.0`, `:latest` (плюс служебные `:-amd64` / `:-arm64` для сборки манифеста). +Теги на каждый реестр: `:`, `:0.1.0`, `:latest` (плюс служебные `:-amd64` / `:-arm64`). -Credentials в Jenkins: +Credentials (как в актуальном `Jenkinsfile`): | ID | Тип | Назначение | |----|-----|------------| -| `harbor-antropoff` | Username/password | robot для `hub.antropoff.ru` | -| `dockerhub-inecs` | Username/password | Docker Hub `inecs` + access token | +| `harbor-devops-tools-push-pull-access` | Username/password | Harbor `devops-tools` | +| `docker-hub` | Username/password | Docker Hub | -Job: Multibranch Pipeline или Pipeline from SCM на этот репозиторий + webhook на push. Pipeline описан в корневом [`Jenkinsfile`](Jenkinsfile). +Agent: label `docker` (pod template с container `docker` / DinD). + +### Jenkins CD (Helm → k3s) + +Как в аддоне [DevOpsTools/K3S `addons/wrapped`](https://git.antropoff.ru/DevOpsTools/K3S): релиз **`wrapped`**, namespace **`wrapped`**, образ по умолчанию `inecs/wrapped:0.1.0`, `pullPolicy: Always`. + +**Первый install** — только с хоста/CI ansible: + +```bash +make addon-wrapped # в репозитории K3S / k3s-ansible +``` + +Дальше обновление образа — отдельный Jenkins job, Script Path = [`Jenkinsfile.deploy`](Jenkinsfile.deploy): + +```text +helm upgrade wrapped ./helm/wrapped \ + --namespace wrapped \ + --reuse-values \ + --set image.repository=… \ + --set image.tag=… \ + --set image.pullPolicy=Always \ + --atomic --wait --timeout 600s +kubectl -n wrapped rollout status deployment/wrapped +``` + +`--reuse-values` сохраняет Ingress, секреты, Postgres/MinIO с кластера (то, что зашил addon). + +| Параметр job | Умолч. | Смысл | +|--------------|--------|--------| +| `IMAGE_REPOSITORY` | `inecs/wrapped` | как `wrapped_image_repository` | +| `IMAGE_TAG` | `0.1.0` | как `wrapped_image_tag` (`latest` / short-sha после build) | +| `IMAGE_PULL_POLICY` | `Always` | как в addon | + +Credential: `k3s-kubeconfig` (Secret file) — тот же, что у devops.org.ru. + +Рекомендуемая связка job’ов: после успешного **Wrapped Builder** (build) → триггер **Wrapped Deploy** (этот `Jenkinsfile.deploy`), либо ручной **Build with Parameters**. ### Git (`make push`)