-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeploy.sh
More file actions
156 lines (129 loc) · 4.54 KB
/
Copy pathdeploy.sh
File metadata and controls
156 lines (129 loc) · 4.54 KB
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
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env bash
set -Eeuo pipefail
APP_DIR="${APP_DIR:-/opt/medshop}"
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.prod.yml}"
ENV_FILE="${ENV_FILE:-.env}"
IMAGE_URI="${IMAGE_URI:?IMAGE_URI is required}"
IMAGE_TAG="${IMAGE_TAG:-latest}"
ROLLBACK_IMAGE_URI=""
ROLLBACK_IMAGE_TAG=""
COMPOSE_LEGACY_V1="false"
cd "$APP_DIR"
if [[ ! -f "$ENV_FILE" ]]; then
echo "Missing required env file: $APP_DIR/$ENV_FILE"
exit 1
fi
if [[ -n "${AWS_REGION:-}" ]]; then
ECR_REGISTRY="${IMAGE_URI%%/*}"
aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$ECR_REGISTRY"
fi
if docker compose version >/dev/null 2>&1; then
COMPOSE_CMD=(docker compose)
elif command -v docker-compose >/dev/null 2>&1; then
COMPOSE_CMD=(docker-compose)
COMPOSE_LEGACY_V1="true"
else
echo "Docker Compose is not available. Install docker compose plugin or docker-compose."
exit 1
fi
get_api_container_id() {
"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" ps -q api 2>/dev/null || true
}
prepare_api_up() {
if [[ "$COMPOSE_LEGACY_V1" != "true" ]]; then
return 0
fi
local api_container_id
api_container_id="$(get_api_container_id)"
if [[ -z "$api_container_id" ]]; then
return 0
fi
echo "docker-compose v1 detected. Removing existing api container to avoid recreate bug."
docker rm -f "$api_container_id" >/dev/null 2>&1 || true
}
api_healthcheck() {
for _ in {1..20}; do
if curl --silent --fail "http://127.0.0.1:3001/api/health" >/dev/null; then
return 0
fi
sleep 3
done
return 1
}
capture_rollback_target() {
local running_image
local api_container_id
api_container_id="$(get_api_container_id)"
if [[ -n "$api_container_id" ]]; then
running_image="$(docker inspect --format '{{.Config.Image}}' "$api_container_id" 2>/dev/null || true)"
else
running_image="$(docker inspect --format '{{.Config.Image}}' medshop-api 2>/dev/null || true)"
fi
if [[ -z "$running_image" ]]; then
echo "No existing api container found. Auto rollback will be unavailable."
return
fi
if [[ "$running_image" == *"@"* ]]; then
echo "Existing image reference uses a digest ($running_image). Auto rollback skipped."
return
fi
local parsed_uri="${running_image%:*}"
local parsed_tag="${running_image##*:}"
if [[ -z "$parsed_uri" || -z "$parsed_tag" || "$parsed_uri" == "$running_image" ]]; then
echo "Could not parse rollback target from '$running_image'. Auto rollback skipped."
return
fi
if [[ "$parsed_uri:$parsed_tag" == "$IMAGE_URI:$IMAGE_TAG" ]]; then
echo "Current container already uses requested image. Auto rollback target unavailable."
return
fi
ROLLBACK_IMAGE_URI="$parsed_uri"
ROLLBACK_IMAGE_TAG="$parsed_tag"
echo "Captured rollback target: ${ROLLBACK_IMAGE_URI}:${ROLLBACK_IMAGE_TAG}"
}
attempt_rollback() {
if [[ -z "$ROLLBACK_IMAGE_URI" || -z "$ROLLBACK_IMAGE_TAG" ]]; then
echo "No rollback target available."
return 1
fi
IMAGE_URI="$ROLLBACK_IMAGE_URI"
IMAGE_TAG="$ROLLBACK_IMAGE_TAG"
export IMAGE_URI IMAGE_TAG
echo "Attempting rollback to ${IMAGE_URI}:${IMAGE_TAG}..."
"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" pull api || true
prepare_api_up
"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --remove-orphans api
echo "Waiting for rollback health check..."
if api_healthcheck; then
echo "Rollback successful."
return 0
fi
echo "Rollback health check failed. Recent API logs:"
"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs --tail=100 api
return 1
}
capture_rollback_target
export IMAGE_URI IMAGE_TAG
if ! "${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" pull api || \
! "${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" run --rm api pnpm --filter @medshop/api migration:run; then
echo "Deployment command failed. Recent API logs:"
"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs --tail=100 api || true
attempt_rollback || true
exit 1
fi
prepare_api_up
if ! "${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --remove-orphans api; then
echo "Deployment command failed. Recent API logs:"
"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs --tail=100 api || true
attempt_rollback || true
exit 1
fi
echo "Waiting for API health check..."
if api_healthcheck; then
echo "Deployment successful."
exit 0
fi
echo "Health check failed. Recent API logs:"
"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs --tail=100 api
attempt_rollback || true
exit 1