Introduction
kubectl works well with shell pipelines because it can read manifests from standard input and emit structured output for downstream tools. Understanding stdin and pipe behavior makes cluster scripts safer and easier to debug. The most important rule is that -f - tells kubectl to read manifest content from stdin.
Reading Kubernetes Manifests from stdin
When you pass -f -, kubectl consumes YAML or JSON from the incoming stream.
cat deployment.yaml | kubectl apply -f -
A heredoc is often clearer in scripts:
1kubectl apply -f - <<'YAML'
2apiVersion: v1
3kind: ConfigMap
4metadata:
5 name: app-config
6data:
7 LOG_LEVEL: info
8YAML
This avoids temporary files and keeps generated manifests close to script logic.
Pipe Output from One Command to Another
Pipes connect command output to command input. With kubectl, common patterns are discover, filter, and act.
kubectl get pods -n demo --no-headers | awk '{print $1}'
Delete only matching pods after preview:
kubectl get pods -n demo --no-headers \
| awk '/^test-/{print $1}' \ | xargs -r -I {} kubectl delete pod -n demo {} ``` Always preview selected resources first when the final command is destructive. ## Prefer Structured Output over Table Parsing Human-readable tables are convenient but brittle in automation. Use machine-friendly formats. JSONPath example: ```bash kubectl get pods -n demo -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' ``` `jq` example: ```bash kubectl get pods -n demo -o json | jq -r '.items[].metadata.name' ``` These approaches survive formatting changes better than parsing column-aligned text. ## `kubectl exec` and stdin Flags For container execution, stdin behavior is controlled by flags: - '`-i` keeps stdin open.' - '`-t` allocates a pseudo terminal.' ```bash kubectl exec -it web-7d9f8 -- sh ``` Pipe data into a command inside a pod: ```bash echo 'hello from stdin' | kubectl exec -i web-7d9f8 -- cat ``` If interactive behavior looks broken, check whether `-t` is being used in non-interactive pipeline contexts. ## Safer Script Pattern with `pipefail` In multi-step pipelines, enable strict shell mode so upstream failures are not hidden. ```bash #!/usr/bin/env bash set -euo pipefail kubectl kustomize ./overlays/staging \ | kubectl apply -f - kubectl rollout status deployment/api -n staging ``` `set -o pipefail` ensures the script fails if manifest generation fails, even when `kubectl apply` might otherwise mask the issue. ## Debugging Broken stdin Pipelines When a piped apply fails, break the flow into inspectable steps: 1. Capture generated YAML into a temp file. 2. Validate it with `kubectl apply --dry-run=client -f file`. 3. Apply once validation succeeds. ```bash kubectl kustomize ./overlays/dev > /tmp/rendered.yaml kubectl apply --dry-run=client -f /tmp/rendered.yaml kubectl apply -f /tmp/rendered.yaml ``` This isolates whether the problem is shell quoting, generator output, or Kubernetes validation. ## Context and Namespace Discipline Pipes make commands compact, but also easier to run in the wrong cluster. Guard every automation script: ```bash kubectl config current-context kubectl config view --minify --output 'jsonpath={..namespace}' ``` Set namespace explicitly in command lines where possible. Hidden defaults are a common root cause of production mistakes. ## Common Pitfalls - Forgetting `-f -` when sending manifests through stdin. - Parsing table output in automation instead of JSON or JSONPath. - Running `xargs kubectl delete` flows without previewing selected resources. - Combining `-t` with non-interactive pipelines and getting broken stdin behavior. - Omitting context and namespace checks in reusable scripts. ## Summary - Use `kubectl apply -f -` to read manifests directly from stdin. - Combine `kubectl` with shell pipes for repeatable workflow automation. - Prefer structured output formats for robust filtering. - Use `-i` and `-t` intentionally for `kubectl exec` behavior. - Add strict shell options and validation steps for safer production scripts.