| name | kubernetes-helm |
| description | Deploy and manage Kubernetes applications with Helm charts. Covers K8s manifests, kubectl, Kustomize, RBAC, and container orchestration. Use for container deployments, microservices, and cloud-native applications. |
Kubernetes & Helm Skill
Expert guidance for Kubernetes container orchestration and Helm package management.
Table of Contents
Quick Reference
Essential kubectl Commands
| Command | Description |
|---|
kubectl get pods -A | List all pods in all namespaces |
kubectl get deploy,svc,ing | List deployments, services, ingresses |
kubectl describe pod <name> | Show detailed pod information |
kubectl logs <pod> -f | Stream pod logs |
kubectl logs <pod> -c <container> | Logs from specific container |
kubectl exec -it <pod> -- /bin/sh | Interactive shell in pod |
kubectl port-forward <pod> 8080:80 | Forward local port to pod |
kubectl apply -f manifest.yaml | Apply configuration |
kubectl delete -f manifest.yaml | Delete resources from file |
kubectl rollout status deploy/<name> | Watch deployment rollout |
kubectl rollout undo deploy/<name> | Rollback deployment |
kubectl top pods | Show pod resource usage |
kubectl get events --sort-by='.lastTimestamp' | Recent cluster events |
Essential Helm Commands
| Command | Description |
|---|
helm install <release> <chart> | Install a chart |
helm upgrade <release> <chart> | Upgrade a release |
helm upgrade --install <release> <chart> | Install or upgrade |
helm list -A | List all releases |
helm status <release> | Show release status |
helm history <release> | Show release history |
helm rollback <release> <revision> | Rollback to revision |
helm uninstall <release> | Uninstall a release |
helm template <chart> | Render templates locally |
helm show values <chart> | Show chart's default values |
helm dependency update | Update chart dependencies |
helm repo add <name> <url> | Add chart repository |
helm search repo <keyword> | Search repositories |
Kubernetes Core Concepts
Pod
The smallest deployable unit in Kubernetes.
apiVersion: v1
kind: Pod
metadata:
name: app-pod
labels:
app: myapp
version: v1
spec:
containers:
- name: app
image: myapp:1.0.0
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: log-level
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
Deployment
Manages ReplicaSets and provides declarative updates for Pods.
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 3
revisionHistoryLimit: 5
selector:
matchLabels:
app: myapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: myapp
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
serviceAccountName: myapp-sa
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: app
image: myapp:1.0.0
imagePullPolicy: IfNotPresent
{}
Service
Exposes pods as a network service.
apiVersion: v1
kind: Service
metadata:
name: myapp
labels:
app: myapp
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
selector:
app: myapp
---
apiVersion: v1
kind: Service
metadata:
name: myapp-lb
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8080
selector:
app: myapp
---
apiVersion: v1
kind:
ConfigMap
Stores non-confidential configuration data.
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
data:
LOG_LEVEL: "info"
FEATURE_FLAG: "true"
MAX_CONNECTIONS: "100"
app.properties: |
server.port=8080
server.timeout=30s
database.pool.size=10
nginx.conf: |
server {
listen 80;
location / {
proxy_pass http://localhost:8080;
}
}
Using ConfigMaps:
envFrom:
- configMapRef:
name: myapp-config
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: myapp-config
key: LOG_LEVEL
volumes:
- name: config
configMap:
name: myapp-config
items:
- key: app.properties
path: application.properties
Secret
Stores sensitive data like passwords, tokens, and keys.
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
type: Opaque
data:
database-password: cGFzc3dvcmQxMjM=
api-key: c2VjcmV0LWFwaS1rZXk=
stringData:
connection-string: "Server=db;Database=myapp;User=admin;Password=secret"
---
apiVersion: v1
kind: Secret
metadata:
name: registry-credentials
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config>
---
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-cert>
tls.key: <base64-encoded-key>
Creating secrets via kubectl:
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password=secret123
kubectl create secret generic tls-secret \
--from-file=tls.crt=./cert.pem \
--from-file=tls.key=./key.pem
kubectl create secret docker-registry regcred \
--docker-server=https://index.docker.io/v1/ \
--docker-username=user \
--docker-password=password
Namespace
Provides scope for names and resource isolation.
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
env: production
team: platform
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "100"
services: "20"
persistentvolumeclaims: "20"
---
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- type: Container
default:
Helm Charts
Chart Structure
mychart/
├── Chart.yaml # Chart metadata
├── Chart.lock # Dependency lock file
├── values.yaml # Default configuration values
├── values.schema.json # JSON schema for values validation
├── .helmignore # Files to ignore when packaging
├── templates/ # Template files
│ ├── NOTES.txt # Post-install notes
│ ├── _helpers.tpl # Template helpers
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ └── tests/
│ └── test-connection.yaml
├── charts/ # Dependency charts
└── crds/ # Custom Resource Definitions
Chart.yaml
apiVersion: v2
name: myapp
description: A Helm chart for MyApp
type: application
version: 1.0.0
appVersion: "2.0.0"
kubeVersion: ">=1.25.0"
keywords:
- myapp
- web
home: https://github.com/org/myapp
sources:
- https://github.com/org/myapp
maintainers:
- name: Platform Team
email: platform@example.com
icon: https://example.com/icon.png
dependencies:
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
- name: redis
version: "17.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition:
values.yaml
replicaCount: 3
image:
repository: myapp
tag: ""
pullPolicy: IfNotPresent
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
create: true
annotations: {}
name: ""
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
service:
type: ClusterIP
port: 80
targetPort: 8080
ingress:
enabled: true
className:
{}
[]
{}
Template Helpers (_helpers.tpl)
{{/*
Expand the name of the chart.
*/}}
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{
}}
{{ }}
{{ }}
{{ }}
{{
}}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{
}}
{{ }}
{{ }}
{{ }}
{{ }}
{{
}}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{
}}
{{ }}
{{ }}
{{ }}
{{ }}
Deployment Template
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
{{ }}
Helm Hooks
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "myapp.fullname" . }}-migrate
labels:
{{- include "myapp.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
metadata:
name: {{ include "myapp.fullname" . }}-migrate
spec:
restartPolicy: Never
containers:
- name: migrate
image: {{ include "myapp.image" . }}
command: ["./migrate.sh"]
envFrom:
- secretRef:
name: {{ include "myapp.fullname" }}
{{ }}
{{ }}
[]
Helm Test
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "myapp.fullname" . }}-test-connection"
labels:
{{- include "myapp.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "myapp.fullname" . }}:{{ .Values.service.port }}/health']
restartPolicy: Never
kubectl Commands
Resource Management
kubectl apply -f manifest.yaml
kubectl apply -f ./manifests/ --recursive
kubectl apply -k ./kustomize/overlays/production/
kubectl create deployment nginx --image=nginx
kubectl create service clusterip nginx --tcp=80:80
kubectl create configmap app-config --from-file=config.properties
kubectl create secret generic db-secret --from-literal=password=secret
kubectl delete pod myapp-pod
kubectl delete -f manifest.yaml
kubectl delete pods --all -n dev
kubectl delete pods -l app=myapp
kubectl edit deployment myapp
kubectl patch deployment myapp -p '{"spec":{"replicas":5}}'
kubectl set image deployment/myapp app=myapp:v2
Viewing Resources
kubectl get pods -o wide
kubectl get pods -o yaml
kubectl get pods -o json
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase
kubectl get all -n production
kubectl describe pod myapp-pod
kubectl describe node node-1
kubectl top nodes
kubectl top pods --containers
kubectl top pods -A --sort-by=memory
kubectl get pods -w
kubectl get events -w --sort-by='.lastTimestamp'
Debugging
kubectl logs myapp-pod
kubectl logs myapp-pod -c sidecar
kubectl logs myapp-pod --previous
kubectl logs -f myapp-pod
kubectl logs -l app=myapp --all-containers
kubectl logs myapp-pod --since=1h
kubectl logs myapp-pod --tail=100
kubectl exec myapp-pod -- ls /app
kubectl exec -it myapp-pod -- /bin/sh
kubectl exec -it myapp-pod -c sidecar -- /bin/bash
kubectl cp myapp-pod:/app/logs/app.log ./app.log
kubectl cp ./config.yaml myapp-pod:/app/config.yaml
kubectl port-forward pod/myapp-pod 8080:80
kubectl port-forward svc/myapp 8080:80
kubectl port-forward deploy/myapp 8080:80
kubectl debug myapp-pod -it --image=busybox --target=app
kubectl debug node/node-1 -it --image=ubuntu
Deployment Operations
kubectl rollout status deployment/myapp
kubectl rollout history deployment/myapp
kubectl rollout history deployment/myapp --revision=2
kubectl rollout undo deployment/myapp
kubectl rollout undo deployment/myapp --to-revision=2
kubectl rollout restart deployment/myapp
kubectl rollout pause deployment/myapp
kubectl rollout resume deployment/myapp
kubectl scale deployment myapp --replicas=5
kubectl autoscale deployment myapp --min=3 --max=10 --cpu-percent=70
Context and Config
kubectl config get-contexts
kubectl config current-context
kubectl config use-context production
kubectl config set-context --current --namespace=myapp
kubectl config set-cluster dev --server=https://dev.k8s.local
kubectl config set-credentials admin --token=<token>
kubectl config set-context dev --cluster=dev --user=admin
kubectl config view
kubectl config view --minify
Kustomize
Directory Structure
kustomize/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── configmap.yaml
│ └── ingress.yaml
└── overlays/
├── development/
│ ├── kustomization.yaml
│ ├── replica-patch.yaml
│ └── config-patch.yaml
├── staging/
│ ├── kustomization.yaml
│ └── namespace.yaml
└── production/
├── kustomization.yaml
├── replica-patch.yaml
├── resource-patch.yaml
└── hpa.yaml
Base kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
- ingress.yaml
commonLabels:
app: myapp
commonAnnotations:
team: platform
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
secretGenerator:
- name: app-secrets
literals:
- API_KEY=default-key
type: Opaque
Production Overlay
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../base
- hpa.yaml
- pdb.yaml
namePrefix: prod-
nameSuffix: ""
commonLabels:
env: production
commonAnnotations:
prometheus.io/scrape: "true"
replicas:
- name: myapp
count: 5
images:
- name: myapp
newTag: v2.0.0
configMapGenerator:
- name: app-config
behavior: merge
literals:
- LOG_LEVEL=warn
- ENABLE_DEBUG=false
patches:
- path: replica-patch.yaml
- target:
Patches
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 10
template:
spec:
containers:
- name: app
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
Kustomize Commands
kubectl kustomize ./overlays/production/
kustomize build ./overlays/production/
kubectl apply -k ./overlays/production/
kubectl diff -k ./overlays/production/
kustomize build ./overlays/production/ -o ./rendered/
Ingress & Networking
Nginx Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/limit-rps: "50"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
- api.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 8080
---
Service Mesh (Istio Example)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp
http:
- match:
- headers:
x-version:
exact: v2
route:
- destination:
host: myapp
subset: v2
- route:
- destination:
host: myapp
subset: v1
weight: 90
- destination:
host: myapp
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: myapp
spec:
RBAC & Security
ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-sa
namespace: production
annotations:
azure.workload.identity/client-id: "<client-id>"
eks.amazonaws.com/role-arn: "arn:aws:iam::123456789:role/myapp-role"
automountServiceAccountToken: true
Role and RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: ServiceAccount
name: myapp-sa
namespace: production
ClusterRole and ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-admin
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["*"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets"]
verbs: ["*"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: namespace-admin-binding
subjects:
- kind:
Pod Security Standards
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:1.0.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
{}
{}
Autoscaling
Horizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type:
Vertical Pod Autoscaler (VPA)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: myapp-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 2
memory: 4Gi
controlledResources: ["cpu", "memory"]
Pod Disruption Budget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: myapp
Persistent Volumes
PersistentVolume and PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolume
metadata:
name: myapp-pv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /data/myapp
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myapp-pvc
spec:
storageClassName: managed-premium
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-premium
provisioner: disk.csi.azure.com
parameters:
skuName: Premium_LRS
cachingMode: ReadOnly
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
StatefulSet with PVC Template
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: database
spec:
serviceName: database
replicas: 3
selector:
matchLabels:
app: database
template:
metadata:
labels:
app: database
spec:
containers:
- name: postgres
image: postgres:15
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secrets
key: password
volumeClaimTemplates:
- metadata:
name: data
spec:
[]
Debugging & Troubleshooting
Common Issues Checklist
| Issue | Diagnostic Commands |
|---|
| Pod not starting | kubectl describe pod <name>, kubectl get events |
| CrashLoopBackOff | kubectl logs <pod> --previous, kubectl describe pod |
| ImagePullBackOff | Check image name/tag, registry credentials |
| Pending pod | Check resource requests, node capacity, affinity rules |
| Service not accessible | kubectl get endpoints, verify selectors match |
| Ingress not working | Check ingress controller, TLS secrets, annotations |
| PVC pending | Check StorageClass, available PVs |
| OOMKilled | Increase memory limits, check for memory leaks |
Debugging Commands
kubectl describe pod <pod-name>
kubectl get pod <pod-name> -o yaml
kubectl logs <pod-name> --all-containers
kubectl logs <pod-name> --previous
kubectl get events --field-selector involvedObject.name=<pod-name>
kubectl run debug --rm -it --image=nicolaka/netshoot -- /bin/bash
kubectl exec -it <pod> -- curl -v http://service-name:port
kubectl exec -it <pod> -- nslookup service-name
kubectl exec -it <pod> -- nc -zv service-name port
kubectl describe node <node-name>
kubectl get node <node-name> -o yaml
kubectl top node
kubectl debug node/<node-name> -it --image=ubuntu
kubectl get pods -o wide --field-selector status.phase!=Running
kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.status.phase!="Running")]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'
kubectl api-resources
kubectl explain deployment.spec.strategy
kubectl get --raw /metrics
Debug Container
kubectl debug myapp-pod -it \
--image=busybox \
--target=app \
--copy-to=myapp-debug
kubectl debug myapp-pod -it \
--image=nicolaka/netshoot \
-- /bin/bash
kubectl debug node/worker-1 -it --image=ubuntu
Common Fixes
kubectl rollout restart deployment/myapp
kubectl delete pod <pod> --grace-period=0 --force
kubectl patch deployment myapp -p '{"spec":{"template":{"metadata":{"annotations":{"restart":"'$(date +%s)'"}}}}}'
kubectl scale deployment myapp --replicas=0
kubectl scale deployment myapp --replicas=3
kubectl cordon <node>
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
kubectl uncordon <node>
kubectl describe resourcequota -n <namespace>
kubectl describe limitrange -n <namespace>
Health Check Patterns
spec:
containers:
- name: app
startupProbe:
httpGet:
path: /health/startup
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 30
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 0
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
Deployment Patterns
Blue-Green Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-blue
labels:
app: myapp
version: blue
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: blue
template:
metadata:
labels:
app: myapp
version: blue
spec:
containers:
- name: app
image: myapp:v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-green
labels:
app: myapp
version: green
spec:
replicas: 3
selector:
matchLabels:
app:
Canary Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-stable
spec:
replicas: 9
selector:
matchLabels:
app: myapp
track: stable
template:
metadata:
labels:
app: myapp
track: stable
spec:
containers:
- name: app
image: myapp:v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-canary
spec:
replicas: 1
selector:
matchLabels:
app: myapp
track: canary
template:
metadata:
labels:
app: myapp
track: canary
Rolling Update Configuration
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 1
template:
spec:
containers:
- name: app
image: myapp:v2
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
terminationGracePeriodSeconds: 60
Multi-Environment Setup
helm upgrade --install myapp ./chart \
-f values.yaml \
-f values.dev.yaml \
--namespace dev
helm upgrade --install myapp ./chart \
-f values.yaml \
-f values.staging.yaml \
--namespace staging
helm upgrade --install myapp ./chart \
-f values.yaml \
-f values.prod.yaml \
--namespace production \
--wait \
--timeout 10m
Best Practices Summary
Security
- ✅ Run containers as non-root
- ✅ Use read-only root filesystem
- ✅ Drop all capabilities, add only what's needed
- ✅ Use Network Policies to restrict traffic
- ✅ Store secrets in external secret managers
- ✅ Enable Pod Security Standards
- ✅ Use RBAC with least privilege
- ✅ Scan images for vulnerabilities
Reliability
- ✅ Set resource requests and limits
- ✅ Configure liveness and readiness probes
- ✅ Use Pod Disruption Budgets
- ✅ Spread pods across zones (topology spread)
- ✅ Use anti-affinity for critical workloads
- ✅ Configure appropriate replica counts
- ✅ Enable HPA for variable workloads
Operations
- ✅ Use namespaces for isolation
- ✅ Label everything consistently
- ✅ Use Helm or Kustomize for templating
- ✅ Version control all manifests
- ✅ Implement GitOps workflows
- ✅ Monitor with Prometheus/Grafana
- ✅ Centralize logging (Loki, ELK)
- ✅ Document runbooks for common issues