The bump-dev (and identically-configured bump-prod) job failed during prepare_script with: ERROR: Job failed: prepare environment: waiting for pod running: pulling image "alpine/git:2.47.0": image pull failed: ... not found Root cause: alpine/git:2.47.0 does not exist on Docker Hub. The alpine/git 2.47.x line starts at 2.47.1 — there is no 2.47.0 build. The runner's image pull correctly fails with 'not found', and GitLab's Kubernetes executor treats an image-pull failure during prepare_script as fatal, so the job never reaches its script block. Fix: pin both bump-dev and bump-prod to alpine/git:2.47.2 (latest 2.47.x). Pinned rather than 'latest' so the job stays reproducible. bump-prod had the same nonexistent tag and would have hit the identical failure on its next run (whenever main advances), so both are fixed together.
166 lines
7.0 KiB
YAML
166 lines
7.0 KiB
YAML
# GitLab-CI dev→prod pipeline for VNCmail+ — GitOps via ArgoCD.
|
|
#
|
|
# Design:
|
|
# - MR into `dev`: verify only (typecheck/lint/unit test/build check). No
|
|
# push, no deploy — this is the multi-developer merge gate.
|
|
# - Push to `dev`: build+push an immutable `sha-<sha>` tag with Docker +
|
|
# docker-in-docker, then commit a one-line tag-bump into
|
|
# overlays/dev/image-tag/kustomization.yaml (`[skip ci]`). ArgoCD's
|
|
# `vncmail-dev` Application syncs it automatically.
|
|
# - Push to `main`: NEVER rebuilds. `main` only advances via
|
|
# `git merge --ff-only dev`, so main's HEAD commit already has a built
|
|
# image. This job just bumps overlays/prod/image-tag/kustomization.yaml
|
|
# to point at that same tag. The actual promotion gate is a HUMAN
|
|
# clicking Sync on the `vncmail-prod` ArgoCD Application.
|
|
#
|
|
# Deliberately single-platform (linux/amd64) — this pipeline serves two
|
|
# known amd64 microk8s clusters, not public multi-arch distribution (that's
|
|
# what the GHCR release workflows are for, untouched by this file).
|
|
#
|
|
# Prerequisite this file assumes:
|
|
# - A GitLab Runner with Docker-in-Docker service support (Kubernetes or
|
|
# Docker executor). The `docker:28.4.0-dind` service requires privileged
|
|
# mode on most Kubernetes executors.
|
|
# - Either "allow this job token to push to this project" enabled
|
|
# (Settings → CI/CD → Job token permissions), OR a project access token
|
|
# with `write_repository` scope in $GITLAB_PUSH_TOKEN. The bump jobs
|
|
# try CI_JOB_TOKEN first (see the script).
|
|
#
|
|
# deploy/k8s/ca/ (the EJBCA internal CA) is never referenced anywhere below,
|
|
# and neither ArgoCD Application in deploy/argocd/ points at it — that stays
|
|
# a fully manual, human-only runbook (see deploy/k8s/ca/README.md).
|
|
|
|
stages:
|
|
- verify
|
|
- build
|
|
- bump-dev
|
|
- bump-prod
|
|
|
|
variables:
|
|
IMAGE: $CI_REGISTRY_IMAGE
|
|
GIT_STRATEGY: clone
|
|
DOCKER_DRIVER: overlay2
|
|
# DinD service is reached at the `docker` alias (set explicitly on the
|
|
# service below), not localhost. TLS disabled so the daemon listens on
|
|
# plaintext 2375 — same pattern as the working vnc-localidp pipeline.
|
|
DOCKER_HOST: tcp://docker:2375
|
|
DOCKER_TLS_CERTDIR: ""
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# verify — required check on every MR into dev. No registry, no cluster.
|
|
# ---------------------------------------------------------------------------
|
|
verify:
|
|
stage: verify
|
|
image: node:24-alpine
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
script:
|
|
- npm ci
|
|
- npm run typecheck
|
|
- npm run lint
|
|
- npm run test:translations
|
|
- npm run build
|
|
# test:integration is deliberately NOT here — it spins up a real Stalwart
|
|
# fixture via docker-compose, which needs an actual Docker daemon this
|
|
# runner's Kubernetes executor doesn't provide without privileged mode
|
|
# (see the build job below). Candidate for a separate scheduled job on a
|
|
# differently-configured runner, not a blocker on every MR.
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build — push to dev only. Builds once; main never rebuilds (see header).
|
|
# ---------------------------------------------------------------------------
|
|
build:
|
|
stage: build
|
|
image: docker:28.4.0
|
|
services:
|
|
- name: docker:28.4.0-dind
|
|
alias: docker
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "dev"'
|
|
before_script:
|
|
- until docker info; do sleep 1; done
|
|
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
|
script:
|
|
- >
|
|
docker build
|
|
--build-arg GIT_COMMIT=$CI_COMMIT_SHA
|
|
-t "$IMAGE:sha-$CI_COMMIT_SHORT_SHA"
|
|
-t "$IMAGE:dev-latest"
|
|
.
|
|
- docker push "$IMAGE:sha-$CI_COMMIT_SHORT_SHA"
|
|
- docker push "$IMAGE:dev-latest"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# bump-dev — no cluster access. Commits the just-built tag into the overlay
|
|
# ArgoCD watches; ArgoCD's automated sync does the actual apply.
|
|
# ---------------------------------------------------------------------------
|
|
bump-dev:
|
|
stage: bump-dev
|
|
# alpine/git:2.47.0 was never published on Docker Hub — the 2.47.x line
|
|
# starts at 2.47.1. Using 2.47.2 (latest 2.47.x).
|
|
image: alpine/git:2.47.2
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "dev"'
|
|
script:
|
|
- TAG="sha-$CI_COMMIT_SHORT_SHA"
|
|
- |
|
|
cat > deploy/k8s/overlays/dev/image-tag/kustomization.yaml <<EOF
|
|
# Owned by CI (bump-dev job in .gitlab-ci.yml) - regenerated every
|
|
# push to dev. Do not hand-edit; edits here get overwritten.
|
|
apiVersion: kustomize.config.k8s.io/v1alpha1
|
|
kind: Component
|
|
images:
|
|
- name: vncmail-plus
|
|
newName: $IMAGE
|
|
newTag: $TAG
|
|
EOF
|
|
- git config user.name "vncmail-ci"
|
|
- git config user.email "ci@vnc.biz"
|
|
- git add deploy/k8s/overlays/dev/image-tag/kustomization.yaml
|
|
- |
|
|
if git diff --cached --quiet; then
|
|
echo "No change (tag already pinned) - nothing to commit"
|
|
else
|
|
git commit -m "chore(deploy): pin dev to $TAG [skip ci]"
|
|
git push "https://gitlab-ci-token:${GITLAB_PUSH_TOKEN:-$CI_JOB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" HEAD:dev
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# bump-prod — no cluster access, no rebuild. Points overlays/prod at the
|
|
# exact tag already running on dev. Does NOT deploy anything: vncmail-prod's
|
|
# ArgoCD Application has manual sync, so this only prepares what a human
|
|
# would be syncing, it doesn't sync it.
|
|
# ---------------------------------------------------------------------------
|
|
bump-prod:
|
|
stage: bump-prod
|
|
image: alpine/git:2.47.2
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"'
|
|
script:
|
|
- TAG="sha-$CI_COMMIT_SHORT_SHA"
|
|
- echo "main advanced to $CI_COMMIT_SHA (must be a dev commit, ff-only) - that image already exists as $IMAGE:$TAG"
|
|
- |
|
|
cat > deploy/k8s/overlays/prod/image-tag/kustomization.yaml <<EOF
|
|
# Owned by CI (bump-prod job in .gitlab-ci.yml) - regenerated every
|
|
# push to main. Do not hand-edit; edits here get overwritten. Bumping
|
|
# this is NOT the same as deploying it - vncmail-prod's ArgoCD
|
|
# Application has manual sync, see the note in the parent
|
|
# kustomization.yaml.
|
|
apiVersion: kustomize.config.k8s.io/v1alpha1
|
|
kind: Component
|
|
images:
|
|
- name: vncmail-plus
|
|
newName: $IMAGE
|
|
newTag: $TAG
|
|
EOF
|
|
- git config user.name "vncmail-ci"
|
|
- git config user.email "ci@vnc.biz"
|
|
- git add deploy/k8s/overlays/prod/image-tag/kustomization.yaml
|
|
- |
|
|
if git diff --cached --quiet; then
|
|
echo "No change (tag already pinned) - nothing to commit"
|
|
else
|
|
git commit -m "chore(deploy): point prod overlay at $TAG (not synced - manual gate in ArgoCD) [skip ci]"
|
|
git push "https://gitlab-ci-token:${GITLAB_PUSH_TOKEN:-$CI_JOB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" HEAD:main
|
|
fi
|