=============================================================================
Example: Refactoring homepage to use Kustomize Components
This shows the BEFORE and AFTER of using components to reduce duplication.
BEFORE: homepage had:
- deployment.yaml (with full security context boilerplate)
- service.yaml (standard template)
- ingress.yaml (Traefik IngressRoute)
- middleware.yaml (middleware chain)
- configmap.yaml (app config)
- serviceaccount.yaml (service account)
- clusterrole.yaml (RBAC)
- kustomization.yaml (listing all resources)
AFTER: homepage uses components:
- kustomization.yaml (references components)
- deployment.yaml (ONLY app-specific spec)
- configmap.yaml (app config)
- ingress-patch.yaml (domain override)
- deployment-patch.yaml (resources + security override)
=============================================================================
── BEFORE: homepage/kustomization.yaml ────────────────────────────────────
OLD (lots of boilerplate):
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: homepage resources:
- deployment.yaml
- service.yaml
- ingress.yaml
- configmap.yaml
- clusterrole.yaml
- serviceaccount.yaml
- middleware.yaml
commonLabels: app.kubernetes.io/name: homepage commonAnnotations: description: "Dashboard UI"
── AFTER: homepage/kustomization.yaml ─────────────────────────────────────
NEW (clean, components provide boilerplate):
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: homepage
Use reusable components
components:
- ../../../../vendor/k3s-lab/kubernetes/components/app-base
- ../../../../vendor/k3s-lab/kubernetes/components/traefik-ingress
- ../../../../vendor/k3s-lab/kubernetes/components/network-policies
Only app-specific resources
resources:
- deployment.yaml
- configmap.yaml
Customize component templates for this app
patchesStrategicMerge:
- ingress-patch.yaml
- deployment-patch.yaml
Standard labels (app-base provides managed-by label)
commonLabels: app.kubernetes.io/name: homepage
── homepage/deployment.yaml (BEFORE - FULL BOILERPLATE) ───────────────────
apiVersion: apps/v1 kind: Deployment metadata: name: homepage namespace: apps # OLD: namespace here labels: app.kubernetes.io/name: homepage spec: revisionHistoryLimit: 3 replicas: 1 strategy: type: RollingUpdate selector: matchLabels: app.kubernetes.io/name: homepage template: metadata: labels: app.kubernetes.io/name: homepage spec: serviceAccountName: homepage automountServiceAccountToken: true dnsPolicy: ClusterFirst enableServiceLinks: true containers: - name: homepage image: "ghcr.io/gethomepage/homepage:v1.12.3@sha256:abc123..." imagePullPolicy: IfNotPresent securityContext: # ← BOILERPLATE allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 seccompProfile: type: RuntimeDefault ports: - name: http containerPort: 8080 env: - name: MY_POD_IP valueFrom: fieldRef: fieldPath: status.podIP volumeMounts: # ← BOILERPLATE (tmp/var-run) - name: tmp mountPath: /tmp - name: var-run mountPath: /var/run resources: # ← Often identical requests: cpu: "10m" memory: "32Mi" limits: cpu: "500m" memory: "256Mi" volumes: - name: tmp emptyDir: {} - name: var-run emptyDir: {}
── homepage/deployment.yaml (AFTER - CLEAN) ───────────────────────────────
apiVersion: apps/v1 kind: Deployment metadata: name: homepage
namespace: ← Provided by kustomization.yaml
spec: revisionHistoryLimit: 3 replicas: 1 strategy: type: RollingUpdate selector: matchLabels: app.kubernetes.io/name: homepage template: metadata: labels: app.kubernetes.io/name: homepage spec: # serviceAccountName: ← Patched by kustomization.yaml # automountServiceAccountToken: ← Provided by app-base # dnsPolicy: ← Provided by app-base # enableServiceLinks: ← Provided by app-base # securityContext: ← Provided by app-base component # volumes: ← Patched by deployment-patch.yaml containers: - name: homepage image: "ghcr.io/gethomepage/homepage:v1.12.3@sha256:abc123..." # imagePullPolicy: ← Provided by app-base # securityContext: ← Provided by app-base ports: - name: http containerPort: 8080 env: - name: MY_POD_IP valueFrom: fieldRef: fieldPath: status.podIP # volumeMounts: ← Patched by deployment-patch.yaml # resources: ← Patched by deployment-patch.yaml
── homepage/ingress-patch.yaml (CUSTOMIZE DOMAIN) ────────────────────────
Patch the IngressRoute from traefik-ingress component
apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: app-https spec: routes: - match: "Host(homepage.kevindb.dev)" # ← Override domain kind: Rule services: - name: homepage # ← Match service name port: 80
── homepage/deployment-patch.yaml (OVERRIDE RESOURCES + VOLUMES) ──────────
Patch to override resources and add volumes
apiVersion: apps/v1 kind: Deployment metadata: name: homepage spec: template: spec: serviceAccountName: homepage containers: - name: homepage runAsUser: 1000 runAsGroup: 1000 resources: requests: cpu: "10m" memory: "32Mi" limits: cpu: "500m" memory: "256Mi" volumeMounts: - name: tmp mountPath: /tmp - name: var-run mountPath: /var/run volumes: - name: tmp emptyDir: {} - name: var-run emptyDir: {}