pdbmux: ship as k8s container, drop per-VM systemd/RPM delivery
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful

The estate direction is all-in-kubernetes, so pdbmux (a long-running daemon)
should run as an in-cluster service rather than an RPM-installed systemd unit
on each VM. The RPM is for workstation/VM CLI tools only; a daemon does not
belong there.

- Remove packaging/pdbmux.service and drop pdbmux (binary, systemd unit,
  completions) from the RPM/nfpm spec and build-rpm.sh.
- Keep pdbmux in the Makefile build and the test suite.
- Add Dockerfile.pdbmux building a static CGO_ENABLED=0 binary on distroless
  (mirrors encapi's image style).
- Add .woodpecker/docker.yaml to build+push git.unkin.net/unkin/pdbmux:<tag>
  on v* tags via the docker-buildx plugin (droneci/DRONECI_PASSWORD creds,
  same as encapi), with k8s resources set.
- Update README/AGENTS.md: deployment is k8s, config via PDBMUX_* env.
This commit is contained in:
Ben Vincent
2026-07-24 23:09:46 +10:00
parent 2aa94f0de7
commit 17ded87439
7 changed files with 112 additions and 72 deletions
+34
View File
@@ -0,0 +1,34 @@
# Build and push the pdbmux container image on a v* tag. pdbmux is a k8s-only
# daemon (deployed via argocd-apps), so it ships as an image rather than in the
# RPM. Mirrors the estate convention (encapi's docker.yaml): the
# woodpeckerci/plugin-docker-buildx plugin pushes to the Gitea registry using
# the droneci / DRONECI_PASSWORD credentials.
when:
- event: tag
ref: refs/tags/v*
steps:
- name: docker-pdbmux
image: woodpeckerci/plugin-docker-buildx
settings:
registry: git.unkin.net
repo: git.unkin.net/unkin/pdbmux
dockerfile: Dockerfile.pdbmux
build_args:
VERSION: ${CI_COMMIT_TAG}
username: droneci
password:
from_secret: DRONECI_PASSWORD
tags:
- ${CI_COMMIT_TAG}
- latest
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 1Gi
cpu: 1
limits:
memory: 2Gi
cpu: 2
+10 -3
View File
@@ -33,10 +33,10 @@ internal/puppet/ # shared: config, puppetdb nodes query, board URLs
go.mod # Go module (module name: node-lookup)
go.sum # dependency checksums
Makefile # build / test / lint / completions / rpm / version-bump targets
packaging/nfpm.yaml # nfpm spec (envsubst-templated) for the RPM (all 4 binaries)
packaging/pdbmux.service # systemd unit for the pdbmux daemon
packaging/nfpm.yaml # nfpm spec (envsubst-templated) for the RPM (CLI tools only)
Dockerfile.pdbmux # container image for the k8s-only pdbmux daemon
scripts/build-rpm.sh # generates completions + packages the RPM with nfpm
.woodpecker/ # CI: build, test, pre-commit (PR) + release (tag)
.woodpecker/ # CI: build, test, pre-commit (PR) + release/docker (tag)
dist/ # build output: binaries, completions, RPM (not committed)
```
@@ -63,6 +63,13 @@ make rpm # build the binary + package it into dist/*.rpm via nfpm
and bundles them alongside `/usr/bin/node-lookup`. On a `v*` tag the release
pipeline builds the RPM and `PUT`s it to the artifactapi `rpm-internal` repo.
The RPM contains the workstation/VM CLI tools only (`node-lookup`, `pburl`,
`pblastreport`). `pdbmux` is a k8s-only daemon and is deliberately excluded from
the RPM — it is released as a container image
(`git.unkin.net/unkin/pdbmux:<tag>`, built by `.woodpecker/docker.yaml` from
`Dockerfile.pdbmux`) and deployed via `argocd-apps`. `make build` and
`go test ./...` still cover pdbmux.
## Shell completions
Cobra provides a `completion` subcommand:
+24
View File
@@ -0,0 +1,24 @@
# Container image for pdbmux, the merging PuppetDB proxy daemon. This repo ships
# several CLI tools (node-lookup/pburl/pblastreport) as an RPM, but pdbmux is a
# k8s-only service, so it gets its own Dockerfile (Dockerfile.pdbmux) and image.
FROM golang:1.25-alpine AS builder
RUN apk add --no-cache git
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
ARG VERSION=dev
RUN CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=${VERSION}" -o pdbmux ./cmd/pdbmux
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /build/pdbmux /usr/local/bin/pdbmux
EXPOSE 8080
ENTRYPOINT ["pdbmux", "serve"]
+34 -13
View File
@@ -1,10 +1,15 @@
# node-lookup tools
PuppetDB CLIs and one proxy daemon, shipped together in a single RPM:
PuppetDB CLIs plus one proxy daemon.
The CLIs ship together in a single RPM for workstations/VMs:
- **`node-lookup`** — query and filter PuppetDB node facts.
- **`pburl`** — print each host's Puppetboard node-page URL.
- **`pblastreport`** — print each host's last Puppet report time + Puppetboard URL.
The proxy daemon is deployed to Kubernetes as a container image (not in the RPM):
- **`pdbmux`** — merging HTTP proxy over two PuppetDBs (see below).
See [AGENTS.md](AGENTS.md) for the CLI tools' flags, config, and internals. This
@@ -71,11 +76,12 @@ unknown fields survive untouched.
Precedence (lowest → highest): **defaults < config file < env vars (`PDBMUX_*`) < flags**.
Config file: `$XDG_CONFIG_HOME/pdbmux/config.yaml` (as an RPM/systemd service:
`/etc/pdbmux/config.yaml`).
Config file: `$XDG_CONFIG_HOME/pdbmux/config.yaml`. In Kubernetes, configuration
is supplied entirely via `PDBMUX_*` env vars (no config file), which is the
supported deployment path — see [Deployment](#deployment).
```yaml
# ~/.config/pdbmux/config.yaml (or /etc/pdbmux/config.yaml under systemd)
# ~/.config/pdbmux/config.yaml (local dev; in k8s use PDBMUX_* env instead)
listen: ":8080"
backends:
- name: old
@@ -123,15 +129,30 @@ NODE_LOOKUP_URL=http://localhost:8080/pdb/query/v4/facts pblastreport somehost
### Deployment
The RPM installs `/usr/bin/pdbmux` plus a systemd unit at
`/usr/lib/systemd/system/pdbmux.service` (reads `/etc/pdbmux/config.yaml`):
`pdbmux` runs **in Kubernetes** as a container, in line with the all-in-k8s
estate direction — it is not shipped as a per-VM RPM/systemd service. The image
is built and pushed on every `v*` tag (`.woodpecker/docker.yaml`) to:
```bash
systemctl enable --now pdbmux
curl -s localhost:8080/healthz
```
git.unkin.net/unkin/pdbmux:<tag>
```
Suited to run as an RPM-managed daemon on a VM alongside the existing Puppet
infra during migration; the same static binary is container-ready for a future
k8s deployment (single listener, `/healthz` liveness/readiness probe, config via
`PDBMUX_*` env).
It is a minimal static (`CGO_ENABLED=0`) binary on a distroless base
(`Dockerfile.pdbmux`), configured entirely via `PDBMUX_*` env vars, with a
single HTTP listener and `/healthz` for liveness/readiness probes.
The Deployment/Service/Gateway manifests live in the estate's `argocd-apps` repo
under `apps/base/pdbmux/` (namespace `pdbmux`, 2 replicas), and it is exposed to
VM/workstation `node-lookup` consumers over HTTPS at:
```
https://pdbmux.k8s.syd1.au.unkin.net
```
Locally you can still run the binary directly for development:
```bash
PDBMUX_BACKENDS='old=http://puppetdbapi.service.consul:8080,new=http://puppetdb.puppet.svc.cluster.local:8080' \
pdbmux serve
curl -s localhost:8080/healthz
```
+5 -23
View File
@@ -42,18 +42,12 @@ contents:
mode: 0755
owner: root
group: root
- src: dist/pdbmux
dst: /usr/bin/pdbmux
file_info:
mode: 0755
owner: root
group: root
# systemd unit for the pdbmux proxy daemon (config: /etc/pdbmux/config.yaml).
- src: packaging/pdbmux.service
dst: /usr/lib/systemd/system/pdbmux.service
file_info:
mode: 0644
# NOTE: pdbmux is intentionally NOT shipped in this RPM. It is a k8s-only
# daemon (deployed via argocd-apps as a container image), not a workstation/VM
# CLI tool, so it has no place in the CLI package. pdbmux is still built and
# tested in this repo (see Makefile) and released as a container image
# (.woodpecker/docker.yaml).
# Shell completions (generated by scripts/build-rpm.sh before packaging).
- src: dist/completions/node-lookup.bash
@@ -92,15 +86,3 @@ contents:
dst: /usr/share/fish/vendor_completions.d/pblastreport.fish
file_info:
mode: 0644
- src: dist/completions/pdbmux.bash
dst: /usr/share/bash-completion/completions/pdbmux
file_info:
mode: 0644
- src: dist/completions/_pdbmux
dst: /usr/share/zsh/site-functions/_pdbmux
file_info:
mode: 0644
- src: dist/completions/pdbmux.fish
dst: /usr/share/fish/vendor_completions.d/pdbmux.fish
file_info:
mode: 0644
-31
View File
@@ -1,31 +0,0 @@
[Unit]
Description=pdbmux - merging proxy over old + new PuppetDB during migration
Documentation=https://git.unkin.net/unkin/node-lookup
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
# Configure via /etc/pdbmux/config.yaml or PDBMUX_* env in this file / a drop-in.
# Example env overrides:
# Environment=PDBMUX_LISTEN=:8080
# Environment=PDBMUX_MERGE=freshness
Environment=XDG_CONFIG_HOME=/etc
ExecStart=/usr/bin/pdbmux serve
Restart=on-failure
RestartSec=5
# Hardening: pdbmux only makes outbound HTTP(S) and listens on a socket.
DynamicUser=yes
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6
RestrictNamespaces=yes
[Install]
WantedBy=multi-user.target
+5 -2
View File
@@ -12,7 +12,10 @@ cd "${ROOT_DIR}"
VERSION="${1:-${CI_COMMIT_TAG:-0.0.0-dev}}"
VERSION="${VERSION#v}" # strip a leading v
BINARY="node-lookup"
BINARIES=(node-lookup pburl pblastreport pdbmux)
# RPM ships the workstation/VM CLI tools only. pdbmux is a k8s-only daemon and
# is deliberately excluded from the RPM (it is released as a container image);
# it is still built + tested in this repo via the Makefile.
BINARIES=(node-lookup pburl pblastreport)
DIST="dist"
for b in "${BINARIES[@]}"; do
@@ -37,7 +40,7 @@ export PACKAGE_VERSION="${VERSION}"
export PACKAGE_RELEASE="1"
export PACKAGE_ARCH="amd64"
export PACKAGE_PLATFORM="linux"
export PACKAGE_DESCRIPTION="CLI tools for PuppetDB: node-lookup (fact lookup/filtering), pburl and pblastreport (Puppetboard URLs and last-report times), plus pdbmux (merging proxy over the old + new PuppetDB during migration)"
export PACKAGE_DESCRIPTION="CLI tools for PuppetDB: node-lookup (fact lookup/filtering), pburl and pblastreport (Puppetboard URLs and last-report times)"
export PACKAGE_MAINTAINER="Ben Vincent <ben@unkin.net>"
export PACKAGE_HOMEPAGE="https://git.unkin.net/unkin/node-lookup"
export PACKAGE_LICENSE="MIT"