kubectl
Kubernetes' command-line client — daily-driver workflows for clusters on AKS and on-prem.
Official docsGet & list resources
kubectl get podsList pods in the current namespace.
kubectl get pods -n kube-systemList pods in a specific namespace. Long form: --namespace=.
kubectl get pods -AAcross every namespace. Long form: --all-namespaces.
kubectl get nodesList cluster nodes.
kubectl get deploymentList Deployments. Aliases: deploy.
kubectl get replicasetList ReplicaSets. Alias: rs.
kubectl get allList the most common workload resources (pods, services, deployments, replicasets) in the namespace.
kubectl get all -ASame, across every namespace.
kubectl get pods -wStream pod state changes. Long form: --watch.
kubectl get events -o wideRecent 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.yamlDump 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 persistentvolumeclaimList PVCs. Alias: pvc.
kubectl get priorityclassList priority classes (used by the scheduler for preemption).
Namespaces & contexts
kubectl create namespace devCreate a namespace.
kubectl config set-context $(kubectl config current-context) --namespace=devPin every kubectl call in this context to a default namespace — saves typing -n on every command.
kubectl config viewShow the merged effective kubeconfig (clusters + users + contexts).
kubectl config get-clustersList the clusters known to your kubeconfig.
kubectl config use-context <ctx>Switch to another context.
kubectl config current-contextPrint the currently active context.
Imperative create (run, create deployment, expose)
kubectl run nginx --image=nginxCreate a single bare pod (no Deployment / ReplicaSet wrapping).
kubectl run nginx --image=nginx --dry-run=client -o yamlGenerate 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.ymlSame, captured to a file.
kubectl create deployment nginx --image=nginxCreate a Deployment.
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > nginx-deployment.yamlGenerate a Deployment manifest.
kubectl create deployment nginx --image=nginx --replicas=4 --dry-run=client -o yaml > nginx-deployment.yamlSame with a custom replica count. --replicas was added in k8s 1.19.
kubectl create -f pod-definition.ymlCreate from a manifest. Imperative — fails if the object already exists.
kubectl create -f pod-definition.yml --namespace=devCreate the manifest into a target namespace.
kubectl run httpd --image=httpd:alpine --port=80 --exposeCreate 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 greenPass 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 greenOverride 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.ymlCreate or update from a manifest. Idempotent — re-running with no changes is a no-op.
kubectl apply -f /path/to/config-filesApply 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 TaintShow only the taints applied to a node.
kubectl describe daemonsets <name>DaemonSet rollout status, selector, current/desired/ready counts.
kubectl describe configmapsConfigMaps in the namespace, with key/value contents.
kubectl describe secretsSecret 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-adminWho has cluster-admin?
kubectl describe serviceaccount defaultServiceAccount detail: linked secrets, mountable, image-pull secrets.
kubectl api-resourcesList every resource kind the cluster knows about, with their short names and group/version.
kubectl api-resources --namespaced=trueOnly namespace-scoped resources (pods, jobs, services, configmaps, ...).
kubectl api-resources --namespaced=falseOnly cluster-scoped resources (nodes, persistentvolumes, clusterroles, namespaces, ...).
kubectl explain podsShow the schema for a resource — what fields it accepts.
kubectl explain pods.specDrill into a sub-field.
kubectl explain pods --recursiveRecursively list every field a manifest can carry. Great for autocomplete-without-autocomplete.
kubectl explain services.spec.ports --recursiveCommon need — full schema for Service ports.
Modify (edit, scale, set image, replace)
kubectl edit replicaset new-replica-setOpen the live object in $EDITOR; on save, kubectl re-applies it.
kubectl scale --replicas=6 -f replica.ymlScale by manifest.
kubectl scale deployment nginx --replicas=5Scale a Deployment.
kubectl scale rs new-replica-set --replicas=5Scale a ReplicaSet directly.
kubectl set image deployment nginx nginx=nginx:1.18Update one container's image — triggers a rolling update.
kubectl replace -f replicaset.yamlReplace an existing object. Errors if it doesn't already exist.
kubectl replace --force -f replicaset.yamlDelete + recreate. Necessary when you change immutable fields (e.g. selectors).
kubectl expose deployment nginx --port 80Create a ClusterIP Service for an existing Deployment.
kubectl expose pod redis --port=6379 --name redis-service --dry-run=client -o yamlGenerate 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 yamlService 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 yamlNodePort 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 yamlNodePort with a fixed node port — but ignores pod labels (uses app=<name>).
Labels, selectors & taints
kubectl get pods -l app=App1Filter by label selector. Long form: --selector.
kubectl get all -l env=prodSelector across all common resource kinds.
kubectl get pods -l env=prod,bu=finance,tier=frontendMultiple labels — comma is AND.
kubectl get all -l env=prod --no-headers | wc -lCount 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-labelsShow all labels per node.
kubectl taint nodes <node> key=value:NoScheduleRepel pods from a node unless they tolerate the taint. Effects: NoSchedule | PreferNoSchedule | NoExecute.
kubectl taint nodes node01 app=myapp:NoScheduleConcrete 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=payrollFind pods by label substring (quick grep when you forgot the exact selector).
DaemonSets & static pods
kubectl get daemonsetsList DaemonSets. Alias: ds.
kubectl get daemonsets -AAcross all namespaces.
kubectl describe daemonsets <name>DaemonSet detail.
ps -aux | grep /usr/bin/kubeletFind the kubelet process — needed to discover its --config flag and the path to its config file.
grep -i staticPodPath /var/lib/kubelet/config.yamlFind 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.yamlCreate 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-myserviceLogs from an init container — needs -c (the init isn't picked by name alone).
kubectl logs my-custom-scheduler -n kube-systemLogs 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 podsList pods at the container-runtime level. Use when the api-server itself is broken and `kubectl get pods` won't answer.
crictl ps -aAll containers (running + exited) — runtime view.
crictl ps -a | grep kube-apiserverFind 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 nodeCPU + memory per node. Requires the metrics-server.
kubectl top podCPU + memory per pod.
kubectl top node --sort-by=memory --no-headers | head -1Top node by memory.
kubectl top pod --sort-by=memory --no-headers | head -1Top pod by memory.
kubectl top pod --sort-by=cpu --no-headers | tail -1Bottom 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=prodCreate from inline values — quick for a few keys.
kubectl create configmap app-config --from-file=app_config.propertiesCreate from a file — better when you have many env vars.
kubectl get configmapsList ConfigMaps. Alias: cm.
kubectl describe configmapsShow keys and values.
kubectl create configmap webapp-config --from-literal=APP_COLOR=darkblue --dry-run=client -o yaml > configmap.yamlGenerate 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=paswrdCreate a generic Secret from inline values.
kubectl create secret generic app-secret --from-file=app_secret.propertiesFrom a properties file.
kubectl get secretsList Secrets.
kubectl describe secretsMetadata only — values are hidden.
kubectl get secrets app-secret -o yamlShow base64-encoded values.
echo -n 'mysql' | base64Encode a value before declaring it in a Secret manifest's data: block.
echo -n 'cGFzd3Jk' | base64 --decodeDecode 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=10Imperative HPA on CPU.
kubectl get hpaList HPAs with current/target metrics.
kubectl get hpa --watchStream changes — useful while load-testing.
kubectl delete hpa my-appRemove 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.yamlInstall the Vertical Pod Autoscaler. VPA is NOT built into k8s — you install it as an add-on.
kubectl get pods -n kube-system | grep vpaVerify the VPA components started (admission controller, updater, recommender).
kubectl get crds | grep verticalpodautoscalerConfirm 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-daemonsetsDon'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 kubeletStandard 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.yamlCheap '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.dbTake an etcd snapshot — etcd has snapshot built in.
ETCDCTL_API=3 etcdctl snapshot status snapshot.dbInspect 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-apiserverRestore 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.yamlSee exactly which certs the kube-apiserver is configured to use.
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -nooutDecode 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 0Base64-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 csrList 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 yamlInspect; 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.yamlThe kube-controller-manager is the component that signs cluster-issued certificates.
Kubeconfig
kubectl config viewShow the merged effective config.
kubectl config view --kubeconfig my-kube-configView a specific file in isolation.
kubectl config --kubeconfig=/root/my-kube-config use-context researchSwitch context inside a specific kubeconfig file (without touching ~/.kube/config).
kubectl config --kubeconfig=/root/my-kube-config current-contextActive context for that file.
export KUBECONFIG=/root/my-kube-configUse 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-clustersList 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/versionHit the api-server directly. Needs valid client certs / token.
curl https://kube-master:6443/api/v1/podsSame as `kubectl get pods` but raw HTTP.
curl https://localhost:6443 -kList the available API surface (-k = skip TLS verify, only for local debugging).
curl https://localhost:6443/apis -k | grep "name"Enumerate API groups.
kubectl proxyStart 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/podsThrough the proxy — no -k, no auth header needed.
RBAC (roles, can-i)
kubectl get rolesRoles in the current namespace.
kubectl get roles -ARoles across all namespaces.
kubectl get roles -A --no-headers | wc -lCount roles cluster-wide.
kubectl get rolebindingsRoleBindings in the namespace.
kubectl get clusterrolesCluster-scoped roles.
kubectl get clusterrolebindingsCluster-scoped bindings.
kubectl describe clusterrolebinding cluster-adminWho has cluster-admin?
kubectl create clusterrolebinding michelle-binding \ --clusterrole=node-admin --user=michelle \ --dry-run=client -o yaml > michelle.yamlGenerate a ClusterRoleBinding manifest.
kubectl auth can-i create deploymentsSelf-permission check — does my current identity have the verb on the resource?
kubectl auth can-i delete nodesSame idea.
kubectl auth can-i create deployments --as dev-userImpersonate another user (requires impersonation rights).
kubectl auth can-i create deployments --as dev-user --namespace testScoped impersonation check.
kubectl auth can-i list storageclasses --as michelleCommon use: 'does this user actually need this binding?' before granting.
kubectl describe pod kube-apiserver-controlplane -n kube-system | grep authorization-modeSee which authorization modes the api-server is running (Node, RBAC, ABAC, Webhook, AlwaysAllow, ...).
Service accounts & tokens
kubectl get serviceaccountEach namespace has a `default` SA out of the box.
kubectl describe serviceaccount defaultSA 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 2hCustom 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 -- whoamiQuick sanity check — what user is the container actually running as?
Network policies & storage
kubectl get networkpolicyList NetworkPolicies. Alias: netpol.
kubectl get persistentvolumeclaimList PVCs. Alias: pvc.
Aliases & productivity
alias k=kubectlThe 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 -- whoamiRun an arbitrary command in a pod without an interactive shell — the cheapest health probe.