DevOps Scripting PatternsLesson 6.3
Building a CI/CD deployment script in Bash
deployment script structure, pre-deploy checks, blue-green deployment pattern, rollback mechanism, health check loop, deployment lock, notifications via curl webhook, idempotency
Production Deployment Script Structure
A production deployment script must be safe to run in CI with no human watching. The key properties: idempotent, rollback-capable, and observable.
#!/usr/bin/env bash
set -euo pipefail
APP="myapp"
VERSION="${1:?Version required}"
ENV="${2:?Environment required}"
SERVICE_URL="https://${APP}.${ENV}.example.com/health"
# Acquire deploy lock
exec 9>/var/run/deploy-${APP}.lock
flock -n 9 || { echo "Deploy already in progress" >&2; exit 1; }
rollback() {
echo "ROLLBACK: reverting to previous version..."
systemctl restart "${APP}-previous" || true
notify_slack "FAILED" "$VERSION" "$ENV"
}
trap rollback ERR
preflight_check() {
command -v docker &>/dev/null || { echo "docker required"; exit 1; }
[[ "$ENV" =~ ^(production|staging)$ ]] || { echo "Invalid env"; exit 1; }
}
wait_for_health() {
local retries=30 delay=5
for (( i=0; i /dev/null; then
return 0
fi
sleep "$delay"
done
return 1
}
preflight_check
docker pull "${APP}:${VERSION}"
docker stop "${APP}" && docker run -d --name "${APP}" "${APP}:${VERSION}"
wait_for_health
notify_slack "SUCCESS" "$VERSION" "$ENV" The trap rollback ERR ensures rollback runs on any unexpected error — not just places you remembered to add error handling.
