diff --git a/app/integration/kubernetes.ts b/app/integration/kubernetes.ts index ec6902e..84ddb00 100644 --- a/app/integration/kubernetes.ts +++ b/app/integration/kubernetes.ts @@ -3,7 +3,7 @@ import { platform } from 'node:os' import { join, resolve } from 'node:path' import { kill } from 'node:process' -import { AppsV1Api, Config, CoreV1Api, KubeConfig } from '@kubernetes/client-node' +import { Config, CoreV1Api, KubeConfig } from '@kubernetes/client-node' import type { Integration } from '.' @@ -57,24 +57,22 @@ async function preflight() { return false } + const skip = process.env.HEADSCALE_INTEGRATION_UNSTRICT + if (skip === 'true' || skip === '1') { + console.warn('Skipping strict Kubernetes integration check') + return true + } + // Some very ugly nesting but it's necessary - const deployment = process.env.DEPLOYMENT_NAME - if (deployment) { - const result = await checkDeployment(deployment, namespace) - if (!result) { - return false - } - } else { - const pod = process.env.POD_NAME - if (pod) { - const result = await checkPod(pod, namespace) - if (!result) { - return false - } - } else { - console.error('No deployment or pod name found') - return false - } + const pod = process.env.POD_NAME + if (!pod) { + console.error('No pod name found (POD_NAME)') + return false + } + + const result = await checkPod(pod, namespace) + if (!result) { + return false } return true @@ -119,45 +117,6 @@ async function checkPod(pod: string, namespace: string) { return true } -async function checkDeployment(deployment: string, namespace: string) { - if (deployment.trim().length === 0) { - console.error('Deployment name is empty') - return false - } - - try { - const kc = new KubeConfig() - kc.loadFromCluster() - - const kAppsV1Api = kc.makeApiClient(AppsV1Api) - const { response, body } = await kAppsV1Api.readNamespacedDeployment( - deployment, - namespace, - ) - - if (response.statusCode !== 200) { - console.error('Failed to read deployment', response.statusCode) - return false - } - - const shared = body.spec?.template.spec?.shareProcessNamespace - if (shared === undefined) { - console.error('Deployment does not have shareProcessNamespace set') - return false - } - - if (!shared) { - console.error('Deployment has disabled shareProcessNamespace') - return false - } - } catch (error) { - console.error('Failed to check deployment', error) - return false - } - - return true -} - async function findPid() { const dirs = await readdir('/proc') diff --git a/docs/integration/Kubernetes.md b/docs/integration/Kubernetes.md index 1eec3c1..bee6268 100644 --- a/docs/integration/Kubernetes.md +++ b/docs/integration/Kubernetes.md @@ -57,8 +57,11 @@ 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 `DEPLOYMENT_NAME` variable should be set -to the name of the deployment (done using the Downward API below). +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 +set `HEADSCALE_INTEGRATION_UNSTRICT` to `true` to 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` @@ -81,6 +84,7 @@ spec: labels: app: headplane spec: + shareProcessNamespace: true serviceAccountName: default containers: - name: headplane @@ -90,7 +94,7 @@ spec: value: 'abcdefghijklmnopqrstuvwxyz' - name: HEADSCALE_INTEGRATION value: 'kubernetes' - - name: DEPLOYMENT_NAME + - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name @@ -119,5 +123,7 @@ spec: claimName: headscale-config ``` -> For a breakdown of each configuration variable, please refer to the [Configuration](/docs/Configuration.md) guide. -> It explains what each variable does, how to configure them, and what the default values are. +> For a breakdown of each configuration variable, please refer to the +[Configuration](/docs/Configuration.md) guide. +> It explains what each variable does, how to configure them, and what the +default values are.