Bash · 4897 bytes Raw Blame History
1 #!/bin/bash
2
3 set -euo pipefail
4
5 DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6 STACK_NAME="zephyrfs"
7 COMPOSE_FILE="$DEPLOY_DIR/deploy/production.yml"
8 ENV_FILE="$DEPLOY_DIR/.env.production"
9
10 log() {
11 echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
12 }
13
14 error() {
15 log "ERROR: $*" >&2
16 exit 1
17 }
18
19 check_prerequisites() {
20 log "Checking prerequisites..."
21
22 command -v docker >/dev/null 2>&1 || error "Docker is not installed"
23 command -v docker-compose >/dev/null 2>&1 || error "Docker Compose is not installed"
24
25 if ! docker info >/dev/null 2>&1; then
26 error "Docker daemon is not running"
27 fi
28
29 if ! docker swarm ca >/dev/null 2>&1; then
30 log "Initializing Docker Swarm..."
31 docker swarm init
32 fi
33
34 if [[ ! -f "$ENV_FILE" ]]; then
35 error "Environment file not found: $ENV_FILE"
36 fi
37
38 log "Prerequisites check passed"
39 }
40
41 build_images() {
42 log "Building Docker images..."
43
44 # Build client image
45 docker build -t zephyrfs/web-client:latest \
46 -f "$DEPLOY_DIR/client/Dockerfile" \
47 "$DEPLOY_DIR/client"
48
49 # Build server image
50 docker build -t zephyrfs/web-server:latest \
51 -f "$DEPLOY_DIR/server/Dockerfile" \
52 "$DEPLOY_DIR/server"
53
54 log "Images built successfully"
55 }
56
57 setup_secrets() {
58 log "Setting up Docker secrets..."
59
60 if ! docker secret inspect jwt_secret >/dev/null 2>&1; then
61 if [[ -n "${JWT_SECRET:-}" ]]; then
62 echo "$JWT_SECRET" | docker secret create jwt_secret -
63 else
64 openssl rand -base64 32 | docker secret create jwt_secret -
65 fi
66 log "JWT secret created"
67 fi
68 }
69
70 setup_volumes() {
71 log "Setting up volumes and directories..."
72
73 local data_path="${DATA_PATH:-/opt/zephyrfs/data}"
74 local ssl_path="${SSL_CERTS_PATH:-/opt/zephyrfs/ssl}"
75
76 sudo mkdir -p "$data_path" "$ssl_path"
77 sudo chown -R 1000:1000 "$data_path"
78
79 log "Volumes configured"
80 }
81
82 deploy_stack() {
83 log "Deploying Docker stack..."
84
85 docker stack deploy \
86 --compose-file "$COMPOSE_FILE" \
87 --with-registry-auth \
88 "$STACK_NAME"
89
90 log "Stack deployment initiated"
91 }
92
93 wait_for_services() {
94 log "Waiting for services to be ready..."
95
96 local max_wait=300
97 local wait_time=0
98
99 while [[ $wait_time -lt $max_wait ]]; do
100 if docker service ls --filter name="${STACK_NAME}_" --format "{{.Replicas}}" | grep -q "0/"; then
101 log "Services still starting... (${wait_time}s)"
102 sleep 10
103 wait_time=$((wait_time + 10))
104 else
105 log "All services are running"
106 return 0
107 fi
108 done
109
110 error "Services failed to start within ${max_wait} seconds"
111 }
112
113 health_check() {
114 log "Performing health checks..."
115
116 local endpoints=(
117 "http://localhost/api/health"
118 "http://localhost:9090/-/healthy"
119 "http://localhost:3001/api/health"
120 )
121
122 for endpoint in "${endpoints[@]}"; do
123 if curl -f -s "$endpoint" >/dev/null; then
124 log "Health check passed: $endpoint"
125 else
126 log "WARNING: Health check failed: $endpoint"
127 fi
128 done
129 }
130
131 update_stack() {
132 log "Performing rolling update..."
133
134 # Update images
135 build_images
136
137 # Deploy with updated images
138 deploy_stack
139
140 # Wait for rolling update to complete
141 wait_for_services
142
143 log "Rolling update completed"
144 }
145
146 rollback_stack() {
147 log "Rolling back to previous version..."
148
149 docker service rollback "${STACK_NAME}_web-client"
150 docker service rollback "${STACK_NAME}_web-server"
151
152 wait_for_services
153
154 log "Rollback completed"
155 }
156
157 cleanup() {
158 log "Cleaning up unused resources..."
159
160 docker system prune -f
161 docker volume prune -f
162
163 log "Cleanup completed"
164 }
165
166 main() {
167 local action="${1:-deploy}"
168
169 case "$action" in
170 deploy)
171 check_prerequisites
172 build_images
173 setup_secrets
174 setup_volumes
175 deploy_stack
176 wait_for_services
177 health_check
178 ;;
179 update)
180 check_prerequisites
181 update_stack
182 health_check
183 ;;
184 rollback)
185 check_prerequisites
186 rollback_stack
187 health_check
188 ;;
189 cleanup)
190 cleanup
191 ;;
192 *)
193 echo "Usage: $0 {deploy|update|rollback|cleanup}"
194 echo ""
195 echo "Commands:"
196 echo " deploy - Initial deployment or full redeploy"
197 echo " update - Rolling update with zero downtime"
198 echo " rollback - Rollback to previous version"
199 echo " cleanup - Clean up unused Docker resources"
200 exit 1
201 ;;
202 esac
203
204 log "Operation '$action' completed successfully"
205 }
206
207 if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
208 main "$@"
209 fi