Bash Project: Deploy with Rollback
A deployment script is a script that moves a new release into place in fixed, checked stages. It keeps a backup ready, so a failed release can roll back.
Backup runs before deploy changes anything
The live version is copied to backup first, then replaced. The live file shows 2.0.0 while the backup still shows 1.0.0, which proves the backup came first.
mkdir -p current backup
printf '1.0.0\n' > current/version.txt
echo "stage: backup"
cp current/version.txt backup/version.txt
echo "stage: deploy"
printf '2.0.0\n' > current/version.txt
echo "stage: verify"
cat current/version.txt
cat backup/version.txtA failed verify restores the backup
The deployed version fails the check, so the script restores the backup and exits nonzero. The live file shows 1.0.0 again, which proves the rollback worked.
cat > deploy.sh <<'DEPLOYEOF'
mkdir -p current backup
printf '1.0.0\n' > current/version.txt
cp current/version.txt backup/version.txt
printf '2.0.0-broken\n' > current/version.txt
if [[ "$(cat current/version.txt)" != "2.0.0" ]]; then
cp backup/version.txt current/version.txt
echo "rolled back"
exit 1
fi
echo "deployed"
DEPLOYEOF
bash deploy.sh || echo "deploy failed"
cat current/version.txtA dry run plans the deploy and changes nothing
The dry-run flag prints the planned version and exits before any write. The live file still shows 1.0.0, which proves nothing changed.
cat > deploy.sh <<'DEPLOYEOF'
mkdir -p current
printf '1.0.0\n' > current/version.txt
if [[ "${1:-}" == "--dry-run" ]]; then
echo "dry run: would deploy 2.0.0"
exit 0
fi
printf '2.0.0\n' > current/version.txt
echo "deployed 2.0.0"
DEPLOYEOF
bash deploy.sh --dry-run
cat current/version.txtExample
if [[ "${1:-}" == "--dry-run" ]]; then
echo "dry run: would deploy 2.0.0"
exit 0
fi
mkdir -p current backup releases
printf '1.0.0\n' > current/version.txt
printf '2.0.0\n' > releases/version.txt
echo "stage: backup"
cp current/version.txt backup/version.txt
echo "stage: deploy"
cp releases/version.txt current/version.txt
echo "stage: verify"
if [[ "$(cat current/version.txt)" != "2.0.0" ]]; then
cp backup/version.txt current/version.txt
echo "rolled back"
exit 1
fi
echo "stage: done"
echo "live version: $(cat current/version.txt)"
echo "backup version: $(cat backup/version.txt)"Key points
- Stages: fixed labels such as backup, deploy, and verify, printed in the same order every run.
- Backup step: copy the live version aside before deploying, so rollback has something to restore.
- Verify step: check the live version after deploy, and roll back when the check fails.
- Rollback: restore the backup over the live files, then report the failure.
- --dry-run: a flag that prints the plan and changes nothing.
- Fail loudly: a failed deploy exits nonzero after rollback, so automation does not mistake it for success.
In this example, a deploy script first handles a dry-run flag, then sets up a live version and a release version. It backs up the live version, deploys the release, and verifies the live version. The check passes, so the script reports the done stage, the live version 2.0.0, and the backup version 1.0.0 kept for rollback.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
A deploy fails its verify step. What must happen before the script reports failure?