feat: Move cluster services to wild-directory as unified packages

Convert all 15 cluster services from embedded API format to
wild-directory packages using the unified manifest format:
- metallb, traefik, cert-manager, longhorn, snapshot-controller
- nfs, smtp, coredns, node-feature-discovery, nvidia-device-plugin
- externaldns, docker-registry, headlamp, crowdsec, utils

Changes:
- wild-manifest.yaml → manifest.yaml with is, defaultConfig, requires
- Eliminated configReferences and serviceConfig fields
- Flattened kustomize.template/ to package root
- Template vars use flat defaultConfig keys
- install.sh paths updated for apps/ layout
- Updated 9 app manifests: cloud.smtp.* → apps.smtp.* with requires
- Removed dead install: true field from 6 app manifests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-17 02:26:46 +00:00
parent aaf74cc00c
commit 9687fad812
128 changed files with 10941 additions and 50 deletions

68
headlamp/deployment.yaml Normal file
View File

@@ -0,0 +1,68 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: headlamp
namespace: headlamp
spec:
replicas: 1
selector:
matchLabels:
app: headlamp
template:
metadata:
labels:
app: headlamp
spec:
serviceAccountName: headlamp-admin
securityContext:
runAsNonRoot: true
runAsUser: 100
runAsGroup: 101
seccompProfile:
type: RuntimeDefault
containers:
- name: headlamp
image: ghcr.io/headlamp-k8s/headlamp:v0.42.0
args:
- "-in-cluster"
- "-plugins-dir=/headlamp/plugins"
- "-kubeconfig=/home/headlamp/.kube/config"
ports:
- containerPort: 4466
name: http
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
readinessProbe:
httpGet:
path: /
port: 4466
initialDelaySeconds: 10
timeoutSeconds: 5
livenessProbe:
httpGet:
path: /
port: 4466
initialDelaySeconds: 15
timeoutSeconds: 5
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
memory: 256Mi
volumeMounts:
- name: kubeconfig
mountPath: /home/headlamp/.kube
readOnly: true
volumes:
- name: kubeconfig
configMap:
name: headlamp-kubeconfig
items:
- key: kubeconfig
path: config
nodeSelector:
kubernetes.io/os: linux

64
headlamp/ingress.yaml Normal file
View File

@@ -0,0 +1,64 @@
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: internal-only
namespace: headlamp
spec:
ipWhiteList:
sourceRange:
- 127.0.0.1/32
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: headlamp-redirect-scheme
namespace: headlamp
spec:
redirectScheme:
scheme: https
permanent: true
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headlamp-https
namespace: headlamp
spec:
entryPoints:
- websecure
routes:
- match: Host(`headlamp.{{ .internalDomain }}`)
kind: Rule
middlewares:
- name: internal-only
namespace: headlamp
services:
- name: headlamp
port: 80
tls:
secretName: wildcard-internal-wild-cloud-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headlamp-http
namespace: headlamp
spec:
entryPoints:
- web
routes:
- match: Host(`headlamp.{{ .internalDomain }}`)
kind: Rule
middlewares:
- name: headlamp-redirect-scheme
namespace: headlamp
services:
- name: headlamp
port: 80

63
headlamp/install.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/bin/bash
set -e
set -o pipefail
if [ -z "${WILD_INSTANCE}" ]; then
echo "ERROR: WILD_INSTANCE is not set"
exit 1
fi
if [ -z "${WILD_API_DATA_DIR}" ]; then
echo "ERROR: WILD_API_DATA_DIR is not set"
exit 1
fi
if [ -z "${KUBECONFIG}" ]; then
echo "ERROR: KUBECONFIG is not set"
exit 1
fi
INSTANCE_DIR="${WILD_API_DATA_DIR}/instances/${WILD_INSTANCE}"
HEADLAMP_DIR="${INSTANCE_DIR}/apps/headlamp"
echo "=== Setting up Headlamp ==="
echo ""
echo "Using pre-compiled Headlamp templates..."
if [ ! -f "${HEADLAMP_DIR}/kustomization.yaml" ]; then
echo "ERROR: Compiled templates not found at ${HEADLAMP_DIR}"
echo "Templates should be compiled before deployment."
exit 1
fi
echo "Waiting for cert-manager certificates to be ready..."
kubectl wait --for=condition=Ready certificate wildcard-internal-wild-cloud -n cert-manager --timeout=300s || echo "Warning: Internal wildcard certificate not ready yet"
NAMESPACE="headlamp"
echo "Copying cert-manager secrets to headlamp namespace..."
kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
if kubectl get secret wildcard-internal-wild-cloud-tls -n cert-manager >/dev/null 2>&1; then
kubectl get secret wildcard-internal-wild-cloud-tls -n cert-manager -o yaml | \
sed "s/namespace: cert-manager/namespace: ${NAMESPACE}/" | \
kubectl apply -f -
else
echo "Warning: wildcard-internal-wild-cloud-tls secret not yet available"
fi
echo "Deploying Headlamp..."
kubectl apply -k "${HEADLAMP_DIR}/"
echo "Waiting for Headlamp to be ready..."
kubectl rollout status deployment/headlamp -n ${NAMESPACE} --timeout=120s
echo ""
echo "Headlamp installed successfully"
echo ""
if [ -n "${INTERNAL_DOMAIN}" ]; then
echo "Access Headlamp at: https://headlamp.${INTERNAL_DOMAIN}"
else
echo "Access Headlamp via the configured internal domain"
fi
echo ""

View File

@@ -0,0 +1,24 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: headlamp-kubeconfig
namespace: headlamp
data:
kubeconfig: |
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
server: https://kubernetes.default.svc
name: in-cluster
contexts:
- context:
cluster: in-cluster
user: headlamp-admin
name: in-cluster
current-context: in-cluster
users:
- name: headlamp-admin
user:
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token

View File

@@ -0,0 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: headlamp
labels:
- includeSelectors: true
pairs:
app: headlamp
managedBy: kustomize
partOf: wild-cloud
resources:
- namespace.yaml
- service-account.yaml
- kubeconfig-cm.yaml
- deployment.yaml
- service.yaml
- ingress.yaml

11
headlamp/manifest.yaml Normal file
View File

@@ -0,0 +1,11 @@
name: headlamp
is: headlamp
description: Modern Kubernetes web UI (SIG UI) with in-cluster authentication
version: v0.42.0
namespace: headlamp
category: infrastructure
requires:
- name: traefik
- name: cert-manager
defaultConfig:
internalDomain: "{{ .cloud.internalDomain }}"

4
headlamp/namespace.yaml Normal file
View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: headlamp

View File

@@ -0,0 +1,20 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: headlamp-admin
namespace: headlamp
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: headlamp-admin
subjects:
- kind: ServiceAccount
name: headlamp-admin
namespace: headlamp
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io

11
headlamp/service.yaml Normal file
View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: headlamp
namespace: headlamp
spec:
ports:
- port: 80
targetPort: 4466
selector:
app: headlamp