Merge feature/onboard-pihole (first WS-APPS onboarding)
This commit is contained in:
3 files changed
+203
-8
No files matched your search
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
# Onboarded services (WS-APPS). Each app is rendered from its catalog/ ServiceDefinition by
|
||||||
|
# catalog/render.py and committed here; the `apps` Flux Kustomization (clusters/base/apps.yaml,
|
||||||
|
# dependsOn platform-config) reconciles this directory. Image-automation CRs are omitted for now
|
||||||
|
# (--no-image-automation) until the Flux image controllers are installed.
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- pihole.yaml
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
---
|
||||||
|
# Namespace (trust zone; default-deny + policies apply)
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: pihole
|
||||||
|
labels:
|
||||||
|
homelab.keithjackson.dev/app-namespace: 'true'
|
||||||
|
gateway-access: shared
|
||||||
|
annotations:
|
||||||
|
homelab.keithjackson.dev/backup-policy: daily-offcluster
|
||||||
|
---
|
||||||
|
# Default-deny baseline (R-NET-01): deny all, allow only DNS
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: default-deny
|
||||||
|
namespace: pihole
|
||||||
|
labels:
|
||||||
|
homelab.keithjackson.dev/baseline: default-deny
|
||||||
|
spec:
|
||||||
|
podSelector: {}
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress: []
|
||||||
|
egress:
|
||||||
|
- to:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: kube-system
|
||||||
|
ports:
|
||||||
|
- protocol: UDP
|
||||||
|
port: 53
|
||||||
|
- protocol: TCP
|
||||||
|
port: 53
|
||||||
|
---
|
||||||
|
# PVC pihole-config (R-STATE)
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: pihole-config
|
||||||
|
namespace: pihole
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: longhorn
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
|
---
|
||||||
|
# Deployment (R-PLAT-02)
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pihole
|
||||||
|
namespace: pihole
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
homelab.keithjackson.dev/egress-class: internet
|
||||||
|
homelab.keithjackson.dev/auth-mode: forward-auth
|
||||||
|
annotations:
|
||||||
|
homelab.keithjackson.dev/auth-mode: forward-auth
|
||||||
|
homelab.keithjackson.dev/auth-groups: platform-admins
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pihole
|
||||||
|
image: pihole/pihole
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /data/config
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: pihole-config
|
||||||
|
---
|
||||||
|
# Service
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pihole
|
||||||
|
namespace: pihole
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
ports:
|
||||||
|
- name: port-80
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
---
|
||||||
|
# HTTPRoute pihole-80 (R-TLS/R-DNS)
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: pihole-80
|
||||||
|
namespace: pihole
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
annotations:
|
||||||
|
homelab.keithjackson.dev/auth-mode: forward-auth
|
||||||
|
homelab.keithjackson.dev/auth-groups: platform-admins
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: shared
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- pihole.home.keithjackson.dev
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: pihole
|
||||||
|
port: 80
|
||||||
|
---
|
||||||
|
# ServiceMonitor (R-OBS-01)
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
name: pihole
|
||||||
|
namespace: pihole
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
namespaceSelector:
|
||||||
|
matchNames:
|
||||||
|
- pihole
|
||||||
|
endpoints:
|
||||||
|
- port: metrics
|
||||||
|
interval: 30s
|
||||||
|
---
|
||||||
|
# PrometheusRule SLI alerts (R-OBS-01)
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: PrometheusRule
|
||||||
|
metadata:
|
||||||
|
name: pihole-slis
|
||||||
|
namespace: pihole
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
app.kubernetes.io/name: pihole
|
||||||
|
spec:
|
||||||
|
groups:
|
||||||
|
- name: pihole.slis
|
||||||
|
rules:
|
||||||
|
- alert: pihole-down
|
||||||
|
expr: up{job="pihole"} == 0
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
service: pihole
|
||||||
|
annotations:
|
||||||
|
summary: pihole is down
|
||||||
|
description: 'pihole has been unreachable for 5m (SLI: up).'
|
||||||
+20
-8
@@ -580,8 +580,14 @@ def r_virtualmachine(s: dict) -> dict:
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Top-level render + emit
|
# Top-level render + emit
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
def render(sd: dict) -> list:
|
def render(sd: dict, image_automation: bool = True) -> list:
|
||||||
"""Return an ordered list of (header_comment, resource_dict) for a ServiceDefinition."""
|
"""Return an ordered list of (header_comment, resource_dict) for a ServiceDefinition.
|
||||||
|
|
||||||
|
image_automation=False omits the Flux ImageRepository/ImagePolicy CRs — used when
|
||||||
|
onboarding apps before the Flux image-reflector/-automation controllers are installed
|
||||||
|
(their CRDs would otherwise be missing and the apps Kustomization would fail). The L1
|
||||||
|
render goldens use the default (True), so their expected output is unchanged.
|
||||||
|
"""
|
||||||
s = apply_defaults(sd)
|
s = apply_defaults(sd)
|
||||||
if s["kind"] not in ("container", "vm"):
|
if s["kind"] not in ("container", "vm"):
|
||||||
raise ValueError(f"unknown kind: {s['kind']!r}")
|
raise ValueError(f"unknown kind: {s['kind']!r}")
|
||||||
@@ -620,8 +626,9 @@ def render(sd: dict) -> list:
|
|||||||
if pr:
|
if pr:
|
||||||
docs.append(("PrometheusRule SLI alerts (R-OBS-01)", pr))
|
docs.append(("PrometheusRule SLI alerts (R-OBS-01)", pr))
|
||||||
|
|
||||||
for res in r_image_automation(s):
|
if image_automation:
|
||||||
docs.append((f"Flux {res['kind']} (R-UPD)", res))
|
for res in r_image_automation(s):
|
||||||
|
docs.append((f"Flux {res['kind']} (R-UPD)", res))
|
||||||
|
|
||||||
return docs
|
return docs
|
||||||
|
|
||||||
@@ -645,8 +652,8 @@ def load_sd(path: Path) -> dict:
|
|||||||
return yaml.safe_load(fh)
|
return yaml.safe_load(fh)
|
||||||
|
|
||||||
|
|
||||||
def render_file(path: Path) -> str:
|
def render_file(path: Path, image_automation: bool = True) -> str:
|
||||||
return emit(render(load_sd(path)))
|
return emit(render(load_sd(path), image_automation=image_automation))
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -745,16 +752,21 @@ def main(argv=None) -> int:
|
|||||||
ap.add_argument("--all", metavar="DIR", help="Render every *.yaml ServiceDefinition in DIR")
|
ap.add_argument("--all", metavar="DIR", help="Render every *.yaml ServiceDefinition in DIR")
|
||||||
ap.add_argument("-o", "--out-dir", help="With --all: write <name>.yaml files into this dir")
|
ap.add_argument("-o", "--out-dir", help="With --all: write <name>.yaml files into this dir")
|
||||||
ap.add_argument("--selftest", action="store_true", help="Run the built-in self-test")
|
ap.add_argument("--selftest", action="store_true", help="Run the built-in self-test")
|
||||||
|
ap.add_argument("--no-image-automation", action="store_true",
|
||||||
|
help="Omit Flux ImageRepository/ImagePolicy CRs (for onboarding before the "
|
||||||
|
"image-reflector/-automation controllers are installed)")
|
||||||
args = ap.parse_args(argv)
|
args = ap.parse_args(argv)
|
||||||
|
|
||||||
if args.selftest:
|
if args.selftest:
|
||||||
return _selftest()
|
return _selftest()
|
||||||
|
|
||||||
|
image_automation = not args.no_image_automation
|
||||||
|
|
||||||
if args.all:
|
if args.all:
|
||||||
src = Path(args.all)
|
src = Path(args.all)
|
||||||
files = sorted(p for p in src.glob("*.yaml") if p.name != "render.py")
|
files = sorted(p for p in src.glob("*.yaml") if p.name != "render.py")
|
||||||
for f in files:
|
for f in files:
|
||||||
text = render_file(f)
|
text = render_file(f, image_automation=image_automation)
|
||||||
if args.out_dir:
|
if args.out_dir:
|
||||||
outdir = Path(args.out_dir)
|
outdir = Path(args.out_dir)
|
||||||
outdir.mkdir(parents=True, exist_ok=True)
|
outdir.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -766,7 +778,7 @@ def main(argv=None) -> int:
|
|||||||
|
|
||||||
if not args.input:
|
if not args.input:
|
||||||
ap.error("provide a ServiceDefinition file, --all DIR, or --selftest")
|
ap.error("provide a ServiceDefinition file, --all DIR, or --selftest")
|
||||||
sys.stdout.write(render_file(Path(args.input)))
|
sys.stdout.write(render_file(Path(args.input), image_automation=image_automation))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user