From e1026b87dbe30c402b4fa89f004bcf6402438af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Sun, 27 Sep 2026 16:44:32 +0200 Subject: [PATCH] fix cd --- .gitea/workflows/build.yaml | 45 +++++++++++++++++++++++++++ deploy/k8s/00-config.yaml | 12 ------- deploy/k8s/10-deployment.yaml | 7 ++++- deploy/k8s/30-ingress.yaml | 4 +++ deploy/k8s/90-secret-tls.example.yaml | 11 +++++++ deploy/k8s/kustomization.yaml | 1 - gitops/README.md | 32 +++++++++++++++++++ gitops/deployment.yaml | 14 +++++++++ gitops/gitsource.yaml | 17 ++++++++++ 9 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 .gitea/workflows/build.yaml create mode 100644 deploy/k8s/90-secret-tls.example.yaml create mode 100644 gitops/README.md create mode 100644 gitops/deployment.yaml create mode 100644 gitops/gitsource.yaml diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..50fe4d8 --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -0,0 +1,45 @@ +# Build and publish here; k8s-helper deploys ./deploy/k8s after the webhook. +name: build + +on: + push: + branches: [main] + +env: + IMAGE: fancydns/fancy-dns + +jobs: + build-push: + runs-on: amd64 + steps: + - uses: actions/checkout@v4 + + - name: Build image + run: | + docker build --build-arg VERSION=${{ gitea.sha }} \ + -t $IMAGE:${{ gitea.sha }} -t $IMAGE:latest . + + - name: Push image + run: | + docker push $IMAGE:${{ gitea.sha }} + docker push $IMAGE:latest + + - name: Reconcile after image is published + env: + GITOPS_WEBHOOK_SECRET: ${{ secrets.GITOPS_WEBHOOK_SECRET }} + run: | + if [ -z "$GITOPS_WEBHOOK_SECRET" ]; then + echo "GITOPS_WEBHOOK_SECRET must match the k8s-helper Gitea webhook secret" >&2 + exit 1 + fi + payload="$(mktemp)" + trap 'rm -f "$payload"' EXIT + printf '{"ref":"%s","after":"%s","repository":{"clone_url":"https://git.k6n.net/mats/fancy-dns.git","ssh_url":"git@git.k6n.net:mats/fancy-dns.git"}}' \ + "$GITHUB_REF" "$GITHUB_SHA" > "$payload" + signature="$(openssl dgst -sha256 -hmac "$GITOPS_WEBHOOK_SECRET" "$payload" | awk '{print $NF}')" + curl --fail --silent --show-error \ + -X POST \ + -H "Content-Type: application/json" \ + -H "X-Gitea-Signature: $signature" \ + --data-binary "@$payload" \ + https://ui.k6n.net/api/gitops/webhooks/gitea diff --git a/deploy/k8s/00-config.yaml b/deploy/k8s/00-config.yaml index 5a60ccf..ecb124e 100644 --- a/deploy/k8s/00-config.yaml +++ b/deploy/k8s/00-config.yaml @@ -109,15 +109,3 @@ data: log: level: info format: json ---- -apiVersion: v1 -kind: Secret -metadata: - name: fancy-dns-tls - namespace: dns -type: kubernetes.io/tls -# Replace with a real cert-manager managed secret in production: -# cert-manager.io/v1 -> Certificate -> CertificateRequest -> Secret -stringData: - tls.crt: "" - tls.key: "" diff --git a/deploy/k8s/10-deployment.yaml b/deploy/k8s/10-deployment.yaml index 568fc60..4ec9398 100644 --- a/deploy/k8s/10-deployment.yaml +++ b/deploy/k8s/10-deployment.yaml @@ -5,6 +5,9 @@ metadata: namespace: dns labels: app.kubernetes.io/name: fancy-dns + annotations: + k8s-helper.io/git-url: "https://git.k6n.net/mats/fancy-dns" + k8s-helper.io/git-ssh: "git@git.k6n.net:mats/fancy-dns.git" spec: serviceName: fancy-dns # A StatefulSet rather than a Deployment because each pod owns a PVC (the @@ -22,6 +25,8 @@ spec: labels: app.kubernetes.io/name: fancy-dns annotations: + k8s-helper.io/git-url: "https://git.k6n.net/mats/fancy-dns" + k8s-helper.io/git-ssh: "git@git.k6n.net:mats/fancy-dns.git" # A config change is a SIGHUP, not a restart: the server re-reads the # file and hot-swaps every component. This annotation is for # stakater/reloader-class controllers; without one, `kubectl rollout @@ -53,7 +58,7 @@ spec: containers: - name: fancy-dns image: fancydns/fancy-dns:latest - imagePullPolicy: IfNotPresent + imagePullPolicy: Always args: - -config - /etc/fancy-dns/config.yaml diff --git a/deploy/k8s/30-ingress.yaml b/deploy/k8s/30-ingress.yaml index b8506ea..d42ddc9 100644 --- a/deploy/k8s/30-ingress.yaml +++ b/deploy/k8s/30-ingress.yaml @@ -7,6 +7,10 @@ metadata: labels: app.kubernetes.io/name: fancy-dns annotations: + k8s-helper.io/name: "fancy-dns" + k8s-helper.io/description: "Recursive DNS resolver and admin dashboard" + k8s-helper.io/group: "Infrastructure" + k8s-helper.io/icon: "network" nginx.ingress.kubernetes.io/backend-protocol: "HTTP" # SSE (the live query log) is the reason for these three. With response # buffering on, nginx holds events until the buffer fills and the log page diff --git a/deploy/k8s/90-secret-tls.example.yaml b/deploy/k8s/90-secret-tls.example.yaml new file mode 100644 index 0000000..2356ddb --- /dev/null +++ b/deploy/k8s/90-secret-tls.example.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Secret +metadata: + name: fancy-dns-tls + namespace: dns +type: kubernetes.io/tls +# Replace with a real cert-manager managed secret in production: +# cert-manager.io/v1 -> Certificate -> CertificateRequest -> Secret +stringData: + tls.crt: "" + tls.key: "" diff --git a/deploy/k8s/kustomization.yaml b/deploy/k8s/kustomization.yaml index 40ff8b8..c85d7f3 100644 --- a/deploy/k8s/kustomization.yaml +++ b/deploy/k8s/kustomization.yaml @@ -11,7 +11,6 @@ namespace: dns resources: - 00-config.yaml - 05-serviceaccount.yaml - - 08-secret-apikey.yaml - 10-deployment.yaml - 20-service.yaml - 30-ingress.yaml diff --git a/gitops/README.md b/gitops/README.md new file mode 100644 index 0000000..df85f47 --- /dev/null +++ b/gitops/README.md @@ -0,0 +1,32 @@ +# Deploying fancy-dns with k8s-helper + +Gitea Actions builds and pushes `fancydns/fancy-dns:` and +`fancydns/fancy-dns:latest` on pushes to `main`. It then sends a signed +reconcile webhook so the agent applies the published image from `./deploy/k8s` +into namespace `dns`. + +## One-time setup + +The k8s-helper GitOps CRDs and agent must be installed, and its dashboard must +have `K8SHELPER_GITOPS_WEBHOOK_SECRET` configured. The GitSource reuses the +existing `dev/gitea-k8s-helper` Secret; its token must have read access to this +repository. The Gitea Actions secret `GITOPS_WEBHOOK_SECRET` must contain the +same webhook key. A user- or organization-level Actions secret can be shared +with other repos. + +Configure this repository's Gitea webhook for push events only: + +- Target: `https://ui.k6n.net/api/gitops/webhooks/gitea` +- Secret: the same value as `K8SHELPER_GITOPS_WEBHOOK_SECRET` + +Bootstrap the GitOps resources once with `kubectl apply -f gitops/`. The +`dns` namespace is declared in the managed kustomization. Before bootstrapping, +create `fancy-dns-apikey` in `dns` as described in `deploy/k8s/08-secret-apikey.yaml` +and ensure the cert-manager-managed `fancy-dns-tls` Secret exists. The GitOps +kustomization intentionally excludes both example Secret manifests so it never +replaces real credentials or TLS material with placeholders. + +The runner uses its existing Docker login. Each successful main build sends a +signed webhook after pushing, which avoids reconciling before the new image is +available. `prune` is initially disabled; inspect the inventory before enabling +it. diff --git a/gitops/deployment.yaml b/gitops/deployment.yaml new file mode 100644 index 0000000..1dbf944 --- /dev/null +++ b/gitops/deployment.yaml @@ -0,0 +1,14 @@ +apiVersion: gitops.k6n.net/v1alpha1 +kind: Deployment +metadata: + name: fancy-dns + namespace: dev +spec: + sourceRef: + kind: GitSource + name: fancy-dns + path: ./deploy/k8s + targetNamespace: dns + prune: false + wait: true + deletionPolicy: Orphan diff --git a/gitops/gitsource.yaml b/gitops/gitsource.yaml new file mode 100644 index 0000000..811cd90 --- /dev/null +++ b/gitops/gitsource.yaml @@ -0,0 +1,17 @@ +# Keep GitOps CRs outside the path they manage. +apiVersion: gitops.k6n.net/v1alpha1 +kind: GitSource +metadata: + name: fancy-dns + namespace: dev +spec: + url: https://git.k6n.net/mats/fancy-dns.git + ref: + branch: main + interval: 5m + secretRef: + name: gitea-k8s-helper + ignore: | + .gitea/ + docs/ + web/