k8s-portal: build off-infra GHA -> ghcr + Keel; remove Woodpecker build (no-local-builds)
Some checks failed
ci/woodpecker/push/default Pipeline was canceled

The last in-cluster image build. GHA build-k8s-portal.yml builds
ghcr.io/viktorbarzin/k8s-portal:latest+sha (path-filtered on the Dockerfile
dir); Keel (force/poll/match-tag) rolls the deployment. Stack image repointed
to ghcr (ignore_changed); .woodpecker/k8s-portal.yml deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Viktor Barzin 2026-06-13 15:21:35 +00:00
parent 9501da81a0
commit b906f61ac3
3 changed files with 50 additions and 53 deletions

View file

@ -9,7 +9,7 @@ resource "kubernetes_namespace" "k8s_portal" {
metadata {
name = "k8s-portal"
labels = {
tier = var.tier
tier = var.tier
"keel.sh/enrolled" = "true"
}
}
@ -40,6 +40,15 @@ resource "kubernetes_deployment" "k8s_portal" {
metadata {
name = "k8s-portal"
namespace = kubernetes_namespace.k8s_portal.metadata[0].name
# ADR-0002 / no-local-builds: image now GHA-built -> ghcr:latest
# (.github/workflows/build-k8s-portal.yml). Keel polls ghcr:latest and rolls
# this deployment (replaces the removed Woodpecker in-cluster build+deploy).
annotations = {
"keel.sh/policy" = "force"
"keel.sh/trigger" = "poll"
"keel.sh/pollSchedule" = "@every 5m"
"keel.sh/match-tag" = "true"
}
labels = {
app = "k8s-portal"
tier = var.tier
@ -68,7 +77,7 @@ resource "kubernetes_deployment" "k8s_portal" {
spec {
container {
name = "portal"
image = "viktorbarzin/k8s-portal:latest"
image = "ghcr.io/viktorbarzin/k8s-portal:latest"
port {
container_port = 3000
}
@ -121,7 +130,8 @@ resource "kubernetes_deployment" "k8s_portal" {
# DRIFT_WORKAROUND: CI pipeline owns image tag (kubectl set image from Woodpecker/GHA); Kyverno mutates dns_config for ndots. Reviewed 2026-04-18.
ignore_changes = [
spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1
spec[0].template[0].spec[0].container[0].image, # CI updates image tag
spec[0].template[0].spec[0].container[0].image, # Keel manages ghcr:latest digest
metadata[0].annotations["keel.sh/update-time"], # KEEL_LIFECYCLE_V1 (Keel stamps on roll)
]
}
}
@ -172,5 +182,5 @@ module "ingress_setup_script" {
ingress_path = ["/setup/script", "/agent"]
tls_secret_name = var.tls_secret_name
# auth = "none": Setup script + agent endpoint must be curl-able without auth (no cookies preserved in automation).
auth = "none"
auth = "none"
}