Mastery isn’t just skill - it’s knowing the right tools and wielding them with precision.
Introduction
Kubectl is probably one of the more underrated tools in the Kubernetes ecosystem. It’s a tool that every beginner starts with and seasoned experts use to hack something into a cluster, or more accurately, use it to extinguish a fire during an emergency.
Because diversity of user profiles using the tool, it packs a lot of goodies under the hood. It can do things as simple as listing all pods in the cluster and showing their status. On the other side of the spectrum are features like kubectl debug
.
Very few people need to know the entire CLI reference by heart, but you’ll benefit heavily from knowing what gems are available directly from kubectl and don’t require any other tooling to be used.
101
Kubectl get
This is likely one of the first commands you’ll use when starting with Kubernetes. get
ting resources to see what’s running in a cluster. You fetch the information about all resources in your cluster this way, including resources managed by an operator, so-called custom resources (based on custom resource definitions). `
The command can be used to fetch all pods that are deployed in a cluster as follows: kubectl get pods --all-namespaces
. The short version of the same command would be kubectl get po -A
. Most common resources in a Kubernetes cluster have a short name next to their long name. For pods, this is po
. The -A
is a direct replacement for the --all-namespaces
.
These are other common short names you can use:
ingress
=ing
configmap
=cm
deployment
=deploy
service
=svc
replicaset
=rs
You can fetch a full list of resources and their short names through kubectl api-resources
. Note that the output you’ll get will differ based on which resources are available in your cluster.
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
podtemplates v1 true PodTemplate
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration
validatingadmissionpolicies admissionregistration.k8s.io/v1 false ValidatingAdmissionPolicy
validatingadmissionpolicybindings admissionregistration.k8s.io/v1 false ValidatingAdmissionPolicyBinding
validatingwebhookconfigurations admissionregistration.k8s.io/v1 false ValidatingWebhookConfiguration
customresourcedefinitions crd,crds apiextensions.k8s.io/v1 false CustomResourceDefinition
apiservices apiregistration.k8s.io/v1 false APIService
controllerrevisions apps/v1 true ControllerRevision
daemonsets ds apps/v1 true DaemonSet
deployments deploy apps/v1 true Deployment
replicasets rs apps/v1 true ReplicaSet
statefulsets sts apps/v1 true StatefulSet
... output omitted ...
Now a final tip for using the kubectl get
command. You can combine multiple resource types in a single request. This allows you to fetch all deployments and pods for a given namespace through the following command kubectl get deploy,po
. The output is simple the concatenation of the output of kubectl get deployment
and kubectl get pod
. There is one special macro that can be used here as well: all
. Contrary to what one would expect, this doesn’t fetch all resources for all resource types. It will return a predefined set of resources.
Kubectl logs
The following command fetches logs from a running container in the cluster. By default, it will fetch the logs of the first container in the pod definition and show all logs that that container has produced so far. Sometimes the logs might have been rotated partially by the log manager of the node. The default command is: kubectl logs <pod-name>
. The output of the command depends on what the container has outputted. With the --all-containers
option, all logs for all containers of a single pod can be outputted together.
You can stream all logs to your machine as they are produced by the container. This can be achieved using the --follow
or -f
for short flag in the command. The log output can be limited to just the last 10 lines by adding the option --tail=10
. Combining these two commands can be very useful when debugging. It shows the last few logs produced and streams all new loglines directly to your terminal.
As with get
there are also some powerful mechanisms built into kubectl to extend the behaviour. The logs command supports streaming all logs for a given set of pods. These pods can be grouped by other concepts in Kubernetes. For example, all logs for a deployment can be viewed by using kubectl logs deployment/<deployment-name>
. This command will fetch all logs and output them.
As with all commands, these options can be combined into powerful debugging commands: kubectl logs deployment/my-deployment -f --all-containers
. This command will stream all logs supporting the my-deployment deployment directly to your terminal.
Kubectl config / context
Any good development platform will have separate environments defined. These environments are typically split by some deployment boundary. This blog won’t dive into how these environments are separated, but kubectl has some useful commands that can help with switching between the different available clusters.
kubectl config set-context --current --namespace <namespace-name>
allows you to set the default namespace for all the following kubectl commands. This prevents you from having to provide the namespace explicitly in every command.
The same structure can be used to switch between clusters (Kube API endpoints). Using kubectl config use-context <nickname-of-context>
you can set the context you want to use moving forward. The nickname used in the command is the name of the context in your kubeconfig file.
There are 2 plugins in kubectl which make switching between clusters and namespaces easier. Both can be easily installed through kubectl krew (another superpower we’ll discuss later): kubectx and kubens.
201 aka docker cli commands
The following commands will be similar for people using Docker through a CLI. Most commands have a direct comparable command in the Docker CLI or are similar to Docker CLI commands in behaviour.
The following commands are interesting to know, but shouldn’t be used on production clusters as they might significantly violate security requirements and repeatability of your deployments. They are useful tools for debugging clusters. Some even require specific tools to be installed in the container image to work.
Kubectl top
This is a simple command to fetch memory and CPU usage metrics for pods and nodes inside the cluster. This can be useful in debugging sessions to get a quick overview of the components heavily (over) utilising resources in the cluster.
kubectl top pod -A
shows a snapshot of the metrics for all pods in a cluster. Use this with caution as for large clusters fetching all pods can be a large request.
kubectl top node
shows the metrics for all nodes in the cluster. By appending a node name, the metrics for a specific node can be fetched. Combined with kubectl get pod --field-selector=spec.nodeName=<nodeName> -A
this can be an easy way to find issues on a node and which pods are causing it.
Kubectl exec
When debugging issues in a cluster, it might be helpful to shell into a container, as you did into VMs in the past, to figure out the environment for example. The command is a direct replica of the capability in the Docker CLI. You can select a pod and container and run an arbitrary command inside the container. There is however one caveat. The container that’s executing the command needs to have a shell available. As a shell is opened to execute the command, using the exec command on a rootless or shellless container will outright fail.
` kubectl exec
Kubectl run
For containers that don’t contain a shell, you can’t use the exec command. In such a situation another tool might be helpful: kubectl run. This command is an easy way to get a quick template for pods. Using this command helps to deploy a pod in the cluster to debug network issues (e.g. deploy a busybox to test if you can wget google.com). The newer kubectl debug
command added a better way of doing this.
Using kubectl run -i -t busybox --image=busybox --restart=Never
you can deploy a busybox into your cluster to start hacking away at your issue.
Kubectl cp
This command does exactly what you expect it to do. It can copy files to and from containers in your cluster. It uses a syntax similar to rsync and the Docker CLI command. It can be used to download the running configuration files in a container on the cluster, especially if you’re using a combination of container image default configuration files, (Helm generated) ConfigMaps and deployment configuration. As with the exec command, there is a specific requirement for tar
to be available in the container images as the command uses it to stream the files between the container and your local machine.
kubectl cp <source-pod-name>:<source-location-in-pod> <target-local-directory-or-file>
will copy a file or even a directory from the default container of the specified pod onto your local machine.
Kubectl port-forward
This is probably the most powerful command in this section of the blog post. It allows you to connect directly to pods (or services) in a cluster as if they were connected to your local machine. If you’re familiar with how SSH port-forwarding works, this is almost identical. It can be used to debug ingress issues and/or when your north-south traffic is broken.
kubectl port-forward <pod-name> 8080
creates a port-forward on your local machine from port 8080 towards port 8080 of the pod’s default container. Note that this is a blocking command until you close the tunnel again.
300 helpful in a pinch
The final set of commands is for specific use cases. They can solve the exact scenario described, but their usage should be minimized as some of them come with significant trade-offs and side effects. They are only recommended for use when you know what their impact will be.
kubectl edit
This is a very powerful command as it allows you to directly edit resources in the cluster. It will open the selected resource in your default editor and allow you to make changes. Once you save in the editor, the changes will be instantly applied towards the cluster.
kubectl edit deployment hello-world
will download a local copy of the yaml describing the hello-world deployment and allow you to edit it directly.
Finalizer cleanup: kubectl patch
This command can clean up the leftover configuration of a badly behaving operator. Some operators add finalizers to objects to prevent the deletion of objects without the linked or child resources being cleaned properly. A good example could be a database operator that adds a finalizer annotation to the custom database object making sure that the pods, volumes etc. are cleaned up before the custom resource is deleted from the cluster. If for whatever reason, the pods are deleted while the operator is down, there will be a reconciliation issue that causes a limbo state. In this case, and please only in this case, it can be used to delete the finalizers to allow the kube-api to delete the resources without waiting on the deletion of the non-existing resources.
kubectl patch postgresql/some-db --type json --patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]'
will remove the finalizer on the postgresql custom database object and delete the object without waiting for the child resources to be cleaned up.
kubectl wait –for-condition=Ready
Kubectl wait is a CLI helper that waits for certain conditions in the cluster to become true. It can be used to wait for specific out-of-the-box conditions or even watch for specific JSON path expressions to become true. Although Kubernetes should be used as an eventually consistent system, the CLI helper can be used during deployment scenarios where you want to wait for a condition before continuing.
I’ve used this for waiting for a validatingwebhook service before deploying additional resources that should be validated by that webhook. kubectl wait deployment -n external-secrets external-secrets-webhook --for condition=Available=True --timeout=120s
This command waits for the webhook to be available before returning the command.
Kubectl create -o yaml –dry-run=client
Finally, the last but perhaps the best life hack of this entire blog post. When creating new resources it’s often cumbersome to get a decent template to start out from. You can google the resource name and take the template from the docs. But that comes with some additional configuration because it showcases common scenarios which may or may not apply to you. The following command allows you to create a bare-bones template for a lot of standard Kubernetes resources: kubectl create <resource-type> <name> --dry-run=client -o yaml > ns.yaml
. This is a great way to create a namespace template.
Caveat: For some reason, the template generates unneeded metadata that you’ll have to remove manually (e.g. timestamp).
Conclusion
A wild foe appeared!
KubeCon London 2025 discovery: Headlamp
This blog post was written during KubeCon 2025 in London. During one of the keynotes, we learned about Headlamp. It’s a web-UI for Kubernetes, supported by the Kubernetes project itself through SIG-UI, that can be installed in a Kubernetes cluster or run locally on a developer’s machine. It can do most if not all of the features mentioned above. From our initial looks at the project, it looks like a decent implementation of the things Lens IDE, Octant and many others tried to achieve over the years. It’s supported directly by a Kubernetes SIG. If you’re a developer who needs to use Kubernetes daily, this might be the best UI for you.
Real conclusion
Kubectl is a super powerful tool with more features than you’d expect. The advanced features can however be a great tool in your toolbox when debugging issues, discovering how certain things work and in general having a better time managing containers at scale using Kubernetes.
This was the point where we’d intended to plug our favourite TUI for Kubernetes k9s, but if Headlamp is as good as it looks on the surface, the necessity to run k9s (however powerful!) might be obsolete.