Javad Zahrabi

kubectl

Kubernetes' command-line client — daily-driver workflows for clusters on AKS and on-prem.

Official docs

Get & list resources

  • kubectl get pods

    List pods in the current namespace.

  • kubectl get pods -n kube-system

    List pods in a specific namespace. Long form: --namespace=.

  • kubectl get pods -A

    Across every namespace. Long form: --all-namespaces.

  • kubectl get nodes

    List cluster nodes.

  • kubectl get deployment

    List Deployments. Aliases: deploy.

  • kubectl get replicaset

    List ReplicaSets. Alias: rs.

  • kubectl get all

    List the most common workload resources (pods, services, deployments, replicasets) in the namespace.

  • kubectl get all -A

    Same, across every namespace.

  • kubectl get pods -w

    Stream pod state changes. Long form: --watch.

  • kubectl get events -o wide

    Recent cluster events with extra columns. Useful when something failed and you don't yet know which object.

  • kubectl get pod webapp -o yaml > my-new-pod.yaml

    Dump a live pod's full spec to YAML — handy as a starting template for a new manifest.

  • kubectl get pods -o custom-columns="NAME:.metadata.name,PRIORITY:.spec.priorityClassName"

    Pick exactly the fields you want, by JSONPath. Great for one-off audits.

  • kubectl get persistentvolumeclaim

    List PVCs. Alias: pvc.

  • kubectl get priorityclass

    List priority classes (used by the scheduler for preemption).

Namespaces & contexts

  • kubectl create namespace dev

    Create a namespace.

  • kubectl config set-context $(kubectl config current-context) --namespace=dev

    Pin every kubectl call in this context to a default namespace — saves typing -n on every command.

  • kubectl config view

    Show the merged effective kubeconfig (clusters + users + contexts).

  • kubectl config get-clusters

    List the clusters known to your kubeconfig.

  • kubectl config use-context <ctx>

    Switch to another context.

  • kubectl config current-context

    Print the currently active context.

Imperative create (run, create deployment, expose)

  • kubectl run nginx --image=nginx

    Create a single bare pod (no Deployment / ReplicaSet wrapping).

  • kubectl run nginx --image=nginx --dry-run=client -o yaml

    Generate a Pod manifest without submitting it. The fastest way to start a YAML file you'll then edit.

  • kubectl run nginx --image=nginx --dry-run=client -o yaml > nginx-pod.yml

    Same, captured to a file.

  • kubectl create deployment nginx --image=nginx

    Create a Deployment.

  • kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > nginx-deployment.yaml

    Generate a Deployment manifest.

  • kubectl create deployment nginx --image=nginx --replicas=4 --dry-run=client -o yaml > nginx-deployment.yaml

    Same with a custom replica count. --replicas was added in k8s 1.19.

  • kubectl create -f pod-definition.yml

    Create from a manifest. Imperative — fails if the object already exists.

  • kubectl create -f pod-definition.yml --namespace=dev

    Create the manifest into a target namespace.

  • kubectl run httpd --image=httpd:alpine --port=80 --expose

    Create a pod AND a ClusterIP Service of the same name in one command.

  • kubectl run redis --image=redis:alpine --labels="tier=db"

    Create a labelled pod.

  • kubectl run webapp-green --image=nginx -- --color green

    Pass arguments to the container's default command. Everything after the bare -- is forwarded as args.

  • kubectl run webapp-green --image=nginx --command -- python app.py --color green

    Override the container's command + args (rather than just appending args). --command flips the meaning of -- to be the full command line.

Declarative apply

  • kubectl apply -f nginx.yml

    Create or update from a manifest. Idempotent — re-running with no changes is a no-op.

  • kubectl apply -f /path/to/config-files

    Apply every manifest in a directory (recursively with -R).

Inspect (describe, explain, api-resources)

  • kubectl describe pod <pod>

    Status, events, env, mounts, pull errors — first stop when a pod misbehaves.

  • kubectl describe node <node>

    Conditions, capacity, taints, allocated resources.

  • kubectl describe node <node> | grep Taint

    Show only the taints applied to a node.

  • kubectl describe daemonsets <name>

    DaemonSet rollout status, selector, current/desired/ready counts.

  • kubectl describe configmaps

    ConfigMaps in the namespace, with key/value contents.

  • kubectl describe secrets

    Secret metadata. Values are NOT printed (shown as <base64-encoded>).

  • kubectl describe role <name>

    RBAC role: rules + verbs + resources.

  • kubectl describe rolebinding <name>

    Subjects bound to a Role.

  • kubectl describe clusterrolebinding cluster-admin

    Who has cluster-admin?

  • kubectl describe serviceaccount default

    ServiceAccount detail: linked secrets, mountable, image-pull secrets.

  • kubectl api-resources

    List every resource kind the cluster knows about, with their short names and group/version.

  • kubectl api-resources --namespaced=true

    Only namespace-scoped resources (pods, jobs, services, configmaps, ...).

  • kubectl api-resources --namespaced=false

    Only cluster-scoped resources (nodes, persistentvolumes, clusterroles, namespaces, ...).

  • kubectl explain pods

    Show the schema for a resource — what fields it accepts.

  • kubectl explain pods.spec

    Drill into a sub-field.

  • kubectl explain pods --recursive

    Recursively list every field a manifest can carry. Great for autocomplete-without-autocomplete.

  • kubectl explain services.spec.ports --recursive

    Common need — full schema for Service ports.

Modify (edit, scale, set image, replace)

  • kubectl edit replicaset new-replica-set

    Open the live object in $EDITOR; on save, kubectl re-applies it.

  • kubectl scale --replicas=6 -f replica.yml

    Scale by manifest.

  • kubectl scale deployment nginx --replicas=5

    Scale a Deployment.

  • kubectl scale rs new-replica-set --replicas=5

    Scale a ReplicaSet directly.

  • kubectl set image deployment nginx nginx=nginx:1.18

    Update one container's image — triggers a rolling update.

  • kubectl replace -f replicaset.yaml

    Replace an existing object. Errors if it doesn't already exist.

  • kubectl replace --force -f replicaset.yaml

    Delete + recreate. Necessary when you change immutable fields (e.g. selectors).

  • kubectl expose deployment nginx --port 80

    Create a ClusterIP Service for an existing Deployment.

  • kubectl expose pod redis --port=6379 --name redis-service --dry-run=client -o yaml

    Generate a Service manifest from a pod (uses the pod's labels as the selector).

  • kubectl create service clusterip redis --tcp=6379:6379 --dry-run=client -o yaml

    Service manifest with a hard-coded selector (app=<name>) — does NOT use the pod's labels.

  • kubectl expose pod nginx --type=NodePort --port=80 --name=nginx-service --dry-run=client -o yaml

    NodePort variant. Auto-uses the pod's labels but you can't specify the node port here.

    Trade-off vs `create service nodeport`: the latter lets you pin the node port but doesn't read pod labels. My usual workflow: run this command, then hand-edit nodePort into the resulting YAML before applying.

  • kubectl create service nodeport nginx --tcp=80:80 --node-port=30080 --dry-run=client -o yaml

    NodePort with a fixed node port — but ignores pod labels (uses app=<name>).

Labels, selectors & taints

  • kubectl get pods -l app=App1

    Filter by label selector. Long form: --selector.

  • kubectl get all -l env=prod

    Selector across all common resource kinds.

  • kubectl get pods -l env=prod,bu=finance,tier=frontend

    Multiple labels — comma is AND.

  • kubectl get all -l env=prod --no-headers | wc -l

    Count matches (no header line skewing the result).

  • kubectl label node <node> <key>=<value>

    Add or update a label on a node.

  • kubectl get nodes --show-labels

    Show all labels per node.

  • kubectl taint nodes <node> key=value:NoSchedule

    Repel pods from a node unless they tolerate the taint. Effects: NoSchedule | PreferNoSchedule | NoExecute.

  • kubectl taint nodes node01 app=myapp:NoSchedule

    Concrete example.

  • kubectl taint nodes controlplane node-role.kubernetes.io/control-plane:NoSchedule-

    Untaint — the trailing - removes the taint (e.g. to allow workloads on a single-node cluster).

  • kubectl get po --show-labels | grep name=payroll

    Find pods by label substring (quick grep when you forgot the exact selector).

DaemonSets & static pods

  • kubectl get daemonsets

    List DaemonSets. Alias: ds.

  • kubectl get daemonsets -A

    Across all namespaces.

  • kubectl describe daemonsets <name>

    DaemonSet detail.

  • ps -aux | grep /usr/bin/kubelet

    Find the kubelet process — needed to discover its --config flag and the path to its config file.

  • grep -i staticPodPath /var/lib/kubelet/config.yaml

    Find the directory the kubelet watches for static-pod manifests (anything dropped here becomes a pod, no api-server involvement).

  • kubectl run static-busybox --restart=Never --image=busybox --dry-run=client -o yaml --command -- sleep 1000 > /etc/kubernetes/manifests/static-busybox.yaml

    Create a static pod by dropping a manifest into the kubelet's watch directory.

Logs, events & debugging (incl. crictl)

  • kubectl logs -f <pod>

    Stream logs.

  • kubectl logs -f <pod> <container>

    In a multi-container pod, kubectl errors without a container name — pass it.

  • kubectl logs <pod> -c init-myservice

    Logs from an init container — needs -c (the init isn't picked by name alone).

  • kubectl logs my-custom-scheduler -n kube-system

    Logs from a control-plane component.

  • kubectl events <kind> <name>

    Events targeted at one object — much less noisy than `get events`.

  • kubectl events hpa nginx-deployment | grep -i "ScalingReplicaSet"

    Filter event log to scaling decisions.

  • crictl pods

    List pods at the container-runtime level. Use when the api-server itself is broken and `kubectl get pods` won't answer.

  • crictl ps -a

    All containers (running + exited) — runtime view.

  • crictl ps -a | grep kube-apiserver

    Find the api-server container when debugging control-plane outages.

  • crictl logs <container-id>

    Container logs straight from the runtime, bypassing the api-server.

  • crictl logs --tail=2 <container-id>

    Last N lines.

Performance (top)

  • kubectl top node

    CPU + memory per node. Requires the metrics-server.

  • kubectl top pod

    CPU + memory per pod.

  • kubectl top node --sort-by=memory --no-headers | head -1

    Top node by memory.

  • kubectl top pod --sort-by=memory --no-headers | head -1

    Top pod by memory.

  • kubectl top pod --sort-by=cpu --no-headers | tail -1

    Bottom pod by CPU (e.g. find idle workloads).

Rollouts

  • kubectl rollout status deployment/<name>

    Watch the rollout finish (good for CI gating).

  • kubectl rollout history deployment/<name>

    Revision history with change-cause where set.

  • kubectl rollout undo deployment <name>

    Roll back to the previous revision. --to-revision=<n> for a specific one.

ConfigMaps

  • kubectl create configmap app-config \
      --from-literal=APP_COLOR=blue \
      --from-literal=APP_MODE=prod

    Create from inline values — quick for a few keys.

  • kubectl create configmap app-config --from-file=app_config.properties

    Create from a file — better when you have many env vars.

  • kubectl get configmaps

    List ConfigMaps. Alias: cm.

  • kubectl describe configmaps

    Show keys and values.

  • kubectl create configmap webapp-config --from-literal=APP_COLOR=darkblue --dry-run=client -o yaml > configmap.yaml

    Generate a ConfigMap manifest you can commit to git.

Secrets

  • kubectl create secret generic app-secret \
      --from-literal=DB_HOST=mysql \
      --from-literal=DB_USER=root \
      --from-literal=DB_PASSWORD=paswrd

    Create a generic Secret from inline values.

  • kubectl create secret generic app-secret --from-file=app_secret.properties

    From a properties file.

  • kubectl get secrets

    List Secrets.

  • kubectl describe secrets

    Metadata only — values are hidden.

  • kubectl get secrets app-secret -o yaml

    Show base64-encoded values.

  • echo -n 'mysql' | base64

    Encode a value before declaring it in a Secret manifest's data: block.

  • echo -n 'cGFzd3Jk' | base64 --decode

    Decode a value from `kubectl get secret -o yaml`.

  • kubectl -n webhook-demo create secret tls webhook-server-tls \
      --cert "/root/keys/webhook-server-tls.crt" \
      --key  "/root/keys/webhook-server-tls.key"

    TLS Secret from a cert + private key file pair.

Autoscaling (HPA / VPA)

  • kubectl autoscale deployment my-app --cpu-percent=50 --min=1 --max=10

    Imperative HPA on CPU.

  • kubectl get hpa

    List HPAs with current/target metrics.

  • kubectl get hpa --watch

    Stream changes — useful while load-testing.

  • kubectl delete hpa my-app

    Remove an HPA.

  • kubectl events hpa nginx-deployment | grep -i "ScalingReplicaSet"

    See scaling decisions in the event log.

  • kubectl apply -f https://github.com/kubernetes/autoscaler/releases/latest/download/vertical-pod-autoscaler.yaml

    Install the Vertical Pod Autoscaler. VPA is NOT built into k8s — you install it as an add-on.

  • kubectl get pods -n kube-system | grep vpa

    Verify the VPA components started (admission controller, updater, recommender).

  • kubectl get crds | grep verticalpodautoscaler

    Confirm the VPA CRDs were registered (verticalpodautoscalers.autoscaling.k8s.io and verticalpodautoscalercheckpoints.autoscaling.k8s.io).

  • kubectl logs -n kube-system $(kubectl get pods -n kube-system --no-headers -o custom-columns=:metadata.name | grep vpa-updater)

    Tail the VPA updater logs.

Node operations (drain / cordon / kubeadm upgrade)

  • kubectl cordon <node>

    Mark a node unschedulable. Existing pods stay; new pods won't land here.

  • kubectl uncordon <node>

    Mark schedulable again.

  • kubectl drain <node>

    Evict pods so the node can be rebooted / patched. Pods are recreated elsewhere by their controllers.

  • kubectl drain <node> --ignore-daemonsets

    Don't error on DaemonSet-managed pods (they always live on every node by design).

  • # control plane:
    apt-get upgrade -y kubeadm=1.30.0-00
    kubeadm upgrade plan v1.30.0
    kubeadm upgrade apply v1.30.0
    apt-get upgrade -y kubelet=1.30.0-00
    systemctl restart kubelet

    Standard kubeadm cluster upgrade on the control plane.

  • # each worker, from the control plane:
    kubectl drain <node> --ignore-daemonsets
    # on the node:
    apt-get upgrade -y kubeadm=1.30.0-00 kubelet=1.30.0-00
    kubeadm upgrade node
    systemctl restart kubelet
    # back on the control plane:
    kubectl uncordon <node>

    Repeat for every worker. Drain is critical so workloads don't get killed mid-upgrade.

Backup & restore (etcd)

  • kubectl get all --all-namespaces -o yaml > all-deploy-services.yaml

    Cheap 'everything as YAML' snapshot. Won't capture cluster-scoped objects (use `get pv,clusterrole,...` for those) but gets you started.

  • ETCDCTL_API=3 etcdctl snapshot save snapshot.db

    Take an etcd snapshot — etcd has snapshot built in.

  • ETCDCTL_API=3 etcdctl snapshot status snapshot.db

    Inspect a snapshot (hash, revision, total size, keys).

  • systemctl stop kube-apiserver
    ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \
      --data-dir /var/lib/etcd-from-backup
    # update the etcd manifest's data-dir to /var/lib/etcd-from-backup
    systemctl daemon-reload
    systemctl restart etcd
    systemctl start kube-apiserver

    Restore sequence. Always restore to a NEW data-dir, then point etcd at it — never overwrite the live one.

Certificates & CSR

  • cat /etc/kubernetes/manifests/kube-apiserver.yaml

    See exactly which certs the kube-apiserver is configured to use.

  • openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout

    Decode a cert: subject, SANs, issuer, validity. The single most useful openssl invocation for k8s PKI.

  • ls /etc/kubernetes/pki/

    Standard kubeadm PKI layout: apiserver.{crt,key}, ca.{crt,key}, sa.{key,pub}, front-proxy-*, etcd/.

  • cat javad.csr | base64 -w 0

    Base64-encode a CSR for the request: field of a CertificateSigningRequest manifest. -w 0 strips the line wrapping that would otherwise corrupt the YAML.

  • kubectl get csr

    List pending CSRs.

  • kubectl certificate approve <csr>

    Approve. The kube-controller-manager (kubernetes.io/kube-apiserver-client signer) signs and issues.

  • kubectl certificate deny <csr>

    Deny.

  • kubectl get csr <name> -o yaml

    Inspect; the issued cert is base64 in status.certificate.

  • kubectl delete csr <csr>

    Drop a CSR (e.g. clean up after testing).

  • cat /etc/kubernetes/manifests/kube-controller-manager.yaml

    The kube-controller-manager is the component that signs cluster-issued certificates.

Kubeconfig

  • kubectl config view

    Show the merged effective config.

  • kubectl config view --kubeconfig my-kube-config

    View a specific file in isolation.

  • kubectl config --kubeconfig=/root/my-kube-config use-context research

    Switch context inside a specific kubeconfig file (without touching ~/.kube/config).

  • kubectl config --kubeconfig=/root/my-kube-config current-context

    Active context for that file.

  • export KUBECONFIG=/root/my-kube-config

    Use a different kubeconfig as the default for the current shell. Add to ~/.bashrc to persist across sessions.

    KUBECONFIG also accepts colon-separated multiple files — kubectl merges them.

  • kubectl config get-clusters

    List clusters in the kubeconfig.

  • kubectl config use-context <ctx>

    Switch contexts in the default kubeconfig.

API server access (curl, proxy)

  • curl https://kube-master:6443/version

    Hit the api-server directly. Needs valid client certs / token.

  • curl https://kube-master:6443/api/v1/pods

    Same as `kubectl get pods` but raw HTTP.

  • curl https://localhost:6443 -k

    List the available API surface (-k = skip TLS verify, only for local debugging).

  • curl https://localhost:6443/apis -k | grep "name"

    Enumerate API groups.

  • kubectl proxy

    Start a local proxy on :8001 that forwards your kubectl auth — you can then curl without supplying credentials per call.

  • curl http://localhost:8001/api/v1/pods

    Through the proxy — no -k, no auth header needed.

RBAC (roles, can-i)

  • kubectl get roles

    Roles in the current namespace.

  • kubectl get roles -A

    Roles across all namespaces.

  • kubectl get roles -A --no-headers | wc -l

    Count roles cluster-wide.

  • kubectl get rolebindings

    RoleBindings in the namespace.

  • kubectl get clusterroles

    Cluster-scoped roles.

  • kubectl get clusterrolebindings

    Cluster-scoped bindings.

  • kubectl describe clusterrolebinding cluster-admin

    Who has cluster-admin?

  • kubectl create clusterrolebinding michelle-binding \
      --clusterrole=node-admin --user=michelle \
      --dry-run=client -o yaml > michelle.yaml

    Generate a ClusterRoleBinding manifest.

  • kubectl auth can-i create deployments

    Self-permission check — does my current identity have the verb on the resource?

  • kubectl auth can-i delete nodes

    Same idea.

  • kubectl auth can-i create deployments --as dev-user

    Impersonate another user (requires impersonation rights).

  • kubectl auth can-i create deployments --as dev-user --namespace test

    Scoped impersonation check.

  • kubectl auth can-i list storageclasses --as michelle

    Common use: 'does this user actually need this binding?' before granting.

  • kubectl describe pod kube-apiserver-controlplane -n kube-system | grep authorization-mode

    See which authorization modes the api-server is running (Node, RBAC, ABAC, Webhook, AlwaysAllow, ...).

Service accounts & tokens

  • kubectl get serviceaccount

    Each namespace has a `default` SA out of the box.

  • kubectl describe serviceaccount default

    SA detail: linked secrets, mountable, image-pull secrets.

  • kubectl create serviceaccount <name>

    Create an SA.

  • kubectl create token <sa-name>

    Issue a short-lived bearer token for the SA (default 1h). Useful for out-of-cluster consumers like CI/CD.

  • kubectl create token <sa-name> --duration 2h

    Custom duration.

  • kubectl patch sa dashboard-sa -p '{"automountServiceAccountToken": false}'

    Stop automatically mounting the SA token into pods that use this SA — defence-in-depth for pods that don't talk to the api-server.

  • kubectl exec <pod> -- ls /var/run/secrets/kubernetes.io/serviceaccount/

    Inspect the mounted SA token, ca.crt and namespace from inside a pod.

  • kubectl exec ubuntu-sleeper -- whoami

    Quick sanity check — what user is the container actually running as?

Network policies & storage

  • kubectl get networkpolicy

    List NetworkPolicies. Alias: netpol.

  • kubectl get persistentvolumeclaim

    List PVCs. Alias: pvc.

Aliases & productivity

  • alias k=kubectl

    The classic. Save in ~/.bashrc.

    Pair it with `complete -F __start_kubectl k` and `source <(kubectl completion bash)` to keep tab-completion working through the alias.

  • kubectl exec ubuntu-sleeper -- whoami

    Run an arbitrary command in a pod without an interactive shell — the cheapest health probe.