golang:1.22-alpine 是 CI 首选镜像,体积小、启动快、预装 go 和 git;需 cgo 时改用 golang:1.22;注意 alpine 无 bash、工具安装需 -modfile、CGO_ENABLED= 0 影响 DNS 解析。

CI 中用 golang:1.22-alpine 镜像最省事
绝大多数 CI 平台(GitHub Actions、GitLab CI、CircleCI)都支持直接拉取 Docker 镜像作为运行环境,golang:1.22-alpine体积小、启动快、预装 go 和git,是首选。它不带cgo,但对纯 Go 项目完全够用;若需cgo(比如调用 C 库或交叉编译带系统依赖的二进制),得切到golang:1.22(Debian 基础)。
常见踩坑点:
-
alpine镜像里没有bash,写 CI 脚本时别用#!/bin/bash,改用#!/bin/sh或显式调用sh -c - 某些 Go工具 (如
goreleaser)在alpine上需额外安装libc6-compat或换非 -alpine 镜像 - Go 模块校验失败(
checksum mismatch)常因 CI 缓存了旧go.sum,建议在go mod download前加rm -f go.sum或启用GOFLAGS=-mod=readonly
GitHub Actions 里用 actions/setup-go 要设 cache 才不慢
官方 actions/setup-go@v4 能自动安装指定版本 Go,但它默认不缓存$GOPATH/pkg/mod,每次都要重新go mod download,大型项目可能多花 1–2 分钟。
正确做法是开启模块缓存:
立即学习“go 语言免费学习笔记(深入)”;
steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: '1.22' cache: true # 必须显式打开 - run: go build -o myapp .
注意:cache: true依赖 GOPATH 默认值,如果项目里自定义了 GOENV 或GOPATH,缓存会失效;另外,它只缓存 go.mod 哈希一致的模块,go get临时升级依赖后缓存会自动失效。
go install在 CI 里要加 -modfile 避免污染主go.mod
CI 流程中常需安装工具(如 golint、staticcheck),但直接go install golang.org/x/lint/golint@latest 会触发 go mod 自动写入当前目录的go.mod,导致提交意外变更。
安全做法是用 -modfile 指向一个临时文件:
go install -modfile=/dev/null golang.org/x/lint/golint@latest
其他等效方式:
- 进空目录再
go install(mkdir /tmp/go-install && cd /tmp/go-install && go install ……) - 用
GO111MODULE=off go get(仅适用于老版本工具,且不推荐) - 改用
curl下载预编译二进制(如staticcheck官网提供.tar.gz)
交叉编译时 CGO_ENABLED=0 不是万能解
CI 打包 Linux 二进制发给生产环境,常加 CGO_ENABLED=0 确保静态链接。但它会让 net 包回退到纯 Go DNS 解析(忽略/etc/resolv.conf),可能导致内网服务域名解析失败。
真实场景处理建议:
- 若必须用
cgo(比如依赖libsqlite3),就用golang:1.22镜像,并在 CI 中apt-get update && apt-get install -y libsqlite3-dev - 若只是 DNS 问题,可保留
CGO_ENABLED=1,但显式设GOOS=linux GOARCH=amd64,并确保 CI 节点有libc(Alpine 不行,得换 Debian 系) -
go build -ldflags '-extldflags"-static"'能强制静态链接 C 部分,但要求宿主机装musl-tools或用golang:alpine配合apk add musl-dev
交叉编译最容易被忽略的是GOARM(ARMv6/v7)或GOAMD64(v1/v2/v3)这类 CPU 特性标志,没设对会导致二进制在目标机器上报Illegal instruction。






























