bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/bash
# Deployment Automation Script with Error Handling
# Usage: ./deploy.sh [production|staging]
set -euo pipefail # Exit on error, undefined vars, pipe failures
# Configuration
ENV="${1:-staging}"
APP_NAME="my-app"
DEPLOY_DIR="/var/www/${APP_NAME}"
BACKUP_DIR="/var/backups/${APP_NAME}"
HEALTH_CHECK_URL="http://localhost:3000/health"
MAX_RETRIES=5
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Error handler
error_exit() {
log_error "$1"
rollback
exit 1
}
# Rollback function
rollback() {
log_warn "Rolling back to previous version..."
if [ -d "${BACKUP_DIR}/latest" ]; then
rm -rf "${DEPLOY_DIR}"
cp -r "${BACKUP_DIR}/latest" "${DEPLOY_DIR}"
systemctl restart "${APP_NAME}"
log_info "Rollback completed"
else
log_error "No backup found for rollback"
fi
}
# Health check with retries
health_check() {
local retries=0
log_info "Performing health check..."
while [ $retries -lt $MAX_RETRIES ]; do
if curl -f -s "${HEALTH_CHECK_URL}" > /dev/null; then
log_info "Health check passed"
return 0
fi
retries=$((retries + 1))
log_warn "Health check failed, retry ${retries}/${MAX_RETRIES}"
sleep 5
done
return 1
}
# Backup current deployment
backup_current() {
log_info "Creating backup..."
mkdir -p "${BACKUP_DIR}"
if [ -d "${DEPLOY_DIR}" ]; then
timestamp=$(date +%Y%m%d_%H%M%S)
cp -r "${DEPLOY_DIR}" "${BACKUP_DIR}/${timestamp}"
ln -sfn "${BACKUP_DIR}/${timestamp}" "${BACKUP_DIR}/latest"
log_info "Backup created: ${timestamp}"
fi
}
# Deploy application
deploy() {
log_info "Starting deployment to ${ENV}..."
# Check if running as correct user
if [ "$(whoami)" != "deploy" ]; then
error_exit "This script must be run as 'deploy' user"
fi
# Backup current version
backup_current || error_exit "Backup failed"
# Pull latest code
log_info "Pulling latest code from Git..."
cd "${DEPLOY_DIR}" || error_exit "Deploy directory not found"
git fetch origin || error_exit "Git fetch failed"
git checkout "${ENV}" || error_exit "Git checkout failed"
git pull origin "${ENV}" || error_exit "Git pull failed"
# Install dependencies
log_info "Installing dependencies..."
npm ci --production || error_exit "npm install failed"
# Build application
log_info "Building application..."
npm run build || error_exit "Build failed"
# Run database migrations
log_info "Running database migrations..."
npm run migrate || error_exit "Migration failed"
# Restart application
log_info "Restarting application..."
systemctl restart "${APP_NAME}" || error_exit "Service restart failed"
# Perform health check
health_check || error_exit "Health check failed"
# Clean old backups (keep last 5)
find "${BACKUP_DIR}" -maxdepth 1 -type d -name "[0-9]*" | \
sort -r | tail -n +6 | xargs rm -rf
log_info "Deployment completed successfully!"
}
# Main execution
main() {
case "${ENV}" in
production|staging)
deploy
;;
*)
log_error "Invalid environment: ${ENV}"
echo "Usage: $0 [production|staging]"
exit 1
;;
esac
}
main