4.3 KiB
Kubernetes Integration
The Kubernetes integration allows you to run Headplane and Headscale together in a cluster. It allows you to unlock full functionality such as automatic reloading of ACLs, DNS management, and Headscale configuration management.
Currently there are a few limitations to the Kubernetes integration:
-
Headplane and Headscale need to run in the same Pod and share the same process space for the integration to work correctly due to a limitation in the Kubernetes API.
-
The only supported methods of deploying the integration are through a
DeploymentorPod(more coming soon). You can still get around this with theHEADSCALE_INTEGRATION_UNSTRICTvariable, but it's not recommended. -
The integration will assume that the Headscale container will always restart because the integration relies on a system call that will exit the container.
Deployment
In order to ensure Headplane can read Kubernetes resources, you'll need to
grant additional RBAC permissions to the default ServiceAccount in the
namespace. This can be done with the following:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: headplane-agent
namespace: default # Adjust namespace as needed
rules:
- apiGroups: ['']
resources: ['pods']
verbs: ['get', 'list']
- apiGroups: ['apps']
resources: ['deployments']
verbs: ['get', 'list']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: headplane-agent
namespace: default # Adjust namespace as needed
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: headplane-agent
subjects:
- kind: ServiceAccount
name: default # If you use a different service account, change this
namespace: default # Adjust namespace as needed
Keep in mind you'll need to make PersistentVolumeClaims for the data and that
they need to be either ReadWriteOnce or ReadWriteMany depending on your
topology. Additionally, you can abstract environment variables and configuration
away into a ConfigMap or Secret for easier management.
The important parts of this deployment are the HEADSCALE_INTEGRATION and
DEPLOYMENT_NAME environment variables. The HEADSCALE_INTEGRATION variable
should be set to kubernetes and the POST_NAME variable should be set
to the name of the pod (done using the Downward API below).
If you are having issues with validating
shareProcessNamespace, you can setHEADSCALE_INTEGRATION_UNSTRICTtotrueto disable the strict checks.
A basic deployment of the integration would look like this. Keep in mind that
you are responsible for setting up a reverse-proxy via an Ingress or Service
otherwise Headplane will not work:
apiVersion: apps/v1
kind: Deployment
metadata:
name: headplane
namespace: default # Adjust namespace as needed
labels:
app: headplane
spec:
replicas: 1
selector:
matchLabels:
app: headplane
template:
metadata:
labels:
app: headplane
spec:
shareProcessNamespace: true
serviceAccountName: default
containers:
- name: headplane
image: ghcr.io/tale/headplane:0.3.2
env:
- name: COOKIE_SECRET
value: 'abcdefghijklmnopqrstuvwxyz'
- name: HEADSCALE_INTEGRATION
value: 'kubernetes'
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# Only set this to false if you aren't behind a reverse proxy
- name: COOKIE_SECURE
value: 'false'
volumeMounts:
- name: headscale-config
mountPath: /etc/headscale
- name: headscale
image: headscale/headscale:0.23.0
command: ['serve']
env:
- name: TZ
value: 'America/New_York'
volumeMounts:
- name: headscale-data
mountPath: /var/lib/headscale
- name: headscale-config
mountPath: /etc/headscale
volumes:
- name: headscale-data
persistentVolumeClaim:
claimName: headscale-data
- name: headscale-config
persistentVolumeClaim:
claimName: headscale-config
For a breakdown of each configuration variable, please refer to the Configuration guide. It explains what each variable does, how to configure them, and what the default values are.