ECR login + docker push aws · docker · ci
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
docker tag myapp:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest Merge EKS into kubeconfig aws · k8s
aws eks update-kubeconfig --name my-cluster --region us-east-1
kubectl config current-context
kubectl get nodes Assume IAM role (CLI session) aws
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/DeployRole --role-session-name deploy
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
aws sts get-caller-identity Verify AWS identity aws · debug
aws sts get-caller-identity
aws configure list Debug DNS/network in pod k8s · debug
kubectl run netshoot --rm -it --image=nicolaka/netshoot --restart=Never -n <ns> -- /bin/bash
# inside: nslookup kubernetes.default, curl -v svc:port Port-forward service locally k8s · debug
kubectl port-forward svc/<service> 8080:80 -n <namespace>
curl -I http://localhost:8080 helm upgrade --install myrelease ./chart -n apps -f values.yaml --dry-run --debug
helm template myrelease ./chart -f values.yaml | kubectl apply --dry-run=client -f - Helm rollback failed release k8s · debug
helm history myrelease -n apps
helm rollback myrelease <revision> -n apps
helm status myrelease -n apps ⚠️ Destructive — Confirm no other apply is running. Run in staging first — wrong unlock can corrupt state.
Terraform force-unlock terraform · debug
terraform force-unlock <LOCK_ID>
# LOCK_ID from error message — confirm no other apply running first Terraform import existing resource terraform
terraform import aws_instance.web i-0abc123def456
terraform state show aws_instance.web Terraform plan to file terraform · ci
terraform init
terraform plan -out=tfplan
terraform apply tfplan Nginx proxy_pass + timeout fix for 502 nginx · debug
location / {
proxy_pass http://backend:8080;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
sudo nginx -t && sudo systemctl reload nginx Tail nginx error log nginx · debug
sudo tail -f /var/log/nginx/error.log
sudo nginx -t ⚠️ Destructive — Removes unused images and volumes cluster-wide. Run in staging first — can break cached builds.
Docker cleanup disk space docker · debug
docker system df
docker system prune -a --volumes
# careful: removes unused images Follow container logs docker · debug
docker logs -f <container>
docker inspect <container> --format='{{.State.ExitCode}}' Logs from crashed pod k8s · debug
kubectl logs <pod> -n <ns> --previous
kubectl describe pod <pod> -n <ns>
kubectl get events -n <ns> --sort-by='.lastTimestamp' Diagnose ImagePullBackOff k8s · debug
kubectl describe pod <pod> -n <ns> | grep -A5 Events
kubectl get secret -n <ns>
# ensure imagePullSecrets if private registry kubectl rollout history deploy/<name> -n <ns>
kubectl rollout undo deploy/<name> -n <ns>
kubectl rollout status deploy/<name> -n <ns> ⚠️ Destructive — Evicts all pods from the node. Run in staging first — causes workload disruption in prod.
kubectl cordon <node>
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
kubectl uncordon <node> Pod CPU/memory usage k8s · debug
kubectl top nodes
kubectl top pods -A --sort-by=memory vault status
vault operator unseal
# repeat until Sealed: false GHA OIDC to AWS (workflow snippet) ci · aws
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123:role/GithubActionsRole
aws-region: us-east-1 GHA build and push image ci · docker
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/org/app:${{ github.sha }} GHA kubectl apply ci · k8s
- uses: azure/setup-kubectl@v4
- run: kubectl apply -f k8s/
env:
KUBECONFIG: ${{ secrets.KUBECONFIG_B64 }} # base64-encoded Bitbucket Pipelines Docker service ci · docker
definitions:
services:
docker:
memory: 2048
pipelines:
default:
- step:
services:
- docker
script:
- docker build -t myapp .
- docker push myapp Revert last commit (safe) git
git revert HEAD
git push origin main git stash list
git stash pop Renew Let's Encrypt cert nginx
sudo certbot renew --dry-run
sudo certbot renew
sudo systemctl reload nginx Follow systemd service logs debug
sudo journalctl -u <service> -f --since "1 hour ago"
sudo systemctl status <service> Find what's using disk debug
df -h
du -sh /* 2>/dev/null | sort -hr | head -20
sudo journalctl --vacuum-time=7d Check ingress TLS cert expiry k8s · nginx · debug
kubectl get certificate -A
kubectl describe certificate <name> -n <ns>
echo | openssl s_client -connect app.example.com:443 2>/dev/null | openssl x509 -noout -dates Debug ingress backend k8s · debug
kubectl describe ingress <name> -n <ns>
kubectl get endpoints -n <ns>
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=50 Compose up with rebuild docker
docker compose up -d --build
docker compose ps
docker compose logs -f <service> Load local image into minikube docker · k8s
docker build -t myapp:local .
minikube image load myapp:local
# set imagePullPolicy: IfNotPresent in deployment kubectl config get-contexts
kubectl config use-context <context>
kubectl cluster-info List terraform state resources terraform · debug
terraform state list
terraform state show aws_instance.web
terraform refresh Fix CI docker push 401 ci · docker · debug
# Verify registry login in CI before push
docker login registry.example.com -u $CI_USER -p $CI_TOKEN
# K8s: create docker-registry secret
kubectl create secret docker-registry regcred --docker-server=... --docker-username=... --docker-password=... -n <ns> Shell into running pod k8s · debug
kubectl exec -it <pod> -n <ns> -- /bin/sh
# or -c <container> if multi-container ⚠️ Destructive — Deletes Failed pods cluster-wide. Verify they are evicted junk, not debugging evidence.
Clean evicted pods k8s · debug
kubectl get pods -A | grep Evicted
kubectl delete pods -A --field-selector=status.phase=Failed Tail CloudWatch logs aws · debug
aws logs tail /aws/lambda/my-function --follow --since 1h
aws logs describe-log-groups --log-group-name-prefix /ecs/ HAProxy backend status debug
echo "show stat" | socat stdio /var/run/haproxy/admin.sock
curl -I http://backend:port Test Redis connectivity debug
redis-cli -h <host> -p 6379 ping
redis-cli -h <host> INFO server Test PostgreSQL connection debug
psql -h <host> -U <user> -d <db> -c "SELECT 1"
pg_isready -h <host> -p 5432 Node NotReady / pressure k8s · debug
kubectl describe node <node>
kubectl get events -A --field-selector involvedObject.kind=Node
# check DiskPressure, MemoryPressure, PIDPressure Switch terraform workspace terraform
terraform workspace list
terraform workspace select prod
terraform plan Fix GitLab runner tag mismatch ci · debug
# .gitlab-ci.yml tags must match runner
# Settings → CI/CD → Runners → note tags
# tags: [docker, aws] ⚠️ Destructive — Delete only after snapshot. Run in staging account first.
Find unattached EBS volumes aws · finops
aws ec2 describe-volumes --filters Name=status,Values=available --query 'Volumes[*].[VolumeId,Size,CreateTime]' --output table
# delete after snapshot:
# aws ec2 delete-volume --volume-id vol-xxx ⚠️ Destructive — Deregister only AMIs not referenced by launch templates. Run in staging first.
List old AMIs you own aws · finops
aws ec2 describe-images --owners self --query 'Images | sort_by(@, &CreationDate)[*].[ImageId,Name,CreationDate]' --output table
# deregister unused:
# aws ec2 deregister-image --image-id ami-xxx Find load balancers with no targets aws · finops
for lb in $(aws elbv2 describe-load-balancers --query 'LoadBalancers[*].LoadBalancerArn' --output text); do
echo "$lb"
aws elbv2 describe-target-health --target-group-arn $(aws elbv2 describe-target-groups --load-balancer-arn $lb --query 'TargetGroups[0].TargetGroupArn' --output text)
done Audit pods missing resource requests k8s · finops
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.containers[].resources.requests == null) | "\(.metadata.namespace)/\(.metadata.name)"' Compare requests vs actual usage k8s · finops · debug
kubectl top pods -A --sort-by=cpu
# vs kubectl get pods -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,CPU:.spec.containers[*].resources.requests.cpu Trivy scan image before deploy docker · finops · ci
trivy image --severity HIGH,CRITICAL myapp:tag
trivy image --exit-code 1 --severity CRITICAL myapp:tag Check Docker image size docker · finops
docker images myapp --format "{{.Repository}}:{{.Tag}} {{.Size}}"
docker history myapp:latest --no-trunc | head -20 S3 buckets by size (top) aws · finops
# requires s3 ls + cloudwatch or aws s3api list-objects-v2
aws s3 ls
# enable S3 Storage Lens or Cost Explorer for detail List long-running EC2 instances aws · finops
aws ec2 describe-instances --filters Name=instance-state-name,Values=running --query 'Reservations[*].Instances[*].[InstanceId,InstanceType,LaunchTime,Tags[?Key==`Name`].Value|[0]]' --output table CloudWatch CPU avg (right-sizing hint) aws · finops
aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name CPUUtilization --dimensions Name=InstanceId,Value=i-xxx --start-time $(date -u -v-7d +%Y-%m-%dT%H:%M:%S) --end-time $(date -u +%Y-%m-%dT%H:%M:%S) --period 86400 --statistics Average PromQL: HTTP 5xx error rate observe · k8s
# 5xx rate / total rate
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# by ingress
sum by (ingress) (rate(nginx_ingress_controller_requests{status=~"5.."}[5m])) PromQL: pod restart rate observe · k8s
sum by (namespace, pod) (increase(kube_pod_container_status_restarts_total[1h])) > 3
# top restarters
topk(10, sum by (pod, namespace) (kube_pod_container_status_restarts_total)) PromQL: P99 latency observe
histogram_quantile(0.99,
sum by (le) (rate(http_request_duration_seconds_bucket[5m]))
)
# ingress latency
histogram_quantile(0.99, sum by (le) (rate(nginx_ingress_controller_request_duration_seconds_bucket[5m]))) PromQL: node disk usage % observe · k8s
100 - (
avg by (instance) (node_filesystem_avail_bytes{mountpoint="/"}) /
avg by (instance) (node_filesystem_size_bytes{mountpoint="/"}) * 100
) PromQL: cert expiry days left observe · k8s
(certmanager_certificate_expiration_timestamp_seconds - time()) / 86400 < 14
# alert when < 7 days
(certmanager_certificate_expiration_timestamp_seconds - time()) / 86400 LogQL: error lines last 15m observe
{namespace="apps"} |= "error" or |= "ERROR" or |= "panic"
| json
| line_format "{{.pod}} {{.message}}"
# rate of error log lines
sum(rate({namespace="apps"} |= "error" [5m])) by (pod) CloudWatch Insights: 5xx / errors observe · aws
fields @timestamp, @message
| filter @message like /(?i)(error|5\d\d|exception)/
| sort @timestamp desc
| limit 100
# EKS container logs
fields @timestamp, kubernetes.pod_name, @message
| filter @message like /ERROR/
| stats count() by kubernetes.pod_name GKE kubeconfig merge gcp · k8s
gcloud container clusters get-credentials my-cluster --region us-central1 --project my-project
kubectl config current-context
kubectl get nodes GCP Artifact Registry docker push gcp · docker · ci
gcloud auth configure-docker us-central1-docker.pkg.dev
docker tag myapp:latest us-central1-docker.pkg.dev/my-project/my-repo/myapp:tag
docker push us-central1-docker.pkg.dev/my-project/my-repo/myapp:tag GKE Workload Identity (KSA → GSA) gcp · k8s · ci
# Bind K8s SA to GCP SA
gcloud iam service-accounts add-iam-policy-binding GSA@PROJECT.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:PROJECT.svc.id.goog[NAMESPACE/KSA]"
# Deployment annotation:
# iam.gke.io/gcp-service-account: GSA@PROJECT.iam.gserviceaccount.com AKS kubeconfig merge azure · k8s
az aks get-credentials --resource-group my-rg --name my-aks
kubectl config current-context
kubectl get nodes Azure ACR docker login + push azure · docker · ci
az acr login --name myregistry
docker tag myapp:latest myregistry.azurecr.io/myapp:tag
docker push myregistry.azurecr.io/myapp:tag Azure federated creds for GitHub OIDC azure · ci
az ad app federated-credential create \
--id $APP_ID \
--parameters '{
"name": "github-main",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:org/repo:ref:refs/heads/main",
"audiences": ["api://AzureADTokenExchange"]
}'
# then azure/login@v2 with client-id, tenant-id, subscription-id PostgreSQL logical backup (pg_dump) backup
pg_dump -h <host> -U <user> -d <db> -Fc -f backup-$(date +%F).dump
# custom format (-Fc) supports parallel restore
aws s3 cp backup-$(date +%F).dump s3://my-backups/postgres/ ⚠️ Destructive — Overwrites target database. Restore to empty DB or staging first.
PostgreSQL restore from pg_dump backup
createdb -h <host> -U <user> restore_test
pg_restore -h <host> -U <user> -d restore_test -c backup-2026-06-21.dump
psql -h <host> -U <user> -d restore_test -c "SELECT count(*) FROM users;" MySQL mysqldump backup backup
mysqldump -h <host> -u <user> -p --single-transaction --routines <db> > backup-$(date +%F).sql
gzip backup-$(date +%F).sql
aws s3 cp backup-$(date +%F).sql.gz s3://my-backups/mysql/ ⚠️ Destructive — Drops and recreates data in target DB. Use staging first.
MySQL restore from dump backup
gunzip -c backup-2026-06-21.sql.gz | mysql -h <host> -u <user> -p <db>
mysql -h <host> -u <user> -p -e "SELECT COUNT(*) FROM users;" <db> MongoDB mongodump archive backup
mongodump --uri="mongodb://user:pass@host:27017/app" --archive=backup-$(date +%F).gz --gzip
aws s3 cp backup-$(date +%F).gz s3://my-backups/mongo/ ⚠️ Destructive — Restores into existing collections. Test on empty DB first.
MongoDB restore from archive backup
mongorestore --uri="mongodb://host:27017" --archive=backup-2026-06-21.gz --gzip --drop
mongosh --eval "db.users.countDocuments()" Redis RDB snapshot (BGSAVE) backup · redis
redis-cli -h <host> BGSAVE
redis-cli -h <host> LASTSAVE
# copy /var/lib/redis/dump.rdb to backup storage
scp redis-host:/var/lib/redis/dump.rdb ./backup-$(date +%F).rdb ⚠️ Destructive — Stop Redis, replace dump.rdb, restart — data loss if wrong file.
Redis restore RDB file backup · redis
sudo systemctl stop redis
sudo cp backup-2026-06-21.rdb /var/lib/redis/dump.rdb
sudo chown redis:redis /var/lib/redis/dump.rdb
sudo systemctl start redis
redis-cli ping Velero backup namespace backup · k8s · aws
velero backup create apps-$(date +%F) --include-namespaces apps --wait
velero backup describe apps-$(date +%F)
velero backup logs apps-$(date +%F) ⚠️ Destructive — Restores resources into cluster — use --namespace-mappings to staging NS first.
Velero restore from backup backup · k8s
velero restore create restore-$(date +%F) --from-backup apps-2026-06-21 --wait
velero restore describe restore-$(date +%F)
kubectl get all -n apps etcd snapshot (control plane) backup · k8s
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%F).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
etcdctl snapshot status /backup/etcd-$(date +%F).db ⚠️ Destructive — Cluster-wide disaster recovery only — follow vendor runbook; wrong step bricks cluster.
etcd restore snapshot backup · k8s
# STOP API server + etcd on all nodes first — follow your K8s distro docs
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-2026-06-21.db \
--data-dir=/var/lib/etcd-restore
# then reconfigure etcd to use restored data dir Terraform state backup (pull local copy) backup · terraform
terraform state pull > terraform.tfstate.backup-$(date +%F).json
# remote backend: enable S3 versioning on state bucket
aws s3api list-object-versions --bucket my-tf-state --prefix prod/terraform.tfstate ⚠️ Destructive — Wrong state version can destroy infra on next apply. Coordinate with team.
Restore Terraform state from S3 version backup · terraform · aws
aws s3api list-object-versions --bucket my-tf-state --prefix prod/terraform.tfstate
aws s3api get-object --bucket my-tf-state --key prod/terraform.tfstate --version-id <VERSION_ID> terraform.tfstate
terraform state push terraform.tfstate # only if intentional AWS RDS manual snapshot backup · aws
aws rds create-db-snapshot --db-instance-identifier mydb --db-snapshot-identifier mydb-pre-upgrade-$(date +%F)
aws rds wait db-snapshot-available --db-snapshot-identifier mydb-pre-upgrade-$(date +%F)
aws rds describe-db-snapshots --db-instance-identifier mydb AWS RDS restore snapshot to new instance backup · aws
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier mydb-restore-test \
--db-snapshot-identifier mydb-pre-upgrade-2026-06-21
# verify app against restore-test endpoint before cutover Sync directory to S3 (config backup) backup · aws
aws s3 sync /etc/nginx s3://my-backups/nginx/$(hostname)/ --exclude "*.tmp"
aws s3 sync s3://my-backups/nginx/$(hostname)/ ./restore-test/ --dryrun ⚠️ Destructive — Overwrites local files. Dry-run first; restore to temp dir.
Restore files from S3 sync backup · aws
aws s3 sync s3://my-backups/nginx/myhost/ /tmp/nginx-restore/ --dryrun
aws s3 sync s3://my-backups/nginx/myhost/ /tmp/nginx-restore/
diff -r /etc/nginx /tmp/nginx-restore/ DNS lookup debug (dig + nslookup) debug · nginx
dig app.example.com +short
dig app.example.com ANY
nslookup app.example.com
# compare to ingress LB: kubectl get ingress -n apps Test TCP port open (nc / curl) debug
nc -zv backend.example.com 443
curl -v telnet://backend:8080
ss -tlnp | grep 8080 Restart service safely (systemd) debug
sudo systemctl status <service>
sudo systemctl restart <service>
sudo journalctl -u <service> -n 50 --no-pager
sudo systemctl is-active <service> Check TLS cert expiry from CLI debug · nginx · backup
echo | openssl s_client -connect app.example.com:443 -servername app.example.com 2>/dev/null | openssl x509 -noout -dates -subject
# days left:
echo | openssl s_client -connect app.example.com:443 2>/dev/null | openssl x509 -noout -checkend 604800 Cron backup script template backup
#!/bin/bash
# /usr/local/bin/backup.sh — install via cron: 0 2 * * * /usr/local/bin/backup.sh
set -euo pipefail
BACKUP_DIR=/var/backups
DATE=$(date +%F)
pg_dump -U app appdb | gzip > "$BACKUP_DIR/appdb-$DATE.sql.gz"
find "$BACKUP_DIR" -name 'appdb-*.sql.gz' -mtime +14 -delete
aws s3 cp "$BACKUP_DIR/appdb-$DATE.sql.gz" s3://my-backups/cron/ PostgreSQL rotate app user password k8s · backup
# 1. Create parallel user
CREATE USER app_v2 WITH PASSWORD 'new-secret';
GRANT ALL ON DATABASE appdb TO app_v2;
GRANT ALL ON ALL TABLES IN SCHEMA public TO app_v2;
# 2. Update K8s secret + rollout restart
kubectl create secret generic db-creds --from-literal=password=new-secret -n apps --dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deploy/myapp -n apps Update K8s secret + rolling restart k8s · ci
kubectl create secret generic app-secrets \
--from-literal=API_KEY=new-key \
-n apps --dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deploy/myapp -n apps
kubectl rollout status deploy/myapp -n apps Verify IRSA role from pod aws · k8s
kubectl exec -it deploy/myapp -n apps -- env | grep AWS
kubectl exec -it deploy/myapp -n apps -- aws sts get-caller-identity
# expect role ARN matching ServiceAccount annotation Restart all pods using ServiceAccount k8s
# after SA annotation change
kubectl rollout restart deploy -n apps
kubectl get pods -n apps -o jsonpath='{range .items[*]}{.metadata.name}{" SA="}{.spec.serviceAccountName}{"\n"}{end}' Vault KV — write new secret version debug
vault kv put secret/apps/myapp db_password=new-secret api_key=new-key
vault kv get secret/apps/myapp
# External Secrets Operator syncs within refreshInterval cert-manager HTTP-01 ClusterIssuer k8s · nginx
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ops@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx cert-manager DNS-01 (Route53 wildcard) k8s · aws
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ops@example.com
privateKeySecretRef:
name: letsencrypt-dns
solvers:
- dns01:
route53:
region: us-east-1
hostedZoneID: Z123456
# Certificate dnsNames: [example.com, '*.example.com'] cert-manager self-signed CA Issuer k8s
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: internal-ca
namespace: apps
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: internal-tls
namespace: apps
spec:
secretName: internal-tls
issuerRef:
name: internal-ca
dnsNames:
- svc.apps.svc.cluster.local Quick diff deploy images across contexts k8s · debug
for ctx in staging prod; do
echo "=== $ctx ==="
kubectl --context=$ctx get deploy -n apps -o custom-columns=NAME:.metadata.name,IMAGE:.spec.template.spec.containers[0].image
done Terraform workspace compare workflow terraform
terraform workspace list
terraform workspace select staging && terraform plan -no-color > /tmp/plan-staging.txt
terraform workspace select prod && terraform plan -no-color > /tmp/plan-prod.txt
diff -u /tmp/plan-staging.txt /tmp/plan-prod.txt || true Argo CD — app status and sync k8s · ci · debug
argocd app list
argocd app get <app> --refresh
argocd app sync <app>
argocd app diff <app> Argo CD — hard refresh stuck app k8s · ci · debug
argocd app get <app> --hard-refresh
kubectl patch application <app> -n argocd --type merge -p '{"operation":{"initiatedBy":{"username":"admin"},"sync":{"revision":"HEAD"}}}' Flux — force reconcile source/kustomization k8s · ci · debug
flux get sources git -A
flux get kustomizations -A
flux reconcile source git <name> -n flux-system
flux reconcile kustomization <name> -n flux-system --with-source Jenkins — kubectl deploy from pipeline ci · k8s
pipeline {
agent any
stages {
stage('Deploy') {
steps {
withKubeConfig([credentialsId: 'kubeconfig']) {
sh 'kubectl apply -f k8s/'
sh 'kubectl rollout status deploy/myapp -n apps'
}
}
}
}
} Fix failing liveness/readiness probe k8s · debug
# describe shows probe failures
kubectl describe pod <pod> -n <ns> | grep -A3 Liveness
# common fix — separate paths, longer initialDelaySeconds
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
failureThreshold: 3 Debug HPA not scaling k8s · debug
kubectl get hpa -n <ns>
kubectl describe hpa <name> -n <ns>
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/<ns>/pods" | head
# metrics-server must be running PromQL: CPU throttling rate observe · k8s
sum by (pod, namespace) (rate(container_cpu_cfs_throttled_seconds_total[5m]))
# top throttled
topk(10, sum by (pod) (rate(container_cpu_cfs_throttled_seconds_total[5m]))) PromQL: pod memory vs limit observe · k8s
sum by (pod, namespace) (container_memory_working_set_bytes)
/
sum by (pod, namespace) (kube_pod_container_resource_limits{resource="memory"}) * 100
# OOM risk > 90% RBAC — can I perform action? k8s · debug
kubectl auth can-i create deployments -n apps
kubectl auth can-i get secrets --as=system:serviceaccount:apps:default -n apps
kubectl describe rolebinding -n apps Elasticsearch cluster health observe · debug
curl -s http://localhost:9200/_cluster/health?pretty
curl -s http://localhost:9200/_cat/indices?v
curl -s http://localhost:9200/_cat/shards?v | grep UNASSIGNED GitLab CI — deploy to K8s ci · k8s
deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl config use-context org/cluster
- kubectl apply -f k8s/
- kubectl rollout status deploy/myapp -n apps
only:
- main GitHub Actions — deploy to GitHub Pages ci
name: Deploy Pages
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: ./public
- uses: actions/deploy-pages@v4 SSH ProxyJump to private host debug · linux
ssh -J bastion@jump.example.com user@10.0.2.50
# ~/.ssh/config:
# Host private
# ProxyJump bastion@jump.example.com
# HostName 10.0.2.50
# User deploy Fail2ban — protect SSH linux · debug
sudo apt install fail2ban
sudo tee /etc/fail2ban/jail.local <<'EOF'
[sshd]
enabled = true
port = ssh
maxretry = 5
bantime = 3600
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd Chrony NTP sync check linux · debug
chronyc tracking
chronyc sources -v
timedatectl status