From 07dd480b5673eabbf20b58538a857d3694ccbba4 Mon Sep 17 00:00:00 2001 From: pyadagiri Date: Tue, 28 Jul 2026 20:12:47 +0530 Subject: [PATCH 1/2] Remove Deployment Exists toleration and add ephemeral slurp helper. Long-lived doks-debug Deployments with operator: Exists can reschedule onto draining nodes and block upgrades; keep Exists only on the DaemonSet and document short-lived node access via script/slurp. --- README.md | 27 ++++++++++ k8s/deployment.yaml | 2 - script/slurp | 124 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 2 deletions(-) create mode 100755 script/slurp diff --git a/README.md b/README.md index cd732ff..8e71ef7 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ The DOKS team provides this image for use as-is and for transparency as the imag # Usage +Prefer the **DaemonSet** when you need debug pods on many nodes, or the ephemeral **`slurp`** helper when you need access to a single node. Avoid leaving a long-lived `doks-debug` Deployment in the cluster. + +## DaemonSet + ```bash kubectl apply -f k8s/daemonset.yaml ``` @@ -18,6 +22,7 @@ This DaemonSet manifest will: 2. Use `hostPID`, `hostIPC`, and `hostNetwork`. 3. Mount the entire host filesystem to `/host` in the containers. 4. Mount the `containerd` socket at `/run/containerd/containerd.sock` from the host into the container. + 5. Tolerate all taints (`operator: Exists`) so pods can land on cordoned or specially tainted nodes. In order to make use of these workloads, you can exec into a pod of choice by name: @@ -33,6 +38,28 @@ POD_NAME=$(kubectl -n kube-system get pods --field-selector spec.nodeName=${NODE kubectl -n kube-system exec -it ${POD_NAME} bash ``` +Clean up when finished: + +```bash +kubectl delete -f k8s/daemonset.yaml +``` + +## Ephemeral single-node access (`slurp`) + +For short-lived access to one node, use `script/slurp`. It creates a `doks-debug` Deployment pinned with a `nodeSelector`, execs into the host via `chroot /host`, and deletes the Deployment when you exit. + +```bash +./script/slurp +``` + +The Deployment manifest does **not** include a default catch-all toleration. A long-lived Deployment with `tolerations: [{operator: Exists}]` can reschedule onto draining nodes and block scale-down or upgrades. If you need to reach a tainted or cordoned node for a brief session, pass `--tolerate-all`: + +```bash +./script/slurp --tolerate-all +``` + +Requires `kubectl`, `curl` (if the local manifest is unavailable), and [`yq`](https://github.com/mikefarah/yq). + Once you're in, you have access to the set of tools listed in the `Dockerfile`. This includes: - [`vim`](https://github.com/vim/vim) - is a greatly improved version of the good old UNIX editor Vi. diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 18d0aca..d6315f1 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -22,8 +22,6 @@ spec: hostPID: true hostIPC: true hostNetwork: true - tolerations: - - operator: Exists containers: - name: doks-debug securityContext: diff --git a/script/slurp b/script/slurp new file mode 100755 index 0000000..46f0fb4 --- /dev/null +++ b/script/slurp @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +# Ephemeral node access via a doks-debug Deployment. +# Pins to one node, execs in, and deletes the Deployment on exit. +# +# Usage: slurp [--tolerate-all] +# +# --tolerate-all Inject tolerations: operator: Exists so the pod can land on +# tainted/cordoned nodes. Use only for short-lived sessions; +# long-lived Deployments with this toleration can block drains +# and upgrades. + +set -euo pipefail + +tolerate_all=false +node_name="" + +usage() { + echo "Usage: $(basename "$0") [--tolerate-all] " + echo " connect and chroot into the node using an ephemeral doks-debug Deployment" +} + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + --tolerate-all) + tolerate_all=true + shift + ;; + -*) + echo "Error: unknown option: $1" >&2 + usage >&2 + exit 1 + ;; + *) + if [[ -n "$node_name" ]]; then + echo "Error: unexpected argument: $1" >&2 + usage >&2 + exit 1 + fi + node_name="$1" + shift + ;; + esac +done + +if [[ -z "$node_name" ]]; then + usage >&2 + exit 1 +fi + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +local_manifest="${script_dir}/../k8s/deployment.yaml" +remote_manifest_url="https://raw.githubusercontent.com/digitalocean/doks-debug/refs/heads/master/k8s/deployment.yaml" + +deployment_name="doks-debug" +deployment_namespace="kube-system" + +cleanup() { + kubectl delete deployment "${deployment_name}" \ + --namespace "${deployment_namespace}" \ + --ignore-not-found=true +} +trap cleanup EXIT + +if [[ -f "$local_manifest" ]]; then + doks_debug_deployment_yaml="$(cat "$local_manifest")" +else + doks_debug_deployment_yaml="$(curl --silent --fail --location "$remote_manifest_url")" +fi + +if [[ -z "$doks_debug_deployment_yaml" ]]; then + echo "Error: failed to load the deployment manifest." >&2 + exit 1 +fi + +if ! command -v yq >/dev/null 2>&1; then + echo "Error: yq is required (https://github.com/mikefarah/yq)." >&2 + exit 1 +fi + +modified_yaml="$( + echo "$doks_debug_deployment_yaml" | \ + nodeName="$node_name" yq '.spec.template.spec.nodeSelector["kubernetes.io/hostname"] = env(nodeName)' +)" + +if [[ "$tolerate_all" == true ]]; then + modified_yaml="$( + echo "$modified_yaml" | \ + yq '.spec.template.spec.tolerations = [{"operator": "Exists"}]' + )" +fi + +echo "$modified_yaml" | kubectl apply -f - + +kubectl wait deployment "${deployment_name}" \ + --namespace "${deployment_namespace}" \ + --for=condition=Available \ + --timeout=120s \ + >/dev/null + +pod_name="$( + kubectl get pods \ + --namespace "${deployment_namespace}" \ + -l name=doks-debug \ + -o jsonpath='{.items[0].metadata.name}' +)" + +if [[ -z "$pod_name" ]]; then + echo "Error: could not find a running pod for the deployment." >&2 + exit 1 +fi + +kubectl wait pod "${pod_name}" \ + --namespace "${deployment_namespace}" \ + --for=condition=Ready \ + --timeout=60s \ + >/dev/null + +kubectl exec -it "${pod_name}" \ + --namespace "${deployment_namespace}" \ + -- chroot /host bash From 31ba4fd4296175e11a07b992cb209d3c643b751f Mon Sep 17 00:00:00 2001 From: pyadagiri Date: Tue, 28 Jul 2026 20:19:43 +0530 Subject: [PATCH 2/2] Rename ephemeral helper from slurp to debug-node. --- README.md | 10 +++++----- script/{slurp => debug-node} | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename script/{slurp => debug-node} (98%) diff --git a/README.md b/README.md index 8e71ef7..98e52f3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The DOKS team provides this image for use as-is and for transparency as the imag # Usage -Prefer the **DaemonSet** when you need debug pods on many nodes, or the ephemeral **`slurp`** helper when you need access to a single node. Avoid leaving a long-lived `doks-debug` Deployment in the cluster. +Prefer the **DaemonSet** when you need debug pods on many nodes, or the ephemeral **`debug-node`** helper when you need access to a single node. Avoid leaving a long-lived `doks-debug` Deployment in the cluster. ## DaemonSet @@ -44,18 +44,18 @@ Clean up when finished: kubectl delete -f k8s/daemonset.yaml ``` -## Ephemeral single-node access (`slurp`) +## Ephemeral single-node access (`debug-node`) -For short-lived access to one node, use `script/slurp`. It creates a `doks-debug` Deployment pinned with a `nodeSelector`, execs into the host via `chroot /host`, and deletes the Deployment when you exit. +For short-lived access to one node, use `script/debug-node`. It creates a `doks-debug` Deployment pinned with a `nodeSelector`, execs into the host via `chroot /host`, and deletes the Deployment when you exit. ```bash -./script/slurp +./script/debug-node ``` The Deployment manifest does **not** include a default catch-all toleration. A long-lived Deployment with `tolerations: [{operator: Exists}]` can reschedule onto draining nodes and block scale-down or upgrades. If you need to reach a tainted or cordoned node for a brief session, pass `--tolerate-all`: ```bash -./script/slurp --tolerate-all +./script/debug-node --tolerate-all ``` Requires `kubectl`, `curl` (if the local manifest is unavailable), and [`yq`](https://github.com/mikefarah/yq). diff --git a/script/slurp b/script/debug-node similarity index 98% rename from script/slurp rename to script/debug-node index 46f0fb4..8db2ba4 100755 --- a/script/slurp +++ b/script/debug-node @@ -2,7 +2,7 @@ # Ephemeral node access via a doks-debug Deployment. # Pins to one node, execs in, and deletes the Deployment on exit. # -# Usage: slurp [--tolerate-all] +# Usage: debug-node [--tolerate-all] # # --tolerate-all Inject tolerations: operator: Exists so the pod can land on # tainted/cordoned nodes. Use only for short-lived sessions;