Kubernetes — Production Guide

Complete Production Implementation Guide

Version: 1.30+ | Category: Orchestration | Level: All

Kubernetes is the industry-standard container orchestration platform. This guide covers everything from cluster setup to day-2 production operations — the way senior engineers actually run it.


Table of Contents

  1. Architecture Deep Dive
  2. Production Cluster Setup
  3. Workloads — Production Patterns
  4. Networking
  5. Storage
  6. RBAC & Security
  7. Autoscaling
  8. Observability
  9. Upgrade Strategy
  10. Production Gotchas
  11. Essential Commands Cheatsheet

1. Architecture Deep Dive {#architecture}

Control Plane Components

| Component | Role | Production Notes | |---|---|---| | kube-apiserver | All REST operations, auth/authz gateway | Run 3+ replicas behind a load balancer | | etcd | Distributed key-value store for all cluster state | Needs NVMe SSD, regular backups, odd number of nodes | | kube-scheduler | Assigns pods to nodes (filter + score) | Extendable with custom schedulers | | kube-controller-manager | Runs all built-in controllers (Deployment, Node, etc.) | Single leader-elected process | | cloud-controller-manager | Talks to cloud provider APIs (AWS, GCP, Azure) | Required for LoadBalancer services, node lifecycle |

Node Components

| Component | Role | |---|---| | kubelet | Node agent — talks to API server, manages containers via CRI | | kube-proxy | Maintains network rules (iptables/ipvs) for Service IPs | | Container Runtime | containerd (default), CRI-O — runs actual containers | | CNI Plugin | Handles pod networking — Cilium (recommended), Calico, Flannel |

What happens when you run kubectl apply

kubectl → kube-apiserver (authn/authz)
       → Admission Controllers (MutatingWebhook → ValidatingWebhook)
       → etcd (persisted)
       → Controller Manager (creates ReplicaSet → creates Pods)
       → Scheduler (assigns Pod.spec.nodeName)
       → kubelet on target node (pulls image, starts container via CRI)
       → CNI (sets up pod networking)
       → kube-proxy (updates iptables for Services)

2. Production Cluster Setup {#setup}

Minimum Production Requirements

| Component | Minimum | Recommended | |---|---|---| | Control plane nodes | 3 (HA) | 3 (odd number always) | | Worker nodes | 3 | Start with 3, use autoscaler | | etcd disk | 50GB SSD | NVMe, <10ms p99 latency | | Control plane CPU | 2 vCPU | 4 vCPU | | Control plane RAM | 4GB | 8GB |

kubeadm HA Cluster Init

bash
1# On first control plane node
2kubeadm init \
3 --control-plane-endpoint "k8s-lb.internal:6443" \
4 --upload-certs \
5 --pod-network-cidr=10.244.0.0/16 \
6 --service-cidr=10.96.0.0/12 \
7 --kubernetes-version=v1.30.0 \
8 --apiserver-cert-extra-sans="k8s-lb.internal,10.0.1.10"
9
10# Save the output! You need:
11# 1. kubeadm join command for control plane nodes
12# 2. kubeadm join command for worker nodes
13# 3. --certificate-key value
14
15# Setup kubeconfig
16mkdir -p $HOME/.kube
17cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
18chown $(id -u):$(id -g) $HOME/.kube/config
19
20# Install Cilium CNI (best choice for production)
21helm repo add cilium https://helm.cilium.io/
22helm install cilium cilium/cilium \
23 --version 1.15.0 \
24 --namespace kube-system \
25 --set kubeProxyReplacement=true \
26 --set k8sServiceHost="k8s-lb.internal" \
27 --set k8sServicePort=6443 \
28 --set hubble.enabled=true \
29 --set hubble.relay.enabled=true \
30 --set hubble.ui.enabled=true
31
32# Join additional control plane nodes
33kubeadm join k8s-lb.internal:6443 \
34 --token <token> \
35 --discovery-token-ca-cert-hash sha256:<hash> \
36 --control-plane \
37 --certificate-key <cert-key>
38
39# Join worker nodes
40kubeadm join k8s-lb.internal:6443 \
41 --token <token> \
42 --discovery-token-ca-cert-hash sha256:<hash>

etcd Backup (run daily via CronJob)

bash
1ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \
2 --endpoints=https://127.0.0.1:2379 \
3 --cacert=/etc/kubernetes/pki/etcd/ca.crt \
4 --cert=/etc/kubernetes/pki/etcd/server.crt \
5 --key=/etc/kubernetes/pki/etcd/server.key
6
7# Verify backup
8ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-latest.db --write-out=table

3. Workloads — Production Patterns {#workloads}

Production-Grade Deployment

yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: api-server
5 namespace: production
6 labels:
7 app: api-server
8 version: "1.2.0"
9 team: platform
10spec:
11 replicas: 3
12 revisionHistoryLimit: 5
13 selector:
14 matchLabels:
15 app: api-server
16 strategy:
17 type: RollingUpdate
18 rollingUpdate:
19 maxUnavailable: 0 # Never kill pod before replacement is ready
20 maxSurge: 1 # One extra pod during update
21 template:
22 metadata:
23 labels:
24 app: api-server
25 version: "1.2.0"
26 annotations:
27 prometheus.io/scrape: "true"
28 prometheus.io/port: "8080"
29 prometheus.io/path: "/metrics"
30 spec:
31 # Spread pods across nodes and AZs
32 topologySpreadConstraints:
33 - maxSkew: 1
34 topologyKey: kubernetes.io/hostname
35 whenUnsatisfiable: DoNotSchedule
36 labelSelector:
37 matchLabels:
38 app: api-server
39 - maxSkew: 1
40 topologyKey: topology.kubernetes.io/zone
41 whenUnsatisfiable: ScheduleAnyway
42 labelSelector:
43 matchLabels:
44 app: api-server
45
46 # Graceful shutdown
47 terminationGracePeriodSeconds: 60
48
49 # Don't run as root
50 securityContext:
51 runAsNonRoot: true
52 runAsUser: 1000
53 fsGroup: 2000
54 seccompProfile:
55 type: RuntimeDefault
56
57 containers:
58 - name: api
59 image: myregistry/api:1.2.0
60 imagePullPolicy: IfNotPresent
61 ports:
62 - name: http
63 containerPort: 8080
64 protocol: TCP
65
66 # ALWAYS set both requests and limits for memory
67 # For CPU: set requests, be careful with limits (throttling)
68 resources:
69 requests:
70 cpu: "100m"
71 memory: "256Mi"
72 limits:
73 memory: "512Mi" # No CPU limit — causes throttling
74
75 # Readiness: when to send traffic
76 readinessProbe:
77 httpGet:
78 path: /ready
79 port: 8080
80 initialDelaySeconds: 5
81 periodSeconds: 5
82 failureThreshold: 3
83 successThreshold: 1
84
85 # Liveness: when to restart
86 livenessProbe:
87 httpGet:
88 path: /healthz
89 port: 8080
90 initialDelaySeconds: 30 # After app fully starts
91 periodSeconds: 15
92 failureThreshold: 3
93 timeoutSeconds: 5
94
95 # Startup: for slow-starting apps (prevents liveness killing it)
96 startupProbe:
97 httpGet:
98 path: /healthz
99 port: 8080
100 failureThreshold: 30 # 30 * 10s = 5 min max startup
101 periodSeconds: 10
102
103 env:
104 - name: PORT
105 value: "8080"
106 - name: DB_PASSWORD
107 valueFrom:
108 secretKeyRef:
109 name: api-secrets
110 key: db-password
111 - name: POD_NAME
112 valueFrom:
113 fieldRef:
114 fieldPath: metadata.name
115 - name: POD_NAMESPACE
116 valueFrom:
117 fieldRef:
118 fieldPath: metadata.namespace
119
120 # Graceful shutdown handler
121 lifecycle:
122 preStop:
123 exec:
124 command: ["/bin/sh", "-c", "sleep 5"] # Let LB drain connections
125
126 securityContext:
127 allowPrivilegeEscalation: false
128 readOnlyRootFilesystem: true
129 capabilities:
130 drop: ["ALL"]
131
132 volumeMounts:
133 - name: tmp
134 mountPath: /tmp
135 - name: config
136 mountPath: /app/config
137 readOnly: true
138
139 volumes:
140 - name: tmp
141 emptyDir: {}
142 - name: config
143 configMap:
144 name: api-config
145
146 # Pull from private registry
147 imagePullSecrets:
148 - name: registry-credentials

PodDisruptionBudget — Protect Against Node Drains

yaml
1apiVersion: policy/v1
2kind: PodDisruptionBudget
3metadata:
4 name: api-server-pdb
5 namespace: production
6spec:
7 minAvailable: 2 # Always keep 2 pods running
8 # OR: maxUnavailable: 1
9 selector:
10 matchLabels:
11 app: api-server

HorizontalPodAutoscaler with Custom Metrics

yaml
1apiVersion: autoscaling/v2
2kind: HorizontalPodAutoscaler
3metadata:
4 name: api-server-hpa
5 namespace: production
6spec:
7 scaleTargetRef:
8 apiVersion: apps/v1
9 kind: Deployment
10 name: api-server
11 minReplicas: 3
12 maxReplicas: 50
13 metrics:
14 - type: Resource
15 resource:
16 name: cpu
17 target:
18 type: Utilization
19 averageUtilization: 70
20 - type: Resource
21 resource:
22 name: memory
23 target:
24 type: Utilization
25 averageUtilization: 80
26 - type: Pods
27 pods:
28 metric:
29 name: http_requests_per_second
30 target:
31 type: AverageValue
32 averageValue: "1000"
33 behavior:
34 scaleDown:
35 stabilizationWindowSeconds: 300 # Wait 5 min before scaling down
36 policies:
37 - type: Percent
38 value: 25
39 periodSeconds: 60
40 scaleUp:
41 stabilizationWindowSeconds: 0 # Scale up immediately
42 policies:
43 - type: Percent
44 value: 100
45 periodSeconds: 15

CronJob — Production Pattern

yaml
1apiVersion: batch/v1
2kind: CronJob
3metadata:
4 name: db-backup
5 namespace: production
6spec:
7 schedule: "0 2 * * *" # 2 AM daily
8 concurrencyPolicy: Forbid # Don't run if previous still running
9 successfulJobsHistoryLimit: 3
10 failedJobsHistoryLimit: 5
11 startingDeadlineSeconds: 3600 # Don't start if >1hr late
12 jobTemplate:
13 spec:
14 backoffLimit: 2
15 activeDeadlineSeconds: 3600 # Kill if runs >1hr
16 template:
17 spec:
18 restartPolicy: OnFailure
19 containers:
20 - name: backup
21 image: myregistry/db-backup:latest
22 resources:
23 requests:
24 cpu: "100m"
25 memory: "128Mi"
26 limits:
27 memory: "256Mi"

4. Networking {#networking}

Service Types — When to Use Each

yaml
1# ClusterIP — internal only (default, most common)
2apiVersion: v1
3kind: Service
4metadata:
5 name: api-service
6spec:
7 type: ClusterIP
8 selector:
9 app: api-server
10 ports:
11 - port: 80
12 targetPort: 8080
13
14---
15# NodePort — avoid in production, use LoadBalancer or Ingress instead
16# Range: 30000-32767
17
18---
19# LoadBalancer — creates cloud LB (AWS NLB, GCP LB, Azure LB)
20apiVersion: v1
21kind: Service
22metadata:
23 name: api-lb
24 annotations:
25 # AWS NLB instead of CLB
26 service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
27 service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
28spec:
29 type: LoadBalancer
30 selector:
31 app: api-server
32 ports:
33 - port: 443
34 targetPort: 8080

Production Ingress with TLS

yaml
1apiVersion: networking.k8s.io/v1
2kind: Ingress
3metadata:
4 name: api-ingress
5 namespace: production
6 annotations:
7 nginx.ingress.kubernetes.io/ssl-redirect: "true"
8 nginx.ingress.kubernetes.io/proxy-body-size: "10m"
9 nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
10 nginx.ingress.kubernetes.io/rate-limit: "100" # req/min per IP
11 cert-manager.io/cluster-issuer: "letsencrypt-prod"
12spec:
13 ingressClassName: nginx
14 tls:
15 - hosts:
16 - api.example.com
17 secretName: api-tls-cert
18 rules:
19 - host: api.example.com
20 http:
21 paths:
22 - path: /
23 pathType: Prefix
24 backend:
25 service:
26 name: api-service
27 port:
28 number: 80

Network Policy — Zero Trust

yaml
1# Default deny all ingress and egress
2apiVersion: networking.k8s.io/v1
3kind: NetworkPolicy
4metadata:
5 name: default-deny-all
6 namespace: production
7spec:
8 podSelector: {}
9 policyTypes:
10 - Ingress
11 - Egress
12
13---
14# Allow specific traffic
15apiVersion: networking.k8s.io/v1
16kind: NetworkPolicy
17metadata:
18 name: api-server-netpol
19 namespace: production
20spec:
21 podSelector:
22 matchLabels:
23 app: api-server
24 policyTypes:
25 - Ingress
26 - Egress
27 ingress:
28 - from:
29 - namespaceSelector:
30 matchLabels:
31 name: ingress-nginx
32 ports:
33 - protocol: TCP
34 port: 8080
35 egress:
36 - to:
37 - podSelector:
38 matchLabels:
39 app: postgres
40 ports:
41 - protocol: TCP
42 port: 5432
43 - to: [] # Allow DNS
44 ports:
45 - protocol: UDP
46 port: 53

5. Storage {#storage}

StorageClass for AWS EBS gp3

yaml
1apiVersion: storage.k8s.io/v1
2kind: StorageClass
3metadata:
4 name: gp3
5 annotations:
6 storageclass.kubernetes.io/is-default-class: "true"
7provisioner: ebs.csi.aws.com
8volumeBindingMode: WaitForFirstConsumer # Don't provision until pod scheduled
9reclaimPolicy: Retain # Don't delete PV when PVC deleted
10allowVolumeExpansion: true
11parameters:
12 type: gp3
13 iops: "3000"
14 throughput: "125"
15 encrypted: "true"

StatefulSet with Persistent Storage

yaml
1apiVersion: apps/v1
2kind: StatefulSet
3metadata:
4 name: postgres
5 namespace: production
6spec:
7 serviceName: postgres-headless
8 replicas: 3
9 selector:
10 matchLabels:
11 app: postgres
12 template:
13 metadata:
14 labels:
15 app: postgres
16 spec:
17 containers:
18 - name: postgres
19 image: postgres:16-alpine
20 ports:
21 - containerPort: 5432
22 resources:
23 requests:
24 cpu: "500m"
25 memory: "1Gi"
26 limits:
27 memory: "2Gi"
28 env:
29 - name: POSTGRES_PASSWORD
30 valueFrom:
31 secretKeyRef:
32 name: postgres-secret
33 key: password
34 - name: PGDATA
35 value: /var/lib/postgresql/data/pgdata
36 volumeMounts:
37 - name: postgres-data
38 mountPath: /var/lib/postgresql/data
39 volumeClaimTemplates:
40 - metadata:
41 name: postgres-data
42 spec:
43 accessModes: ["ReadWriteOnce"]
44 storageClassName: gp3
45 resources:
46 requests:
47 storage: 100Gi

6. RBAC & Security {#security}

Least-Privilege ServiceAccount

yaml
1# ServiceAccount
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5 name: api-server-sa
6 namespace: production
7 annotations:
8 # AWS IRSA — let pod assume IAM role without storing credentials
9 eks.amazonaws.com/role-arn: "arn:aws:iam::123456789:role/api-server-role"
10automountServiceAccountToken: false # Don't mount unless needed
11
12---
13# Role — namespace-scoped
14apiVersion: rbac.authorization.k8s.io/v1
15kind: Role
16metadata:
17 name: api-server-role
18 namespace: production
19rules:
20- apiGroups: [""]
21 resources: ["configmaps"]
22 verbs: ["get", "list", "watch"]
23- apiGroups: [""]
24 resources: ["secrets"]
25 resourceNames: ["api-secrets"] # Only this specific secret
26 verbs: ["get"]
27
28---
29# RoleBinding
30apiVersion: rbac.authorization.k8s.io/v1
31kind: RoleBinding
32metadata:
33 name: api-server-rolebinding
34 namespace: production
35subjects:
36- kind: ServiceAccount
37 name: api-server-sa
38 namespace: production
39roleRef:
40 kind: Role
41 apiGroup: rbac.authorization.k8s.io
42 name: api-server-role

OPA Gatekeeper — Enforce Policies

yaml
1# Require all pods to have resource limits
2apiVersion: constraints.gatekeeper.sh/v1beta1
3kind: K8sRequiredResources
4metadata:
5 name: require-resource-limits
6spec:
7 match:
8 kinds:
9 - apiGroups: [""]
10 kinds: ["Pod"]
11 excludedNamespaces: ["kube-system", "cert-manager", "monitoring"]
12 parameters:
13 limits: ["cpu", "memory"]
14 requests: ["cpu", "memory"]

7. Autoscaling {#autoscaling}

Karpenter — Better Than Cluster Autoscaler

yaml
1# NodePool — define what nodes Karpenter can provision
2apiVersion: karpenter.sh/v1beta1
3kind: NodePool
4metadata:
5 name: default
6spec:
7 template:
8 spec:
9 nodeClassRef:
10 name: default
11 requirements:
12 - key: karpenter.sh/capacity-type
13 operator: In
14 values: ["spot", "on-demand"]
15 - key: node.kubernetes.io/instance-type
16 operator: In
17 values: ["m5.large", "m5.xlarge", "m5.2xlarge", "m6i.large", "m6i.xlarge"]
18 - key: topology.kubernetes.io/zone
19 operator: In
20 values: ["us-east-1a", "us-east-1b", "us-east-1c"]
21 limits:
22 cpu: "1000"
23 memory: "4000Gi"
24 disruption:
25 consolidationPolicy: WhenUnderutilized
26 consolidateAfter: 30s
27 expireAfter: 720h # Rotate nodes every 30 days

Vertical Pod Autoscaler (Recommendation Mode)

yaml
1apiVersion: autoscaling.k8s.io/v1
2kind: VerticalPodAutoscaler
3metadata:
4 name: api-server-vpa
5 namespace: production
6spec:
7 targetRef:
8 apiVersion: apps/v1
9 kind: Deployment
10 name: api-server
11 updatePolicy:
12 updateMode: "Off" # Recommendation only, don't auto-apply
13 resourcePolicy:
14 containerPolicies:
15 - containerName: api
16 minAllowed:
17 cpu: "50m"
18 memory: "64Mi"
19 maxAllowed:
20 cpu: "4"
21 memory: "8Gi"

8. Observability {#observability}

Prometheus ServiceMonitor

yaml
1apiVersion: monitoring.coreos.com/v1
2kind: ServiceMonitor
3metadata:
4 name: api-server-monitor
5 namespace: monitoring
6 labels:
7 release: kube-prometheus-stack
8spec:
9 selector:
10 matchLabels:
11 app: api-server
12 namespaceSelector:
13 matchNames:
14 - production
15 endpoints:
16 - port: http
17 path: /metrics
18 interval: 15s
19 scrapeTimeout: 10s

PrometheusRule — Alerting

yaml
1apiVersion: monitoring.coreos.com/v1
2kind: PrometheusRule
3metadata:
4 name: api-server-alerts
5 namespace: monitoring
6spec:
7 groups:
8 - name: api-server
9 interval: 30s
10 rules:
11 - alert: HighErrorRate
12 expr: |
13 sum(rate(http_requests_total{job="api-server",status=~"5.."}[5m]))
14 /
15 sum(rate(http_requests_total{job="api-server"}[5m])) > 0.01
16 for: 5m
17 labels:
18 severity: critical
19 team: platform
20 annotations:
21 summary: "API error rate > 1%"
22 description: "Error rate is {{ $value | humanizePercentage }}"
23 runbook: "https://runbooks.internal/api-high-error-rate"
24
25 - alert: PodCrashLooping
26 expr: |
27 rate(kube_pod_container_status_restarts_total[15m]) * 60 * 15 > 5
28 for: 0m
29 labels:
30 severity: critical
31 annotations:
32 summary: "Pod {{ $labels.pod }} is crash looping"

9. Upgrade Strategy {#upgrades}

bash
1# Step 1: Check upgrade path (never skip minor versions)
2# 1.28 → 1.29 → 1.30 (not 1.28 → 1.30 directly)
3
4# Step 2: Update kubeadm
5apt-mark unhold kubeadm && apt-get install kubeadm=1.30.0-00 && apt-mark hold kubeadm
6
7# Step 3: Verify upgrade plan
8kubeadm upgrade plan
9
10# Step 4: Apply upgrade to control plane
11kubeadm upgrade apply v1.30.0
12
13# Step 5: Upgrade kubelet on each node (one at a time)
14kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
15apt-mark unhold kubelet kubectl && \
16 apt-get install kubelet=1.30.0-00 kubectl=1.30.0-00 && \
17 apt-mark hold kubelet kubectl
18systemctl daemon-reload && systemctl restart kubelet
19kubectl uncordon <node>
20
21# Step 6: Verify
22kubectl get nodes
23kubectl version

10. Production Gotchas {#gotchas}

| Gotcha | Impact | Fix | |---|---|---| | CPU limits cause throttling | App becomes slow under load even with spare CPU | Remove CPU limits, keep only requests | | etcd on slow disk | Slow API server, timeouts, leader elections fail | Use NVMe SSD, keep p99 latency <10ms | | Default ndots:5 | Every DNS lookup does 5 queries (slow) | Set dnsConfig.options: ndots: 2 | | No PodDisruptionBudget | Rolling restarts kill all pods of a deployment | Always create PDB for production workloads | | ImagePullPolicy Always | Pulls image on every pod start, slow and fragile | Use IfNotPresent with immutable image tags | | Running as root | Security risk, many exploits target this | Set runAsNonRoot: true, runAsUser: 1000 | | No terminationGracePeriod tuning | In-flight requests killed during shutdown | Set period > max request timeout + 5s buffer | | Default resource requests only | Node oversubscription, OOMKill storms | Set both requests AND limits for memory | | NodePort for production traffic | Bypasses ingress, no TLS, port exposure | Always use Ingress + LoadBalancer | | Secrets in environment variables | Appear in kubectl describe, logs | Use secret volumes or external secrets operator |


11. Essential Commands Cheatsheet {#cheatsheet}

bash
1# ── Cluster Info ──────────────────────────────
2kubectl cluster-info
3kubectl get nodes -o wide
4kubectl top nodes
5kubectl get events --sort-by='.lastTimestamp' -A
6
7# ── Pods ──────────────────────────────────────
8kubectl get pods -A -o wide
9kubectl describe pod <pod> -n <ns>
10kubectl logs <pod> -n <ns> --previous # Previous container logs
11kubectl logs <pod> -n <ns> -c <container> -f # Follow multi-container
12kubectl exec -it <pod> -- /bin/sh # Shell into pod
13kubectl debug <pod> -it --image=busybox # Debug without modifying pod
14kubectl top pod <pod> --containers # Per-container resource usage
15
16# ── Deployments ───────────────────────────────
17kubectl rollout status deployment/<name>
18kubectl rollout history deployment/<name>
19kubectl rollout undo deployment/<name> # Rollback
20kubectl rollout undo deployment/<name> --to-revision=2
21kubectl set image deployment/<name> <container>=<image>:<tag>
22kubectl scale deployment/<name> --replicas=5
23
24# ── Troubleshooting ───────────────────────────
25kubectl get pod <pod> -o jsonpath='{.status.containerStatuses[0].lastState.terminated.exitCode}'
26kubectl get events --field-selector involvedObject.name=<pod>
27kubectl auth can-i create pods --as=system:serviceaccount:production:api-sa
28kubectl get ep <service> # Check service endpoints
29
30# ── Resources ─────────────────────────────────
31kubectl api-resources --verbs=list -o name
32kubectl explain deployment.spec.template.spec.containers
33kubectl diff -f deployment.yaml # Diff before apply
34
35# ── Context / Namespace ───────────────────────
36kubectl config get-contexts
37kubectl config use-context <context>
38kubectl config set-context --current --namespace=production
39kubens production # If kubectx installed
40
41# ── Quick resource creation ───────────────────
42kubectl create deployment nginx --image=nginx --replicas=3 --dry-run=client -o yaml
43kubectl create service clusterip nginx --tcp=80:80 --dry-run=client -o yaml
44kubectl create secret generic mysecret --from-literal=password=secret123
45kubectl create configmap myconfig --from-file=config.yaml
46
47# ── Port forwarding ───────────────────────────
48kubectl port-forward svc/<service> 8080:80
49kubectl port-forward pod/<pod> 8080:8080
50
51# ── Useful aliases ────────────────────────────
52alias k=kubectl
53alias kgp='kubectl get pods'
54alias kgpa='kubectl get pods -A'
55alias kdp='kubectl describe pod'
56alias klogs='kubectl logs'