120 lines
3.7 KiB
Python
120 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Build all microservice images via docker buildx bake."""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
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
|
|
ARG GOPROXY="https://goproxy.cn,direct"
|
|
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,
|
|
}
|
|
|
|
bakefile = ROOT_DIR / ".bake.json"
|
|
try:
|
|
bakefile.write_text(json.dumps(bake, 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", str(bakefile), *batch],
|
|
check=True,
|
|
)
|
|
finally:
|
|
bakefile.unlink(missing_ok=True)
|
|
|
|
|
|
main()
|