| name | k8s-deploy-auto |
| description | Kubernetes deployment automation workflows for CI/CD pipelines, GitOps, and scripted deployments. Use when automating k8s deployments, creating deployment scripts, integrating with GitHub Actions/GitLab CI, implementing rollout strategies, or setting up ArgoCD/Flux workflows. |
Kubernetes Deployment Automation
Deployment Script Template
Basic Deploy Script
#!/usr/bin/env bash
set -euo pipefail
NAMESPACE="${NAMESPACE:-default}"
MANIFEST_DIR="${MANIFEST_DIR:-.}"
TIMEOUT="${TIMEOUT:-300s}"
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"; }
die() { log "ERROR: $*"; exit 1; }
command -v kubectl >/dev/null || die "kubectl not found"
kubectl auth can-i create deployments -n "$NAMESPACE" >/dev/null || die "No deploy permissions"
log "Validating manifests..."
kubectl apply --dry-run=server -f "$MANIFEST_DIR" -n "$NAMESPACE" || die "Validation failed"
log "Applying manifests to $NAMESPACE..."
kubectl apply -f "$MANIFEST_DIR" -n "$NAMESPACE"
log "Waiting for rollout..."
for deploy in $(kubectl get deploy -n "$NAMESPACE" -o name 2>/dev/null); do
log "Checking $deploy..."
kubectl rollout status "$deploy" -n "$NAMESPACE" --timeout="$TIMEOUT" || die "Rollout failed: $deploy"
done
log "Verifying pods..."
kubectl get pods -n "$NAMESPACE" -o wide
log "Deployment complete!"
Deploy with Rollback
#!/usr/bin/env bash
set -euo pipefail
NAMESPACE="${1:?Usage: $0 <namespace> <deployment> <image>}"
DEPLOYMENT="${2:?}"
IMAGE="${3:?}"
TIMEOUT="${TIMEOUT:-300s}"
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"; }
PREV_REVISION=$(kubectl rollout history "deployment/$DEPLOYMENT" -n "$NAMESPACE" | tail -2 | head -1 | awk '{print $1}')
log "Current revision: $PREV_REVISION"
log "Updating $DEPLOYMENT to $IMAGE..."
kubectl set image "deployment/$DEPLOYMENT" "$DEPLOYMENT=$IMAGE" -n "$NAMESPACE"
kubectl annotate "deployment/$DEPLOYMENT" kubernetes.io/change-cause="Image: $IMAGE" --overwrite -n "$NAMESPACE"
log "Monitoring rollout..."
if ! kubectl rollout status -n --=;
kubectl rollout undo -n --to-revision=
kubectl rollout status -n --=
1
kubectl get pods -n -l -o wide
CI/CD Integration
GitHub Actions
name: Deploy to Kubernetes
on:
push:
branches: [main]
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
default: 'staging'
type: choice
options: [staging, production]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Registry
uses:
GitLab CI
stages:
- build
- deploy
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
build:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- main
.deploy_template: &deploy
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl config set-cluster k8s --server="$K8S_SERVER" --certificate-authority="$K8S_CA_CERT"
-
GitOps Patterns
ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
targetRevision: HEAD
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
Kustomize Structure
k8s/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── staging/
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── patches/
│ └── replicas.yaml
└── production/
├── kustomization.yaml
├── namespace.yaml
└── patches/
├── replicas.yaml
└── resources.yaml
base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
overlays/production/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../base
- namespace.yaml
patches:
- path: patches/replicas.yaml
- path: patches/resources.yaml
images:
- name: myapp
newTag: v1.2.3
Canary Deployment
Manual Canary
#!/usr/bin/env bash
NAMESPACE="${NAMESPACE:-default}"
CANARY_REPLICAS=1
STABLE_REPLICAS=9
kubectl apply -f canary-deployment.yaml -n "$NAMESPACE"
kubectl scale deployment/app-stable --replicas="$STABLE_REPLICAS" -n "$NAMESPACE"
kubectl scale deployment/app-canary --replicas="$CANARY_REPLICAS" -n "$NAMESPACE"
echo "Canary deployed. Monitor metrics..."
echo "To promote: kubectl scale deployment/app-canary --replicas=10 && kubectl delete deployment/app-stable"
echo "To rollback: kubectl delete deployment/app-canary"
Argo Rollouts
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: myapp
spec:
replicas: 10
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v1
strategy:
canary:
steps:
- setWeight: 10
- pause: {duration: 5m}
- setWeight: 30
- pause: {duration: 5m}
- setWeight: 50
- pause: {duration: 5m}
canaryService: myapp-canary
stableService: myapp-stable
Health Check Verification
#!/usr/bin/env bash
NAMESPACE="${1:?namespace required}"
DEPLOYMENT="${2:?deployment required}"
ENDPOINT="${3:-/healthz}"
RETRIES=30
DELAY=10
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"; }
log "Waiting for pods..."
kubectl wait --for=condition=ready pod -l "app=$DEPLOYMENT" -n "$NAMESPACE" --timeout=300s
POD=$(kubectl get pods -n "$NAMESPACE" -l "app=$DEPLOYMENT" -o jsonpath='{.items[0].metadata.name}')
log "Testing pod: $POD"
for i in $(seq 1 $RETRIES); do
if kubectl exec "$POD" -n "$NAMESPACE" -- wget -q -O /dev/null "http://localhost:8080$ENDPOINT" 2>/dev/null; then
log "Health check passed!"
exit 0
fi
1
Secrets Management
Sealed Secrets
brew install kubeseal
kubectl create secret generic mysecret --dry-run=client -o yaml \
--from-literal=password=secret123 | \
kubeseal --controller-name=sealed-secrets --controller-namespace=kube-system -o yaml > sealed-secret.yaml
kubectl apply -f sealed-secret.yaml
External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: app-secrets
data:
- secretKey: database-password
remoteRef:
key: prod/app/database
property: password
Monitoring Deployment
watch -n1 'kubectl get pods -n production -o wide; echo "---"; kubectl get events -n production --sort-by=.lastTimestamp | tail -10'
kubectl logs -f -l app=myapp -n production --all-containers --since=5m
kubectl top pods -n production --sort-by=memory