Boosting your kubectl productivity
April 2019
If you work with Kubernetes, then kubectl is probably one of your most-used tools. Whenever you spend a lot of time working with a specific tool, it is worth to get to know it very well and learn how to use it efficiently.
This article contains a series of tips and tricks to make your usage of kubectl more efficient and effective. At the same time, it aims at deepening your understanding of how various aspects of Kubernetes work.
The goal of this article is not only to make your daily work with Kubernetes more efficient but also more enjoyable!
Contents
- Introduction: what is kubectl?
- 1. Save typing with command completion
- 2. Quickly look up resource specifications
- 3. Use the custom columns output format
- 4. Switch between clusters and namespaces with ease
- 5. Save typing with auto-generated aliases
- 6. Extend kubectl with plugins
Introduction: what is kubectl?
Before learning how to use kubectl more efficiently, you should have a basic understanding of what it is and how it works.
From a user's point of view, kubectl is your cockpit to control Kubernetes. It allows you to perform every possible Kubernetes operation.
From a technical point of view, kubectl is a client for the Kubernetes API.
The Kubernetes API is an HTTP REST API. This API is the real Kubernetes user interface. Kubernetes is fully controlled through this API. This means that every Kubernetes operation is exposed as an API endpoint and can be executed by an HTTP request to this endpoint.
Consequently, the main job of kubectl is to carry out HTTP requests to the Kubernetes API:
Kubernetes is a fully resource-centred system. That means, Kubernetes maintains an internal state of resources, and all Kubernetes operations are CRUD operations on these resources. You fully control Kubernetes by manipulating these resources (and Kubernetes figures out what to do based on the current state of resources). For this reason, the Kubernetes API reference is organised as a list of resource types with their associated operations.
Let's consider an example.
Imagine you want to create a ReplicaSet resource. To do so, you would define the ReplicaSet in a file named replicaset.yaml
file, and then run the following command:
bash
kubectl create -f replicaset.yaml
Obviously, this creates your ReplicaSet in Kubernetes. But what happens behind the scenes?
Kubernetes has a create ReplicaSet operation, and like all Kubernetes operations, it is exposed as an API endpoint. The specific API endpoint for this operation is as follows:
POST /apis/apps/v1/namespaces/{namespace}/replicasets
You can find the API endpoints of all Kubernetes operations in the API reference). To make an actual request to an endpoint, you need to prepend the URL of the API server to the endpoint paths that are listed in the API reference.
Consequently, when you execute the above command, kubectl makes an HTTP POST request to the above API endpoint. The ReplicaSet definition (that you provided in the replicaset.yaml
file) is passed in the body of the request.
This is how kubectl works for all commands that interact with the Kubernetes cluster. In all these cases, kubectl simply makes HTTP requests to the appropriate Kubernetes API endpoints.
Note that it's totally possible to control Kubernetes with a tool like
curl
by manually issuing HTTP requests to the Kubernetes API. Kubectl just makes it easier for you to use the Kubernetes API.
These are the basics of what kubectl is and how it works. But there is much more about the Kubernetes API that every kubectl user should know. To this end, let's briefly dive into the Kubernetes internals.
Kubernetes internals
Kubernetes consists of a set of independent components that run as separate processes on the nodes of a cluster. Some components run on the master nodes and others run on the worker nodes, and each component has a very specific function.
These are the most important components on the master nodes:
- Storage backend: stores resource definitions (usually etcd is used)
- API server: provides Kubernetes API and manages storage backend
- Controller manager: ensures resource statuses match specifications
- Scheduler: schedules Pods to worker nodes
And this is the most important component on the worker nodes:
- Kubelet: manages execution of containers on a worker node
To see how these components work together, let's consider an example.
Assume, you just executed kubectl create -f replicaset.yaml
, upon which kubectl made an HTTP POST request to the create ReplicaSet API endpoint (passing along your ReplicaSet resource definition).
What effects causes this in the cluster? Watch it below:
- 1/7
Following
kubectl create -f replicaset.yaml
, the API server saves your ReplicaSet resource definition in the storage backend. - 2/7
This triggers the ReplicaSet controller in the controller manager, who watches for creations, updates, and deletions of ReplicaSet resources.
- 3/7
The ReplicaSet controller creates a Pod definition for each replica of the ReplicaSet (according to the Pod template in the ReplicaSet definition) and saves them in the storage backend.
- 4/7
This triggers the scheduler who watches for Pods that have not yet been assigned to a worker node.
- 5/7
The scheduler chooses a suitable worker node for each Pod and adds this information to the Pod definitions in the storage backend.
- 6/7
This triggers the kubelet on the worker node that the Pods have been scheduled to, who watches for Pods that have been scheduled to its worker node.
- 7/7
The kubelet reads the Pod definitions from the storage backend and instructs the container runtime (Docker, for example) to run the containers on the worker node.
And here follows the textual description.
The API request to the create ReplicaSet endpoint is handled by the API server. The API server authenticates the request and saves your ReplicaSet resource definition in the storage backend.
This event triggers the ReplicaSet controller, which is a sub-process of the controller manager. The ReplicaSet controller watches for creations, updates, and deletions of ReplicaSet resources in the storage backend, and gets notified by an event when this happens.
The job of the ReplicaSet controller is to make sure that the required number of replica Pods of a ReplicaSet exists. In our example, no Pods exist yet, so the ReplicaSet controller creates these Pod definitions (according to the Pod template in the ReplicaSet definition) and saves them in the storage backend.
The creation of the new Pods triggers the scheduler, who watches for Pod definitions that are not yet scheduled to a worker node. The scheduler chooses a suitable worker node for each Pod and updates the Pod definitions in the storage backend with this information.
Note that up to this point, no workload code is being run anywhere in the cluster. All that has been done so far is creating and updating resources in the storage backend on the master node.
This event triggers the kubelets who watch for Pods that are scheduled to their worker nodes. The kubelet of the worker node your ReplicaSet Pods have been scheduled to instructs the configured container runtime (which may be Docker) to download the required container images and run the containers.
At this point, finally, your ReplicaSet application is running!
The role of the Kubernetes API
As you can see from the above example, Kubernetes components (except the API server and the storage backend) work by watching for resource changes in the storage backend and manipulating resources in the storage backend.
However, these components do not access the storage backend directly, but only through the Kubernetes API.
Consider the following examples:
- The ReplicaSet controller uses the list ReplicaSets API endpoint API operation with a
watch
parameter for watching for changes to ReplicaSet resources. - The ReplicaSet controller uses the create Pod API endpoint for creating Pods.
- The scheduler uses the patch Pod API endpoint for updating Pods with the information about the selected worker node.
As you can see, this is the same API that is also used by kubectl.
This double usage of the Kubernetes API for internal components as well as for external users is a fundamental design concept of Kubernetes.
With this knowledge, you can summarise how Kubernetes works as follows:
- The storage backend stores the state (i.e. resources) of Kubernetes.
- The API server provides an interface to the storage backend in the form of the Kubernetes API.
- All other Kubernetes components and users read, watch, and manipulate the state (i.e. resources) of Kubernetes through the Kubernetes API.
Being familiar with these concepts will help you a lot to understand kubectl better and make the most use of it!
Let's now look at a series of concrete tips and tricks to help you boost your kubectl productivity.
1. Save typing with command completion
One of the most useful, but often overlooked, tricks to boost your kubectl productivity is command completion.
Command completion allows you to auto-complete individual parts of kubectl commands with the Tab key. This works for sub-commands, options, and arguments, including hard-to-type things like resource names.
Here you can see kubectl command completion in action:
Command completion is available for the Bash and Zsh shells.
The official documentation contains detailed instructions for setting up command completion, but the following sections provide a recap for you.
How command completion works
In general, command completion is a shell feature that works by the means of a completion script. A completion script is a shell script that defines the completion behaviour for a specific command. Sourcing a completion script enables completion for the corresponding command.
Kubectl can automatically generate and print out the completion scripts for Bash and Zsh with the following commands:
bash
kubectl completion bash
# or
kubectl completion zsh
In theory, sourcing the output of this command in the appropriate shell enables kubectl command completion.
However, in practice, the details differ for Bash (including a difference between Linux and macOS) and Zsh. The following sections explain all these cases:
- Set up command completion for Bash on Linux
- Set up command completion for Bash on macOS
- Set up command completion for Zsh
Bash on Linux
The completion script for Bash depends on the bash-completion project, so you have to install that first.
You can install bash-completion with various package managers. For example:
bash
sudo apt-get install bash-completion
# or
yum install bash-completion
You can test if bash-completion is correctly installed with the following command:
bash
type _init_completion
If this outputs the code of shell function, then bash-completion has been correctly installed. If the command outputs a not found
error, you have to add the following line to your ~/.bashrc
file:
bash
source /usr/share/bash-completion/bash_completion
Whether you have to add this line to your
~/.bashrc
file or not, depends on the package manager you used to install bash-completion. For APT it's necessary, for yum not.
Once bash-completion is installed, you have to set things up so that the kubectl completion script gets sourced in all your shell sessions.
One way to do this is to add the following line to your ~/.bashrc
file:
.bashrc
source <(kubectl completion bash)
Another possibility is to add the kubectl completion script to the /etc/bash_completion.d
directory (create it, if it doesn't exist):
bash
kubectl completion bash >/etc/bash_completion.d/kubectl
All completion scripts in the
/etc/bash_completion.d
directory are automatically sourced by bash-completion.
Both approaches are equivalent.
After reloading your shell, kubectl command completion should be working!
Bash on macOS
With macOS, there is a slight complication. The reason is that the default version of Bash on macOS is 3.2, which is quite outdated. The kubectl completion script unfortunately requires at least Bash 4.1 and thus doesn't work with Bash 3.2.
The reason that Apple includes an outdated version of Bash in macOS is that newer versions use the GPLv3 license, which Apple doesn't support.
That means, to use kubectl command completion on macOS, you have to install a newer version of Bash. You can even make it your new default shell, which will save you a lot of trouble of this kind in the future. It's actually not difficult, and you can find instructions in an Upgrading Bash on macOS article that I wrote previously.
Before continuing, make sure that you are now indeed using Bash 4.1 or newer (find out with bash --version
).
The completion script for Bash depends on the bash-completion project, so you have to install that first.
You can install bash-completion with Homebrew:
bash
brew install bash-completion@2
The
@2
stands for of bash-completion v2. The kubectl completion script requires bash-completion v2, and bash-completion v2 requires at least Bash 4.1. This is the reason that you can't use the kubectl completion script on Bash versions lower than 4.1.
The output of the brew install
command includes a "Caveats" section with instructions to add the following lines to your ~/.bash_profile
file:
.bash_profile
export BASH_COMPLETION_COMPAT_DIR=/usr/local/etc/bash_completion.d
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"
You have to do this in order to complete the installation of bash-completion. However, I recommend adding these lines to your ~/.bashrc
instead of ~/.bash_profile
file. This ensures that bash-completion is also available in sub-shells.
After reloading your shell, you can test if bash-completion is correctly installed with the following command:
bash
type _init_completion
If this outputs the code of a shell function, then you're all set.
Now, you have to set things up so that the kubectl completion script gets sourced in all your shell sessions.
One way to do this is to add the following line to your ~/.bashrc
file:
.bashrc
source <(kubectl completion bash)
Another possibility is to add the kubectl completion script to the /usr/local/etc/bash_completion.d
directory:
bash
kubectl completion bash >/usr/local/etc/bash_completion.d/kubectl
This only works if you installed bash-completion with Homebrew. In that case, bash-completion sources all completion scripts in this directory.
In case you also installed kubectl with Homebrew, you don't even have to do the above step, because the completion script should already have been put in the /usr/local/etc/bash_completion.d
directory by the kubectl Homebrew formula. In that case, kubectl completion should just start working automatically after installing bash-completion.
In the end, all of these approaches are equivalent.
After reloading your shell, kubectl completion should be working!
Zsh
The completion script for Zsh doesn't have any dependencies. So, all you have to do is to set things up so it gets sourced in all your shell sessions.
You can do this by adding the following line to your ~/.zshrc
file:
.zshrc
source <(kubectl completion zsh)
In case you get a command not found: compdef
error after reloading your shell, you have to enable the compdef
builtin, which you can do by adding the following to the beginning of your ~/.zshrc
file:
.zshrc
autoload -Uz compinit
compinit
2. Quickly look up resource specifications
When you create YAML resource definitions, you need to know the fields and their meanings of these resources. One location to look up this information is in the API reference, which contains the full specifications of all resources.
However, switching to a web browser each time you need to look up something is tedious. Therefore, kubectl provides the kubectl explain
command, which can print out the resource specifications of all resources right in your terminal.
The usage of kubectl explain
is as follows:
bash
kubectl explain resource[.field]...
The command outputs the specification of the requested resource or field. The information shown by kubectl explain
is identical to the information in the API reference.
Here you can see kubectl explain
in action:
By default, kubectl explain
displays only a single level of fields. You can display the entire tree of fields with the --recursive
flag:
bash
kubectl explain deployment.spec --recursive
In case you're not sure about which resource names you can use with kubectl explain
, you can display all of them with the following command:
bash
kubectl api-resources
This command displays the resource names in their plural form (e.g. deployments
instead of deployment
). It also displays the shortname (e.g. deploy
) for those resources that have one. Don't worry about these differences. All of these name variants are equivalent for kubectl. That is, you can use any of them for kubectl explain
.
For example, all of the following commands are equivalent:
bash
kubectl explain deployments.spec
# or
kubectl explain deployment.spec
# or
kubectl explain deploy.spec
3. Use the custom columns output format
The default output format of the kubectl get
command (for reading resources) is as follows:
bash
kubectl get pods
NAME READY STATUS RESTARTS AGE
engine-544b6b6467-22qr6 1/1 Running 0 78d
engine-544b6b6467-lw5t8 1/1 Running 0 78d
engine-544b6b6467-tvgmg 1/1 Running 0 78d
web-ui-6db964458-8pdw4 1/1 Running 0 78d
That's a nice human-readable format, but it contains only a limited amount of information. As you can see, just some few fields (compared to the full resource definitions) are shown for each resource.
That's where the custom columns output format comes in. It lets you freely define the columns and the data to display in them. You can choose any field of a resource to be displayed as a separate column in the output
The usage of the custom columns output option is as follows:
-o custom-columns=<header>:<jsonpath>[,<header>:<jsonpath>]...
You have to define each output column as a <header>:<jsonpath>
pair:
<header>
is the name of the column, you can choose anything you want.<jsonpath>
is an expression that selects a resource field (explained in more detail below).
Let's look at a simple example:
bash
kubectl get pods -o custom-columns='NAME:metadata.name'
NAME
engine-544b6b6467-22qr6
engine-544b6b6467-lw5t8
engine-544b6b6467-tvgmg
web-ui-6db964458-8pdw4
Here, the output consists of a single column displaying the names of all Pods.
The expression selecting the Pod names is metadata.name
. The reason for this is that the name of a Pod is defined in the name
field of the metadata
field of a Pod resource (you can look this up in the API reference or with kubectl explain pod.metadata.name
).
Now, imagine you want to add an additonal column to the output, for example, showing the node that each Pod is running on. To do so, you can just add an appropriate column specification to the custom columns option:
bash
kubectl get pods \
-o custom-columns='NAME:metadata.name,NODE:spec.nodeName'
NAME NODE
engine-544b6b6467-22qr6 ip-10-0-80-67.ec2.internal
engine-544b6b6467-lw5t8 ip-10-0-36-80.ec2.internal
engine-544b6b6467-tvgmg ip-10-0-118-34.ec2.internal
web-ui-6db964458-8pdw4 ip-10-0-118-34.ec2.internal
The expression selecting the node name is spec.nodeName
. This is because the node a Pod has been scheduled to is saved in the spec.nodeName
field of a Pod (see kubectl explain pod.spec.nodeName
).
Note that Kubernetes resource fields are case-sensitive.
You can set any field of a resource as an output column in that way. Just browse the resource specifications and try it out with any fields you like!
But first, let's have a closer look at these field selection expressions.
JSONPath expressions
The expressions for selecting resource fields are based on JSONPath.
JSONPath is a language to extract data from JSON documents (it is similar to XPath for XML). Selecting a single field is only the most basic usage of JSONPath. It has a lot of features, like list selectors, filters, and more.
However, with kubectl explain
, only a subset of the JSONPath capabilities is supported. The following summarises these supported features with example usages:
bash
# Select all elements of a list
kubectl get pods -o custom-columns='DATA:spec.containers[*].image'
# Select a specific element of a list
kubectl get pods -o custom-columns='DATA:spec.containers[0].image'
# Select those elements of a list that match a filter expression
kubectl get pods -o custom-columns='DATA:spec.containers[?(@.image!="nginx")].image'
# Select all fields under a specific location, regardless of their name
kubectl get pods -o custom-columns='DATA:metadata.*'
# Select all fields with a specific name, regardless of their location
kubectl get pods -o custom-columns='DATA:..image'
Of particular importance is the []
operator. Many fields of Kubernetes resources are lists, and this operator allows you to select items of these lists. It is often used with a wildcard as [*]
to select all items of the list.
Below you will find some examples that use this notation.
Example applications
The possibilities for using the custom columns output format are endless, as you can display any field, or combination of fields, of a resource in the output. Here are some example applications, but feel free to explore on your own and find applications that are useful to you!
Tip: if you end up using one of these a commands frequently, you can create a shell alias for it.
Display container images of Pods
bash
kubectl get pods \
-o custom-columns='NAME:metadata.name,IMAGES:spec.containers[*].image'
NAME IMAGES
engine-544b6b6467-22qr6 rabbitmq:3.7.8-management,nginx
engine-544b6b6467-lw5t8 rabbitmq:3.7.8-management,nginx
engine-544b6b6467-tvgmg rabbitmq:3.7.8-management,nginx
web-ui-6db964458-8pdw4 wordpress
This command displays the names of all the container images of each Pod.
Remember that a Pod may contain more than one container. In that case, the container images of a single Pod are displayed as a comma-separated list in the same column.
Display availability zones of nodes
bash
kubectl get nodes \
-o custom-columns='NAME:metadata.name,ZONE:metadata.labels.failure-domain\.beta\.kubernetes\.io/zone'
NAME ZONE
ip-10-0-118-34.ec2.internal us-east-1b
ip-10-0-36-80.ec2.internal us-east-1a
ip-10-0-80-67.ec2.internal us-east-1b
This command can be useful if your Kubernetes cluster is deployed on a public cloud infrastructure (such as AWS, Azure, or GCP). It displays the availability zone that each node is in.
The availability zone is a cloud concept that denotes a point of replication within a geographical region.
The availability zones for each node are obtained through the special failure-domain.beta.kubernetes.io/zone
label. If the cluster runs on a public cloud infrastructure, then this label is automatically created and its value is set to the name of the availability zone of the node.
Labels are not part of the Kubernetes resource specifications, so you can't find the above label in the API reference. However, you can see it (as well as all other labels), if you output the nodes as YAML or JSON:
bash
kubectl get nodes -o yaml
# or
kubectl get nodes -o json
This is generally a good way to discover even more information about your resources, in addition to exploring the resource specifications.
4. Switch between clusters and namespaces with ease
When kubectl has to make a request to the Kubernetes API, it reads the so-called kubeconfig file on your system to get all the connection parameters it needs to access and make a request to the API server.
The default kubeconfig file is
~/.kube/config
. This file is usually automatically created or updated by some command (for example,aws eks update-kubeconfig
orgcloud container clusters get-credentials
, if you use managed Kubernetes services).
When you work with multiple clusters, then you have connection parameters for multiple clusters configured in your kubeconfig file. This means, you need a way to tell kubectl to which of these clusters you want it to connect.
Within a cluster, you can set up multiple namespaces (a namespace is kind of "virtual" clusters within a physical cluster). Kubectl determines which namespace to use for a request from the kubeconfig file as well. So, you need a way to tell kubectl which of these namespaces you want it to use.
This section explains how this works and how you can do it effortlessly.
Note that you can also have multiple kubeconfig files by listing them in the
KUBECONFIG
environment variable. In that case, all these files will be merged into a single effective configuration at execution time. You can also overwrite the default kubeconfig file with the--kubeconfig
option for every kubectl command. See the official documentation.
Kubeconfig files
Let's see what a kubeconfig file actually contains:
As you can see, a kubeconfig file consists of a set of contexts. A context contains the following three elements:
- Cluster: URL of the API server of a cluster
- User: authentication credentials for a specific user of the cluster
- Namespace: the namespace to use when connecting to the cluster
In practice, people often use a single context per cluster in their kubeconfig file. However, you could also have multiple contexts per cluster, differing in their user or namespace. But this seems to be less common so that often there is a one-to-one mapping between clusters and contexts.
At any given time, one of these contexts is set as the current context (through a dedicated field in the kubeconfig file):
When kubectl reads a kubeconfig file, it always uses the information from the current context. Thus, in the above example, kubectl would connect to the Hare cluster.
Consequently, to switch to another cluster, you can just change the current context in the kubeconfig file:
In the above example, kubectl would now connect to the Fox cluster.
And to switch to another namespace in the same cluster, you can change the value of the namespace element of the current context:
In the above example, kubectl would now use the Prod namespace in the Fox cluster (instead of the Test namespace that was set before).
Note that kubectl also provides the
--cluster
,--user
,--namespace
, and--context
options that allow you to overwrite individual elements and the current context itself, regardless of what is set in the kubeconfig file. Seekubectl options
.
In theory, you could do these changes by manually editing the kubeconfig file. But of course this is tedious. The following sections present various tools that allow you to do these changes automatically.
Use kubectx
A very popular tool for switching between clusters and namespaces is kubectx.
This tool provides the kubectx
and kubens
commands that allow you to change the current context and namespace, respectively.
As mentioned, changing the current context means changing the cluster, if you have only a single context per cluster.
Here you can see these two commands in action:
Under the hood, these commands just edit the kubeconfig file as explained in the previous section.
To install kubectx, just follow the instructions on the GitHub page.
Both kubectx
and kubens
provide command completion through a completion script. This allows you to auto-complete the context names and namespaces so that you don't have to fully type them. You can find the instructions to set up completion on the GitHub page as well.
Another useful feature of kubectx is the interactive mode. This works in conjunction with the fzf tool, which you have to install separately (in fact, installing fzf, automatically enables kubectx interactive mode). The interactive mode allows you to select the target context or namespace through an interactive fuzzy search interface (provided by fzf).
Use shell aliases
Actually, you don't really need separate tools to change the current context and namespace, because kubectl provides commands for doing this too. In particular, the kubectl config
command provides sub-commands for editing kubeconfig files. Here are some of them:
kubectl config get-contexts
: list all contextskubectl config current-context
: get the current contextkubectl config use-context
: change the current contextkubectl config set-context
: change an element of a context
However, using these commands directly is not very convenient, because they are long to type. But what you can do is wrapping them into shell aliases that can be more easily executed.
I created a set of aliases based on these commands that provide a similar functionality as kubectx. Here you can see them in action:
Note that the aliases use fzf to provide an interactive fuzzy search interface (like the interactive mode of kubectx). That means, you need to install fzf in order to use these aliases.
Here are the definitions of the aliases:
.bashrc
# Get current context
alias krc='kubectl config current-context'
# List all contexts
alias klc='kubectl config get-contexts -o name | sed "s/^/ /;\|^ $(krc)$|s/ /*/"'
# Change current context
alias kcc='kubectl config use-context "$(klc | fzf -e | sed "s/^..//")"'
# Get current namespace
alias krn='kubectl config get-contexts --no-headers "$(krc)" | awk "{print \$5}" | sed "s/^$/default/"'
# List all namespaces
alias kln='kubectl get -o name ns | sed "s|^.*/| |;\|^ $(krn)$|s/ /*/"'
# Change current namespace
alias kcn='kubectl config set-context --current --namespace "$(kln | fzf -e | sed "s/^..//")"'
To install these aliases, you just have to add the above definitions to your ~/.bashrc
or ~/.zshrc
file and reload your shell!
Use plugins
Kubectl allows installing plugins that can be invoked like native commands. You can, for example, install a plugin named kubectl-foo and then invoke it as kubectl foo
.
Kubectl plugins will be described in detail in a later section of this article.
Wouldn't it be nice to be able to change the current context and namespace like that? For example, running kubectl ctx
to change the context and kubectl ns
to change the namespace?
I created two plugins that allow to do that:
Internally, the plugins build on the aliases from the previous section.
Here you can see the plugins in action:
Note that the plugins use fzf to provide an interactive fuzzy search interface. That means, you need to install fzf in order to use these plugins.
To install the plugins, you just have to download the shell scripts named kubectl-ctx
and kubectl-ns
to any directory in your PATH
and make them executable (for example, with chmod +x
). That's it! Immediately after that, you should be able to use kubectl ctx
and kubectl ns
!
5. Save typing with auto-generated aliases
Shell aliases are generally a good way to save typing. The kubectl-aliases project takes this idea to heart and provides about 800 aliases for common kubectl commands.
You might wonder how you could possibly remember 800 aliases? Actually, you don't need to remember them, because they are all generated according to a simple scheme, which is shown below together with some example aliases:
Try to hover over the example aliases for a visual effect.
-
base
- kubectl
- kubectl
-
System
- -n kube-system
- -n kube-system
-
Operation
- get
- describe
- rm (delete)
- logs -f
- exec -it
- apply -f
-
Resource
- pods
- deployment
- secret
- ingress
- node
- svc (service)
- ns (namespace)
- cm (configmap)
-
Options
- oyaml: -o yaml
- ojson: -o json
- owide: -o wide
- all: --all-namespaces
- w: --watch
- sl: --show-labels
- f: -f
- l: -l
As you can see, the aliases consist of components, each standing for a specific element of a kubectl command. Each alias can have one component for the base command, operation, and resource, and multiple components for the options, and you just "fill in" these components from left to right according to the above scheme.
Please note that the current and fully detailed scheme is on the GitHub page. There you can also find the full list of aliases.
For example, the alias kgpooyamlall
stands for the command kubectl get pods -o yaml --all-namespaces
:
Note that the relative order of most option components doesn't matter. So, kgpooyamlall
is equivalent to kgpoalloyaml
.
You don't need to use all the components for an alias. For example, k
, kg
, klo
, ksys
, or kgpo
are valid aliases too. Furthermore, you can combine aliases with other words on the command-line.
For example, you could use k proxy
for running kubectl proxy
:
Or you could use kg roles
for running kubectl get roles
(there doesn't currently exist an alias component for the Roles resource):
To get a specific Pod, you could use kgpo my-pod
for running kubectl get pod my-pod
:
Note that some aliases even require a further argument on the command-line. For example, the kgpol
alias stands for kubectl get pods -l
. The -l
option requires an argument (a label specification). So, you have to use this alias, for example, like this:
For that reason, you can use the
a
,f
, andl
components only at the end of an alias.
In general, once you get the hang of this scheme, you can intuitively deduce the alias names from the commands you want to execute and save a lot of typing!
Installation
To install kubectl-aliases, you just have to download the .kubectl-aliases
file from GitHub and source it in your ~/.bashrc
or ~/.zshrc
file:
.bashrc
source ~/.kubectl_aliases
That's it! After reloading your shell, you should be able to use all the 800 kubectl aliases!
Completion
As you have seen, you often append further words to an alias on the command-line. For example:
bash
kgpooyaml test-pod-d4b77b989
If you use kubectl command completion, then you're probably used to auto-complete things like resource names. But can you still do that when you use the aliases?
That's an important question because if it wouldn't work, that would undo some of the benefits of these aliases!
The answer depends on which shell you use.
For Zsh, completion works out-of-the-box for aliases.
For Bash, unfortunately, completion doesn't work by default for aliases. The good news is that it can be made working with some extra steps. The next section explains how to do this.
Enable completion for aliases in Bash
The problem with Bash is that it attempts completion (whenever you press Tab) on the alias name, instead of on the aliased command (like Zsh). Since you don't have a completion script for all the 800 aliases, this doesn't work.
The complete-alias project provides a general solution to this problem. It taps into the completion mechanism for an alias, internally expands the alias to the aliased command, and returns the completion suggestion for the expanded command. This means, it makes completion for an alias behave exactly the same as for the aliased command.
In the following, I will first explain how to install complete-alias, and then how to configure it to enable completion for all of the kubectl aliases.
Install complete-alias
First of all, complete-alias depends on bash-completion. So you need to ensure that bash-completion is installed before installing complete-alias. Instructions for this have been given earlier for Linux and macOS.
Important note for macOS users: like the kubectl completion script, complete-alias does not work with Bash 3.2, which is the default version of Bash on macOS. In particular, complete-alias depends on bash-completion v2 (
brew install bash-completion@2
), which requires at least Bash 4.1. That means, to use complete-alias on macOS, you need to install a newer version of Bash.
To install complete-alias, you just have to download the bash_completion.sh
script from the GitHub repository, and source it in your ~/.bashrc
file:
.bashrc
source ~/bash_completion.sh
After reloading your shell, complete-alias should be correctly installed.
Enable completion for kubectl aliases
Technically, complete-alias provides the _complete_alias
shell function. This function inspects an alias and returns the completion suggestions for the aliased command.
To hook this up with a specific alias, you have to use the complete
Bash builtin to set _complete_alias
as the completion function of the alias.
As an example, let's take the k
alias that stands for the kubectl
command. To set _complete_alias
as the completion function for this alias, you have to execute the following command:
bash
complete -F _complete_alias k
The effect of this is that whenever you auto-complete on the k
alias, the _complete_alias
function is invoked, which inspects the alias and returns the completion suggestions for the kubectl
command.
As another example, let's take the kg
alias that stands for kubectl get
:
bash
complete -F _complete_alias kg
Similarly, the effect of this is that when you auto-complete on kg
, you get the same completion suggestions that you would get for kubectl get
.
Note that can use complete-alias in this way for any alias on your system.
Consequently, to enable completion for all the kubectl aliases, you just have to run the above command for each of them. The following snippet does exactly that (assuming you installed kubectl-aliases to ~/.kubectl-aliases
):
.bashrc
for _a in $(sed '/^alias /!d;s/^alias //;s/=.*$//' ~/.kubectl_aliases); do
complete -F _complete_alias "$_a"
done
Just add this snippet to your ~/.bashrc
file, reload your shell, and now you should be able to use completion for all the 800 kubectl aliases!
6. Extend kubectl with plugins
Since version 1.12, kubectl includes a plugin mechanism that allows you to extend kubectl with custom commands.
Here is an example of a kubectl plugin that can be invoked as kubectl hello
:
In case you're familiar with it, the kubectl plugin mechanisms closely follows the design of the Git plugin mechanism.
This section will show you how to install plugins, where you can find existing plugins, and how to create your own plugins.
Installing plugins
Kubectl plugins are distributed as simple executable files with a name of the form kubectl-x
. The prefix kubectl-
is mandatory, and what follows is the new kubectl sub-command that allows invoking the plugin.
For example, the hello plugin shown above would be distributed as a file named kubectl-hello
.
To install a plugin, you just have to copy the kubectl-x
file to any directory in your PATH
and make it executable (for example, with chmod +x
). Immediately after that, you can invoke the plugin with kubectl x
.
You can use the following command to list all the plugins that are currently installed on your system:
bash
kubectl plugin list
This command also displays warnings if you have multiple plugins with the same name, or if there is a plugin file that is not executable.
Finding and installing plugins with krew
Kubectl plugins lend themselves to be shared and reused like software packages. But where can you find plugins that were shared by others?
The krew) project aims at providing a unified solution for sharing, finding, installing, and managing kubectl plugins. The project refers to itself as a "package manager for kubectl plugins" (the name krew is a hint at brew).
Krew is centred around an index of kubectl plugins from which you can choose and install. Here you can see krew in action:
As you can see, krew itself is a kubectl plugin. That means, installing krew works in essence like installing any other kubectl plugin. You can find the detailed installation instructions for krew on the GitHub page.
The most important krew commands are as follows:
bash
# Search the krew index (with an optional search query)
kubectl krew search [<query>]
# Display information about a plugin
kubectl krew info <plugin>
# Install a plugin
kubectl krew install <plugin>
# Upgrade all plugins to the newest versions
kubectl krew upgrade
# List all plugins that have been installed with krew
kubectl krew list
# Uninstall a plugin
kubectl krew remove <plugin>
Note that installing plugins with krew does not prevent installing plugins the traditional way. Even if you use krew, you can still install plugins that you find elsewhere (or create yourself) by other means.
Note that the
kubectl krew list
command does only list the plugins that have been installed with krew, whereas thekubectl plugin list
command lists all plugins, that is, those installed with krew and those installed in other ways.
Creating your own plugins
Of course, you can create your own kubectl plugins, and it is very easy to do so.
You just have to create an executable file that does what you want, give it a name of the form kubectl-x
, and then install it as described above.
The executable can be of any type, a Bash script, a compiled Go program, a Python script, it really doesn't matter. The only requirement is that it can be directly executed by the operating system.
Let's create an example plugin right now. In a previous section, you used a kubectl command to list the container images of each pod. You can easily turn this command into a plugin that you can invoke with, say, kubectl img
.
To do so, just create a file named kubectl-img
with the following content:
kubectl-img
#!/bin/bash
kubectl get pods -o custom-columns='NAME:metadata.name,IMAGES:spec.containers[*].image'
Now make the file executable with chmod +x kubectl-img
and move it to any directory in your PATH
. Immediately after that, you can start using the plugin with kubectl img
!
As mentioned, kubectl plugins can be written in any programming or scripting language. If you use shell scripts, you have the advantage that you can easily invoke kubectl from the plugin. However, you can write more sophisticated plugins with real programming languages, for example, using a Kubernetes client library. If you use Go, you can also use the cli-runtime library, which exists specifically for writing kubectl plugins.
Sharing your plugins
If you think that one of your plugins might be useful for others, feel free to share it on GitHub. Make sure to add it to the kubectl-plugins topic, so that others can find it.
You can also request to add your plugin to the krew index. You can find the instructions for how to do this in the krew GitHub repository.
Command completion
At the moment, the plugin mechanism unfortunately doesn't yet support command completion. This means that you need to fully type the plugin names, as well as any arguments for the plugins.
However, there is an open feature request for this in the kubectl GitHub repository. So, it is possible that this feature will be implemented sometime in the future.
That's all folks!
If you enjoyed this article, you might find the following articles interesting:
- How to practice chaos engineering and reduce costs with Kubernetes and spot instances.
- Scaling Microservices with Message Queues, Spring Boot and Kubernetes. Learn how to use the Horizontal Pod Autoscaler to resize your fleet of applications dynamically.