From cd2c6d41922434903e2684a21ae25fd3e2c029c4 Mon Sep 17 00:00:00 2001 From: zetaloop Date: Thu, 23 Apr 2026 02:35:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=9B=B4=E5=A5=BD=E7=9A=84?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/dev/README.md | 15 +++--- deploy/dev/build.py | 120 +++++++++++++++++++++++++++++++++++++++++++ deploy/dev/build.sh | 99 ----------------------------------- 3 files changed, 128 insertions(+), 106 deletions(-) create mode 100644 deploy/dev/build.py delete mode 100755 deploy/dev/build.sh diff --git a/deploy/dev/README.md b/deploy/dev/README.md index 87740fa..012ecda 100644 --- a/deploy/dev/README.md +++ b/deploy/dev/README.md @@ -3,7 +3,7 @@ ## 前置条件 - Docker(需要 buildx) -- Python 3(构建脚本用于生成 bake 定义) +- Python 3(构建脚本) ## 使用 @@ -11,7 +11,8 @@ cd deploy/dev # 1. 构建所有微服务镜像 -./build.sh +# 默认 8 并行,可通过环境变量 BAKE_BATCH_SIZE 调整 +python3 build.py # 2. 启动 docker compose up -d @@ -60,11 +61,11 @@ docker compose up -d postgres redis snowflake player-rpc player-api 管理员账户通过环境变量配置,`users-rpc` 启动时自动初始化: -| 变量 | 说明 | 默认值 | -| ---------------- | ------------ | ----------------- | -| ADMIN_USERNAME | 管理员用户名 | admin | -| ADMIN_PASSWORD | 管理员密码 | admin123 | -| ADMIN_EMAIL | 管理员邮箱 | admin@juwan.dev | +| 变量 | 说明 | 默认值 | +| -------------- | ------------ | --------------- | +| ADMIN_USERNAME | 管理员用户名 | admin | +| ADMIN_PASSWORD | 管理员密码 | admin123 | +| ADMIN_EMAIL | 管理员邮箱 | admin@juwan.dev | ## 认证 diff --git a/deploy/dev/build.py b/deploy/dev/build.py new file mode 100644 index 0000000..441b80c --- /dev/null +++ b/deploy/dev/build.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +"""Build all microservice images via docker buildx bake.""" + +import json +import os +import subprocess +import sys +import tempfile +from glob import glob +from pathlib import Path + +ROOT_DIR = Path(__file__).resolve().parent.parent.parent +IMAGE_PREFIX = os.environ.get("IMAGE_PREFIX", "juwan") +IMAGE_TAG = sys.argv[1] if len(sys.argv) > 1 else "dev" +BAKE_BATCH_SIZE = int(os.environ.get("BAKE_BATCH_SIZE", "8")) + +DOCKERFILE_TPL = """\ +# syntax=docker/dockerfile:1.7 +FROM golang:1.25-alpine AS builder +RUN apk add --no-cache tzdata +WORKDIR /build +COPY go.mod go.sum ./ +RUN --mount=type=cache,target=/go/pkg/mod go mod download +COPY . . +RUN --mount=type=cache,target=/go/pkg/mod \\ + --mount=type=cache,target=/root/.cache/go-build \\ + go build -ldflags="-s -w" -o /app/main ./{service_dir} + +FROM alpine:latest +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai +ENV TZ=Asia/Shanghai +WORKDIR /app +COPY --from=builder /app/main /app/main +COPY {service_dir}/etc /app/etc +CMD ["./main", "-f", "etc/{config_name}"] +""" + +DOCKERFILE_NO_CONFIG_TPL = """\ +# syntax=docker/dockerfile:1.7 +FROM golang:1.25-alpine AS builder +RUN apk add --no-cache tzdata +WORKDIR /build +COPY go.mod go.sum ./ +RUN --mount=type=cache,target=/go/pkg/mod go mod download +COPY . . +RUN --mount=type=cache,target=/go/pkg/mod \\ + --mount=type=cache,target=/root/.cache/go-build \\ + go build -ldflags="-s -w" -o /app/main ./{service_dir} + +FROM alpine:latest +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai +ENV TZ=Asia/Shanghai +WORKDIR /app +COPY --from=builder /app/main /app/main +CMD ["./main"] +""" + + +def discover_targets(): + targets = {} + for service_dir in sorted(glob(str(ROOT_DIR / "app" / "*" / "*"))): + service_dir_rel = Path(service_dir).relative_to(ROOT_DIR).as_posix() + service_type = Path(service_dir).name + if service_type not in ("api", "rpc", "mq", "adapter"): + continue + go_files = glob(os.path.join(service_dir, "*.go")) + if not go_files or not any("package main" in open(f).read() for f in go_files): + continue + + yamls = glob(os.path.join(service_dir, "etc", "*.yaml")) + service_name = Path(service_dir).parent.name + target_name = f"{service_name}-{service_type}" + + if yamls: + config_name = Path(yamls[0]).name + dockerfile = DOCKERFILE_TPL.format( + service_dir=service_dir_rel, config_name=config_name + ) + else: + dockerfile = DOCKERFILE_NO_CONFIG_TPL.format(service_dir=service_dir_rel) + + targets[target_name] = { + "dockerfile-inline": dockerfile, + "tags": [f"{IMAGE_PREFIX}/{target_name}:{IMAGE_TAG}"], + } + return targets + + +def main(): + os.chdir(ROOT_DIR) + targets = discover_targets() + if not targets: + print("No targets found") + sys.exit(1) + + bake = { + "group": {"default": {"targets": list(targets.keys())}}, + "target": targets, + } + + fd, bakefile = tempfile.mkstemp(prefix="juwan-bake-", suffix=".json") + try: + with os.fdopen(fd, "w") as f: + json.dump(bake, f, indent=2) + print(f"Generated {len(targets)} targets -> {bakefile}") + + names = list(targets.keys()) + for i in range(0, len(names), BAKE_BATCH_SIZE): + batch = names[i : i + BAKE_BATCH_SIZE] + subprocess.run( + ["docker", "buildx", "bake", "--load", "-f", bakefile, *batch], + check=True, + ) + finally: + os.unlink(bakefile) + + +main() diff --git a/deploy/dev/build.sh b/deploy/dev/build.sh deleted file mode 100755 index b1174c7..0000000 --- a/deploy/dev/build.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)" -IMAGE_PREFIX="${IMAGE_PREFIX:-juwan}" -IMAGE_TAG="${1:-dev}" - -cd "$ROOT_DIR" - -bakefile=$(mktemp "${TMPDIR:-/tmp}/juwan-bake-XXXXXX") -mv "$bakefile" "${bakefile}.json" -bakefile="${bakefile}.json" - -python3 - "$IMAGE_PREFIX" "$IMAGE_TAG" "$bakefile" <<'PYEOF' -import json, os, subprocess, sys, glob - -prefix, tag, outpath = sys.argv[1], sys.argv[2], sys.argv[3] - -dockerfile_tpl = """\ -# syntax=docker/dockerfile:1.7 -FROM golang:1.25-alpine AS builder -RUN apk add --no-cache tzdata -WORKDIR /build -COPY go.mod go.sum ./ -RUN --mount=type=cache,target=/go/pkg/mod go mod download -COPY . . -RUN --mount=type=cache,target=/go/pkg/mod \ - --mount=type=cache,target=/root/.cache/go-build \ - go build -ldflags="-s -w" -o /app/main ./{service_dir} - -FROM alpine:latest -COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai -ENV TZ=Asia/Shanghai -WORKDIR /app -COPY --from=builder /app/main /app/main -COPY {service_dir}/etc /app/etc -CMD ["./main", "-f", "etc/{config_name}"] -""" - -dockerfile_no_config_tpl = """\ -# syntax=docker/dockerfile:1.7 -FROM golang:1.25-alpine AS builder -RUN apk add --no-cache tzdata -WORKDIR /build -COPY go.mod go.sum ./ -RUN --mount=type=cache,target=/go/pkg/mod go mod download -COPY . . -RUN --mount=type=cache,target=/go/pkg/mod \ - --mount=type=cache,target=/root/.cache/go-build \ - go build -ldflags="-s -w" -o /app/main ./{service_dir} - -FROM alpine:latest -COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai -ENV TZ=Asia/Shanghai -WORKDIR /app -COPY --from=builder /app/main /app/main -CMD ["./main"] -""" - -targets = {} -for service_dir in sorted(glob.glob("app/*/*")): - service_dir = service_dir.replace("\\", "/") - service_type = os.path.basename(service_dir) - if service_type not in ("api", "rpc", "mq", "adapter"): - continue - go_files = glob.glob(os.path.join(service_dir, "*.go")) - has_main = any("package main" in open(f).read() for f in go_files) if go_files else False - if not has_main: - continue - yamls = glob.glob(os.path.join(service_dir, "etc", "*.yaml")) - service_name = os.path.basename(os.path.dirname(service_dir)) - target_name = f"{service_name}-{service_type}" - - if yamls: - config_name = os.path.basename(yamls[0]) - dockerfile = dockerfile_tpl.format(service_dir=service_dir, config_name=config_name) - else: - dockerfile = dockerfile_no_config_tpl.format(service_dir=service_dir) - - targets[target_name] = { - "dockerfile-inline": dockerfile, - "tags": [f"{prefix}/{target_name}:{tag}"], - } - -bake = { - "group": {"default": {"targets": list(targets.keys())}}, - "target": targets, -} - -with open(outpath, "w") as f: - json.dump(bake, f, indent=2) - -print(f"Generated {len(targets)} targets -> {outpath}") -PYEOF - -docker buildx bake --load -f "$bakefile" -rm -f "$bakefile"