Imperative Commands and Aliases
SummaryShell environment setup (aliases, bash completion, .vimrc), imperative...
Shell environment setup (aliases, bash completion, .vimrc), imperative...
Shell environment setup (aliases, bash completion, .vimrc), imperative kubectl commands for Pods, Deployments, Services, ConfigMaps, Secrets, Jobs, and CronJobs, the --dry-run=client -o yaml pattern, kubectl explain, api-resources, and context switching.
Imperative Commands and Aliases
The first two minutes of your exam should be spent setting up your shell. The remaining 118 minutes benefit from every shortcut you configure during that window.
Shell Setup: The First Two Minutes
Open your terminal and type these commands before touching a single task.
Alias: k for kubectl
alias k=kubectl
This saves 6 characters per command. Over the course of an exam with 200+ kubectl invocations, that adds up to over a thousand keystrokes. More importantly, it reduces cognitive load — k get pods reads faster than kubectl get pods.
The Dry-Run Export Variable
export do="--dry-run=client -o yaml"
This variable lets you append $do to any imperative command to generate YAML instead of creating the resource:
k run nginx --image=nginx $do > pod.yaml
That single line generates a complete Pod manifest. Without this variable, you would type --dry-run=client -o yaml every time — 27 characters that you now replace with 3.
Bash Completion
source <(kubectl completion bash)
This enables tab completion for kubectl subcommands, resource types, resource names, and flags. After running this, typing k get dep<TAB> expands to k get deployments, and typing k get pods my-<TAB> completes to the full Pod name.
To make the alias k work with bash completion:
complete -o default -F __start_kubectl k
Without this second line, tab completion works for kubectl but not for k. Run both commands.
.vimrc for YAML Editing
The exam environment uses vim as the default editor. YAML is whitespace-sensitive — a single misaligned space breaks your manifest. Configure vim to handle YAML correctly:
cat <<EOF >> ~/.vimrc
set tabstop=2
set shiftwidth=2
set expandtab
set ai
EOF
What each setting does:
tabstop=2— Displays tab characters as 2 spaces wide.shiftwidth=2— Indentation operations (>>,<<) move text by 2 spaces.expandtab— Pressing Tab inserts spaces, not a tab character. YAML does not allow tab characters.ai(auto-indent) — New lines inherit the indentation level of the previous line. When you press Enter inside a YAML block, the cursor starts at the correct indentation.
Complete Setup Block
Here is the entire setup as a single paste:
alias k=kubectl
export do="--dry-run=client -o yaml"
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
cat <<EOF >> ~/.vimrc
set tabstop=2
set shiftwidth=2
set expandtab
set ai
EOF
Memorize this block. Practice typing it until you can enter it in under 30 seconds without looking at notes.
Imperative Commands: Why They Matter
The CKAD exam does not grade your YAML. It grades whether the requested resource exists in the cluster with the correct configuration. A Pod created via kubectl run is identical to a Pod created by applying a YAML file — Kubernetes does not distinguish between them.
Writing YAML from scratch is slow and error-prone. A Pod spec has 10+ fields even for a minimal definition. An imperative command creates the same Pod in one line:
k run nginx --image=nginx --port=80
Versus writing this by hand:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
run: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
The imperative command is faster, and the declarative YAML is what you need when the task requires fields that imperative flags do not cover — like resource limits, volume mounts, or probes. The strategy: generate the scaffold imperatively, then edit the parts that need customization.
Pod Creation: kubectl run
Create a Pod with a specific image:
k run my-pod --image=nginx
Add labels:
k run my-pod --image=nginx --labels="app=web,tier=frontend"
Set resource requests and limits:
k run my-pod --image=nginx --requests="cpu=100m,memory=128Mi" --limits="cpu=200m,memory=256Mi"
Expose a container port:
k run my-pod --image=nginx --port=80
Run a Pod with a specific command:
k run my-pod --image=busybox --command -- sh -c "echo hello && sleep 3600"
Note the --command flag and -- separator. Everything after -- is the container command.
Generate YAML without creating the Pod:
k run my-pod --image=nginx --port=80 $do > my-pod.yaml
Open the file, add what you need (probes, volumes, environment variables), then apply:
k apply -f my-pod.yaml
Deployment Creation: kubectl create deployment
k create deployment my-deploy --image=nginx --replicas=3
This creates a Deployment with 3 replicas running the nginx image. The Deployment name, label selector, and Pod template are all configured automatically.
Set the container port:
k create deployment my-deploy --image=nginx --replicas=3 --port=80
Generate the YAML scaffold:
k create deployment my-deploy --image=nginx --replicas=3 $do > deploy.yaml
Common exam pattern: Create a Deployment imperatively, then edit the YAML to add resource limits, environment variables, or volume mounts before applying.
To scale an existing Deployment:
k scale deployment my-deploy --replicas=5
To update the image (rolling update):
k set image deployment/my-deploy nginx=nginx:1.25
To check rollout status:
k rollout status deployment/my-deploy
To undo the last rollout:
k rollout undo deployment/my-deploy
Service Exposure: kubectl expose
Expose a Pod:
k expose pod my-pod --port=80 --target-port=80 --name=my-svc
Expose a Deployment:
k expose deployment my-deploy --port=80 --target-port=80 --type=ClusterIP
Create a NodePort service:
k expose deployment my-deploy --port=80 --target-port=80 --type=NodePort
Generate the Service YAML:
k expose deployment my-deploy --port=80 --target-port=80 $do > svc.yaml
Key distinction: --port is the Service port (what clients connect to). --target-port is the container port (where traffic is forwarded). If they are the same, you can omit --target-port.
ConfigMap Creation: kubectl create configmap
From literal values:
k create configmap my-config --from-literal=DB_HOST=mysql --from-literal=DB_PORT=3306
From a file:
k create configmap my-config --from-file=config.properties
From an entire directory:
k create configmap my-config --from-file=./config-dir/
Generate YAML:
k create configmap my-config --from-literal=key1=value1 $do > cm.yaml
Secret Creation: kubectl create secret
Generic secret from literal values:
k create secret generic my-secret --from-literal=username=admin --from-literal=password=s3cret
From a file:
k create secret generic my-secret --from-file=ssh-key=./id_rsa
Docker registry secret:
k create secret docker-registry my-reg --docker-server=registry.example.com --docker-username=user --docker-password=pass
Generate YAML:
k create secret generic my-secret --from-literal=pass=s3cret $do > secret.yaml
Exam note: Secrets created via kubectl create secret are base64-encoded automatically. If you write YAML by hand, you must base64-encode the values yourself using echo -n 'value' | base64.
Job and CronJob Creation
Create a Job:
k create job my-job --image=busybox -- echo "processing complete"
Create a Job from an existing CronJob (useful for testing):
k create job test-run --from=cronjob/my-cronjob
This triggers an immediate run of a CronJob — valuable when you need to verify CronJob behavior without waiting for the schedule.
Create a CronJob:
k create cronjob my-cron --image=busybox --schedule="*/5 * * * *" -- echo "tick"
Generate YAML for a CronJob:
k create cronjob my-cron --image=busybox --schedule="*/5 * * * *" $do > cron.yaml
Then edit the YAML to add concurrencyPolicy, activeDeadlineSeconds, successfulJobsHistoryLimit, or other fields not available as imperative flags.
The —dry-run=client -o yaml Pattern
This is the most important pattern in the entire exam. It converts any imperative create/run command into a YAML template without creating the resource:
k run nginx --image=nginx --port=80 $do > pod.yaml
k create deployment web --image=nginx --replicas=3 $do > deploy.yaml
k create configmap app-config --from-literal=env=prod $do > cm.yaml
k create secret generic db-cred --from-literal=pass=abc $do > secret.yaml
k create job batch --image=busybox $do > job.yaml
k create cronjob report --image=busybox --schedule="0 * * * *" $do > cron.yaml
k expose pod nginx --port=80 $do > svc.yaml
The workflow for every exam task:
- Generate — Run the imperative command with
$doto produce YAML. - Edit — Open the file in vim and add fields that imperative flags do not support (probes, volumes, nodeSelector, tolerations, securityContext).
- Apply —
k apply -f file.yaml - Verify —
k get,k describe, ork logsto confirm correctness.
This workflow takes 2–3 minutes per task. Writing YAML from memory takes 5–10 minutes and introduces indentation errors.
kubectl explain: The Built-In Reference
When you forget the exact field structure for a spec, use kubectl explain:
k explain pod.spec.containers
This prints the fields available under pod.spec.containers with types and descriptions.
For a recursive view showing the entire tree:
k explain pod.spec.containers --recursive
This outputs every nested field without descriptions — useful for seeing the structure at a glance.
Practical examples:
k explain deployment.spec.strategy
k explain pod.spec.volumes.persistentVolumeClaim
k explain cronjob.spec.jobTemplate.spec.template
k explain networkpolicy.spec.ingress
kubectl explain is faster than searching the documentation website when you know the resource type but forget a field name. Use it as your first lookup method.
kubectl api-resources: Short Names
k api-resources
This lists all resource types with their short names, API group, and whether they are namespaced. The output you care about during the exam:
| Short Name | Full Name |
|---|---|
po | pods |
deploy | deployments |
svc | services |
cm | configmaps |
secret | secrets |
pvc | persistentvolumeclaims |
pv | persistentvolumes |
ns | namespaces |
no | nodes |
ing | ingresses |
netpol | networkpolicies |
sa | serviceaccounts |
cj | cronjobs |
ds | daemonsets |
sts | statefulsets |
rs | replicasets |
Use short names everywhere:
k get po
k get deploy
k get svc
k describe cm my-config
k get pvc -n storage
Context Switching
Every exam task specifies which context and namespace to use. If you solve a task in the wrong context, you get zero points for that task. Switch context at the start of every task:
kubectl config use-context <context-name>
The task provides the exact context name. Copy-paste it — do not type it by hand.
Set the default namespace for the current context:
kubectl config set-context --current --namespace=<namespace>
This means subsequent kubectl commands operate in that namespace without requiring -n <namespace> on every command. This prevents one of the most common exam mistakes: creating a resource in the default namespace instead of the specified one.
Verify your current context and namespace:
kubectl config current-context
kubectl config view --minify | grep namespace
Pattern for every task:
- Read the task — note the context name and namespace.
kubectl config use-context <context>kubectl config set-context --current --namespace=<ns>- Solve the task.
- Verify the resource is in the correct namespace:
k get <resource> -n <ns>
This five-step pattern eliminates namespace errors. It takes 10 seconds and saves the 10 minutes you would lose redoing a task in the wrong namespace.
Putting It All Together: A Sample Task
Task: Create a Pod named log-collector in namespace monitoring using the busybox:1.36 image. The Pod should run the command tail -f /var/log/app.log. Mount a volume named log-vol of type emptyDir at /var/log.
Approach:
- Switch context and namespace:
k config set-context --current --namespace=monitoring
- Generate scaffold:
k run log-collector --image=busybox:1.36 --command $do -- tail -f /var/log/app.log > log-collector.yaml
- Edit the YAML to add the volume and volume mount:
vim log-collector.yaml
Add under spec:
volumes:
- name: log-vol
emptyDir: {}
Add under spec.containers[0]:
volumeMounts:
- name: log-vol
mountPath: /var/log
- Apply:
k apply -f log-collector.yaml
- Verify:
k get pod log-collector -n monitoring
k describe pod log-collector -n monitoring | grep -A5 Mounts
Total time: under 3 minutes. The imperative command generated 80% of the YAML. You edited two blocks — volumes and volumeMounts. No indentation errors because vim is configured correctly. No namespace errors because you set the context first.
This is the speed difference that separates candidates who finish 15 tasks from those who finish 10.