kubectl fluency
The imperative commands that generate most exam YAML, the output formats and jsonpath recipes that read any cluster in one line, and the shell setup that makes all of it faster.
Key ideas in this lesson · tap one for a simple explanation
What you will be able to do
- Produce a correct manifest for a Pod, Deployment, Service, ConfigMap or Secret with a kubectl generator and --dry-run=client -o yaml, and find the generator for any other kind with --help.
- Extract exactly the fields a question asks for with -o jsonpath, custom-columns, --sort-by and selectors.
- Choose between edit, apply, replace --force and delete --force based on whether the field is mutable.
Two hours, up to twenty tasks: that is six minutes per task including reading, doing and checking. The difference between passing comfortably and running out of time is almost never Kubernetes knowledge; it is how many keystrokes stand between you and a correct object. This lesson is the keystroke budget. Everything here runs on the lab exactly as written.
Shell setup: sixty seconds that pay back all exam
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
# Then the two commands you will use most:
k create deploy web --image=nginx:1.27 --replicas=2 $do > web.yaml
k delete pod stuck $nowLearn the patterns, not the commands
You do not need to memorize seventy commands. Almost every way of making or changing an object follows one of five shapes, and one sentence holds them all: run a , expose a , create everything else, set or scale to change it, and add $do to see the instead.
run always makes a Pod, so the command has no kind.
Imperative generators
The generators you will use from the first week, grouped by topic. Skim each block once and press Explain on anything new; the practice cards after them are where it sticks.
# A Pod
k run web --image=nginx:1.27 --port=80 --labels=app=web
k run once --image=busybox:1.36 --restart=Never -- sh -c 'date'
k run web2 --image=nginx:1.27 --command -- sh -c 'sleep 3600'
k run tmp --image=busybox:1.36 -it --rm --restart=Never -- sh
# A Deployment
k create deploy web --image=nginx:1.27 --replicas=3 --port=80# A Service for an existing object (--type can also be NodePort or LoadBalancer)
k expose deploy web --name=web-svc --port=80 --target-port=8080 --type=ClusterIP
# A Service on its own (the selector becomes app=web, from the name)
k create svc clusterip web --tcp=80:8080# A ConfigMap
k create cm app-cfg --from-literal=KEY=value --from-file=app.properties
k create cm app-env --from-env-file=.env
# A Secret
k create secret generic db --from-literal=password=s3cret
# A Namespace
k create ns team-a# Scale, or change the image
k scale deploy web --replicas=5
k set image deploy/web nginx=nginx:1.26
# Labels (a trailing - removes one)
k label pod web tier=frontend --overwrite
k label pod web tier-Every other kind of object has a generator too, and you will meet each one in the lesson about that object: and in Workloads, Roles and in RBAC, in Networking, in Scheduling and in Upgrades. The exam cheat sheet puts them all on one page. Until then, k create --help lists every kind it can make.
# 1. Generate a manifest without touching the cluster
k -n team-a create deploy api --image=nginx:1.27 --replicas=3 $do > api.yaml
# 2. Find the field you need to add, with the exact spelling and type
k explain deploy.spec.strategy
k explain pod.spec.containers.livenessProbe --recursive | less
k explain pod.spec.tolerations
# 3. Edit the file in vim, then apply it
k apply -f api.yaml
# Multi-resource trick: generate a pod, pipe straight into a label change, apply in one line
k run tmp --image=busybox:1.36 --restart=Never $do -- sleep 3600 | k label --local -f - tier=debug -o yaml | k apply -f -
# --help is faster than the docs for flags
k create deploy --help | less
k run --help | grep -A2 -- --commandPractice: make it from memory
0 of 10 knownRead the task, type the command without looking up, then check. Cards you miss come back at the end of the round. Your progress stays in this browser.
Card 1 of 10
A Pod named web running nginx:1.27.
Reading the cluster
k get pods -o wide # node, IP, nominated node, readiness gates
k get deploy web -o yaml # the whole object; pipe to grep or less
k get pod web -o json | less
k get pods -o name # pod/web, pod/api... handy for xargs and loops
k get pods -A # every namespace
k get pods -l app=web,tier!=cache # label selectors; also 'env in (prod,staging)'
k get pods --show-labels
k get pods --field-selector=status.phase!=Running -A
k get pods --sort-by=.metadata.creationTimestamp
k get events --sort-by=.lastTimestamp -n team-a
k get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,IP:.status.podIP
k get pods -w # watch; Ctrl+C to stop
k api-resources | grep -i policy # short names, api groups, namespaced or not
k api-versions | grep autoscaling# One field
k get deploy web -o jsonpath='{.spec.replicas}'
# A list, space separated
k get pods -o jsonpath='{.items[*].metadata.name}'
# One item per line, several fields: range ... end
k get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.nodeInfo.kubeletVersion}{"\n"}{end}'
# Filter inside a list: the address whose type is InternalIP
k get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.addresses[?(@.type=="InternalIP")].address}{"\n"}{end}'
# Filter whole items: pods on one node
k get pods -A -o jsonpath='{range .items[?(@.spec.nodeName=="cka-worker")]}{.metadata.namespace}{"/"}{.metadata.name}{"\n"}{end}'
# Container images in a Deployment, taints on nodes, the InternalIP of one node
k get deploy web -o jsonpath='{.spec.template.spec.containers[*].image}'
k get nodes -o jsonpath='{range .items[*]}{.metadata.name}{": "}{.spec.taints[*].key}{"\n"}{end}'
k get node cka-worker -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}'
# Tabular output sorted by a jsonpath (sorted on the server response, works with custom-columns)
k -n kube-system get pods --sort-by=.metadata.name -o custom-columns=POD:.metadata.name,NODE:.spec.nodeName
# When jsonpath gets ugly, yq is on the exam hosts
k get deploy web -o yaml | yq '.spec.template.spec.containers[].image'Practice: read the cluster
0 of 7 knownSame idea for reading: type the command, then check.
Card 1 of 7
Every Pod in every namespace, with the node it runs on.
Changing objects: which tool
Which fields are immutable? A Pod's image can change. Its ' names, its volumes, its nodeName, resources on a running Pod (without the in-place resize feature) and most of a Service's or a Job's spec cannot. When k edit refuses to save, it writes your version to a file under /tmp and prints the path: run k replace --force -f on that file.
Contexts and namespaces
k config get-contexts # the * marks the current one
k config use-context kind-cka
k config current-context
k config set-context --current --namespace=team-a # every later command defaults to team-a
k config view --minify # the active cluster, user and namespace only
k config view --minify -o jsonpath='{..namespace}'
# When a kubeconfig is given as a file in the task
k --kubeconfig=/root/other.kubeconfig get nodes
export KUBECONFIG=/root/other.kubeconfigIn the official docs· open on exam day too
- kubectl quick referencesearch: cheat sheet
- JSONPath supportsearch: jsonpath
- kubectl create (generated reference)search: kubectl create
- Configure access to multiple clusterssearch: configure access multiple clusters
Generate a manifest, then apply it
/tmp/cka/fluency/web.yaml: name web, namespace fd-fluency, image nginx:1.27, 2 replicas. Add the label tier=frontend to the Deployment's own metadata in that file, then create the Deployment from the file. Both the file and the live Deployment must carry the label and have 2 replicas.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-1/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-1/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-1/cleanup | bash
Node names and InternalIPs with jsonpath
kubectl get nodes command with a jsonpath expression, write the name and the InternalIP of every node in the cluster to /tmp/cka/fluency/nodes.txt. One node per line, in the form <name> <ip> separated by one space, nothing else in the file.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-2/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-2/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-2/cleanup | bash
A sorted custom-columns listing
kube-system namespace to /tmp/cka/fluency/kube-system-pods.txt. Use kubectl custom columns with exactly two columns, headed POD (the Pod name) and NODE (the node the Pod runs on), sorted by Pod name. Keep the header line.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-3/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-3/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-fluency-3/cleanup | bash
Finished this lesson?
0 of 3 tasks passed. Your readiness counts tasks, so run them before you move on.