Skip to content

Kubernetes Tips & Tricks

Removing Stuck Finalizers from namespaces

Sometimes, when deleting a resource in kubernetes, you might encounter issues where the resource gets stuck in a "Terminating" state due to finalizers. Finalizers are used to ensure that certain cleanup tasks are completed before the resource is fully deleted. However, if these tasks fail or take too long, the resource can remain stuck.

In newer versions of kubernetes, the finalizers have been moved to the metadata section of the resource. This allows you to easily remove them if needed. Unfortunately, the Namespace resource is a bit special and requires a different approach to remove the finalizers. Due to the need to provide full backwards compatibility, the Namespace resource still has the finalizers in the spec section. Thus requiring a different approach to remove them.

bash
export namespace="stuck-ns"
kubectl get namespace "$namespace" -o json | jq '.spec.finalizers=[]' | kubectl replace --raw "/api/v1/namespaces/$namespace/finalize" -f -````
powershell
$namespace = "stuck-ns"
$ns = kubectl get namespace $namespace -o json | ConvertFrom-Json
$ns.spec.finalizers = @()
$nsJson = $ns | ConvertTo-Json -Depth 10
$nsJson | kubectl replace --raw "/api/v1/namespaces/$namespace/finalize" -f -

Debug Pod

When debugging kubernetes issues, the first thing I do is to create a debug pod in the same namespace as the application I'm trying to debug. This allows me to have a clean environment with all the necessary tools to troubleshoot the issue.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: netshoot
  namespace: default
spec:
  containers:
  - name: netshoot
    image: nicolaka/netshoot
    command: ["/bin/bash"]
    args: ["-c", "while true; do ping localhost; sleep 60;done"]

Privileged Debug Pod

If you need to perform more advanced node debugging, and you do not have easy access to the underlying host operating system (e.g. in a managed kubernetes environment), you can create a privileged debug pod.

In this example I'll be showcasing a privileged debug DeamonSet that has full access to the host.

WARNING

Running a privileged pod can pose significant security risks. Ensure you understand the implications and restrict access to trusted users only. Remove the privileged pod as soon as you are done debugging.

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: troubleshoot
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: host-debug
  namespace: troubleshoot
labels:
  app: host-debug
spec:
  selector:
    matchLabels:
      app: host-debug
  template:
    metadata:
      labels:
        app: host-debug
    spec:
      # share host namespaces so tools see the node's view
      hostNetwork: true
      hostPID: true
      dnsPolicy: ClusterFirstWithHostNet

      tolerations:
        - operator: "Exists"          # land on tainted nodes too
      containers:
        - name: netshoot
          image: nicolaka/netshoot:latest
          imagePullPolicy: IfNotPresent
          command: ["/bin/bash", "-lc"]
          args:
            - |
              echo "Host debug pod ready. Use: kubectl -n troubleshoot exec -it <pod> -- bash";
              sleep infinity
          securityContext:
            privileged: true
            allowPrivilegeEscalation: true
            capabilities:
              add: ["NET_ADMIN","NET_RAW","SYS_ADMIN","SYS_MODULE","SYS_PTRACE","SYS_CHROOT","MKNOD"]
          volumeMounts:
            # mount host views so /proc/sys and /sys are the node's
            - name: host-proc
              mountPath: /host/proc
              readOnly: true
            - name: host-sys
              mountPath: /host/sys
              readOnly: true
            - name: host-lib-modules
              mountPath: /lib/modules
              readOnly: true
            - name: host-run
              mountPath: /host/run
            - name: host-etc
              mountPath: /host/etc
              readOnly: true
      volumes:
        - name: host-proc
          hostPath:
            path: /proc
        - name: host-sys
          hostPath:
            path: /sys
        - name: host-lib-modules
          hostPath:
            path: /lib/modules
        - name: host-run
          hostPath:
            path: /run
        - name: host-etc
          hostPath:
            path: /etc

Common Aliases

AliasCommandDescription
kgakubectl get pods -o wide -AList all pods in all namespaces (wide view)
kgallkubectl get allGet all resources in the current namespace
kdpkubectl describe podDescribe a pod
kdelpkubectl delete podDelete a pod
klkubectl logsView logs for a pod
klfkubectl logs -fView logs with continuous output
klfakubectl logs -f --all-containersView logs of all containers in a pod
kexeckubectl exec -itExecute a command in a pod (for troubleshooting)
kapkubectl apply -fApply a manifest file
kdelkubectl delete -fDelete resources from a manifest file
kckubectl config current-contextGet current context
kctxkubectl config get-contextsList all contexts
ksctxkubectl config use-contextSwitch context
knodeskubectl get nodes -o wideGet nodes with wide output
kpvckubectl get pvc -AGet persistent volume claims in all namespaces
ksvckubectl get svcGet services in the current namespace
kapdkubectl apply -f .Apply all YAML files in current directory

Advanced Aliases

AliasCommandDescription
knrkubectl get pods --field-selector=status.phase!=RunningGet all pods not in "Running" state
kreskubectl rollout restart deploymentRestart all pods in a deployment
kpfkubectl port-forward svc/Port forward to a specific service
keventskubectl get events -A --sort-by=.metadata.creationTimestampGet events in all namespaces (sorted by time)
knskubectl config view --minify --output "jsonpath={..namespace}"Get current namespace
ktopnkubectl top nodesView resource usage (CPU/memory) of nodes
ktopkubectl top podsView resource usage (CPU/memory) of pods
klckubectl logs -f -cTail logs of a specific container in a pod

Quick Setup

I keep an update list of these aliases in a PDS function so it can be easily configured on any linux instance.

bash
# install pds if not already installed
set_aliases

to add these aliases to your shell, simply copy and paste them into your terminal or add them to your shell configuration file (e.g., ~/.bashrc or ~/.zshrc).

bash
alias kga='kubectl get pods -o wide -A'
alias kgall='kubectl get all'
alias kdp='kubectl describe pod'
alias kdelp='kubectl delete pod'
alias kl='kubectl logs'
alias klf='kubectl logs -f'
alias klfa='kubectl logs -f --all-containers'
alias kexec='kubectl exec -it'
alias kap='kubectl apply -f'
alias kdel='kubectl delete -f'
alias kc='kubectl config current-context'
alias kctx='kubectl config get-contexts'
alias ksctx='kubectl config use-context'
alias knodes='kubectl get nodes -o wide'
alias kpvc='kubectl get pvc -A'
alias ksvc='kubectl get svc'
alias kapd='kubectl apply -f .'
alias knr='kubectl get pods --field-selector=status.phase!=Running'
alias kres='kubectl rollout restart deployment'
alias kpf='kubectl port-forward svc/'
alias kevents='kubectl get events -A --sort-by=.metadata.creationTimestamp'
alias kns='kubectl config view --minify --output "jsonpath={..namespace}"'
alias ktopn='kubectl top nodes'
alias ktop='kubectl top pods'
alias klc='kubectl logs -f -c'