OnCallReady

Lesson 15.3 · Kubernetes: Architecture & Workloads · 24 min read

The speed kit, and the shape of every kubectl command

In plain words

A professional chef doesn't write out a recipe from scratch every time; they have a set of sharp knives in reach, pre-printed order tickets they just fill in, and a way to glance at the recipe book in seconds. Speed comes from tools and habits, not from rushing.

The kubectl speed kit is that: alias k=kubectl plus completion for k (completion is keyed on the command word, so the alias needs its own complete line), $do (--dry-run=client -o yaml) to generate a YAML skeleton instead of writing it, kubectl explain to look up any field in seconds, and api-resources to find short names, API groups and whether a type is namespaced. Every command then follows the same grammar: k <verb> <type> [name] [flags].

Why set up speed on day one

You will type kubectl thousands of times, and in the Kubernetes admin exam in your plan (15.1) you get 2 hours for 15-20 practical tasks. It does not test whether you know Kubernetes; it tests how fast you can make it do things. So you set up a small "speed kit" now, and every lab from here on becomes practice. This lesson also teaches the one shape almost every kubectl command has, so new commands stop looking like noise.

What you need to know already: the cluster and kubectl (15.1), aliases and type (1.9), environment variables (2.21), ~/.bashrc, heredocs and process substitution <( ) (6.8, 6.18), YAML (11.31).

The speed kit: five lines

$ alias k=kubectl
$ export do="--dry-run=client -o yaml"
$ export now="--force --grace-period=0"
$ source <(kubectl completion bash)
$ complete -o default -F __start_kubectl k

Line by line:

To make them survive new shells, append them to ~/.bashrc and run source ~/.bashrc. Check them with:

$ type k
k is aliased to `kubectl'      # (bash's own `quoting' style)
$ complete -p k
complete -o default -F __start_kubectl k

(type says what a word means to bash; complete -p k prints the completion rule for k.)

Objects, kinds and resource types

Before the grammar, three words you will see everywhere:

You will meet many kinds in this chapter. You don't need to know them yet, but so the examples below make sense:

kindin one linetaught in
Poda running container (or a few that belong together)15.14
Deployment"keep N identical pods running, and update them one by one"15.16
ReplicaSetthe helper a Deployment uses to keep the count at N15.16
StatefulSetlike a Deployment, for databases: stable names and disks15.19
DaemonSetone pod on every node15.22
Job / CronJobrun to completion / run on a schedule15.24
ConfigMap / Secretsettings and passwords handed to pods15.29, 15.33
Namespacea named folder that groups objects15.26
Servicea stable address in front of podsCh 16

The grammar

Almost every kubectl command is:

kubectl  <verb>  <type>  [<name>]  [flags]
k        get     pods    web-7d9f  -n shop -o wide

Type and name can also be written as one word, type/name, which is what kubectl itself prints. k create deployment web --image=nginx:1.27 --replicas=3 creates a Deployment called web running 3 copies of the nginx:1.27 image:

$ k create deployment web --image=nginx:1.27 --replicas=3
deployment.apps/web created
$ k get deploy web          # same as
$ k get deploy/web          # same as
$ k get deployments.apps web

deploy is a short name for deployments; .apps is its API group (below).

Several types at once, comma-separated, no spaces:

$ k get deploy,rs,pods
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   3/3     3            3           8s

NAME                             DESIRED   CURRENT   READY   AGE
replicaset.apps/web-vf2s9shm74   3         3         3       7s

NAME                       READY   STATUS    RESTARTS   AGE
pod/web-vf2s9shm74-65fv5   1/1     Running   0          7s
...

One Deployment made one ReplicaSet, which made three pods (you will read every column of these tables in 15.14 and 15.16; for now: 3/3 = 3 of 3 wanted are ready, AGE = how long ago it was created).

Types, short names, groups: api-resources

kubectl api-resources lists every resource type this API server knows:

$ k api-resources
NAME                     SHORTNAMES   APIVERSION        NAMESPACED   KIND
configmaps               cm           v1                true         ConfigMap
namespaces               ns           v1                false        Namespace
nodes                    no           v1                false        Node
pods                     po           v1                true         Pod
services                 svc          v1                true         Service
daemonsets               ds           apps/v1           true         DaemonSet
deployments              deploy       apps/v1           true         Deployment
replicasets              rs           apps/v1           true         ReplicaSet
statefulsets             sts          apps/v1           true         StatefulSet
cronjobs                 cj           batch/v1          true         CronJob
jobs                                  batch/v1          true         Job
...
columnmeans
NAMEthe resource type you type in full
SHORTNAMESthe abbreviation: po, deploy, svc, cm, ns, no, sts, ds, cj
APIVERSIONthe API group and version, written in a manifest's apiVersion: line. Core types are just v1; the rest are group/version: Deployments are apps/v1, never v1
NAMESPACEDtrue = the object lives inside a namespace. false = cluster-wide (nodes, namespaces themselves...); -n is ignored for those
KINDthe kind: you write in a manifest

An API group is just a family of related types (apps for workloads, batch for Jobs); it lets the API grow without name clashes.

$ k api-resources --namespaced=false        # only the cluster-wide types
$ k api-resources --api-group=apps          # only one group

Field docs without leaving the terminal: explain

Every object in YAML has fields (spec.replicas, spec.template...). kubectl explain prints the built-in documentation for any field path. The exam allows the official docs, but finding a field in a browser costs a minute; explain costs five seconds:

$ k explain deployment.spec.strategy
GROUP:      apps
KIND:       Deployment
VERSION:    v1

FIELD: strategy <DeploymentStrategy>

DESCRIPTION:
    The deployment strategy to use to replace existing pods with new ones.

FIELDS:
  rollingUpdate	<RollingUpdateDeployment>
    Rolling update config params. Present only if DeploymentStrategyType =
    RollingUpdate.

  type	<string>
    Type of deployment. Can be "Recreate" or "RollingUpdate". Default is
    RollingUpdate.

The path is the kind, then the fields separated by dots. The word in angle brackets tells you the YAML shape of the value:

shapein YAML
<string>, <integer>, <boolean>a single value: name: web, replicas: 3, paused: true
<Object> or a named type like <DeploymentStrategy>a nested block of more fields
<[]Container>a list (lines starting with - ) of objects
<map[string]string>free key: value pairs

-required- marks mandatory fields. --recursive prints the whole subtree as an indented outline - the fastest way to recall a deep path.

Manifests: generate them, don't write them

A manifest is a YAML file describing one or more objects - what you give to kubectl apply -f file.yaml. Every manifest has the same four top-level parts:

apiVersion: v1          # API group/version (from api-resources)
kind: Pod               # what sort of object
metadata:               # its name, labels, namespace...
  name: nginx
spec:                   # what you want it to be
  ...

Writing one from memory under time pressure is how typos happen. kubectl has generators - k run (a Pod) and k create <kind> - that build a correct object from flags. Add $do and they print YAML instead of creating anything:

$ k run nginx --image=nginx:1.27 $do
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx:1.27
    name: nginx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

k run nginx --image=nginx:1.27 = "a pod named nginx running image nginx:1.27". The generator added a label run: nginx (a name tag, 15.26), named the container after the pod, and some harmless noise (creationTimestamp: null, resources: {}, status: {}) you can leave in or delete. The generators you will use most:

k run NAME --image=IMG $do                                  # Pod
k create deployment NAME --image=IMG --replicas=3 $do       # Deployment
k create job NAME --image=IMG $do -- CMD ARGS               # Job
k create cronjob NAME --image=IMG --schedule='*/5 * * * *' $do -- CMD
k create configmap NAME --from-literal=K=V $do
k create secret generic NAME --from-literal=K=V $do
k expose deployment NAME --port=80 --target-port=8080 $do   # Service

Everything after a lone -- is the command the container runs. Then > file.yaml, edit the file, and k apply -f file.yaml.

Output formats you will use every day

-o wide                       more columns (IP and NODE for pods)
-o yaml | -o json             the full object as the API stores it
-o name                       pod/web-7d9f..., for piping into other commands
-o jsonpath='{...}'           extract single fields (15.38)
-o custom-columns=A:.x,B:.y   your own table (15.38)
--show-labels                 add a LABELS column
-l app=web                    only objects with label app=web
-A                            all namespaces (short for --all-namespaces)
-w                            keep watching and print a line on every change (Ctrl+C stops)

A mistake to make once and remember: -o yaml on a command that returns several objects gives you a wrapper, kind: List, with the objects under items:; on one named object it gives the object itself. That matters when you extract fields later (15.38).

What you can now do:

Why it helps

The Kubernetes admin exam (Ch 19) is 2 hours for 15-20 hands-on tasks, and many people fail on time, not knowledge. Generating a Deployment with k create deployment web --image=nginx --replicas=3 $do > d.yaml and editing it is minutes faster than typing YAML, and avoids indentation mistakes. At work the same kit makes you quick during incidents: k explain answers "what's the field for the readiness probe port?" without a browser, and api-resources --namespaced=false answers "why does -n not work for nodes?". Knowing that apps/v1 is the group for Deployments saves the classic "no matches for kind Deployment in version v1" error.

Commands in this lesson

alias export source type

FAQ

Why does Tab completion not work after my alias k?

Bash completion is registered per command word. source <(kubectl completion bash) registers the function __start_kubectl for kubectl only. Your alias k needs the same function registered: complete -o default -F __start_kubectl k. Put both lines, and the alias, in ~/.bashrc so new shells have them.

Is --force --grace-period=0 safe to use?

In the exam, for throwaway pods, yes, it saves waiting. In production it's dangerous: it deletes the API object immediately without confirming the container stopped, so the process may keep running on the node. For a StatefulSet pod that can mean two instances of db-0 writing the same data. Don't make $now a habit outside the exam.

How do I know the apiVersion to put in a manifest?

kubectl api-resources shows it in the APIVERSION column: core objects like Pod, Service and ConfigMap are v1; Deployments, StatefulSets and DaemonSets are apps/v1; Jobs and CronJobs are batch/v1. kubectl explain <kind> also prints the group and version. Generating YAML with $do gets it right automatically.

What does kubectl explain show that the docs don't?

The exact schema of your cluster's version, instantly: the field's type in angle brackets (<string>, <[]Container>, <map[string]string>), whether it's required, and its description. --recursive prints the whole subtree as an outline, the fastest way to recall a nested path like spec.template.spec.containers.readinessProbe.httpGet.port.

Why does -o yaml sometimes show kind: List?

When a get returns several objects, kubectl wraps them in a List with items:. On one named object you get the object itself. That changes jsonpath: {.items[*].metadata.name} for a list, {.metadata.name} for a single object. Mixing them up returns nothing, silently.

In an interview Junior

How do you create Kubernetes manifests quickly without writing YAML from scratch?

Let kubectl's generators write them, and print instead of create:

export do="--dry-run=client -o yaml"
k run nginx --image=nginx:1.27 $do > pod.yaml
k create deployment web --image=nginx:1.27 --replicas=3 $do > web.yaml
k create job pi --image=busybox:1.36 $do -- sh -c 'echo hi' > job.yaml

--dry-run=client builds the object without sending it; -o yaml prints it. Edit the file, then k apply -f web.yaml.

When a field is not covered by a flag, look it up instead of guessing: k explain deployment.spec.strategy (add --recursive for the whole subtree), and k api-resources for the short name (deploy, cm, sts), the apiVersion (apps/v1) and whether it is namespaced.

Every command has the same shape - kubectl <verb> <type> [<name>] [flags] - and the speed kit (alias k=kubectl, Tab completion for k) makes the rest fast.

Also asked: What does kubectl api-resources tell you? · How do you look up the fields of a Kubernetes object from the command line? · What are the four top-level parts of every manifest?

Practise this lesson in the terminal Free, in your browser - a real Ubuntu terminal to try it in, with missions that check your work.