🧠 Kubernetes Mastery: command and args in YAML Manifests and kubectl¶
Kubernetes empowers developers and operators to customize container behavior without modifying images. The command and args fields in Pod, Deployment, Job, or CronJob specs override the Docker image's ENTRYPOINT and CMD, respectively. This enables precise control over executables, arguments, and scripts—critical for orchestration, debugging, and workload adaptation.
This guide synthesizes foundational concepts, syntactic variations, CLI integrations, pitfalls, and practices into a logical progression: from Docker origins to advanced YAML patterns, CLI mechanics, error avoidance, and optimization. Examples draw from common images like BusyBox (ENTRYPOINT: [], CMD: ["/bin/sh"]) and Nginx/Python for contrast.
1. Foundational Concepts: Docker to Kubernetes Mapping¶
Docker images embed startup logic: - ENTRYPOINT: The fixed executable (e.g., ["/bin/sh"] in some shells). - CMD: Default arguments (e.g., empty in BusyBox, or ["nginx", "-g", "daemon off;"] in Nginx).
Kubernetes interprets these as: - command: Array overriding ENTRYPOINT (first element: executable; rest: fixed args). - args: Array overriding/appending to CMD (passed to the final executable).
Runtime Execution: <command[0]> <command[1]?> ... <args[0]> <args[1]> ...
| Kubernetes Field | Docker Equivalent | Purpose | Omission Behavior |
|---|---|---|---|
command | ENTRYPOINT | Core executable + fixed args | Inherits image's ENTRYPOINT |
args | CMD | Variable arguments | Inherits/appends to image's CMD |
🧠 Intellectual Note: Empty ENTRYPOINT (BusyBox) means args becomes the command line. Fixed ENTRYPOINT (e.g., Nginx) requires command override for replacement. Inspect via docker inspect <image> > .Config.{Entrypoint,Cmd}.
2. YAML Syntax Variations: From Simple to Complex¶
YAML supports compact arrays ([]) for brevity or expanded lists for readability. Use double quotes (") for env var expansion ($VAR); single quotes (') for literals. Multiline | folds blocks into single strings.
2.1 Basic Executable Overrides¶
For standalone binaries:
# Compact: Self-contained
command: ["sleep", "1000"]
# Expanded List: Readable
command:
- sleep
- "1000"
# CLI
--image=busybox --command -- sleep 1000
sleep 1000 (indefinite wait). Overrides fully if command specified. 2.2 Modular Split: Command + Args¶
For parameterizable runs:
command: ["sleep"]
args: ["1000"]
# Or expanded:
# command:
# - sleep
# args:
# - "1000"
# CLI
--image=busybox -- sleep 1000
args overrides (e.g., via downward API). - 🧠 Insight: Promotes reusability—image-agnostic for varying durations. 2.3 Shell Invocation: sh -c for Scripting (or if the command needs to be run in a shell)¶
Case # 1: For logic (loops, chaining), invoke the shell explicitly—especially when running multiple commands, piping, or scripts. This wraps the payload in a shell environment for features like variables, conditionals, and redirection.
# Inline Compact
command: ["sh", "-c", "echo 'Hello: $USER' && date"]
# Expanded List
command:
- sh
- -c
- echo 'Hello: $USER' && date
# Split Modular
command: ["sh", "-c"]
args: ["echo 'Hello: $USER' && date"]
# Expanded List
command:
- sh
- -c
args:
- echo 'Hello: $USER' && date
In the `ckad-job` namespace, create a cronjob named `simple-node-job` to run every `30 minutes` to list all the running processes inside a container that used `node image` (**the command needs to be run in a shell**). In Unix-based operating systems, `ps -eaf` can be use to list all the running processes.
root@student-node ~ ➜ k create cj simple-node-job -n ckad-job --schedule "*/30 * * * *" --image node -- sh -c "ps -eaf"
cronjob.batch/simple-node-job created
command:
- sh
- -c
- ps -eaf
-c flags shell to execute the next arg as a script string. && chains on success; ; always. Env vars expand unless single-quoted. - 🧠 Insight: -c transforms sh into an interpreter; omitting it treats the script as a filename (failure). 2.4 Multiline Scripts: Readability at Scale¶
For extended logic:
command:
- sh
- -c
- |
echo "Dir: $PWD"
ls -l /etc/os-release
while true; do sleep 5; echo "Loop: $USER"; done
| concatenates indented lines into one sh -c string. - 🧠 Insight: Avoids escapes; ideal for conditionals or file ops in production manifests. 2.5 Tool-Specific Patterns: e.g., Python -c¶
For interpreters:
# Split (Preferred for Flexibility)
command: ["python"]
args: ["-c", "print(f'PID: {__import__("os").getpid()}'); import time; time.sleep(60)"]
# Inline Compact
command: ["python", "-c", "print('Inline Python')"]
-c is a flag; script follows as next arg. Split isolates executable. - 🧠 Insight: Differs from shell—Python consumes -c <code> as a unit; misplacement treats code as positional arg. Tool Comparison: -c Behaviors
| Tool | -c Role | Placement Strategy | Pitfall Avoidance |
|---|---|---|---|
sh/bash | Execute next arg as shell script | command: ["sh", "-c"], args: [script] | Bundle -c in command |
python | Execute next arg as code | command: ["python"], args: ["-c", code] | Keep -c code in args |
3. CLI Integration: kubectl Overrides¶
kubectl commands use -- to delimit options from container payloads. Behavior varies: run supports --command for explicit overrides; create (job, cronjob, deployment) parses post--- as the full command array (all tokens concatenated; no separate args).
3.1 kubectl run: Dual-Mode Flexibility¶
kubectl run <name> --image=<image> [--command] -- [tokens...]
| Mode | CLI Example | YAML Mapping | Behavior |
|---|---|---|---|
| Args Only (Default) | --image=nginx -- -g "daemon off;" | args: ["-g", "daemon off;"] | Appends to image ENTRYPOINT |
| Full Command | --image=busybox --command -- sleep 10 | command: ["sleep", "10"] | Replaces entirely |
| Shell Script | --image=busybox --command -- sh -c "echo Hi && date" | command: ["sh", "-c", "echo Hi && date"] | Modular chaining |
3.2 kubectl create: Full Command Override¶
No --command flag; all post--- tokens form the command array (executable + all args bundled). This fully overrides image defaults without using args.
| Purpose | CLI Example | YAML Mapping | Behavior |
|---|---|---|---|
| Simple Command | --image=busybox -- date | command: ["date"] | Direct exec |
| With Args | --image=busybox -- sleep 10 | command: ["sleep", "10"] | All in command |
| Shell Script | --image=busybox -- sh -c "echo Hi && date" | command: ["sh", "-c", "echo Hi && date"] | Full script in command |
| Python Inline | --image=python:3.9 -- python -c "print('Hi')" | command: ["python", "-c", "print('Hi')"] | All flags/code in command |
CronJob Snippet (from Shell Example):
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-cronjob
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: busybox
image: busybox
command: ["sh", "-c", "echo 'Hello from cron' && date"] # All in command
restartPolicy: OnFailure
🧠 Insight: create bundles everything into command—lead with executable (e.g., sh/python) for scripts. For BusyBox, -- echo "Hi" yields command: ["echo", "Hi"] (direct, no shell).
4. Pitfalls: Subtle Failures and Resolutions¶
Misconfigurations often stem from quoting, placement, or defaults.
# ❌ Incorrect
command: ['sh', '-c', 'echo $PWD', 'sleep 3600']
&&, ;, or multiline string (|). | Issue | Cause | Resolution Example |
|---|---|---|
| Env Var Not Expanding | Single quotes block shell ('$ABC' prints literal) | "echo $ABC && sleep 3600" (double/no quotes) |
Multi-Token After -c Ignored | Shell takes only first string post--c | Correct: ["sh", "-c", "cmd1 && cmd2"] |
No -c for Shell | Interprets script as filename | Always: sh -c "script" |
Python -c Misplaced | Code as positional arg (unreliable) | args: ["-c", "code"] |
CLI Without -- | kubectl consumes tokens | --image=img -- cmd arg |
| BusyBox Default Misuse | Empty ENTRYPOINT + args runs shell implicitly | Explicit: -- sh -c "..." for chaining |
🧠 Insight: Test iteratively: kubectl run --rm -it for REPL-like debugging; kubectl describe pod for spec inspection.
5. Applied Examples: End-to-End Testing¶
Shell Pod (YAML + CLI)¶
apiVersion: v1
kind: Pod
metadata: { name: demo-shell }
spec:
containers:
- name: shell
image: busybox
command: ["sh", "-c", "echo 'Hello: $USER' && ls / && sleep 3600"]
kubectl run demo --image=busybox --rm --command -- sh -c "echo 'Hi' && sleep 10". Python Job (Create Command)¶
kubectl create job pyjob --image=python:3.9-slim -- python -c "print('Processed'); import time; time.sleep(5)"
command: ["python", "-c", "print('Processed'); time.sleep(5)"]. Verification: kubectl logs <pod/job-pod>—expect output; scale to CronJob for scheduling.