fix: publish backend images through Harbor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# sw2 Docker 部署
|
||||
|
||||
前端镜像统一发布至 `harbor.fuhua91.com/game/sw2:<版本>`。发布服务器需先通过 `docker login harbor.fuhua91.com` 配置 push/pull 权限;脚本在替换容器前完成推送、拉取和摘要校验。前端独立发布入口位于前端仓库 `deploy/`,也支持直接指定 Harbor 版本拉取部署。
|
||||
后端镜像发布至 `harbor.fuhua91.com/game/sw2-backend:<版本>`,前端镜像发布至 `harbor.fuhua91.com/game/sw2:<版本>`。发布服务器需先通过 `docker login harbor.fuhua91.com` 配置两个镜像仓库的 push/pull 权限;也可将本应用的 Docker 登录配置放在部署根目录的 `harbor-docker/` 下,脚本优先使用该配置。脚本在替换容器前完成两个镜像的推送、拉取和摘要校验,并使用 Harbor 返回的摘要启动容器。前端独立发布入口位于前端仓库 `deploy/`,也支持直接指定 Harbor 版本拉取部署。
|
||||
|
||||
沿用 226 服务器 `/www/wwwroot/live.fuhua91.com` 的 Docker 网络、持久化目录和宝塔反向代理结构。使用独立的 `sw2-backend`、`sw2-frontend`、`sw2-net`,兼容服务器现有 Docker 18.06,不依赖 Compose。
|
||||
|
||||
|
||||
+25
-14
@@ -5,10 +5,12 @@ TAG="${1:?Usage: deploy.sh TAG [--build-only]}"
|
||||
MODE="${2:-}"
|
||||
[[ "$TAG" =~ ^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}$ ]] || { echo 'Invalid release tag' >&2; exit 1; }
|
||||
[[ -z "$MODE" || "$MODE" == '--build-only' ]] || { echo 'Unknown mode' >&2; exit 1; }
|
||||
BASE_DIR=/www/wwwroot/sw2.fuhua91.com
|
||||
BASE_DIR="${SW_DEPLOY_BASE:-/www/wwwroot/sw2.fuhua91.com}"
|
||||
RELEASE="$BASE_DIR/releases/$TAG"
|
||||
BACKEND_IMAGE="sw2/backend:$TAG"
|
||||
FRONTEND_IMAGE="harbor.fuhua91.com/game/sw2:$TAG"
|
||||
BACKEND_REPOSITORY=harbor.fuhua91.com/game/sw2-backend
|
||||
FRONTEND_REPOSITORY=harbor.fuhua91.com/game/sw2
|
||||
BACKEND_IMAGE="$BACKEND_REPOSITORY:$TAG"
|
||||
FRONTEND_IMAGE="$FRONTEND_REPOSITORY:$TAG"
|
||||
NETWORK=sw2-net
|
||||
NAMES=(sw2-backend sw2-frontend)
|
||||
|
||||
@@ -19,17 +21,26 @@ test -f "$RELEASE/frontend/Dockerfile"
|
||||
|
||||
docker build --build-arg "VERSION=$TAG" -t "$BACKEND_IMAGE" "$RELEASE/backend"
|
||||
docker build --build-arg "VERSION=$TAG" -t "$FRONTEND_IMAGE" "$RELEASE/frontend"
|
||||
registry_args=()
|
||||
if [[ -s "$BASE_DIR/harbor-docker/config.json" ]]; then registry_args=(--config "$BASE_DIR/harbor-docker"); fi
|
||||
docker "${registry_args[@]}" push "$FRONTEND_IMAGE"
|
||||
docker "${registry_args[@]}" pull "$FRONTEND_IMAGE"
|
||||
frontend_digests=$(docker inspect --format '{{range .RepoDigests}}{{println .}}{{end}}' "$FRONTEND_IMAGE")
|
||||
frontend_ref=''
|
||||
while IFS= read -r reference; do
|
||||
if [[ "$reference" == 'harbor.fuhua91.com/game/sw2@sha256:'* && "${reference##*@}" =~ ^sha256:[a-f0-9]{64}$ ]]; then frontend_ref="$reference"; break; fi
|
||||
done <<< "$frontend_digests"
|
||||
[[ -n "$frontend_ref" ]] || { echo 'Harbor frontend digest is missing' >&2; exit 1; }
|
||||
FRONTEND_IMAGE="$frontend_ref"
|
||||
if [[ -s "$BASE_DIR/harbor-docker/config.json" ]]; then export DOCKER_CONFIG="$BASE_DIR/harbor-docker"; fi
|
||||
publish_image() {
|
||||
local repository=$1
|
||||
local image="$repository:$TAG"
|
||||
local digests reference
|
||||
# Explicitly propagate failures inside command substitutions on Bash 4.2.
|
||||
docker push "$image" >&2 || return 1
|
||||
docker pull "$image" >&2 || return 1
|
||||
digests=$(docker inspect --format '{{range .RepoDigests}}{{println .}}{{end}}' "$image") || return 1
|
||||
while IFS= read -r reference; do
|
||||
if [[ "$reference" == "$repository@sha256:"* && "${reference##*@}" =~ ^sha256:[a-f0-9]{64}$ ]]; then
|
||||
printf '%s\n' "$reference"
|
||||
return 0
|
||||
fi
|
||||
done <<< "$digests"
|
||||
echo "Harbor image digest is missing: $image" >&2
|
||||
return 1
|
||||
}
|
||||
BACKEND_IMAGE=$(publish_image "$BACKEND_REPOSITORY")
|
||||
FRONTEND_IMAGE=$(publish_image "$FRONTEND_REPOSITORY")
|
||||
docker run --rm "$BACKEND_IMAGE" /app/kratos-admin -h >/dev/null
|
||||
docker run --rm --add-host sw2-backend:127.0.0.1 "$FRONTEND_IMAGE" nginx -t
|
||||
if [[ "$MODE" == '--build-only' ]]; then exit 0; fi
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)/deploy.sh
|
||||
TEST_TMP=$(cd -- "${TMPDIR:-/tmp}" && pwd -P)
|
||||
TEST_ROOT=$(mktemp -d "$TEST_TMP/sw-joint-deploy-test.XXXXXX")
|
||||
cleanup() {
|
||||
[[ "$TEST_ROOT" == "$TEST_TMP/sw-joint-deploy-test."* ]] || exit 1
|
||||
rm -rf -- "$TEST_ROOT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir "$TEST_ROOT/bin"
|
||||
cat > "$TEST_ROOT/bin/docker" <<'DOCKER'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf '%s\n' "$*" >> "$TEST_STATE/calls"
|
||||
if [[ "$TEST_MODE" == isolated-config ]]; then
|
||||
[[ "${DOCKER_CONFIG:-}" == "$SW_DEPLOY_BASE/harbor-docker" || "$1" == build ]] || exit 1
|
||||
else
|
||||
[[ "${DOCKER_CONFIG:-}" == "$TEST_ROOT/default-config" ]] || exit 1
|
||||
fi
|
||||
component=frontend
|
||||
image="${!#}"
|
||||
if [[ "$image" == *sw2-backend:* ]]; then component=backend; fi
|
||||
case "$1" in
|
||||
build) exit 0 ;;
|
||||
push|pull)
|
||||
[[ "$TEST_MODE" != "$component-$1-fail" ]] || exit 1
|
||||
echo 'registry progress output' ;;
|
||||
inspect)
|
||||
[[ "$TEST_MODE" != "$component-inspect-fail" ]] || exit 1
|
||||
case "$TEST_MODE" in
|
||||
"$component-digest-missing") exit 0 ;;
|
||||
"$component-digest-wrong-repo") printf 'example.com/wrong@sha256:%064d\n' 1 ;;
|
||||
"$component-digest-malformed") printf '%s@sha256:invalid\n' "${image%:*}" ;;
|
||||
*)
|
||||
# An unrelated digest may precede the correct registry digest.
|
||||
printf 'example.com/old@sha256:%064d\n' 1
|
||||
printf '%s@sha256:%064d\n' "${image%:*}" 1 ;;
|
||||
esac ;;
|
||||
run) [[ "$*" == *'@sha256:'* && "$*" == *'--rm'* ]] ;;
|
||||
*) echo "Unexpected Docker command: $*" >&2; exit 1 ;;
|
||||
esac
|
||||
DOCKER
|
||||
printf '#!/usr/bin/env bash\nexit 0\n' > "$TEST_ROOT/bin/curl"
|
||||
chmod +x "$TEST_ROOT/bin/"*
|
||||
export TEST_ROOT PATH="$TEST_ROOT/bin:$PATH"
|
||||
|
||||
for scenario in success isolated-config \
|
||||
backend-push-fail backend-pull-fail backend-inspect-fail backend-digest-missing backend-digest-wrong-repo backend-digest-malformed \
|
||||
frontend-push-fail frontend-pull-fail frontend-inspect-fail frontend-digest-missing frontend-digest-wrong-repo frontend-digest-malformed; do
|
||||
export TEST_MODE="$scenario" TEST_STATE="$TEST_ROOT/$scenario"
|
||||
export SW_DEPLOY_BASE="$TEST_STATE/base" DOCKER_CONFIG="$TEST_ROOT/default-config"
|
||||
mkdir -p "$SW_DEPLOY_BASE/releases/new/backend" "$SW_DEPLOY_BASE/releases/new/frontend"
|
||||
touch "$SW_DEPLOY_BASE/releases/new/backend/Dockerfile" "$SW_DEPLOY_BASE/releases/new/frontend/Dockerfile"
|
||||
if [[ "$scenario" == isolated-config ]]; then
|
||||
mkdir "$SW_DEPLOY_BASE/harbor-docker"
|
||||
printf '{}\n' > "$SW_DEPLOY_BASE/harbor-docker/config.json"
|
||||
fi
|
||||
result=0
|
||||
bash "$SCRIPT" new --build-only > "$TEST_STATE/output" 2>&1 || result=$?
|
||||
case "$scenario" in
|
||||
success|isolated-config)
|
||||
[[ "$result" == 0 ]] || { cat "$TEST_STATE/output" >&2; exit 1; }
|
||||
for repository in harbor.fuhua91.com/game/sw2-backend harbor.fuhua91.com/game/sw2; do
|
||||
grep -qFx "push $repository:new" "$TEST_STATE/calls"
|
||||
grep -qFx "pull $repository:new" "$TEST_STATE/calls"
|
||||
grep -qE "^run .* $repository@sha256:[a-f0-9]{64} " "$TEST_STATE/calls"
|
||||
done ;;
|
||||
*)
|
||||
[[ "$result" != 0 ]]
|
||||
! grep -qE '^(run|stop|rename|rm) ' "$TEST_STATE/calls" ;;
|
||||
esac
|
||||
! grep -qE 'sw2/(backend|frontend):' "$TEST_STATE/calls"
|
||||
printf 'passed: %s\n' "$scenario"
|
||||
done
|
||||
Reference in New Issue
Block a user