76ba500417
CI / docker (push) Successful in 2m4s
OpenAI-compatible AI gateway with Vue admin UI, multi-provider egress, ingress key governance, monitoring, and security controls. Co-authored-by: Cursor <cursoragent@cursor.com>
183 lines
7.4 KiB
Markdown
183 lines
7.4 KiB
Markdown
# 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` |
|