#!/bin/sh # 只启动已安装的明确镜像和配置;迁移是独立维护命令。 set -eu if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then echo "用法:启动.sh <发布目录> <部署环境文件> [明确的覆盖配置]" >&2 exit 2 fi release_dir=$(cd "$1" && pwd) environment_file=$(cd "$(dirname "$2")" && pwd)/$(basename "$2") override_file=${3:-} compose() { if [ -n "$override_file" ]; then set -- -f "$override_file" "$@" fi docker compose --project-directory "$release_dir" --env-file "$environment_file" \ -f "$release_dir/compose.yaml" "$@" } # 先核镜像身份和包内构建身份,再开放服务端口;核对进程不启动HTTP、不读数据库。 compose config --format json | python3 -c ' import json,re,sys image=json.load(sys.stdin)["services"]["web"]["image"] if not re.fullmatch(r"(?:sha256:|[^\s]+@sha256:)[0-9a-f]{64}",image): raise SystemExit("需要镜像摘要或完整本地镜像ID,不能用可变标签启动") ' expected_build=$(python3 -c 'import json,sys; r=json.load(open(sys.argv[1]));print(r["build_id"],r["release_id"])' "$release_dir/发布清单.json") actual_build=$(compose run --rm --no-deps --entrypoint /opt/muse/bin/python web -I -c \ 'import json;from muse.资源加载 import 核对资源;print(核对资源()["构建身份"],json.load(open("/opt/muse-release.json"))["release_id"])') if [ "$actual_build" != "$expected_build" ]; then echo "镜像与本发布目录的构建身份不一致,拒绝启动" >&2 exit 1 fi compose up -d --wait --wait-timeout 90