95 lines
2.6 KiB
Bash
95 lines
2.6 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
|
|
IMAGE_ARCHIVE="${1:?IMAGE_ARCHIVE is required}"
|
|
IMAGE_TAG="${2:?IMAGE_TAG is required}"
|
|
REMOTE_DIR="${3:-/opt/caiwuxitong}"
|
|
DEPLOY_SHA="${4:?DEPLOY_SHA is required}"
|
|
RUN_MIGRATIONS="${5:-0}"
|
|
KEEP_IMAGES="${6:-2}"
|
|
IMAGE_NAME="caiwu_akaunting"
|
|
LOCK_FILE="$REMOTE_DIR/.deploy.lock"
|
|
|
|
cleanup() {
|
|
rm -f "$IMAGE_ARCHIVE"
|
|
}
|
|
|
|
trap cleanup EXIT INT TERM
|
|
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "activate-release.sh must run as root" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$REMOTE_DIR/runtime/.env" ]; then
|
|
echo "Missing $REMOTE_DIR/runtime/.env; run bootstrap-server.sh first" >&2
|
|
exit 1
|
|
fi
|
|
|
|
exec 9>"$LOCK_FILE"
|
|
if ! flock -n 9; then
|
|
echo "Another CaiWuXiTong deployment is already running" >&2
|
|
exit 1
|
|
fi
|
|
|
|
PREVIOUS_IMAGE="$(docker inspect caiwu_app --format '{{.Config.Image}}' 2>/dev/null || true)"
|
|
PREVIOUS_SHA="$(cat "$REMOTE_DIR/.deployed-sha" 2>/dev/null || true)"
|
|
|
|
docker load --input "$IMAGE_ARCHIVE"
|
|
rm -f "$IMAGE_ARCHIVE"
|
|
|
|
LOADED_SHA="$(docker image inspect "$IMAGE_NAME:$IMAGE_TAG" --format '{{index .Config.Labels "org.opencontainers.image.revision"}}')"
|
|
if [ "$LOADED_SHA" != "$DEPLOY_SHA" ]; then
|
|
echo "Image revision mismatch: expected $DEPLOY_SHA, got $LOADED_SHA" >&2
|
|
exit 1
|
|
fi
|
|
|
|
cd "$REMOTE_DIR"
|
|
export IMAGE_TAG RUN_MIGRATIONS
|
|
docker compose -f compose.jiangling.yml up -d --remove-orphans
|
|
|
|
healthy=0
|
|
attempt=1
|
|
while [ "$attempt" -le 30 ]; do
|
|
if curl -fsS -o /dev/null http://127.0.0.1/; then
|
|
healthy=1
|
|
break
|
|
fi
|
|
|
|
sleep 5
|
|
attempt=$((attempt + 1))
|
|
done
|
|
|
|
if [ "$healthy" -ne 1 ]; then
|
|
docker compose -f compose.jiangling.yml logs --tail 120 app >&2 || true
|
|
|
|
case "$PREVIOUS_IMAGE" in
|
|
"$IMAGE_NAME":*)
|
|
IMAGE_TAG="${PREVIOUS_IMAGE#*:}"
|
|
RUN_MIGRATIONS=0
|
|
export IMAGE_TAG RUN_MIGRATIONS
|
|
docker compose -f compose.jiangling.yml up -d app || true
|
|
;;
|
|
esac
|
|
|
|
echo "Release failed health check; previous image was restored when available" >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf '%s\n' "$DEPLOY_SHA" > "$REMOTE_DIR/.deployed-sha.tmp"
|
|
mv "$REMOTE_DIR/.deployed-sha.tmp" "$REMOTE_DIR/.deployed-sha"
|
|
|
|
docker image ls "$IMAGE_NAME" --format '{{.Repository}}:{{.Tag}}' \
|
|
| awk '!seen[$0]++' \
|
|
| tail -n "+$((KEEP_IMAGES + 1))" \
|
|
| while IFS= read -r old_image; do
|
|
[ -n "$old_image" ] && docker image rm "$old_image" >/dev/null 2>&1 || true
|
|
done
|
|
|
|
docker image prune -f --filter 'label=com.caiwu.project=CaiWuXiTong' >/dev/null || true
|
|
docker compose -f compose.jiangling.yml ps
|
|
echo "DEPLOYED_SHA=$DEPLOY_SHA"
|
|
|
|
# Keep the variable for rollback diagnostics without printing any secret.
|
|
: "$PREVIOUS_SHA"
|