Learn about the common kubectl commands and use-cases they cover, get familiar with kubectl operating modes, deep dive into command syntax and read additional pro tips.
🎉 Kubecost 2.0 is here! Learn more about the massive new feature additions and predictive learning

Kubectl Cheat Sheet

Like this Article?

Subscribe to our Linkedin Newsletter to receive more educational content

Subscribe now

Kubectl is the default tool for interacting with a Kubernetes cluster. Kubectl is built and released as part of Kubernetes and follows the same versioning number system. It can be used on most mainstream operating systems, such as Windows, macOS, and Linux.

This article will walk you through the kubectl commands you need to know about.

Executive Summary

Section Command Comment
Managing Contexts kubectl config get-contexts Lists the current kubectl contexts
kubectl config use-context Selects a context to use for subsequent kubectl commands
Querying the Cluster kubectl -n NS get pods Lists the pods in the namespace NS
kubectl get deploy DEP -o yaml Shows the manifest and status of deployment DEP
kubectl describe svc/MYSVC Shows the details of the service MYSVC
kubectl logs MYPOD Shows the logs produced by MYPOD
kubectl version Shows the versions of kubectl and your Kubernetes cluster
Managing Resources kubectl apply -f MANIFEST.YAML Creates or updates the resources specified in the manifest file
kubectl delete -f MANIFEST.YAML Deletes the resources specified in the manifest file
Commands for Deployment kubectl rollout Manages deployment updates
kubectl scale Scales a deployment out and in
Debugging kubectl describe Inspects a resource
kubectl port-forward Accesses a pod’s port on your local machine
kubectl logs Shows a pod’s logs
kubectl exec Executes a command inside a pod

Comprehensive Kubernetes cost monitoring & optimization

Kubectl Modes

Before getting into the specifics of commands, it is important to understand the various modes in which kubectl can work.

Imperative Mode

Commands issued in imperative mode directly instruct Kubernetes on what to do with specific objects. Examples of such commands are kubectl create service or kubectl delete pvc.

Declarative Mode

The declarative mode tells Kubernetes the desired end state and lets Kubernetes do whatever work is required to achieve that state. This mode takes manifest files as input that describe the desired end state. A typical example of such a command is kubectl apply -f MANIFEST.YAML.

Imperative Object Configuration Mode

Finally, the imperative object configuration mode mixes the previous two. It takes a manifest file as input but instructs Kubernetes directly to perform specific actions on certain objects. The typical command for this mode is kubectl create -f MANIFEST.YAML.

Choosing the Right Mode

Generally speaking, you should strive to use the declarative mode because Kubernetes will usually make the right decisions to achieve your desired end state. Please note that the declarative mode is incomplete at the time of writing because it can only create or update Kubernetes objects. It can’t delete such objects yet, except via the --prune option. This option is currently in alpha, so it is not recommended, especially if working in a production environment. To delete objects, you will still need to use the imperative mode, for example, using kubectl delete -f MANIFEST.YAML. Please note that although we use a manifest file, this is still imperative mode because we are using the delete command. A true declarative mode would still use the apply command and delete resources that are not declared anymore in the manifest file.

Object Addressing Notations

Note that for most commands, kubectl accepts two different notations to address objects:

  • Slash Notation (“object_type/object_name”): This notation is accepted for almost all kubectl commands. Example: “pod/mypod”
  • Space Notation (“object_type object_name”): This notation is allowed on some often-used commands. Example: “pod mypod”

In this article, we will use these notations interchangeably.

Commands in Detail

Managing Contexts

When you work on more than one Kubernetes cluster, kubectl needs to know on which cluster to run your commands. This is done using the concept of contexts. A context is a set of data used by kubectl to identify where to reach the Kubernetes API for a particular cluster, which credentials to use, etc. Contexts are usually stored in a kubeconfig file, which is by default located at ~/.kube/config on macOS and Linux and %USERPROFILE%\.kube\config on Windows.

You can lists contexts using the get-contexts command as follows:

$ kubectl config get-contexts
CURRENT   NAME        CLUSTER     AUTHINFO    NAMESPACE
*         kind-kind   kind-kind   kind-kind
          minikube    minikube    minikube    default

The CURRENT column shows which context is currently selected. To switch to a different context, use the use-context command:

$ kubectl config use-context minikube
Context "minikube" modified.
$ kubectl config get-contexts
CURRENT   NAME        CLUSTER     AUTHINFO    NAMESPACE
          kind-kind   kind-kind   kind-kind
*         minikube    minikube    minikube    default

Contexts will usually be created by whatever tool you used to create the cluster, and you usually don’t need to concern yourself about creating or modifying them. When you delete a cluster, the tool you are using will usually remove the corresponding context as well. If it doesn’t, for some reason, you can use the following command to remove a context manually:

$ kubectl config delete-context minikube

Querying the Cluster

kubectl get

The most important command for cluster querying is the kubectl get command, which can retrieve information and manifest files for all Kubernetes object types as well as cluster nodes. Used on its own, the kubectl get command will retrieve and display a basic set of information. This command also accepts a number of options to modify and expand its output:

  • -o wide adds more useful information to the output. What data is provided depends on the queried object type.
  • -o yaml (or -o json, but this tends to be less readable) returns a manifest of the queried objects (i.e., their specifications) as well as their current state. Such output can be modified and reapplied to update the objects or create new objects.
  • -o jsonpath allows you to accurately select the information you want to fetch using jsonpath notation. This is useful for scripting.
  • -o go-template allows you to apply Go templates for advanced features.

There are also a few other output options that you can list using kubectl get --help.

Let’s now go through a number of commonly used kubectl get commands.

To list the pods in the “default” namespace, run the following:

$ kubectl get pods
No resources found in default namespace.

In this case, there are no pods in the “default” namespace.

To get more details about a specific pod, you can run this:

$ kubectl --namespace demo get po myapp-0 -o wide
NAME      READY   STATUS    RESTARTS   AGE     IP           NODE           NOMINATED NODE   READINESS GATES
myapp-0   1/1     Running   0          2m27s   10.244.1.3   minikube-m02   <none>     <none>

The -o wide option adds interesting information, such as the pod’s IP address.

To get the manifest and state of the same pod as above, use the following:

$ kubectl -n demo get pod/myapp-0 -o yaml
apiVersion: v1
kind: Pod
metadata:
...etc...

Here is how to get information about your cluster’s nodes:

$ kubectl get node
NAME           STATUS   ROLES                  AGE    VERSION
minikube       Ready    control-plane,master   123m   v1.23.3
minikube-m02   Ready    <none>           120m   v1.23.3
minikube-m03   Ready    <none>           119m   v1.23.3

Here is a very useful command to get the value of a secret:

$ kubectl get secret SECRET_NAME \
    -o 'jsonpath={.data.PASSWORD}' | base64 -d
Unbreakable password

Obviously, replace SECRET_NAME and PASSWORD by the secret’s name and the data key inside the secret, respectively. If you don’t have the base64 program available on your system, it is possible to use pure Go templates like this:

$ kubectl get secret SECRET_NAME \
    -o 'go-template={{.data.PASSWORD | base64decode}}'
Unbreakable password

You can use the kubectl get command on any object type managed by your Kubernetes cluster.

Pro-tip: the following command will list all the object types managed by your cluster, including custom resource definitions (CRDs), and whether or not they are namespaced:
$ kubectl api-resources 
NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
bindings                                       v1                                     true         Binding
componentstatuses                 cs           v1                                     false        ComponentStatus
configmaps                        cm           v1                                     true         ConfigMap

kubectl describe

Another important way to get information from the cluster is the kubectl describe command, which shows detailed information about a specific object that is very useful for debugging. For example:

$ kubectl -n demo describe pod/myapp-0
Name:         myapp-0
Namespace:    demo
Priority:     0
...etc…
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
...etc...
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  72m   default-scheduler  0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims.
  Normal   Scheduled         72m   default-scheduler  Successfully assigned demo/myapp-0 to minikube-m02
  Normal   Pulling           72m   kubelet            Pulling image "busybox"

The displayed information is somewhat similar to the output of a get -o yaml command but includes more details, such as the pod’s events.

Running this command on nodes provides a lot of useful information:

$ kubectl describe node minikube-m02
Name:               minikube-m02
Roles:              <none>
...etc…
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  MemoryPressure   False   Tue, 26 Jul 2022 20:37:52 +0100   Tue, 26 Jul 2022 18:20:42 +0100   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure     False   Tue, 26 Jul 2022 20:37:52 +0100   Tue, 26 Jul 2022 18:20:42 +0100   KubeletHasNoDiskPressure     kubelet has no disk pressure
  PIDPressure      False   Tue, 26 Jul 2022 20:37:52 +0100   Tue, 26 Jul 2022 18:20:42 +0100   KubeletHasSufficientPID      kubelet has sufficient PID available
  Ready            True    Tue, 26 Jul 2022 20:37:52 +0100   Tue, 26 Jul 2022 18:21:13 +0100   KubeletReady                 kubelet is posting ready status
...etc...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests   Limits
  --------           --------   ------
  cpu                100m (5%)  100m (5%)
  memory             50Mi (0%)  50Mi (0%)
  ephemeral-storage  0 (0%)     0 (0%)
  hugepages-2Mi      0 (0%)     0 (0%)
Events:              <none>

As you can see, the output shows you whether or not the node is under stress in terms of memory, CPU, and disk utilization.

kubectl logs

One very important function is retrieving the logs of a given pod, which is done like so:

$ kubectl logs -n demo myapp-1 -c myapp
Defaulted container "myapp" out of: myapp, init (init)
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
...etc...

If your pod contains more than one container, you need to use the -c option followed by the container’s name to specify which container you want to query the logs from.

You also need to be aware that this command will query the logs from the current log file on the node running the pod. After a while, it is likely that this log file will get rotated, in which case you will miss older logs. The solution to this is to either look at the log files directly on the node (which is quite cumbersome and not recommended) or use a log aggregator such as Loki or Splunk. If you do need the whole log history or are running production workloads, you probably need to invest in such a logging solution.

K8s clusters handling 10B daily API calls use Kubecost

kubectl version

To get the versions of kubectl and your Kubernetes cluster, which requires querying its APIs, run this:

$ kubectl version --short
Client Version: v1.24.3
Kustomize Version: v4.5.4
Server Version: v1.23.3

You should ensure that the versions of kubectl and the Kubernetes cluster are close to each other; otherwise, strange behavior might occur.

Managing Resources

Now let’s move on to commands that actually perform some actions on your cluster, such as creating, updating, and deleting resources.

Creating Objects

To create Kubernetes objects, you can use imperative commands, but as we saw earlier, this is not recommended except to quickly create a resources while doing some development. As an example, here is how to create a pod using imperative mode:

$ kubectl run www --image=nginx

This will create a pod named “www” running the “nginx” image. As you can see, some object types use specific commands, and complex object specifications will be nearly impossible to specify using the command line only. If you want to learn more about imperative commands, Kubernetes has a dedicated page for them.

Here is another example of an imperative creation, this time for a deployment:

$ kubectl create deployment www --image=nginx --replicas=3
deployment.apps/www created
$ $ kubectl get pod
NAME                  READY   STATUS    RESTARTS   AGE
www-6d49b97f5-ct7cn   1/1     Running   0          50s
www-6d49b97f5-jb689   1/1     Running   0          50s
www-6d49b97f5-nggsm   1/1     Running   0          50s

You probably noticed that this time, we used the standard kubectl create command. Most objects can be created imperatively using the kubectl create command, but a few (like pods) have their own commands.

The recommended method is to use the declarative mode like this:

$ kubectl apply -f MANIFEST.YAML

The manifest file is a YAML-formatted file. Here are its specifications. Using a manifest file allows you to better track the changes you make to your cluster, and such files can be kept in revision control. As an example, here is the manifest file for a pod:

apiVersion: v1
kind: Pod
metadata:
  name: debug
  namespace: myns
spec:
  containers:
name: debug
     image: nicolaka/netshoot
     command: [sh, -c, while true; do sleep 60; done]

This example is actually very useful because the “nicolaka/netshoot” image contains a lot of networking-related tools that are very helpful for debugging connectivity issues inside a cluster.

Pro-tip: After creating some CRDs, you won’t be able to immediately create objects of the types defined by these CRDs. This is because Kubernetes has a race condition internally, and you will need to wait for a few seconds before attempting to create objects of the new types.

Updating Objects

Again, it is possible to update objects using imperative mode. There are actually four different ways to effect changes to objects.

First, you can make the changes directly using the edit command:

$ kubectl edit deploy/www

This will fire up your favorite text editor with the manifest and status of the object you selected. You will then need to make the desired changes directly, and once you exit and save, Kubernetes will apply the changes.

The second way is to use the replace command, which works like this:

$ kubectl get deploy/www -o yaml > tmp.yaml
$ myeditor tmp.yaml  # make some changes
$ kubectl replace -f tmp.yaml

Please note that the replace command is not equivalent to the apply command, even though they look very similar.

Pro-tip: Not everything can be modified on an existing Kubernetes object. Sometimes you will need to delete and recreate the object.

The next imperative way to modify an object is to use the patch command, which works like this:

$ kubectl patch deployment/www -p '{"spec": {"replicas": 2}}'
deployment.apps/www patched
$ k get pod
NAME                  READY   STATUS    RESTARTS   AGE
www-6d49b97f5-ct7cn   1/1     Running   0          82s
www-6d49b97f5-nggsm   1/1     Running   0          82s

The -p option accepts both YAML and JSON, although you will struggle to type any YAML on the command line.

Finally, you can use the set command to make direct changes to objects. This command is quite idiosyncratic, so very few people actually use it and we won’t cover it here. If you are interested in learning more, just run kubectl set --help.

Once again, we recommend that you use the declarative method via the apply -f command. It is actually simpler because you just need to edit the manifest file you used to create the objects in the first place and run the same command again:

$ kubectl apply -f MANIFEST.YAML

As you can see, this is mucher easier, less error-prone, and allows you to revision-control your code. You can apply all the manifest files in a given directory at once as well:

$ kubectl apply -f DIR

You can see that the same command, kubectl apply -f, is used both to create and update objects. Kubernetes will compute the differences between the new manifest files and the current state of the objects and will apply the differences intelligently. It should be noted that, as discussed previously, this method won’t delete objects that you removed from the manifest files.

If you used kustomization files, you should use the -k option rather than -f (and the argument must be a directory):

$ kubectl apply -k DIR
Pro-tip: Unfortunately, when making changes to role-based access control (RBAC) permissions, Kubernetes requires a bit more gymnastics. The reasons for this are complex and outside the scope of this article. Just remember to run kubectl auth reconcile -f MANIFEST.YAML before running kubectl apply -f MANIFEST.YAML whenever you make some changes to RBAC objects.

Deleting Objects

At the time of writing, the only way to delete objects is with the imperative delete command. You can still use the -f flag and pass the manifest files you used to create/update the objects in the first place, so that makes your life a bit easier:

$ kubectl delete -f MANIFEST.YAML
Pro-tip: Use the --now flag to speed up the delete command. This is especially useful when deleting pods; otherwise, it takes Kubernetes quite a while to go through the motions to actually delete the pod.

Commands for Deployments

Deployments in Kubernetes receive special treatment with some added bonuses. When you update a deployment — and the same applies to daemon sets and stateful sets — you can view the status of the update using:

$ kubectl rollout status deploy/www

If the update is still in progress, you can cancel it like so:

$ kubectl rollout undo statefulset/mydb

You can view the update history using this:

$ kubectl rollout history sts/mydb

Next, you can manually modify the number of replicas using the following imperative command:

$ kubectl scale --replicas=N deployment/www

Now, in practice, it is unlikely that you will use these commands. You will be much more likely to use a higher-level tool such as Helm to manage such deployments, and you will probably set up some sort of autoscaling for your deployments rather than manually scaling them out and in.

Debugging

In Kubernetes, things sometimes go wrong, especially during the development phase. However, problems can occur even in production, so it’s very useful to know how to debug issues in your cluster.

In many cases, it makes sense to first try to get a high-level picture of the state of various objects. You can do this using the describe command that we saw earlier. To check a pod, for example, you would run:

$ kubectl describe pod/MYPOD

You might also want to manually check what a given pod or service is serving; the port-forward command is very helpful here. For example, to access the service MYSVC running on port 80 via port 8000 of your computer, you would run the following:

$ kubectl port-forward service/MYSVC 8000:80

You could then manually run some requests to port 8000 on your local computer, for example using curl or Postman.

Next, you probably want to know what a misbehaving pod is doing, and the first port of call is to check its logs, which would be done like so:

$ kubectl logs MYPOD

You can also add the -f flag for the kubectl logs command to continuously poll the logs in real time and display them as they come:

$ kubectl logs -f MYPOD

One of the most useful debugging commands is kubectl exec, which allows you to run commands inside a suspicious pod. The drawback of this command is that the program you want to execute must exist inside the pod. Here is a typical example to start a shell to allow you to explore what’s inside the pod:

$ kubectl exec -it www-6d49b97f5-j4dlb -- /bin/sh
root@www-6d49b97f5-j4dlb:/#

If you have more than one container running inside the pod, you might need to specify which container you want to execute the command in using the -c flag:

$ kubectl exec -it www-6d49b97f5-j4dlb -c istio-proxy -- /bin/sh
istio-proxy@www-6d49b97f5-j4dlb:/$ 

Another command that is sometimes useful is kubectl cp, which allows you to copy files in and out of the pod.

Other Helpful kubectl Commands

Now let’s have a look at some helpful kubectl commands.

First of all, it’s often useful to see what containers are running in a pod. Here’s how to get a list of the names of a pod’s containers:

$ kubectl get pod www -o jsonpath='{.spec.containers[*].name}'
nginx istio-proxy

You can build some pretty complex expressions using jsonpath. Here’s an example to get the name of the image for a given container:

$ kubectl get pod www \
    -o jsonpath='{.spec.containers[?(@.name=="istio-proxy")].image}'
docker.io/istio/proxyv2:1.13.6

If your Docker images are pulled from a private registry, Kubernetes will need some credentials to connect to the registry and pull your images. Here is a quick solution suitable for a development environment (not a production one, though).

First, manually login to the Docker registry using the docker login command. Then run the following:

$ kubectl create secret generic SECRET_NAME \
    --type=kubernetes.io/dockerconfigjson \
    --from-file=.dockerconfigjson=$HOME/.docker/config.json

You will obviously need to replace the path to your Docker config.json file for your own operating system.

Possibly the most useful command of all is, of course, the “help” command:

$ kubectl --help

To get help on a specific subcommand, add -–help after the command name. For example:

$ kubectl logs --help

Kubectl’s help is quite well-written and accessible. Make it your first port of call when you have questions about kubectl.

Finally, here is a very useful command to test your RBAC rules:

$ kubectl --as=system:serviceaccount:NAMESPACE:SERVICE_ACCOUNT \
    auth can-i get secret/SECRET_NAME
yes

The example above will test whether the specified service account can get the given secret. Of course, you will need to replace the capitalized names with what is relevant for your setup.

Learn how to manage K8s costs via the Kubecost APIs

Shell Autocompletion

When typing kubectl commands all day, you will find shell autocompletion very helpful. Kubectl has a built-in mechanism for that:

$ source <(kubectl completion bash)

Please note that the above will work for your current session only. To make autocompletion permanent, you will need to add that line to your shell initialization file (such as ~/.bashrc for bash).

Kubectl has support for a number of shells, and you can get more details by consulting the Kubernetes documentation or just entering:

$ kubectl completion --help
Pro-tip: If you use bash, you will need to have the bash-completion package installed first.
Another pro-tip: Many people like to make the alias “k” for kubectl. To do so, add the following line to your ~/.bashrc (or equivalent for your system):
complete -F __start_kubectl k

Word of Advice

If you are juggling two or more clusters throughout the day, there is a very high chance that you will eventually run a kubectl command against the wrong cluster. If you find yourself with multiple clusters, I would strongly suggest that you specify the context on every command line like so:

$ kubectl --context=minikube apply -f BIG_CHANGE.YAML

Yes, it will be a chore to repeat that every time, but applying the wrong command to the wrong cluster could potentially be catastrophic.

Conclusion

Kubectl is the main and official tool to interact with a Kubernetes cluster. It is quite a complex tool, and hopefully, this cheat sheet will be useful to you in your Kubernetes journey.

There are a number of user-interface tools (as opposed to a command-line tool like kubectl), such as k9s, Kubernetes Lens, etc. Although such tools are easier to use, please keep in mind that they might not be as fully featured as kubectl.

Comprehensive Kubernetes cost monitoring & optimization

Continue reading this series