OnCallReady

Lesson 19.3 · CKA Exam Drilling · 20 min read

The speed kit: alias, $do, generators, editors, explain

In plain words

Imagine building with Lego. You could make every brick yourself from melted plastic, or you could open the box and use the ready-made bricks, snapping them together and only shaping the few special pieces. The second way isn't cheating; it's how you finish before the bell.

The speed kit is the ready-made bricks: alias k=kubectl with completion, export do="--dry-run=client -o yaml" so k create deploy api --image=nginx $do > api.yaml prints a correct skeleton, generators for most objects, k set/scale/patch for changes, kubectl explain --recursive for field names, and an editor that inserts spaces, not tabs. The rule: never write YAML from a blank file.

Two minutes of setup, then never write YAML from scratch

The problem. Typing a Deployment's YAML by hand takes five minutes and one typo loses the task. Generators (kubectl create ... $do) write it in seconds; a two-minute setup at the start of the exam pays back on every task.

What you need to know already: the speed kit and $do (15.3), imperative vs declarative (15.40), -o jsonpath / custom-columns (15.38), shell aliases and export, nano (1.5).

The shell

On an exam task host k and completion exist already. Check, and add what is missing:

candidate@cka3962:~$ alias k
alias k='kubectl'
candidate@cka3962:~$ echo "$do"

candidate@cka3962:~$ export do="--dry-run=client -o yaml"
candidate@cka3962:~$ export now="--force --grace-period=0"

For your own machines (and killer.sh, KillerCoda) the full kit, at the end of ~/.bashrc:

alias k=kubectl
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
export do="--dry-run=client -o yaml"
export now="--force --grace-period=0"
$ k delete pod web-0 $now
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "web-0" force deleted

Generate, then edit

The rule from the plan: never write a manifest from nothing. Every object with a generator starts as generated YAML:

# $do renders each object into a file; nothing is created in the cluster
$ k run web --image=nginx:1.27 --port=80 $do > web.yaml
$ k create deploy api --image=nginx:1.27 --replicas=3 $do > api.yaml
$ k create cronjob report --image=busybox:1.36 --schedule='*/10 * * * *' $do -- sh -c 'date' > cj.yaml
$ k create job once --image=busybox:1.36 $do -- sh -c 'echo hi' > job.yaml
$ k create cm app-config --from-literal=MODE=fast $do > cm.yaml
$ k create secret generic db --from-literal=password=s3cr3t $do > secret.yaml
$ k create role reader --verb=get,list --resource=pods $do > role.yaml
$ k create ingress web --class=nginx --rule="shop.lab/api*=api:80" $do > ing.yaml
$ k create pdb api --selector=app=api --min-available=2 $do > pdb.yaml
$ k create quota team --hard=pods=10,requests.cpu=2 $do > quota.yaml

k expose is the one generator that reads the cluster: it copies the selector from the object you name, so that object has to exist first, $do or not:

$ k expose deploy api --port=80 --target-port=8080 --type=NodePort $do > svc.yaml
Error from server (NotFound): deployments.apps "api" not found
$ k apply -f api.yaml
deployment.apps/api created
$ k expose deploy api --port=80 --target-port=8080 --type=NodePort $do > svc.yaml

Many tasks need no file at all - the generator IS the answer: k create role, k create rolebinding, k expose, k set image, k set resources, k scale, k autoscale, k label, k taint, k create job --from=cronjob/X. Use them straight, no YAML.

Objects without a generator - copy from the docs page instead: PersistentVolume, PersistentVolumeClaim, StorageClass, NetworkPolicy, DaemonSet (generate a Deployment and change the kind, delete replicas/strategy), HTTPRoute/Gateway, anything with affinity or probes (generate the Deployment, then add the block).

$ k create deploy node-agent --image=busybox:1.36 $do > ds.yaml
$ sed -i 's/^kind: Deployment/kind: DaemonSet/; /replicas:/d; /strategy: {}/d' ds.yaml

Changing what exists

to changeuse
imagek set image deploy/X CONTAINER=IMAGE
requests / limitsk set resources deploy/X --requests=cpu=100m --limits=memory=256Mi
envk set env deploy/X KEY=VALUE
replicask scale deploy/X --replicas=5
one field, anywherek patch (strategic merge) or --type=json with an op
several fieldsk edit - or k get -o yaml > f.yaml, edit, k apply -f
a field the API will not change (pod spec)k replace --force -f f.yaml (deletes and recreates)
# an illustration: exam-style task state (the mock tasks build it)
k edit pod web
error: pods "web" is invalid
A copy of your changes has been stored to "/tmp/kubectl-edit-2190451742.yaml"
error: Edit cancelled, no valid changes were saved.
k replace --force -f /tmp/kubectl-edit-2190451742.yaml
pod "web" deleted
pod/web replaced

Most pod fields are immutable after creation; edit refuses but saves your copy. replace --force with that file is the one-liner way out. On a Deployment you never need it - the template can change.

Editors

The exam hosts have vim and nano. YAML breaks on tabs, so either editor needs two settings:

# an illustration: exam-style task state (the mock tasks build it)
cat ~/.vimrc
set expandtab
set tabstop=2
set shiftwidth=2
cat ~/.nanorc
set tabsize 2
set tabstospaces

The vim you need, and nothing more: i insert, Esc, :wq save and quit, :q! quit without saving, dd delete a line, yy/p copy/paste a line, u undo, /text search, :set paste before pasting a block (stops auto-indent from staircasing it), V + > / < to indent a selected block, :%s/old/new/g.

(simulator) Only nano is simulated here; kubectl edit opens nano. Your vim muscle memory has to come from a real box.

For small, exact changes sed -i beats any editor - especially in manifests on a node:

# an illustration: exam-style task state (the mock tasks build it)
sudo sed -i 's#--kubeconfig=/etc/kubernetes/scheduler.config#--kubeconfig=/etc/kubernetes/scheduler.conf#' /etc/kubernetes/manifests/kube-scheduler.yaml

kubectl explain

Field names without leaving the terminal:

$ k explain pod.spec.containers.livenessProbe --recursive | head -12
KIND:       Pod
VERSION:    v1

FIELD: livenessProbe <Probe>

DESCRIPTION:
    Periodic probe of container liveness.

FIELDS:
  exec	<ExecAction>
    command	<[]string>
  failureThreshold	<integer>
  grpc	<GRPCAction>

--recursive prints the whole subtree - the shape of nodeAffinity or a CronJob's jobTemplate in one screen. Without it you get one level with descriptions and defaults (k explain job.spec.backoffLimit says 6).

Answers into files

Some tasks want a value written to a file. The output shapers:

# on a task's cluster (the mock tasks build shop)
$ k get pods -n shop -o jsonpath='{.items[*].metadata.name}'
api-5d8f9c7b6-2kq9x web-7c9d8f6b5-8xz2m
$ k get pods -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,NODE:.spec.nodeName --sort-by=.spec.nodeName
$ k top pod -n kube-system --sort-by=memory --no-headers | head -1 | awk '{print $1}'
$ k get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kubeletVersion}{"\n"}{end}'
$ k config get-contexts -o name

The speed habits, in one list

  1. The task's context/ssh line first. Always.
  2. Namespace on every command (-n NS), or k config set-context --current --namespace=NS for a task with many commands - and set it back after.
  3. Generator or $do, never a blank file.
  4. One verify command before moving on: get, describe, auth can-i, exec ... wget, cat file.

Why it helps

On the exam, typing YAML from memory is where minutes and points disappear: a wrong indent, a misspelled field, a tab. Generators remove most of that risk and many tasks need no YAML at all (create role, create rolebinding, expose, set image, autoscale). Knowing which objects have no generator (PV, PVC, StorageClass, NetworkPolicy, DaemonSet) tells you when to go to the docs instead.

The same kit makes you faster every working day: generating a Job or a debug pod in seconds, reshaping output with jsonpath and custom-columns for a quick report, fixing an immutable pod field with replace --force. And kubectl explain answers "what's the field called?" without leaving the terminal, which matters on the exam and in any restricted environment.

Commands in this lesson

sed

FAQ

Why doesn't Tab completion work after k?

Completion is registered for the word kubectl, not for your alias. Add complete -o default -F __start_kubectl k after source <(kubectl completion bash). On the exam task hosts k and its completion are already set up; on your own machines and practice environments, put both lines in ~/.bashrc.

Why is my $do variable empty after ssh?

Exported variables live in your current shell and don't travel over ssh. Each exam task host is a new shell, so run export do="--dry-run=client -o yaml" again there (and now if you use it). It takes two seconds, and echo "$do" confirms it's set.

How do I make a DaemonSet if there's no generator?

Generate a Deployment and convert it: k create deploy node-agent --image=busybox:1.36 $do > ds.yaml, then change kind: Deployment to kind: DaemonSet and delete the replicas and strategy lines (sed does it in one go). Add tolerations if it must run on tainted nodes too.

kubectl edit says the pod is invalid. Did I lose my changes?

No. When an edit touches an immutable pod field, kubectl refuses but saves your version to a file under /tmp and prints its path. Run k replace --force -f /tmp/kubectl-edit-....yaml, which deletes the pod and creates it from your file. For a Deployment you never need this; its pod template can change.

Why is --sort-by rejecting my column name?

--sort-by takes a JSONPath expression, not a column header: --sort-by=.metadata.creationTimestamp or --sort-by=.spec.nodeName. kubectl top is the exception, with --sort-by=cpu or memory. And jsonpath output has no trailing newline, so if a task wants one value per line, use a range with {"\n"} or append a newline.

In an interview Junior

How do you create a Kubernetes manifest quickly without writing it from scratch?

Never start from a blank file:

Plus the setup: alias k=kubectl, completion with complete -o default -F __start_kubectl k, and an editor that uses spaces, not tabs.

Also asked: How do you find the right field name or structure for a Kubernetes object? · A pod field you need to change is immutable. What do you do? · Why does Tab completion not work for an alias without extra setup?

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