fix(deploy): publish unified services to temporary gray environment

This commit is contained in:
2026-10-07 11:02:47 +08:00
parent 6346e7bd95
commit ec0c06ff88
9 changed files with 211 additions and 72 deletions
+21 -20
View File
@@ -1,4 +1,4 @@
name: firstleg-test
name: firstleg-${DEPLOY_ENV:-test}
x-common: &common
restart: "on-failure:3"
@@ -8,17 +8,17 @@ x-common: &common
extra_hosts:
- "host.docker.internal:host-gateway"
environment: &common-environment
DEPLOY_ENV: test
DEPLOY_ENV: ${DEPLOY_ENV:-test}
BAIYUE_RELEASE_ID: ${RELEASE_ID:-local}
BAIYUE_RUNTIME_SCHEDULING_ENABLED: ${BAIYUE_RUNTIME_SCHEDULING_ENABLED:-true}
SERVER_SHUTDOWN: graceful
SPRING_LIFECYCLE_TIMEOUT_PER_SHUTDOWN_PHASE: ${SHUTDOWN_PHASE_TIMEOUT:-30s}
SPRING_PROFILES_ACTIVE: test
SPRING_PROFILES_ACTIVE: ${DEPLOY_ENV:-test}
NACOS_SERVER_ADDR: ${NACOS_SERVER_ADDR}
NACOS_USERNAME: ${NACOS_USERNAME}
NACOS_PASSWORD: ${NACOS_PASSWORD}
NACOS_GROUP: ${NACOS_GROUP:-BAIYUE}
NACOS_NAMESPACE: ${NACOS_NAMESPACE:?actual TEST namespace ID required}
NACOS_NAMESPACE: ${NACOS_NAMESPACE:?actual environment namespace ID required}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT:-6379}
REDIS_PASSWORD: ${REDIS_PASSWORD}
@@ -32,7 +32,7 @@ x-common: &common
REDIS_TOKEN_KEY_PREFIX: ${REDIS_TOKEN_KEY_PREFIX:-baiyue:auth}
SPRING_SQL_INIT_MODE: never
ROCKETMQ_NAME_SERVER: ${ROCKETMQ_NAME_SERVER}
MQ_TOPIC_PREFIX: test-
MQ_TOPIC_PREFIX: ${MQ_TOPIC_PREFIX:-test-}
INTERNAL_SERVICE_TOKEN: ${INTERNAL_SERVICE_TOKEN}
BAIYUE_AUDIT_ENDPOINT: http://audit-service:9700/internal/audit/events
SERVER_MAX_HTTP_REQUEST_HEADER_SIZE: ${SERVER_MAX_HTTP_REQUEST_HEADER_SIZE:-32KB}
@@ -50,11 +50,12 @@ services:
gateway:
<<: *common
image: ${IMAGE_REPOSITORY}/gateway:${IMAGE_TAG}
container_name: firstleg-test-gateway
container_name: firstleg-${DEPLOY_ENV:-test}-gateway
ports: ["${PUBLISHED_BIND_ADDRESS:-127.0.0.1}:${GATEWAY_PUBLISHED_PORT:-${GATEWAY_PORT:-9000}}:9000"]
environment:
<<: *common-environment
SERVER_PORT: 9000
SPRING_PROFILES_ACTIVE: ${DEPLOY_ENV:-test},cn
SWAGGER_ENABLED: ${SWAGGER_ENABLED:-false}
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
CORS_ALLOW_CREDENTIALS: ${CORS_ALLOW_CREDENTIALS:-false}
@@ -62,7 +63,7 @@ services:
auth:
<<: *common
image: ${IMAGE_REPOSITORY}/auth:${IMAGE_TAG}
container_name: firstleg-test-auth
container_name: firstleg-${DEPLOY_ENV:-test}-auth
expose: ["9100"]
environment:
<<: *common-environment
@@ -76,7 +77,7 @@ services:
iam:
<<: *common
image: ${IMAGE_REPOSITORY}/iam:${IMAGE_TAG}
container_name: firstleg-test-iam
container_name: firstleg-${DEPLOY_ENV:-test}-iam
expose: ["9201"]
environment:
<<: *common-environment
@@ -90,7 +91,7 @@ services:
firstleg:
<<: *common
image: ${IMAGE_REPOSITORY}/firstleg:${IMAGE_TAG}
container_name: firstleg-test-business
container_name: firstleg-${DEPLOY_ENV:-test}-business
expose: ["9202"]
environment:
<<: *common-environment
@@ -133,7 +134,7 @@ services:
finance:
<<: *common
image: ${IMAGE_REPOSITORY}/finance:${IMAGE_TAG}
container_name: firstleg-test-finance
container_name: firstleg-${DEPLOY_ENV:-test}-finance
expose: ["9203"]
environment:
<<: *common-environment
@@ -156,7 +157,7 @@ services:
order:
<<: *common
image: ${IMAGE_REPOSITORY}/order:${IMAGE_TAG}
container_name: firstleg-test-order
container_name: firstleg-${DEPLOY_ENV:-test}-order
expose: ["9204"]
environment:
<<: *common-environment
@@ -168,7 +169,7 @@ services:
warehouse:
<<: *common
image: ${IMAGE_REPOSITORY}/warehouse:${IMAGE_TAG}
container_name: firstleg-test-warehouse
container_name: firstleg-${DEPLOY_ENV:-test}-warehouse
expose: ["9205"]
environment:
<<: *common-environment
@@ -180,7 +181,7 @@ services:
file:
<<: *common
image: ${IMAGE_REPOSITORY}/file:${IMAGE_TAG}
container_name: firstleg-test-file
container_name: firstleg-${DEPLOY_ENV:-test}-file
expose: ["9206"]
volumes:
- "${FILE_UPLOADS_HOST_DIR:-/data/firstleg/uploads}:/data/files"
@@ -202,7 +203,7 @@ services:
print:
<<: *common
image: ${IMAGE_REPOSITORY}/print:${IMAGE_TAG}
container_name: firstleg-test-print
container_name: firstleg-${DEPLOY_ENV:-test}-print
expose: ["9207"]
environment:
<<: *common-environment
@@ -212,7 +213,7 @@ services:
integration-service:
<<: *common
image: ${IMAGE_REPOSITORY}/integration-service:${IMAGE_TAG}
container_name: firstleg-test-integration
container_name: firstleg-${DEPLOY_ENV:-test}-integration
expose: ["9210"]
environment:
<<: *common-environment
@@ -261,7 +262,7 @@ services:
audit-service:
<<: *common
image: ${IMAGE_REPOSITORY}/audit-service:${IMAGE_TAG}
container_name: firstleg-test-audit
container_name: firstleg-${DEPLOY_ENV:-test}-audit
expose: ["9700"]
environment:
<<: *common-environment
@@ -276,7 +277,7 @@ services:
lastleg-service:
<<: *common
image: ${IMAGE_REPOSITORY}/lastleg-service:${IMAGE_TAG}
container_name: firstleg-test-lastleg
container_name: firstleg-${DEPLOY_ENV:-test}-lastleg
expose: ["9303"]
environment:
<<: *common-environment
@@ -303,7 +304,7 @@ services:
warehouse-overseas-service:
<<: *common
image: ${IMAGE_REPOSITORY}/warehouse-overseas-service:${IMAGE_TAG}
container_name: firstleg-test-warehouse-overseas
container_name: firstleg-${DEPLOY_ENV:-test}-warehouse-overseas
expose: ["9305"]
environment:
<<: *common-environment
@@ -316,7 +317,7 @@ services:
networks:
firstleg-network:
name: firstleg-test-network
name: firstleg-${DEPLOY_ENV:-test}-network
infra-network:
external: true
name: ${INFRA_NETWORK:-firstleg-test-infra-network}
name: ${INFRA_NETWORK:-firstleg-${DEPLOY_ENV:-test}-infra-network}
+43 -4
View File
@@ -29,18 +29,23 @@ for value_name in HEALTH_TIMEOUT_SECONDS HEALTH_POLL_SECONDS; do
done
[ "$DEPLOY_ENV" = "test" ] || { echo "Only test is supported" >&2; exit 2; }
case "$DEPLOY_ENV" in test|production) ;; *) echo "Only test and production are supported" >&2; exit 2 ;; esac
case "$SERVICE" in
gateway|auth|iam|firstleg|finance|order|warehouse|file|print|integration-service|lastleg-service|warehouse-overseas-service|audit-service) ;;
*) echo "Unknown or retired service: $SERVICE" >&2; exit 2 ;;
esac
[ "${TARGET_IS_LOCAL:-false}" = "true" ] || { echo "TEST deploy must run on the target host" >&2; exit 2; }
case "$IMAGE_REPOSITORY" in ''|*[!a-zA-Z0-9._:/-]*) echo "Invalid image repository" >&2; exit 2 ;; esac
case "$IMAGE_TAG" in ''|*[!a-zA-Z0-9_.-]*) echo "Invalid image tag" >&2; exit 2 ;; esac
case "${ALLOW_SAME_CONTRACT_ROLLBACK:-false}" in true|false) ;; *) exit 2 ;; esac
if [ "$DEPLOY_ENV" = "test" ] && [ "${TARGET_IS_LOCAL:-false}" != "true" ]; then
echo "TEST deploy must run on the target host" >&2; exit 2
fi
[ -f "$ENV_FILE" ] || { echo "Environment file missing" >&2; exit 2; }
env_file_value() { sed -n "s/^$1=//p" "$ENV_FILE" | tail -n 1 | tr -d '\r'; }
for key in NACOS_SERVER_ADDR NACOS_NAMESPACE NACOS_USERNAME NACOS_PASSWORD REDIS_HOST REDIS_PORT REDIS_DATABASE REDIS_TOKEN_KEY_PREFIX INTERNAL_SERVICE_TOKEN JWT_RSA_JWK_SET JWT_CURRENT_KID ROCKETMQ_NAME_SERVER; do
[ -n "$(env_file_value "$key")" ] || { echo "Missing $key" >&2; exit 2; }
done
[ "$(env_file_value MQ_TOPIC_PREFIX)" = "test-" ] || { echo "MQ_TOPIC_PREFIX must be test-" >&2; exit 2; }
[ "$(env_file_value MQ_TOPIC_PREFIX)" = "$DEPLOY_ENV-" ] || { echo "MQ_TOPIC_PREFIX must be $DEPLOY_ENV-" >&2; exit 2; }
case "$SERVICE" in
gateway|print|integration-service) db_prefix='' ;;
lastleg-service) db_prefix=LASTLEG ;;
@@ -138,6 +143,7 @@ wait_for_local_health() {
}
deploy_local() {
export DEPLOY_ENV IMAGE_REPOSITORY IMAGE_TAG
deploy_docker_config=$(mktemp -d)
DOCKER_CONFIG="$deploy_docker_config"
export DOCKER_CONFIG
@@ -223,4 +229,37 @@ deploy_local() {
return 1
}
deploy_local
deploy_remote() {
: "${TARGET_SSH_TARGET:?TARGET_SSH_TARGET required}"
: "${TARGET_SSH_KEY:?TARGET_SSH_KEY required}"
: "${TARGET_SSH_KNOWN_HOSTS:?TARGET_SSH_KNOWN_HOSTS required}"
[ -f "$TARGET_SSH_KEY" ] && [ -f "$TARGET_SSH_KNOWN_HOSTS" ] || exit 2
run_ssh() {
ssh -i "$TARGET_SSH_KEY" -o BatchMode=yes -o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="$TARGET_SSH_KNOWN_HOSTS" -o ConnectTimeout=10 "$TARGET_SSH_TARGET" "$@"
}
run_scp() {
scp -i "$TARGET_SSH_KEY" -o BatchMode=yes -o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="$TARGET_SSH_KNOWN_HOSTS" -o ConnectTimeout=10 "$@"
}
remote_dir=$(run_ssh 'umask 077; mktemp -d /tmp/firstleg-production-release.XXXXXXXXXX')
case "$remote_dir" in /tmp/firstleg-production-release.*) ;; *) echo "Invalid remote temporary directory" >&2; exit 2 ;; esac
case "$remote_dir" in *[!a-zA-Z0-9/._-]*) exit 2 ;; esac
cleanup_remote() { run_ssh "rm -rf -- '$remote_dir'" >/dev/null 2>&1; }
trap cleanup_remote EXIT HUP INT TERM
run_ssh "mkdir -p '$remote_dir/deploy/scripts'"
run_scp "$ENV_FILE" "$TARGET_SSH_TARGET:$remote_dir/deployment.env"
run_scp "$COMPOSE_FILE" "$TARGET_SSH_TARGET:$remote_dir/deploy/docker-compose.yml"
run_scp deploy/scripts/deploy-built-service.sh "$TARGET_SSH_TARGET:$remote_dir/deploy/scripts/deploy-built-service.sh"
# Registry credentials only travel over stdin, never in process arguments or files.
{ printf '%s\n' "$REGISTRY_USER"; printf '%s' "$REGISTRY_PASSWORD"; } | run_ssh \
"cd '$remote_dir' && IFS= read -r REGISTRY_USER && REGISTRY_PASSWORD=\$(cat) && export REGISTRY_USER REGISTRY_PASSWORD TARGET_IS_LOCAL=true ALLOW_SAME_CONTRACT_ROLLBACK='${ALLOW_SAME_CONTRACT_ROLLBACK:-false}' DEPLOY_HEALTH_TIMEOUT_SECONDS='$HEALTH_TIMEOUT_SECONDS' DEPLOY_HEALTH_POLL_SECONDS='$HEALTH_POLL_SECONDS' && sh deploy/scripts/deploy-built-service.sh production '$IMAGE_REPOSITORY' '$IMAGE_TAG' '$SERVICE' deployment.env"
cleanup_remote
trap - EXIT HUP INT TERM
}
if [ "${TARGET_IS_LOCAL:-false}" = "true" ]; then
deploy_local
else
deploy_remote
fi