excalidraw: migrate image build to GHA -> private ghcr (ADR-0002)
The image was still built by hand and pushed to DockerHub (v1..v4), predating the all-builds-off-infra doctrine; Viktor chose to move it onto the standard pipeline while shipping the export/rename feature rather than keep the manual flow. Mirrors the k8s-portal pattern: .github/workflows/build-excalidraw.yml (go test + buildx linux/amd64, pushes ghcr latest+sha), excalidraw ns added to the Kyverno ghcr-credentials allowlist (package is PRIVATE), deployment now pins ghcr :latest with pullPolicy Always + pull secret, Keel force/match-tag/5m annotations seed the metadata (live values win via ignore_changes). DockerHub viktorbarzin/excalidraw-library:v4 stays frozen as the rollback image. Docs: ci-cd.md + .claude/CLAUDE.md image lists updated (also backfilled the missing k8s-portal rows in ci-cd.md). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
1cbc1e962b
commit
8fc657f431
5 changed files with 77 additions and 7 deletions
|
|
@ -137,7 +137,7 @@ audiobook-search) now also land on ghcr.
|
|||
chrome-service-novnc, android-emulator.
|
||||
- **PRIVATE ghcr:** f1-stream, job-hunter, instagram-poster, payslip-ingest,
|
||||
wealthfolio-sync, fire-planner, recruiter-responder, tripit, infra-cli,
|
||||
infra-ci, k8s-portal. Pulled via the Kyverno-synced `ghcr-credentials` allowlist
|
||||
infra-ci, k8s-portal, excalidraw-library. Pulled via the Kyverno-synced `ghcr-credentials` allowlist
|
||||
(`stacks/kyverno/modules/kyverno/ghcr-credentials.tf`; NOT cluster-wide; cred
|
||||
= Vault `secret/viktor/ghcr_pull_token`, a dedicated classic PAT scoped to
|
||||
`read:packages` (UI-minted 2026-06-15; no longer the admin `github_pat`
|
||||
|
|
@ -153,7 +153,9 @@ github↔forgejo divergence was deliberately NOT reconciled):
|
|||
`build-cli.yml` → DockerHub `viktorbarzin/infra` (kept) + `ghcr.io/viktorbarzin/infra-cli`;
|
||||
`build-infra-ci.yml` → `ghcr.io/viktorbarzin/infra-ci`; `build-k8s-portal.yml` →
|
||||
PRIVATE `ghcr.io/viktorbarzin/k8s-portal` (Keel-deployed; the LAST in-cluster
|
||||
Woodpecker build, migrated 2026-06-13 — completes "no local builds"). **infra-ci**
|
||||
Woodpecker build, migrated 2026-06-13 — completes "no local builds"); `build-excalidraw.yml` →
|
||||
PRIVATE `ghcr.io/viktorbarzin/excalidraw-library` (Keel-deployed; replaced
|
||||
manual DockerHub pushes 2026-07-02 — DockerHub `:v4` frozen as rollback). **infra-ci**
|
||||
is the image the `.woodpecker/default.yml` apply step + `drift-detection.yml` run
|
||||
in (proven by pipelines 165/166). chatterbox-tts is already built by tripit's GHA → ghcr.
|
||||
The Woodpecker `build-ci-image.yml` + `build-cli.yml` pipelines were REMOVED;
|
||||
|
|
|
|||
42
.github/workflows/build-excalidraw.yml
vendored
Normal file
42
.github/workflows/build-excalidraw.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
name: Build excalidraw-library
|
||||
|
||||
# ADR-0002 / no-local-builds: excalidraw-library (infra-owned Go app behind
|
||||
# draw.viktorbarzin.me) builds off-infra on GHA → private ghcr; Keel polls
|
||||
# ghcr:latest and rolls the deployment. Replaces the manual DockerHub pushes
|
||||
# (viktorbarzin/excalidraw-library:v4 stays frozen as the rollback image).
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
paths:
|
||||
- 'stacks/excalidraw/project/**'
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
- run: go test ./...
|
||||
working-directory: stacks/excalidraw/project
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: stacks/excalidraw/project
|
||||
platforms: linux/amd64
|
||||
provenance: false
|
||||
push: true
|
||||
tags: |
|
||||
ghcr.io/viktorbarzin/excalidraw-library:latest
|
||||
ghcr.io/viktorbarzin/excalidraw-library:${{ github.sha }}
|
||||
|
|
@ -94,7 +94,7 @@ can't reach Forgejo's public hairpin.
|
|||
| Visibility | Packages | Pull mechanism |
|
||||
|------------|----------|----------------|
|
||||
| **Public** | beadboard, nextcloud-todos, claude-agent-service, claude-memory-mcp, kms-website, freedify, tuya_bridge, x402-gateway, chrome-service-novnc, android-emulator | Anonymous |
|
||||
| **Private** | f1-stream, job-hunter, instagram-poster, payslip-ingest, wealthfolio-sync, fire-planner, recruiter-responder, tripit, infra-cli, infra-ci | `ghcr-credentials` dockerconfigjson |
|
||||
| **Private** | f1-stream, job-hunter, instagram-poster, payslip-ingest, wealthfolio-sync, fire-planner, recruiter-responder, tripit, infra-cli, infra-ci, k8s-portal, excalidraw-library | `ghcr-credentials` dockerconfigjson |
|
||||
|
||||
Private-image pulls use the `ghcr-credentials` dockerconfigjson, cloned by the
|
||||
kyverno stack's `sync-ghcr-credentials` ClusterPolicy to an explicit
|
||||
|
|
@ -188,6 +188,8 @@ reconciled — the workflows were added to the GitHub lineage via PR):
|
|||
| android-emulator | `build-android-emulator.yml` | public `ghcr.io/viktorbarzin/android-emulator` |
|
||||
| infra CLI | `build-cli.yml` | DockerHub `viktorbarzin/infra` (kept) + `ghcr.io/viktorbarzin/infra-cli` |
|
||||
| infra-ci | `build-infra-ci.yml` | private `ghcr.io/viktorbarzin/infra-ci` |
|
||||
| k8s-portal | `build-k8s-portal.yml` | private `ghcr.io/viktorbarzin/k8s-portal` (Keel rolls `:latest` digests) |
|
||||
| excalidraw-library | `build-excalidraw.yml` | private `ghcr.io/viktorbarzin/excalidraw-library` (Keel rolls `:latest` digests; DockerHub `:v4` frozen as rollback) |
|
||||
|
||||
**`infra-ci`** is the image the `.woodpecker/default.yml` apply step and
|
||||
`drift-detection.yml` run in (proven by pipelines 165/166). `chatterbox-tts` is
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ resource "kubernetes_namespace" "excalidraw" {
|
|||
name = "excalidraw"
|
||||
labels = {
|
||||
"istio-injection" : "disabled"
|
||||
tier = local.tiers.aux
|
||||
tier = local.tiers.aux
|
||||
"keel.sh/enrolled" = "true"
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,15 @@ resource "kubernetes_deployment" "excalidraw" {
|
|||
app = "excalidraw"
|
||||
tier = local.tiers.aux
|
||||
}
|
||||
# Keel rolls new ghcr:latest digests (k8s-portal pattern). Values here are
|
||||
# recreate-correct seeds only — the keys are in ignore_changes below, so
|
||||
# the live annotations win on an existing deployment.
|
||||
annotations = {
|
||||
"keel.sh/policy" = "force"
|
||||
"keel.sh/trigger" = "poll"
|
||||
"keel.sh/match-tag" = "true"
|
||||
"keel.sh/pollSchedule" = "@every 5m"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
replicas = 1
|
||||
|
|
@ -67,9 +76,19 @@ resource "kubernetes_deployment" "excalidraw" {
|
|||
}
|
||||
}
|
||||
spec {
|
||||
# GHCR pull secret: the ghcr-credentials Secret in this namespace is
|
||||
# cloned in by the kyverno stack's sync-ghcr-credentials ClusterPolicy
|
||||
# (allowlisted private-ghcr namespaces only — ADR-0002). Source of
|
||||
# truth: stacks/kyverno/modules/kyverno/ghcr-credentials.tf.
|
||||
image_pull_secrets {
|
||||
name = "ghcr-credentials"
|
||||
}
|
||||
container {
|
||||
image = "viktorbarzin/excalidraw-library:v4"
|
||||
image_pull_policy = "IfNotPresent"
|
||||
# ADR-0002: GHA-built (.github/workflows/build-excalidraw.yml),
|
||||
# PRIVATE ghcr; Keel rolls new :latest digests. DockerHub
|
||||
# viktorbarzin/excalidraw-library:v4 is the frozen rollback image.
|
||||
image = "ghcr.io/viktorbarzin/excalidraw-library:latest"
|
||||
image_pull_policy = "Always"
|
||||
name = "excalidraw"
|
||||
port {
|
||||
container_port = 8080
|
||||
|
|
@ -107,7 +126,7 @@ resource "kubernetes_deployment" "excalidraw" {
|
|||
}
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1
|
||||
spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1
|
||||
spec[0].template[0].spec[0].container[0].image, # KEEL_IGNORE_IMAGE — Keel manages tag updates
|
||||
metadata[0].annotations["keel.sh/policy"],
|
||||
metadata[0].annotations["keel.sh/trigger"],
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ locals {
|
|||
# ghcr.io/passionprojectsanca/book-plotter (built by GHA in Anca's repo,
|
||||
# under her own org's ghcr). The deployment references the cloned secret.
|
||||
"plotting-book",
|
||||
# excalidraw: infra-owned image migrated from manual DockerHub pushes to
|
||||
# PRIVATE ghcr.io/viktorbarzin/excalidraw-library (ADR-0002, built by
|
||||
# .github/workflows/build-excalidraw.yml). The deployment references the
|
||||
# cloned secret.
|
||||
"excalidraw",
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue