k8s-portal: build off-infra GHA -> ghcr + Keel; remove Woodpecker build (no-local-builds)
Some checks failed
ci/woodpecker/push/default Pipeline was canceled
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:
parent
9501da81a0
commit
b906f61ac3
3 changed files with 50 additions and 53 deletions
36
.github/workflows/build-k8s-portal.yml
vendored
Normal file
36
.github/workflows/build-k8s-portal.yml
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
name: Build k8s-portal
|
||||||
|
|
||||||
|
# ADR-0002 / no-local-builds: k8s-portal (infra-owned Go portal) builds off-infra
|
||||||
|
# on GHA → public ghcr; Keel polls ghcr:latest and rolls the deployment. Replaces
|
||||||
|
# the in-cluster .woodpecker/k8s-portal.yml build.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
paths:
|
||||||
|
- 'stacks/platform/modules/k8s-portal/files/**'
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- 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/platform/modules/k8s-portal/files
|
||||||
|
platforms: linux/amd64
|
||||||
|
provenance: false
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
ghcr.io/viktorbarzin/k8s-portal:latest
|
||||||
|
ghcr.io/viktorbarzin/k8s-portal:${{ github.sha }}
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
when:
|
|
||||||
event: push
|
|
||||||
branch: master
|
|
||||||
path:
|
|
||||||
include:
|
|
||||||
- "stacks/platform/modules/k8s-portal/files/**"
|
|
||||||
|
|
||||||
clone:
|
|
||||||
git:
|
|
||||||
image: woodpeckerci/plugin-git
|
|
||||||
settings:
|
|
||||||
attempts: 5
|
|
||||||
backoff: 10s
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build-and-push
|
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
|
||||||
settings:
|
|
||||||
username: "viktorbarzin"
|
|
||||||
password:
|
|
||||||
from_secret: dockerhub-pat
|
|
||||||
repo: viktorbarzin/k8s-portal
|
|
||||||
dockerfile: stacks/platform/modules/k8s-portal/files/Dockerfile
|
|
||||||
context: stacks/platform/modules/k8s-portal/files
|
|
||||||
platforms:
|
|
||||||
- linux/amd64
|
|
||||||
tag: ["${CI_PIPELINE_NUMBER}", "latest"]
|
|
||||||
cache_from: "viktorbarzin/k8s-portal:latest"
|
|
||||||
cache_to: "type=inline"
|
|
||||||
|
|
||||||
- name: deploy
|
|
||||||
image: bitnami/kubectl:latest
|
|
||||||
commands:
|
|
||||||
- "kubectl set image deployment/k8s-portal portal=viktorbarzin/k8s-portal:${CI_PIPELINE_NUMBER} -n k8s-portal"
|
|
||||||
- "kubectl rollout status deployment/k8s-portal -n k8s-portal --timeout=120s"
|
|
||||||
- "echo 'k8s-portal deployed successfully (build ${CI_PIPELINE_NUMBER})'"
|
|
||||||
|
|
||||||
- name: slack
|
|
||||||
image: curlimages/curl
|
|
||||||
commands:
|
|
||||||
- |
|
|
||||||
curl -s -X POST -H 'Content-type: application/json' \
|
|
||||||
--data "{\"text\":\"K8s Portal: build #${CI_PIPELINE_NUMBER} ${CI_PIPELINE_STATUS}\"}" \
|
|
||||||
"$SLACK_WEBHOOK" || true
|
|
||||||
environment:
|
|
||||||
SLACK_WEBHOOK:
|
|
||||||
from_secret: slack_webhook
|
|
||||||
when:
|
|
||||||
status: [success, failure]
|
|
||||||
|
|
@ -9,7 +9,7 @@ resource "kubernetes_namespace" "k8s_portal" {
|
||||||
metadata {
|
metadata {
|
||||||
name = "k8s-portal"
|
name = "k8s-portal"
|
||||||
labels = {
|
labels = {
|
||||||
tier = var.tier
|
tier = var.tier
|
||||||
"keel.sh/enrolled" = "true"
|
"keel.sh/enrolled" = "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +40,15 @@ resource "kubernetes_deployment" "k8s_portal" {
|
||||||
metadata {
|
metadata {
|
||||||
name = "k8s-portal"
|
name = "k8s-portal"
|
||||||
namespace = kubernetes_namespace.k8s_portal.metadata[0].name
|
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 = {
|
labels = {
|
||||||
app = "k8s-portal"
|
app = "k8s-portal"
|
||||||
tier = var.tier
|
tier = var.tier
|
||||||
|
|
@ -68,7 +77,7 @@ resource "kubernetes_deployment" "k8s_portal" {
|
||||||
spec {
|
spec {
|
||||||
container {
|
container {
|
||||||
name = "portal"
|
name = "portal"
|
||||||
image = "viktorbarzin/k8s-portal:latest"
|
image = "ghcr.io/viktorbarzin/k8s-portal:latest"
|
||||||
port {
|
port {
|
||||||
container_port = 3000
|
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.
|
# 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 = [
|
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, # 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"]
|
ingress_path = ["/setup/script", "/agent"]
|
||||||
tls_secret_name = var.tls_secret_name
|
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": Setup script + agent endpoint must be curl-able without auth (no cookies preserved in automation).
|
||||||
auth = "none"
|
auth = "none"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue