ops: add production observability and recovery
This commit is contained in:
84
infra/scripts/restore.ps1
Normal file
84
infra/scripts/restore.ps1
Normal file
@@ -0,0 +1,84 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$BackupDirectory,
|
||||
[string]$ComposeFile = "",
|
||||
[string]$PostgresDatabase = $env:POSTGRES_DB,
|
||||
[string]$PostgresUser = $env:POSTGRES_USER,
|
||||
[string]$Confirm = $env:RESTORE_CONFIRM,
|
||||
[string]$BackupHelperImage = "alpine:3.21",
|
||||
[switch]$SkipApplicationServices
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
if ($Confirm -ne "restore-ai-ticket-platform") {
|
||||
throw "恢复会替换当前 PostgreSQL 与 MinIO 数据;请传入 -Confirm restore-ai-ticket-platform。"
|
||||
}
|
||||
|
||||
$scriptDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$infraDirectory = [IO.Path]::GetFullPath((Join-Path $scriptDirectory ".."))
|
||||
if (-not $ComposeFile) {
|
||||
$ComposeFile = Join-Path $infraDirectory "docker-compose.prod.yml"
|
||||
}
|
||||
$ComposeFile = (Resolve-Path -LiteralPath $ComposeFile).Path
|
||||
$target = (Resolve-Path -LiteralPath $BackupDirectory).Path
|
||||
if (-not $PostgresDatabase) { $PostgresDatabase = "ai_ticket_platform" }
|
||||
if (-not $PostgresUser) { $PostgresUser = "ai_ticket" }
|
||||
|
||||
& (Join-Path $scriptDirectory "verify-backup.ps1") -BackupDirectory $target
|
||||
|
||||
$postgresTemp = "/tmp/ai-ticket-restore-$PID.dump"
|
||||
$minioContainer = & docker compose -f $ComposeFile ps -q minio
|
||||
if ($LASTEXITCODE -ne 0 -or -not "$minioContainer".Trim()) {
|
||||
throw "未找到 MinIO 容器"
|
||||
}
|
||||
$minioContainer = "$minioContainer".Trim()
|
||||
|
||||
function Invoke-Compose {
|
||||
param([Parameter(Mandatory = $true)][string[]]$Arguments)
|
||||
& docker compose -f $ComposeFile @Arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "docker compose 执行失败:$($Arguments -join ' ')"
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $SkipApplicationServices) {
|
||||
Invoke-Compose @("stop", "backend", "worker", "beat")
|
||||
}
|
||||
Invoke-Compose @("stop", "minio")
|
||||
|
||||
try {
|
||||
Invoke-Compose @("cp", (Join-Path $target "postgres.dump"), "postgres:$postgresTemp")
|
||||
Invoke-Compose @(
|
||||
"exec", "-T", "postgres",
|
||||
"dropdb", "-U", $PostgresUser, "--if-exists", "--force", $PostgresDatabase
|
||||
)
|
||||
Invoke-Compose @(
|
||||
"exec", "-T", "postgres",
|
||||
"createdb", "-U", $PostgresUser, $PostgresDatabase
|
||||
)
|
||||
Invoke-Compose @(
|
||||
"exec", "-T", "postgres",
|
||||
"pg_restore", "-U", $PostgresUser, "-d", $PostgresDatabase,
|
||||
"--no-owner", "--exit-on-error", $postgresTemp
|
||||
)
|
||||
|
||||
& docker run --rm `
|
||||
--volumes-from $minioContainer `
|
||||
-v "${target}:/backup:ro" `
|
||||
$BackupHelperImage `
|
||||
sh -c "find /data -mindepth 1 -maxdepth 1 -exec rm -rf -- {} + && tar -C /data -xzf /backup/minio-data.tar.gz"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "MinIO 数据恢复失败"
|
||||
}
|
||||
Invoke-Compose @("up", "-d", "--wait", "minio")
|
||||
}
|
||||
finally {
|
||||
& docker compose -f $ComposeFile exec -T postgres rm -f $postgresTemp 2>$null
|
||||
}
|
||||
|
||||
if (-not $SkipApplicationServices) {
|
||||
Invoke-Compose @("start", "backend", "worker", "beat")
|
||||
}
|
||||
|
||||
Write-Output "恢复完成。请立即检查 /api/system/health/ready 并执行核心业务冒烟测试。"
|
||||
Reference in New Issue
Block a user