The hand-authored UniFi VM manifests used column-aligned inline flow mappings
(`{ name: inform, port: 8080, protocol: TCP }`), which yamllint's `commas`
rule rejects as "too many spaces after comma". That made `make -C ci lint` FAIL,
so the merge gate has been BLOCKED on `main` since the UniFi commits landed —
every other static stage was green.
Collapse each run of spaces after a comma to one, and re-align the trailing
comments so the port tables stay readable. Whitespace only:
`kubectl kustomize apps/vms` renders byte-for-byte identically before and after.
The lint config is left untouched — relaxing the rule to make failing files pass
is moving the goalposts, not fixing the code.
Also refresh these files' stale `STAGING / DRAFT` headers: the tree is live,
reconciled by the non-gating `apps-vms` Flux Kustomization.
Gate after this change: spec-immutability / lint / l0 / l1 all green,
MERGE GATE: PASS.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
77 lines
3.8 KiB
YAML
77 lines
3.8 KiB
YAML
---
|
|
# LIVE — reconciled by the non-gating `apps-vms` Flux Kustomization (see namespace.yaml header).
|
|
#
|
|
# ============================================================================================
|
|
# L4 EXPOSURE (the hard part) — why the shared HTTPS Gateway is NOT enough for UniFi.
|
|
# ============================================================================================
|
|
# The Gateway API `shared` Gateway is an L7 HTTPS terminator (host-routed :443 -> backend). It
|
|
# CANNOT express: raw TCP on non-HTTP ports (8080 inform, 6789), UDP at all (3478 STUN, 10001
|
|
# discovery), or the device-facing protocols that never speak HTTP. UniFi device ADOPTION rides
|
|
# exactly those L4 ports. So the controller is exposed as a type=LoadBalancer Service whose VIP
|
|
# is pulled from the CiliumLoadBalancerIPPool `default-pool` (192.168.1.53-.60) and ARP-announced
|
|
# on the flat LAN by the existing CiliumL2AnnouncementPolicy `default-l2` — the SAME L2/LB-IPAM
|
|
# machinery the Gateway ingress VIP already uses (platform-config/cilium/*). No new Cilium config
|
|
# is required; these Services just consume the pool.
|
|
#
|
|
# ONE VIP, TWO SERVICES: a LoadBalancer Service is single-protocol-friendly, so TCP and UDP are
|
|
# split into two Services that SHARE ONE IP via Cilium's `lbipam.cilium.io/sharing-key`. The IP is
|
|
# PINNED (lbipam.cilium.io/ips) so devices have a STABLE inform/STUN target that never moves.
|
|
# (Alternative: one mixed-protocol Service — needs the MixedProtocolLBService feature, GA on
|
|
# k3s v1.31 — but the shared-key split is the lower-risk, Cilium-native pattern.)
|
|
#
|
|
# selector kubevirt.io/vm=unifi -> the virt-launcher pod; masquerade forwards the declared ports
|
|
# into the guest. externalTrafficPolicy: Local preserves the LAN client source IP and keeps the
|
|
# VIP pinned to the node running the VM (also what L2 announcement does).
|
|
#
|
|
# FLAG: confirm 192.168.1.54 is free, inside default-pool, and reserved in tofu (the Gateway
|
|
# already holds one pool IP, typically .53). Adjust if it collides.
|
|
#
|
|
# REUSABLE PATTERN (the deferred `minecraft` :25565/L4 problem is the same shape): expose an
|
|
# L4-only workload as a Cilium LoadBalancer on a pinned, L2-announced VIP with a per-app sharing
|
|
# key; publish its A record from the Service via external-dns. minecraft = one TCP port; unifi is
|
|
# the multi-port TCP+UDP generalization.
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: unifi-l4-tcp
|
|
namespace: unifi
|
|
labels:
|
|
app.kubernetes.io/name: unifi
|
|
annotations:
|
|
lbipam.cilium.io/sharing-key: "unifi"
|
|
lbipam.cilium.io/ips: "192.168.1.54"
|
|
# external-dns (source: service) publishes A unifi.home.keithjackson.dev -> 192.168.1.54.
|
|
# This is the browser + device target; UI is https://unifi.home.keithjackson.dev:11443.
|
|
external-dns.alpha.kubernetes.io/hostname: "unifi.home.keithjackson.dev"
|
|
spec:
|
|
type: LoadBalancer
|
|
externalTrafficPolicy: Local
|
|
selector:
|
|
kubevirt.io/vm: unifi
|
|
ports:
|
|
- { name: inform, port: 8080, targetPort: 8080, protocol: TCP }
|
|
- { name: ui, port: 11443, targetPort: 11443, protocol: TCP }
|
|
- { name: ui-legacy, port: 8443, targetPort: 8443, protocol: TCP }
|
|
- { name: portal-http, port: 8880, targetPort: 8880, protocol: TCP }
|
|
- { name: portal-https, port: 8843, targetPort: 8843, protocol: TCP }
|
|
- { name: throughput, port: 6789, targetPort: 6789, protocol: TCP }
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: unifi-l4-udp
|
|
namespace: unifi
|
|
labels:
|
|
app.kubernetes.io/name: unifi
|
|
annotations:
|
|
lbipam.cilium.io/sharing-key: "unifi" # same key + same IP => shares the VIP with -tcp
|
|
lbipam.cilium.io/ips: "192.168.1.54"
|
|
spec:
|
|
type: LoadBalancer
|
|
externalTrafficPolicy: Local
|
|
selector:
|
|
kubevirt.io/vm: unifi
|
|
ports:
|
|
- { name: stun, port: 3478, targetPort: 3478, protocol: UDP }
|
|
- { name: discovery, port: 10001, targetPort: 10001, protocol: UDP }
|