# Gitea Actions CI 模板(Go + Vue) 复制整个 `.gitea/` 目录到新仓库即可启用 CI:**可选 go test** + **Docker 构建/推送**(Go 编译与 Vue 构建在 Dockerfile 内完成)。 ## 项目约定 | 路径 | 说明 | |------|------| | `go.mod` | 仓库根目录 | | `Dockerfile` | 仓库根目录,多阶段构建(含前端 `web/`) | | `web/` | 可选;由 Dockerfile 内 `npm run build` 处理,CI 不再单独构建 | ## Dockerfile 要求 工作流的 **Build image** 步骤在仓库根目录(或 Variable `DOCKERFILE` 指定路径)执行 `docker buildx build`,**不会**在 CI 里单独装 Node / 跑 `npm`。因此 Dockerfile 必须能独立完成构建与(运行时)启动。 ### 基本要求 | 项 | 要求 | |----|------| | 位置 | 默认仓库根目录 `Dockerfile`;其他路径用 Variable `DOCKERFILE` | | 构建上下文 | 仓库根目录 `.`(整个仓库会被 `COPY` 进镜像) | | Go 版本 | `go.mod` 里 `go` 行与 `golang` 基础镜像大版本一致 | | 多架构 | `go build` 须使用 `GOARCH="$TARGETARCH"`(buildx 注入);推荐 `CGO_ENABLED=0` | | Go 模块代理 | **必须**在镜像内显式设置 `GOPROXY` / `GOSUMDB`(见下);容器内不会自动读取 `go.env` | | 基础镜像加速 | 支持构建参数 `IMAGE_PREFIX`(CI 默认 `docker.1panel.live/library/`) | | 前端(可选) | 存在 `web/` 时在 Dockerfile 内完成 `npm ci` + `npm run build` | ### CI 自动传入的构建参数 | 参数 | 默认 | 说明 | |------|------|------| | `IMAGE_PREFIX` | `docker.1panel.live/library/` | 基础镜像前缀;`hub` 表示 Docker Hub | | `GOPROXY` | `https://goproxy.cn,direct` | 与 workflow / Variable 一致 | | `GOSUMDB` | `sum.golang.google.cn` | checksum 数据库 | buildx 还会注入 `TARGETARCH`、`BUILDPLATFORM` 等,无需在 workflow 里写。 ### 推荐:Go + Vue 多阶段模板 ```dockerfile # syntax=docker/dockerfile:1 ARG IMAGE_PREFIX= # 1) 前端(无 web/ 时可删整个 stage,并去掉 go-builder 里 COPY dist) FROM --platform=$BUILDPLATFORM ${IMAGE_PREFIX}node:20-alpine AS web-builder WORKDIR /src/web COPY web/package.json web/package-lock.json web/.npmrc ./ RUN npm ci COPY web/ ./ RUN npm run build # 2) Go 编译 FROM --platform=$BUILDPLATFORM ${IMAGE_PREFIX}golang:1.25-alpine AS go-builder ARG TARGETARCH ARG GOPROXY=https://goproxy.cn,direct ARG GOSUMDB=sum.golang.google.cn ENV GOPROXY=${GOPROXY} GOSUMDB=${GOSUMDB} WORKDIR /src COPY go.mod go.sum ./ RUN --mount=type=cache,target=/go/pkg/mod go mod download COPY cmd/ ./cmd/ COPY internal/ ./internal/ # 若静态资源嵌入 Go:COPY --from=web-builder /src/web/dist/ ./path/to/static/ RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ CGO_ENABLED=0 GOOS=linux GOARCH="$TARGETARCH" \ go build -ldflags="-w -s" -o /app ./cmd/yourapp # 3) 运行镜像 FROM ${IMAGE_PREFIX}alpine:3.20 RUN apk add --no-cache ca-certificates tzdata COPY --from=go-builder /app /usr/local/bin/yourapp ENTRYPOINT ["/usr/local/bin/yourapp"] ``` 按项目调整:`./cmd/yourapp`、静态资源路径、运行用户、`EXPOSE` / `VOLUME` 等。 ### 仅 Go(无前端) 删除 `web-builder` stage;`go-builder` 中不要 `COPY` 前端产物;其余 `GOPROXY` / `TARGETARCH` / `IMAGE_PREFIX` 要求相同。 ### 前端 npm 源(国内) 在 `web/.npmrc` 配置 registry,并在 Dockerfile 里与 `package.json` 一并 `COPY`: ```ini registry=https://registry.npmmirror.com ``` ### 本地验证(与 CI 一致) ```bash docker buildx build --platform linux/amd64 \ --build-arg IMAGE_PREFIX=docker.1panel.live/library/ \ --build-arg GOPROXY=https://goproxy.cn,direct \ -f Dockerfile -t myapp:test . ``` ### 常见 Dockerfile 构建错误 | 报错 | 原因 | 处理 | |------|------|------| | `proxy.golang.org` timeout | 镜像内未设 `ENV GOPROXY` | go-builder 阶段加 `ARG`/`ENV GOPROXY` | | `node` / Vite 版本不符 | 基础镜像 Node 过旧 | 使用 `node:20-alpine` 及以上 | | 某架构 build 失败 | 未使用 `TARGETARCH` | `GOARCH="$TARGETARCH"` | | 拉基础镜像 timeout | Hub 不可达 | `--build-arg IMAGE_PREFIX=docker.1panel.live/library/` 或 1Panel 配镜像加速 | ## 一次性配置 1. **Runner**:部署 act_runner,标签含 `ubuntu-latest`,并挂载 `docker.sock`(见 [act-runner/README.md](act-runner/README.md))。 2. **Secret**:仓库 Settings → Actions → Secrets,添加 `REGISTRY_TOKEN`(PAT,`write:package` 权限)。 3. **Variable(推荐)**:若 runner 与 Gitea 同机、或 `gitea.server_url` 为内网地址,必须设置 `REGISTRY=你的公网域名`(如 `git.example.com`,**不要**填 `172.17.0.1:13827`)。 4. **Gitea Registry**:服务端 `[packages] ENABLED = true`,`ROOT_URL` 正确;穿透场景建议 `PUBLIC_URL_DETECTION = never`(Gitea 1.26+)。 `REGISTRY` 未设置时,会从 `GITEA_ROOT_URL` 或 `gitea.server_url` 推断;均为内网地址时 workflow 会提前失败并提示。 ## 可选 Variables 仓库 Settings → Actions → Variables(留空则用默认值): | 变量 | 默认 | 说明 | |------|------|------| | `REGISTRY` | 见下方推断顺序 | **公网** Registry 主机名,如 `git.example.com`(勿用内网 IP:13827) | | `GITEA_ROOT_URL` | (空) | 当 `gitea.server_url` 为内网时,可设 `https://git.example.com/` | | `IMAGE_NAME` | 仓库名小写 | 镜像名,非 owner/repo 全路径 | | `DOCKERFILE` | `Dockerfile` | Dockerfile 路径 | | `DOCKER_PLATFORMS` | `linux/amd64,linux/arm64` | push 时 buildx 平台 | | `GO_TEST_SCOPE` | `./...` | `go test` 包路径 | | `RUN_GO_TEST` | (空,即运行) | 设 `false` 跳过 go test,仅 Docker 构建 | | `DOCKER_IMAGE_PREFIX` | `1panel` | 基础镜像前缀;可选 `hub` / `daocloud` | | `GOPROXY` | `https://goproxy.cn,direct` | Go 模块代理 | | `GOSUMDB` | `sum.golang.google.cn` | Go checksum 数据库 | ## 触发与镜像 tag - **pull_request**:go test(可关)+ 单架构 `docker build` 验证(不推送) - **push main/master**:go test + 多架构构建并推送 `:latest`、`:sha-xxxxxxx` - **push tag v\***:额外推送 `:v1.2.3` 等 示例(仓库 `rose_cat707/Prism`,Gitea 在 `git.example.com`): ```text git.example.com/rose_cat707/prism:latest git.example.com/rose_cat707/prism:sha-35b3b48 ``` ## 目录结构 ```text .gitea/ ├── README.md # 本文件 ├── workflows/ │ └── ci.yml # 主工作流 └── act-runner/ # runner 部署参考(可选) ├── README.md ├── config.yaml ├── docker-compose.yml └── .env.example ``` ## 本地验证 Registry ```bash host=$(echo "https://你的-gitea-地址/" | sed -e 's|^https://||' -e 's|/.*||') curl -s -D - "https://${host}/v2/" -o /dev/null | grep -i www-authenticate docker pull "${host}/owner/image:latest" # 公开 Registry 无需 login ``` 推送镜像(CI)仍需仓库 Secret `REGISTRY_TOKEN`(`write:package`)。仅拉取公开包不需要登录。 `realm` 应指向公网 Gitea 域名,而非 `127.0.0.1`。 ## 常见 Registry 错误 | 报错 | 原因 | 处理 | |------|------|------| | `Get "https://172.17.0.1:13827/v2/"` HTTP/HTTPS | Variable `REGISTRY` 或 `gitea.server_url` 为内网地址 | 设 `REGISTRY=git.example.com` | | token 指向 `127.0.0.1` | Gitea `realm` 配置错误 | `PUBLIC_URL_DETECTION=never` + 正确 `ROOT_URL` |