kubectl Commands and Kubernetes YAML Examples

kubectl applies declarative YAML, generates manifests with dry-run, patches live objects, and filters output with JSONPath and custom columns on any Kubernetes cluster.

Published

Updated

Read time 14 min read

Reviewed byDeepak Prasad

kubectl commands for dry-run, apply, patch, JSONPath and imperative YAML generation
Tested on Rocky Linux 10.2 (Red Quartz) workstation
Package kubectl 1.36.3
Applies to Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora
Kubernetes cluster
Cert prep CKA · CKAD
Lab environment Any Kubernetes cluster — install Kubernetes with kubeadm for the lab used here
Privilege Normal user (no sudo required on the workstation)
Man page kubectl command reference
Scope Imperative manifest generation, client and server dry-run, kubectl apply and patch, kubectl explain, JSONPath, custom columns, diff, scale, and label workflows. Does not cover cluster installation, RBAC design, or Helm/Kustomize project layout.
Related guides Kubernetes annotations

kubectl — quick reference

Get, describe, and output formats

List objects and shape how kubectl prints them.

When to use Command
List resources in the current or named namespace kubectl get pods / kubectl get deploy -n NAMESPACE
Show extra columns (node, IP, image) kubectl get pods -o wide
Return one field with JSONPath kubectl get pods -o jsonpath='{.items[*].metadata.name}'
Build your own table from object fields kubectl get pods -o custom-columns=NAME:.metadata.name,IP:.status.podIP
Print full API representation kubectl get deploy NAME -o yaml / -o json
Show events and conditions for one object kubectl describe pod NAME
Filter by label selector kubectl get pods -l app=web,tier=frontend

Imperative create and generate YAML

Fast exam-style object creation; pair with --dry-run=client -o yaml to capture manifests.

When to use Command
Create a Deployment from an image kubectl create deployment NAME --image=IMAGE --replicas=N
Create a ConfigMap from literals kubectl create configmap NAME --from-literal=key=value
Create a generic Secret from literals kubectl create secret generic NAME --from-literal=key=value
Expose a workload as a ClusterIP Service kubectl expose deployment NAME --port=80 --target-port=80
Run a one-off Pod (debug / throwaway) kubectl run NAME --image=IMAGE --restart=Never
Print starter YAML without persisting the object kubectl create deployment NAME --image=IMAGE --dry-run=client -o yaml

Declarative apply, diff, and replace

Manage manifests stored in Git or on disk.

When to use Command
Create or update objects from a file or stdin kubectl apply -f manifest.yaml
Validate against the API server without persisting kubectl apply -f manifest.yaml --dry-run=server
Show what would change before apply kubectl diff -f manifest.yaml
Replace an object wholesale (overwrite) kubectl replace -f manifest.yaml
Apply a directory of manifests kubectl apply -f ./manifests/
Delete objects defined in a manifest kubectl delete -f manifest.yaml

Patch, scale, and metadata

Change live objects without re-applying the full file.

When to use Command
Strategic merge patch (default for supported built-in resource types; not supported for CRDs) kubectl patch deploy NAME -p '{"spec":{"replicas":3}}'
JSON Patch (RFC 6902 operations) kubectl patch deploy NAME --type=json -p='[{"op":"replace","path":"/spec/replicas","value":3}]'
Merge patch (object fields merge; lists in the patch replace the whole list) kubectl patch deploy NAME --type=merge -p '{"spec":{"replicas":3}}'
Scale a controller kubectl scale deployment NAME --replicas=N
Change a container image kubectl set image deployment/NAME CONTAINER=IMAGE:TAG
Add or change labels kubectl label deploy NAME tier=web --overwrite
Add or change annotations kubectl annotate deploy NAME owner=team-a --overwrite

Schema discovery and dry-run modes

When to use Command
Document a resource field while writing YAML kubectl explain pod.spec.containers
Drill into nested fields kubectl explain deployment.spec.strategy --recursive
Preview the object without submitting the write request kubectl apply -f file.yaml --dry-run=client
API server admission without persistence kubectl apply -f file.yaml --dry-run=server
List API resources on the connected cluster kubectl api-resources
Print supported API versions kubectl api-versions

Context, namespace, and global flags

When to use Command
Pin a namespace for one command kubectl get pods -n kube-system
Set default namespace in kubeconfig kubectl config set-context --current --namespace=dev
Target another cluster context kubectl --context=CONTEXT get nodes
Impersonate a user or ServiceAccount kubectl --as=system:serviceaccount:ns:sa get pods
Confirm RBAC before a change kubectl auth can-i create deployments -n NAMESPACE

kubectl — command syntax

kubectl sends HTTPS requests to the Kubernetes API server using credentials from kubeconfig. Synopsis from kubectl --help on kubectl 1.36.3:

text
kubectl controls the Kubernetes cluster manager.

Basic Commands (Beginner):
  create          Create a resource from a file or from stdin
  expose          Take a replication controller, service, deployment or pod and expose it as a new Kubernetes service
  run             Run a particular image on the cluster
  set             Set specific features on objects

Basic Commands (Intermediate):
  explain         Get documentation for a resource
  get             Display one or many resources
  edit            Edit a resource on the server
  delete          Delete resources by file names, stdin, resources and names, or by resources and label selector

Deploy Commands:
  rollout         Manage the rollout of a resource
  scale           Set a new size for a deployment, replica set, or replication controller
  autoscale       Auto-scale a deployment, replica set, stateful set, or replication controller

Advanced Commands:
  diff            Diff the live version against a would-be applied version
  apply           Apply a configuration to a resource by file name or stdin
  patch           Update fields of a resource
  replace         Replace a resource by file name or stdin
  wait            Wait for a specific condition on one or many resources
  kustomize       Build a kustomization target from a directory or URL

Install kubectl and point it at a cluster before you run the examples — see install kubectl and configure kubeconfig. If commands hang against a private API address, check whether an HTTP proxy is intercepting traffic; extend NO_PROXY for cluster networks or unset proxy variables in that shell.


kubectl — command examples

Essential Generate YAML with client dry-run

Use client dry-run when you want a starter manifest that is not submitted for persistence — common in CKAD/CKA tasks where you paste YAML into an editor.

Run the command:

bash
kubectl create deployment web --image=nginx:1.27 --replicas=2 --dry-run=client -o yaml

Sample output:

output
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: nginx:1.27
        name: nginx
        resources: {}
status: {}

Save the YAML, edit fields such as resources or probes, then apply it with kubectl apply -f. Drop the status: {} line from manifests you write — Kubernetes controllers and system components populate status after the object exists; kubectl does not fill it in for you.

Essential Validate with server dry-run

Server dry-run sends the object through admission controllers and validation webhooks. Use it when client-side YAML looks fine but the API might reject it.

Run the command:

bash
kubectl apply -f - --dry-run=server <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-cm
  namespace: demo
data:
  key: value
EOF

Sample output:

output
configmap/demo-cm created (server dry run)

The (server dry run) suffix confirms nothing was persisted. Create the demo namespace first with kubectl create namespace demo if it does not exist.

Essential Inspect fields with kubectl explain

kubectl explain reads OpenAPI schema from the API server — faster than guessing field names when you write YAML. For deeper discovery of groups and versions, see Kubernetes API resources.

Run the command:

bash
kubectl explain pod.spec.containers --api-version=v1 | head -12

Sample output:

output
KIND:       Pod
VERSION:    v1

FIELD: containers <[]Container>


DESCRIPTION:
    List of containers belonging to the pod. Containers cannot currently be
    added or removed. There must be at least one container in a Pod. Cannot be
    updated.

Add --recursive on supported types to print the whole subtree, for example kubectl explain deployment.spec --recursive.

Essential Filter output with JSONPath

JSONPath pulls one or more fields from kubectl get -o json without dumping the full object — useful in scripts and quick cluster audits.

Run the command:

bash
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kubeletVersion}{"\n"}{end}'

Sample output:

output
k8s-cp	v1.36.3
worker01	v1.36.3

{range .items[*]} iterates through every node object, while {"\t"} and {"\n"} format the output into columns and rows. Use {.items[0].metadata.name} when you need a single match.

Essential Apply a Deployment from YAML

Declarative apply is the default workflow for manifests you store in Git. kubectl creates the object on first apply and patches it on later runs.

Create a lab namespace if you need one:

bash
kubectl create namespace demo

Create the manifest and apply it:

bash
kubectl apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  namespace: demo
  labels:
    app: nginx-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
      - name: nginx
        image: nginx:1.27
        ports:
        - containerPort: 80
EOF

Sample output:

output
deployment.apps/nginx-demo created

Wait until replicas are available:

bash
kubectl rollout status deployment/nginx-demo -n demo --timeout=60s

Sample output:

output
deployment "nginx-demo" successfully rolled out

created on the first apply becomes configured when you change the same manifest and apply again.

Common Build tables with custom columns

Custom columns are readable in the terminal and map cleanly to the fields you care about during rollouts.

Run the command:

bash
kubectl get pods -n demo -l app=nginx-demo -o custom-columns=NAME:.metadata.name,IP:.status.podIP,NODE:.spec.nodeName,READY:.status.containerStatuses[0].ready

Sample output:

output
NAME                          IP            NODE       READY
nginx-demo-846cc57b79-fv6cb   192.168.5.6   worker01   true
nginx-demo-846cc57b79-x79xp   192.168.5.5   worker01   true

Pods still starting may show <none> for IP and false for READY until kubelet reports the container state.

Common Patch a live Deployment

Patch when you need a one-field change and do not want to open the full YAML — exams often test strategic merge and JSON Patch syntax.

Run the strategic merge patch (default):

bash
kubectl patch deployment nginx-demo -n demo -p '{"spec":{"replicas":3}}'

Sample output:

output
deployment.apps/nginx-demo patched

Confirm the new replica count:

bash
kubectl get deployment nginx-demo -n demo -o jsonpath='{.spec.replicas}{"\n"}'

Sample output:

output
3

For explicit JSON Patch operations, add --type=json and a list of op, path, and value entries.

Common Scale, relabel, and retag imperatively

Imperative commands mutate objects in place. They are quick for labs; prefer YAML in production so changes stay reviewable.

Scale the Deployment:

bash
kubectl scale deployment nginx-demo -n demo --replicas=2

Sample output:

output
deployment.apps/nginx-demo scaled

Add a label and change the container image:

bash
kubectl label deployment nginx-demo -n demo tier=web --overwrite
bash
kubectl set image deployment/nginx-demo -n demo nginx=nginx:1.27-alpine

Sample output:

output
deployment.apps/nginx-demo labeled
deployment.apps/nginx-demo image updated

Verify labels on the controller:

bash
kubectl get deployment nginx-demo -n demo --show-labels

Sample output:

output
NAME         READY   UP-TO-DATE   AVAILABLE   AGE   LABELS
nginx-demo   2/2     2            2           54s   app=nginx-demo,tier=web

set image triggers a rolling update when the image reference changes.

Common Preview changes with kubectl diff

kubectl diff compares the live object with the version that would result if the supplied manifest were applied. Exit code 1 with a unified diff is normal when changes exist.

Run the command:

bash
kubectl diff -f /tmp/nginx-demo-diff.yaml

Sample output:

output
diff -u -N /tmp/LIVE-784548609/apps.v1.Deployment.demo.nginx-demo /tmp/MERGED-1271217826/apps.v1.Deployment.demo.nginx-demo
--- /tmp/LIVE-784548609/apps.v1.Deployment.demo.nginx-demo
+++ /tmp/MERGED-1271217826/apps.v1.Deployment.demo.nginx-demo
@@ -17,7 +17,7 @@
 spec:
   progressDeadlineSeconds: 600
-  replicas: 2
+  replicas: 5
   revisionHistoryLimit: 10

The minus and plus lines show what apply would change. Generate /tmp/nginx-demo-diff.yaml from your edited manifest or export the live object, change one field, and diff again.

Advanced Expose a Deployment as a Service

Imperative expose creates a Service that selects Pod labels from an existing controller — handy when you already have Pods running and need a ClusterIP quickly.

Run the command:

bash
kubectl expose deployment nginx-demo -n demo --port=80 --target-port=80 --name=nginx-demo

Sample output:

output
service/nginx-demo exposed

List the Service:

bash
kubectl get svc nginx-demo -n demo

Sample output:

output
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
nginx-demo   ClusterIP   10.100.130.182   <none>        80/TCP    5s

For production, check the generated Service into Git or capture a manifest with client dry-run. kubectl expose reads and reuses the Deployment selector:

bash
kubectl expose deployment nginx-demo -n demo --port=80 --target-port=80 --name=nginx-demo --dry-run=client -o yaml
Advanced Create a ConfigMap and capture YAML

Literal ConfigMaps are common for exam questions. Client dry-run prints the manifest you can paste into an editor.

Run the command:

bash
kubectl create configmap demo-cm2 -n demo --from-literal=env=prod --dry-run=client -o yaml

Sample output:

output
apiVersion: v1
data:
  env: prod
kind: ConfigMap
metadata:
  name: demo-cm2
  namespace: demo

Mount or reference this ConfigMap from a Pod env, envFrom, or volume — see the ConfigMap tutorial when you wire it into a workload.


kubectl — when to use / when not

Use kubectl when Use something else when
  • You manage objects on any Kubernetes cluster from a workstation
  • You need quick imperative commands or YAML generation for labs and exams
  • You inspect schema with kubectl explain while writing manifests
  • You apply, patch, or diff resources you store in Git
  • You install the cluster itself — install Kubernetes with kubeadm
  • You package releases with templated charts — Helm
  • You need deep API group theory without command focus — Kubernetes API resources
  • You debug running Pods — kubectl port-forward

Imperative kubectl vs declarative apply

Imperative (create, run, expose, set) Declarative (apply, Git-managed YAML)
Source of truth Last command wins; harder to audit Files in version control
Idempotency create fails if the object exists apply updates the same object safely
Exam speed Fast for one-off objects Fast when you already have a manifest
Rollback story kubectl rollout undo on supported controllers (works after imperative or declarative changes) Re-apply a known-good manifest from Git, or kubectl rollout undo to revert the live controller
Generation tip Add --dry-run=client -o yaml Add --dry-run=server before first real apply

Most teams use declarative apply in CI/CD and imperative commands for debugging. CKAD rewards knowing both.


kubectl — interview corner

What is the difference between --dry-run=client and --dry-run=server?

Client dry-run prints the object kubectl would send without submitting it. API server validation and admission do not run.

Server dry-run sends the request with a dry-run flag. The API server runs validation and admission, then discards the change. You see errors such as forbidden fields or quota violations before anything is stored.

A strong answer is:

"Client dry-run prints the object without sending the write request. Server dry-run asks the API server to validate and admit without storing — I use server dry-run before applying risky manifests."

When do you use JSONPath versus custom-columns?

Both read fields from API objects. JSONPath fits scripts and one-line extractions (-o jsonpath=...). custom-columns prints a stable human table with named headers.

JSONPath can walk arrays with {range}; custom-columns use dotted paths and display <none> for missing values.

A strong answer is:

"JSONPath for automation and single values; custom-columns when I want a readable table in the shell. Both beat grepping raw YAML."

What patch types does kubectl patch support?

Common --type values:

  • strategic (default for supported built-in resource types; not supported for CRDs) — merge lists with merge keys
  • merge — JSON merge patch (RFC 7386); object fields merge, but any list you include replaces the whole list
  • json — JSON Patch (RFC 6902) with op, path, value

Wrong patch type can replace a whole list instead of updating one entry.

A strong answer is:

"Strategic merge is the default for supported built-in resources such as Deployments and Pods; JSON Patch is useful for explicit operations on individual paths."

Why prefer kubectl apply over kubectl create for production?

kubectl create fails when the object already exists. kubectl apply records last-applied configuration and performs a three-way merge on updates, so the same file can be run repeatedly from CI.

create is still useful with --dry-run=client -o yaml to generate a first manifest.

A strong answer is:

"create is one-shot; apply is idempotent and merge-aware — production manifests should be applied from Git, not recreated."

How does kubectl explain help you write YAML?

kubectl explain queries the OpenAPI schema published by the API server. Start at the resource (pod.spec) and drill into nested fields (pod.spec.containers.resources).

--recursive prints nested fields in one pass for large types such as Pod or Deployment.

A strong answer is:

"explain shows field types, defaults, and descriptions from the live API — I use it instead of guessing YAML keys or copying outdated blog posts."

Why does kubectl diff exit with code 1 when a diff exists?

kubectl diff follows the Unix diff convention: exit code 0 means no changes, 1 means differences were printed, and higher codes mean failure.

In scripts, treat 1 as "changes detected", not necessarily an error.

A strong answer is:

"Exit 1 only means a diff was found — I still read the +/- lines, then run apply if the change is intended."


Troubleshooting

Symptom Likely cause Fix
error: the server doesn't have a resource type Wrong API version, typo, or CRD not installed kubectl api-resources | grep -i '<resource-name-or-kind>' (for example kubectl api-resources | grep -i ingress); fix apiVersion in YAML
Forbidden on apply or patch RBAC denies the verb on that resource kubectl auth can-i create deployments -n NAMESPACE; fix RoleBinding
error validating data: unknown field Field removed or renamed in current API kubectl explain RESOURCE; compare apiVersion with kubectl api-resources
AlreadyExists on create Object name taken in the namespace kubectl get the object; switch to apply or pick a new name
Empty JSONPath output Path does not exist on that object kubectl get OBJECT -o json and trace the path; watch for unset status fields on new Pods
diff shows only metadata churn Exported manifest includes resourceVersion, status, or last-applied annotation noise Strip status, metadata.resourceVersion, and managed fields before diffing

What's Next


References

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)