Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
DATABASE_URL_SYNC=postgresql://external:secret@db.example:5432/auth \
REDIS_URL=redis://cache.example:6379/0 \
docker compose config --quiet
docker compose -f docker-compose.yml -f docker-compose.migrate.yml config --quiet

pr-image:
name: Container build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ jobs:
# 旧实例不理解 auth_generation;迁移前先停流量,关闭双写协议窗口。
docker compose -f docker-compose.yml stop auth
fi
if ! docker compose -f docker-compose.yml run --rm --no-deps auth alembic upgrade head; then
if ! docker compose -f docker-compose.yml -f docker-compose.migrate.yml run --rm --no-deps auth alembic upgrade head; then
migration_failed=1
if [ "$auth_generation_cutover" -eq 1 ]; then
echo "::error::数据库迁移失败,恢复已停止的旧容器"
Expand Down
7 changes: 7 additions & 0 deletions docker-compose.migrate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
auth:
# One-off migration containers run alongside the live auth service, so they
# must not inherit its dedicated ingress address.
networks:
auth_edge:
ipv4_address: !reset null
17 changes: 12 additions & 5 deletions tests/test_deploy_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ def _workflow() -> str:


GENERATION_MIGRATION = "alembic/versions/c8d9e0f1a2b3_add_auth_generation.py"
MIGRATION_COMMAND = (
"docker compose -f docker-compose.yml -f docker-compose.migrate.yml "
"run --rm --no-deps auth alembic upgrade head"
)


def test_deploy_detects_auth_generation_cutover_from_previous_sha():
Expand All @@ -21,7 +25,7 @@ def test_deploy_builds_stops_migrates_then_switches_for_generation_cutover():
deploy_sequence = workflow.split("# 先构建新镜像,再按迁移类型安全切换。", 1)[1]
build = "docker compose -f docker-compose.yml build auth"
stop = "docker compose -f docker-compose.yml stop auth"
migrate = "docker compose -f docker-compose.yml run --rm --no-deps auth alembic upgrade head"
migrate = MIGRATION_COMMAND
switch = "docker compose -f docker-compose.yml up -d --no-build auth"

assert build in deploy_sequence
Expand All @@ -40,13 +44,16 @@ def test_generation_migration_failure_restores_source_and_restarts_stopped_old_c
assert "docker compose -f docker-compose.yml start auth" in recovery
assert "http://127.0.0.1:8100/health" in recovery
assert "docker compose -f docker-compose.yml build auth" not in recovery
assert (
'if ! docker compose -f docker-compose.yml run --rm --no-deps auth alembic upgrade head; then'
in workflow
)
assert f"if ! {MIGRATION_COMMAND}; then" in workflow
assert "数据库迁移失败,恢复已停止的旧容器" in workflow


def test_migration_container_does_not_reuse_live_static_ip():
override = (Path(__file__).parents[1] / "docker-compose.migrate.yml").read_text()

assert "ipv4_address: !reset null" in override


def test_generation_migration_success_disables_legacy_sha_rollback_on_new_container_failure():
workflow = _workflow()
assert 'if [ "$auth_generation_cutover" -eq 1 ] && [ "$migration_succeeded" -eq 1 ]; then' in workflow
Expand Down