Kubernetes DevOps Tools
Chapter 9: Kubectl Cheat Sheet
Like this article?
Subscribe to our LinkedIn newsletter to receive more educational content.
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 |
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 list 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
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
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 120m v1.23.3
minikube-m03 Ready 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
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:
...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:
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.
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
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]
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 theedit
command:
$ kubectl edit deploy/www
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
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 much 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 runkubectl auth reconcile -f MANIFEST.YAML
before runningkubectl 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
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.
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
$ 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.