# Headlamp Helm Chart Headlamp is an easy-to-use and extensible Kubernetes web UI that provides: - 🚀 Modern, fast, and responsive interface - 🔒 OIDC authentication support - 🔌 Plugin system for extensibility - 🎯 Real-time cluster state updates ## Prerequisites - Kubernetes 1.21+ - Helm 3.x - Cluster admin access for initial setup ## Quick Start Add the Headlamp repository and install the chart: ```console $ helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/ $ helm repo update $ helm install my-headlamp headlamp/headlamp --namespace kube-system ``` Access Headlamp: ```console $ kubectl port-forward -n kube-system svc/my-headlamp 8080:80 ``` Then open http://localhost:8080 in your browser. ## Installation ### Basic Installation ```console $ helm install my-headlamp headlamp/headlamp --namespace kube-system ``` ### Installation with OIDC ```console $ helm install my-headlamp headlamp/headlamp \ --namespace kube-system \ --set config.oidc.clientID=your-client-id \ --set config.oidc.clientSecret=your-client-secret \ --set config.oidc.issuerURL=https://your-issuer-url ``` ### Installation with Ingress ```console $ helm install my-headlamp headlamp/headlamp \ --namespace kube-system \ --set ingress.enabled=true \ --set ingress.hosts[0].host=headlamp.example.com \ --set ingress.hosts[0].paths[0].path=/ ``` ## Configuration ### Core Parameters | Key | Type | Default | Description | |-----|------|---------|-------------| | replicaCount | int | `1` | Number of desired pods | | image.registry | string | `"ghcr.io"` | Container image registry | | image.repository | string | `"headlamp-k8s/headlamp"` | Container image name | | image.tag | string | `""` | Container image tag (defaults to Chart appVersion) | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | ### Application Configuration | Key | Type | Default | Description | |--------------------|--------|-----------------------|---------------------------------------------------------------------------| | config.inCluster | bool | `true` | Run Headlamp in-cluster | | config.baseURL | string | `""` | Base URL path for Headlamp UI | | config.sessionTTL | int | `86400` | The time in seconds for the internal session to remain valid (Default: 86400/24h, Min: 1 , Max: 31536000/1yr) | | config.pluginsDir | string | `"/headlamp/plugins"` | Directory to load Headlamp plugins from | | config.enableHelm | bool | `false` | Enable Helm operations like install, upgrade and uninstall of Helm charts | | config.extraArgs | array | `[]` | Additional arguments for Headlamp server | | config.tlsCertPath | string | `""` | Certificate for serving TLS | | config.tlsKeyPath | string | `""` | Key for serving TLS | ### OIDC Configuration | Key | Type | Default | Description | |-----|------|---------|-------------| | config.oidc.clientID | string | `""` | OIDC client ID | | config.oidc.clientSecret | string | `""` | OIDC client secret | | config.oidc.issuerURL | string | `""` | OIDC issuer URL | | config.oidc.scopes | string | `""` | OIDC scopes to be used | | config.oidc.usePKCE | bool | `false` | Use PKCE (Proof Key for Code Exchange) for enhanced security in OIDC flow | | config.oidc.secret.create | bool | `true` | Create OIDC secret using provided values | | config.oidc.secret.name | string | `"oidc"` | Name of the OIDC secret | | config.oidc.externalSecret.enabled | bool | `false` | Enable using external secret for OIDC | | config.oidc.externalSecret.name | string | `""` | Name of external OIDC secret | | config.oidc.meUserInfoURL | string | `""` | URL to fetch additional user info for the /me endpoint. Useful for providers like oauth2-proxy. | There are three ways to configure OIDC: 1. Using direct configuration: ```yaml config: oidc: clientID: "your-client-id" clientSecret: "your-client-secret" issuerURL: "https://your-issuer" scopes: "openid profile email" meUserInfoURL: "https://headlamp.example.com/oauth2/userinfo" ``` 2. Using automatic secret creation: ```yaml config: oidc: secret: create: true name: oidc ``` 3. Using external secret: ```yaml config: oidc: secret: create: false externalSecret: enabled: true name: your-oidc-secret ``` ### Deployment Configuration | Key | Type | Default | Description | |-----|------|---------|-------------| | replicaCount | int | `1` | Number of desired pods | | image.registry | string | `"ghcr.io"` | Container image registry | | image.repository | string | `"headlamp-k8s/headlamp"` | Container image name | | image.tag | string | `""` | Container image tag (defaults to Chart appVersion) | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | | imagePullSecrets | list | `[]` | Image pull secrets references | | nameOverride | string | `""` | Override the name of the chart | | fullnameOverride | string | `""` | Override the full name of the chart | | namespaceOverride | string | `""` | Override the deployment namespace; defaults to .Release.Namespace | | initContainers | list | `[]` | Init containers to run before main container | ### Security Configuration | Key | Type | Default | Description | |-----|------|---------|-------------| | automountServiceAccountToken | bool | `true` | Mount Service Account token in pod | | serviceAccount.create | bool | `true` | Create service account | | serviceAccount.name | string | `""` | Service account name | | serviceAccount.annotations | object | `{}` | Service account annotations | | clusterRoleBinding.create | bool | `true` | Create cluster role binding | | clusterRoleBinding.clusterRoleName | string | `"cluster-admin"` | Kubernetes ClusterRole name | | clusterRoleBinding.annotations | object | `{}` | Cluster role binding annotations | | hostUsers | bool | `true` | Run in host uid namespace | | podSecurityContext | object | `{}` | Pod security context (e.g., fsGroup: 2000) | | securityContext.runAsNonRoot | bool | `true` | Run container as non-root | | securityContext.privileged | bool | `false` | Run container in privileged mode | | securityContext.runAsUser | int | `100` | User ID to run container | | securityContext.runAsGroup | int | `101` | Group ID to run container | | securityContext.capabilities | object | `{}` | Container capabilities (e.g., drop: [ALL]) | | securityContext.readOnlyRootFilesystem | bool | `false` | Mount root filesystem as read-only | NOTE: for `hostUsers=false` user namespaces must be supported. See: https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/ ### Storage Configuration | Key | Type | Default | Description | |-----|------|---------|-------------| | persistentVolumeClaim.enabled | bool | `false` | Enable PVC | | persistentVolumeClaim.annotations | object | `{}` | PVC annotations | | persistentVolumeClaim.size | string | `""` | PVC size (required if enabled) | | persistentVolumeClaim.storageClassName | string | `""` | Storage class name | | persistentVolumeClaim.accessModes | list | `[]` | PVC access modes | | persistentVolumeClaim.selector | object | `{}` | PVC selector | | persistentVolumeClaim.volumeMode | string | `""` | PVC volume mode | | volumeMounts | list | `[]` | Container volume mounts | | volumes | list | `[]` | Pod volumes | ### Network Configuration | Key | Type | Default | Description | |-----|------|---------|-------------| | service.type | string | `"ClusterIP"` | Kubernetes service type | | service.port | int | `80` | Kubernetes service port | | ingress.enabled | bool | `false` | Enable ingress | | ingress.ingressClassName | string | `""` | Ingress class name | | ingress.annotations | object | `{}` | Ingress annotations (e.g., kubernetes.io/tls-acme: "true") | | ingress.labels | object | `{}` | Additional labels for the Ingress resource | | ingress.hosts | list | `[]` | Ingress hosts configuration | | ingress.tls | list | `[]` | Ingress TLS configuration | Example ingress configuration: ```yaml ingress: enabled: true annotations: kubernetes.io/tls-acme: "true" labels: app.kubernetes.io/part-of: traefik environment: prod hosts: - host: headlamp.example.com paths: - path: / type: ImplementationSpecific tls: - secretName: headlamp-tls hosts: - headlamp.example.com ``` ### HTTPRoute Configuration (Gateway API) For users who prefer Gateway API over classic Ingress resources, Headlamp supports HTTPRoute configuration. | Key | Type | Default | Description | |-----|------|---------|-------------| | httpRoute.enabled | bool | `false` | Enable HTTPRoute resource for Gateway API | | httpRoute.annotations | object | `{}` | Annotations for HTTPRoute resource | | httpRoute.labels | object | `{}` | Additional labels for HTTPRoute resource | | httpRoute.parentRefs | list | `[]` | Parent gateway references (REQUIRED when enabled) | | httpRoute.hostnames | list | `[]` | Hostnames for the HTTPRoute | | httpRoute.rules | list | `[]` | Custom routing rules (optional, defaults to path prefix /) | Example HTTPRoute configuration: ```yaml httpRoute: enabled: true annotations: gateway.example.com/custom-annotation: "value" labels: app.kubernetes.io/component: ingress parentRefs: - name: my-gateway namespace: gateway-namespace hostnames: - headlamp.example.com # Optional custom rules (defaults to path prefix / if not specified) rules: - matches: - path: type: PathPrefix value: /headlamp backendRefs: - name: my-headlamp port: 80 ``` ### Resource Management | Key | Type | Default | Description | |-----|------|---------|-------------| | resources | object | `{}` | Container resource requests/limits | | nodeSelector | object | `{}` | Node labels for pod assignment | | tolerations | list | `[]` | Pod tolerations | | affinity | object | `{}` | Pod affinity settings | | topologySpreadConstraints | list | `[]` | Topology spread constraints for pod assignment | | podAnnotations | object | `{}` | Pod annotations | | podLabels | object | `{}` | Pod labels | | env | list | `[]` | Additional environment variables | Example resource configuration: ```yaml resources: limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi ``` Example environment variables: ```yaml env: - name: KUBERNETES_SERVICE_HOST value: "localhost" - name: KUBERNETES_SERVICE_PORT value: "6443" ``` Example topology spread constraints: ```yaml # Spread pods across availability zones with best-effort scheduling topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway # Prefer spreading but allow scheduling even if it violates the constraint matchLabelKeys: - pod-template-hash - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule # Hard requirement - don't schedule if it violates the constraint matchLabelKeys: - pod-template-hash ``` The `labelSelector` is automatically populated with the pod's selector labels if not specified. You can also provide a custom `labelSelector`: ```yaml topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app.kubernetes.io/name: headlamp custom-label: value ``` ### Pod Disruption Budget (PDB) | Key | Type | Default | Description | |-----|------|---------|-------------| | podDisruptionBudget.enabled | bool | `false` | Create a PodDisruptionBudget resource | | podDisruptionBudget.minAvailable | integer \| string \| null | `0` | Minimum pods that must be available. Rendered only when set to a positive integer or a percentage string (e.g. `"1"` or `"50%"`). Schema default is 0, but the chart skips rendering `0`. | | podDisruptionBudget.maxUnavailable | integer \| string \| null | `null` | Maximum pods allowed to be unavailable. Accepts integer >= 0 or percentage string. Mutually exclusive with `minAvailable`; the template renders this field when set. | | podDisruptionBudget.unhealthyPodEvictionPolicy | string \| null | `null` | Eviction policy: `"IfHealthyBudget"` or `"AlwaysAllow"`. Emitted only on clusters running Kubernetes >= 1.27 and when explicitly set in values. | Note: Ensure `minAvailable` and `maxUnavailable` are not both set (use `null` to disable one). To include `minAvailable` in the rendered PDB, set a positive integer or percentage; the template omits a `0` value. Example, Require at least 1 pod available (ensure maxUnavailable is disabled): ```yaml podDisruptionBudget: enabled: true minAvailable: 1 maxUnavailable: null ``` Example, Allow up to 50% of pods to be unavailable: ```yaml podDisruptionBudget: enabled: true maxUnavailable: "50%" minAvailable: null ``` Example, Set unhealthyPodEvictionPolicy (requires Kubernetes >= 1.27): ```yaml podDisruptionBudget: enabled: true maxUnavailable: 1 minAvailable: null unhealthyPodEvictionPolicy: "IfHealthyBudget" ``` Ensure your replicaCount and maintenance procedures respect the configured PDB to avoid blocking intended operations. ### pluginsManager Configuration | Key | Type | Default | Description | | ------------- | ------- | ----------------- | ----------------------------------------------------------------------------------------- | | enabled | boolean | `false` | Enable plugin manager | | configFile | string | `plugin.yml` | Plugin configuration file name | | configContent | string | `""` | Plugin configuration content in YAML format. This is required if plugins.enabled is true. | | baseImage | string | `node:lts-alpine` | Base node image to use | | version | string | `latest` | Headlamp plugin package version to install | | env | list | `[]` | Plugin manager env variable configuration | | resources | object | `{}` | Plugin manager resource requests/limits | | volumeMounts | list | `[]` | Plugin manager volume mounts | Example resource configuration: ```yaml pluginsManager: enabled: true baseImage: node:lts-alpine version: latest env: - name: HTTPS_PROXY value: "proxy.example.com:8080" resources: requests: cpu: "500m" memory: "2048Mi" limits: cpu: "1" memory: "4Gi" ``` ## Contributing We welcome contributions to the Headlamp Helm chart! To contribute: 1. Fork the repository and create your branch from `main`. 2. Make your changes and test them thoroughly. 3. Run Helm chart template tests to ensure your changes don't break existing functionality: ```console $ make helm-template-test ``` This command executes the script at `charts/headlamp/tests/test.sh` to validate Helm chart templates against expected templates. 4. If you've made changes that intentionally affect the rendered templates (like version updates or new features): ```console $ make helm-update-template-version ``` This updates the expected templates with the current versions from Chart.yaml and only shows files where versions changed. 5. Review the updated templates carefully to ensure they contain only your intended changes. 6. Submit a pull request with a clear description of your changes. For more details, refer to our [contributing guidelines](https://github.com/kubernetes-sigs/headlamp/blob/main/CONTRIBUTING.md). ## Links - [GitHub Repository](https://github.com/kubernetes-sigs/headlamp) - [Documentation](https://headlamp.dev/) - [Maintainers](https://github.com/kubernetes-sigs/headlamp/blob/main/OWNERS_ALIASES)