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. getting 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 -c -i -t -- bash` will open a bash shell running directly in the container.

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.

Pieter rarely sees problems, just too many solutions sometimes. That’s why K’nex was his favorite pastime as a child. Nowadays, he builds cloud platforms so organizations don’t have to worry about their IT infrastructure but can focus on their clients.