部署优化

This commit is contained in:
wchino
2026-06-13 22:16:14 +08:00
parent 21dd9957f0
commit 73a94e6be3
28 changed files with 899 additions and 129 deletions

View File

@@ -1,13 +1,15 @@
# 构建 api / player / admin 生产镜像并导出为 tar
# 用法(在项目根目录或本目录执行均可):
# .\docs\docker\build-and-export-images.ps1
# .\docs\docker\build-and-export-images.ps1 -Tag v1.2.3
# .\build-and-export-images.ps1 -UseCache
# .\build-and-export-images.ps1 -ExportOnly
param(
[string]$Tag = $env:IMAGE_TAG,
[switch]$UseCache,
[switch]$ExportOnly,
[string]$Output = "thebet365-images.tar"
[string]$Output = ""
)
$ErrorActionPreference = "Stop"
@@ -18,6 +20,21 @@ $ComposeFile = "docker-compose.prod.yml"
$EnvFile = ".env.docker"
$Services = @("api", "player", "admin")
function Get-DefaultTag {
try {
$short = (& git rev-parse --short HEAD 2>$null).Trim()
if ($short) { return $short }
} catch {}
return Get-Date -Format "yyyyMMdd-HHmmss"
}
function Assert-ImageTag {
param([string]$Value)
if ($Value -notmatch '^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$') {
throw "镜像 tag 不合法: $Value"
}
}
if (-not (Test-Path $ComposeFile)) {
throw "未找到 $ComposeFile(当前目录: $Root"
}
@@ -31,8 +48,16 @@ if (-not (Test-Path $EnvFile)) {
}
}
if ([string]::IsNullOrWhiteSpace($Tag)) {
$Tag = Get-DefaultTag
}
Assert-ImageTag $Tag
if ([string]::IsNullOrWhiteSpace($Output)) {
$Output = "thebet365-images-$Tag.tar"
}
if (-not $ExportOnly) {
Write-Host "==> 构建镜像: $($Services -join ', ')"
Write-Host "==> 构建镜像: $($Services -join ', ') (tag: $Tag)"
$buildArgs = @(
"compose", "-f", $ComposeFile, "--env-file", $EnvFile, "build"
)
@@ -40,28 +65,72 @@ if (-not $ExportOnly) {
$buildArgs += "--no-cache"
}
$buildArgs += $Services
& docker @buildArgs
if ($LASTEXITCODE -ne 0) { throw "docker build 失败,退出码 $LASTEXITCODE" }
$oldImageTag = $env:IMAGE_TAG
try {
$env:IMAGE_TAG = $Tag
& docker @buildArgs
if ($LASTEXITCODE -ne 0) { throw "docker build 失败,退出码 $LASTEXITCODE" }
} finally {
$env:IMAGE_TAG = $oldImageTag
}
}
$OutputPath = if ([System.IO.Path]::IsPathRooted($Output)) { $Output } else { Join-Path $Root $Output }
Write-Host "==> 导出镜像 -> $OutputPath"
& docker save `
thebet365-api:latest `
thebet365-player:latest `
thebet365-admin:latest `
"thebet365-api:${Tag}" `
"thebet365-player:${Tag}" `
"thebet365-admin:${Tag}" `
-o $OutputPath
if ($LASTEXITCODE -ne 0) { throw "docker save 失败,退出码 $LASTEXITCODE" }
$manifestPath = if ($OutputPath.EndsWith(".tar")) {
$OutputPath.Substring(0, $OutputPath.Length - 4) + ".manifest.txt"
} else {
"$OutputPath.manifest.txt"
}
$gitCommit = "unknown"
$gitDirty = "unknown"
try {
$gitCommit = (& git rev-parse HEAD 2>$null).Trim()
& git diff --quiet
$diffExit = $LASTEXITCODE
& git diff --cached --quiet
$cachedExit = $LASTEXITCODE
$gitDirty = if ($diffExit -eq 0 -and $cachedExit -eq 0) { "false" } else { "true" }
} catch {}
$tarHash = (Get-FileHash -Algorithm SHA256 $OutputPath).Hash.ToLowerInvariant()
$apiImageId = (& docker image inspect "thebet365-api:${Tag}" --format "{{.Id}}").Trim()
$playerImageId = (& docker image inspect "thebet365-player:${Tag}" --format "{{.Id}}").Trim()
$adminImageId = (& docker image inspect "thebet365-admin:${Tag}" --format "{{.Id}}").Trim()
@(
"tag=$Tag"
"built_at=$((Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))"
"git_commit=$gitCommit"
"git_dirty=$gitDirty"
"tar=$([System.IO.Path]::GetFileName($OutputPath))"
"tar_sha256=$tarHash"
"api_image=thebet365-api:${Tag}"
"api_image_id=$apiImageId"
"player_image=thebet365-player:${Tag}"
"player_image_id=$playerImageId"
"admin_image=thebet365-admin:${Tag}"
"admin_image_id=$adminImageId"
) | Set-Content -Encoding UTF8 $manifestPath
$sizeMb = [math]::Round((Get-Item $OutputPath).Length / 1MB, 2)
Write-Host "完成: $OutputPath (${sizeMb} MB)"
Write-Host "Manifest: $manifestPath"
Write-Host @"
:
./scripts/deploy-first.sh --images thebet365-images.tar
./scripts/deploy-first.sh --images $([System.IO.Path]::GetFileName($OutputPath)) --tag $Tag
:
./scripts/deploy-update.sh --images thebet365-images.tar
./scripts/deploy-update.sh --images $([System.IO.Path]::GetFileName($OutputPath)) --tag $Tag
"@