From 6d7cdd59e3dd9b9295ba5dfd1a5ca42003027a4b Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Fri, 24 Jul 2026 23:40:56 +1000 Subject: [PATCH] pdbmux: deploy the merging PuppetDB proxy in-cluster (#275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why During the VM -> k8s Puppet migration, two PuppetDBs coexist and nodes move between them as they migrate. `node-lookup` (and `pblastreport`) need a single, consistent PuppetDB v4 view spanning both. `pdbmux` is a small merging proxy that provides exactly that. Per the all-in-kubernetes estate direction it runs as an in-cluster service, not a per-VM systemd unit. pdbmux now lives in its own repository (https://git.unkin.net/unkin/pdbmux) — split out of the earlier node-lookup prototype — and is released as a container image on its own `v*` tags. ## Changes - Add `apps/base/pdbmux/` (namespace, configmap, deployment, service, gateway, httproute), modeled directly on the encapi app. - Deployment: 2 replicas, image `git.unkin.net/unkin/pdbmux:v0.1.0`, port 8080, `/healthz` liveness + readiness, config via `PDBMUX_*` env from a ConfigMap. - Backends: `old=http://puppetdbapi.service.consul:8080`, `new=http://puppetdb.puppet.svc.cluster.local:8080` (in-cluster, verified against `apps/base/puppet/service_puppetdb.yaml` port `pdb-http`/8080 — the in-cluster address is preferred over the external gateway). `new` is primary/prefer, merge = freshness. - Expose over HTTPS at `pdbmux.k8s.syd1.au.unkin.net` via a `traefik-internal` Gateway (cert-manager `vault-issuer`, external-dns), plain-HTTP backend on a port-80 Service — same shape as the puppetdb/encapi gateways — so VM/workstation `node-lookup` can reach it. - Add `apps/overlays/au-syd1/pdbmux/` and wire pdbmux into the platform ApplicationSet (`apps/overlays/*/pdbmux`) and the platform AppProject (`pdbmux` namespace destination), exactly as encapi is wired. No new woodpecker ServiceAccount is required: the pdbmux image push uses the `docker-buildx` plugin against the Gitea registry with the `default` SA (same as encapi), not artifactapi. ## Verification - `kubectl kustomize apps/overlays/au-syd1/pdbmux` builds clean (image resolves to `git.unkin.net/unkin/pdbmux:v0.1.0`). - ApplicationSet + AppProject YAML validated. ## Merge gates 1. The pdbmux repo initial-content PR (https://git.unkin.net/unkin/pdbmux/pulls/1) must merge first. 2. `v0.1.0` must then be tagged on the pdbmux repo so the image `git.unkin.net/unkin/pdbmux:v0.1.0` is built and pushed by that repo`s `.woodpecker/docker.yaml`. 3. Then merge this PR. (If the first release tag differs from `v0.1.0`, update the image tag in `apps/base/pdbmux/deployment.yaml` to match before merging.) --------- Co-authored-by: benvin Reviewed-on: https://git.unkin.net/unkin/argocd-apps/pulls/275 Co-authored-by: Ben Vincent Co-committed-by: Ben Vincent --- apps/base/pdbmux/configmap.yaml | 19 ++++++ apps/base/pdbmux/deployment.yaml | 63 +++++++++++++++++++ apps/base/pdbmux/gateway.yaml | 37 +++++++++++ apps/base/pdbmux/httproute.yaml | 49 +++++++++++++++ apps/base/pdbmux/kustomization.yaml | 11 ++++ apps/base/pdbmux/namespace.yaml | 5 ++ apps/base/pdbmux/service.yaml | 17 +++++ .../au-syd1/pdbmux/kustomization.yaml | 6 ++ argocd/applicationsets/platform.yaml | 1 + argocd/projects/platform.yaml | 2 + 10 files changed, 210 insertions(+) create mode 100644 apps/base/pdbmux/configmap.yaml create mode 100644 apps/base/pdbmux/deployment.yaml create mode 100644 apps/base/pdbmux/gateway.yaml create mode 100644 apps/base/pdbmux/httproute.yaml create mode 100644 apps/base/pdbmux/kustomization.yaml create mode 100644 apps/base/pdbmux/namespace.yaml create mode 100644 apps/base/pdbmux/service.yaml create mode 100644 apps/overlays/au-syd1/pdbmux/kustomization.yaml diff --git a/apps/base/pdbmux/configmap.yaml b/apps/base/pdbmux/configmap.yaml new file mode 100644 index 0000000..1238425 --- /dev/null +++ b/apps/base/pdbmux/configmap.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: pdbmux-env + namespace: pdbmux +data: + PDBMUX_LISTEN: ":8080" + # Two PuppetDB backends merged during the VM -> k8s migration: + # old = legacy Consul-registered puppetdbapi (reachable from pods via the + # Consul DNS the puppet workloads already use) + # new = the in-cluster k8s PuppetDB (plain HTTP on 8080; in-cluster address + # is preferred over the external gateway to avoid a hairpin). + PDBMUX_BACKENDS: "old=http://puppetdbapi.service.consul:8080,new=http://puppetdb.puppet.svc.cluster.local:8080" + # "new" (the k8s PuppetDB) is the primary for non-merged pass-through and the + # preferred backend for ties / static-merge fallback. + PDBMUX_PRIMARY: "new" + PDBMUX_PREFER: "new" + PDBMUX_MERGE: "freshness" diff --git a/apps/base/pdbmux/deployment.yaml b/apps/base/pdbmux/deployment.yaml new file mode 100644 index 0000000..d51b947 --- /dev/null +++ b/apps/base/pdbmux/deployment.yaml @@ -0,0 +1,63 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pdbmux + namespace: pdbmux + annotations: + reloader.stakater.com/auto: "true" +spec: + replicas: 2 + selector: + matchLabels: + app: pdbmux + strategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + app: pdbmux + spec: + automountServiceAccountToken: false + containers: + - name: pdbmux + # Image is published by the pdbmux repo's .woodpecker/docker.yaml on + # a v* tag. It only exists after that tag is cut (see PR merge gates). + image: git.unkin.net/unkin/pdbmux:v0.1.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + protocol: TCP + envFrom: + # PDBMUX_LISTEN / PDBMUX_BACKENDS / PDBMUX_PRIMARY / PDBMUX_PREFER / + # PDBMUX_MERGE + - configMapRef: + name: pdbmux-env + optional: false + livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 15 + periodSeconds: 30 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 500m + memory: 256Mi + restartPolicy: Always diff --git a/apps/base/pdbmux/gateway.yaml b/apps/base/pdbmux/gateway.yaml new file mode 100644 index 0000000..100d2d9 --- /dev/null +++ b/apps/base/pdbmux/gateway.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + labels: + traefik.io/instance: internal + annotations: + cert-manager.io/cluster-issuer: vault-issuer + cert-manager.io/common-name: pdbmux.k8s.syd1.au.unkin.net + cert-manager.io/private-key-size: "4096" + external-dns.alpha.kubernetes.io/hostname: pdbmux.k8s.syd1.au.unkin.net + external-dns.alpha.kubernetes.io/target: 198.18.200.4 + name: pdbmux + namespace: pdbmux +spec: + gatewayClassName: traefik-internal + listeners: + - allowedRoutes: + namespaces: + from: Same + hostname: pdbmux.k8s.syd1.au.unkin.net + name: http + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: Same + hostname: pdbmux.k8s.syd1.au.unkin.net + name: https + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - group: "" + kind: Secret + name: pdbmux-tls + mode: Terminate diff --git a/apps/base/pdbmux/httproute.yaml b/apps/base/pdbmux/httproute.yaml new file mode 100644 index 0000000..a6fac82 --- /dev/null +++ b/apps/base/pdbmux/httproute.yaml @@ -0,0 +1,49 @@ +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: pdbmux-http-redirect + namespace: pdbmux +spec: + hostnames: + - pdbmux.k8s.syd1.au.unkin.net + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: pdbmux + sectionName: http + rules: + - filters: + - type: RequestRedirect + requestRedirect: + scheme: https + statusCode: 301 + matches: + - path: + type: PathPrefix + value: / +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: pdbmux + namespace: pdbmux +spec: + hostnames: + - pdbmux.k8s.syd1.au.unkin.net + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: pdbmux + sectionName: https + rules: + - backendRefs: + - group: "" + kind: Service + name: pdbmux + port: 80 + weight: 1 + matches: + - path: + type: PathPrefix + value: / diff --git a/apps/base/pdbmux/kustomization.yaml b/apps/base/pdbmux/kustomization.yaml new file mode 100644 index 0000000..372a7e3 --- /dev/null +++ b/apps/base/pdbmux/kustomization.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - namespace.yaml + - configmap.yaml + - deployment.yaml + - service.yaml + - gateway.yaml + - httproute.yaml diff --git a/apps/base/pdbmux/namespace.yaml b/apps/base/pdbmux/namespace.yaml new file mode 100644 index 0000000..12d2180 --- /dev/null +++ b/apps/base/pdbmux/namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: pdbmux diff --git a/apps/base/pdbmux/service.yaml b/apps/base/pdbmux/service.yaml new file mode 100644 index 0000000..6b21ef2 --- /dev/null +++ b/apps/base/pdbmux/service.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: pdbmux + namespace: pdbmux +spec: + internalTrafficPolicy: Cluster + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http + selector: + app: pdbmux + sessionAffinity: None + type: ClusterIP diff --git a/apps/overlays/au-syd1/pdbmux/kustomization.yaml b/apps/overlays/au-syd1/pdbmux/kustomization.yaml new file mode 100644 index 0000000..a9520c4 --- /dev/null +++ b/apps/overlays/au-syd1/pdbmux/kustomization.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../../base/pdbmux diff --git a/argocd/applicationsets/platform.yaml b/argocd/applicationsets/platform.yaml index 71b298d..28174aa 100644 --- a/argocd/applicationsets/platform.yaml +++ b/argocd/applicationsets/platform.yaml @@ -29,6 +29,7 @@ spec: - path: apps/overlays/*/jfrog - path: apps/overlays/*/kanidm - path: apps/overlays/*/node-feature-discovery + - path: apps/overlays/*/pdbmux - path: apps/overlays/*/priority-classes - path: apps/overlays/*/puppet - path: apps/overlays/*/purelb diff --git a/argocd/projects/platform.yaml b/argocd/projects/platform.yaml index db8f7df..ac32f91 100644 --- a/argocd/projects/platform.yaml +++ b/argocd/projects/platform.yaml @@ -39,6 +39,8 @@ spec: server: https://kubernetes.default.svc - namespace: 'node-feature-discovery' server: https://kubernetes.default.svc + - namespace: 'pdbmux' + server: https://kubernetes.default.svc - namespace: 'priority-classes' server: https://kubernetes.default.svc - namespace: 'purelb'