Go 1.21+ 是硬性门槛,必须从官网下载二进制包安装并配置 GOPROXY;项目须按 Standard Layout 初始化目录结构,集成 Viper、Zap、gRPC/HTTP 及 Docker Compose 联调,且所有服务监听 0.0.0.0。

Go 1.21+ 是硬性门槛,低于这个版本的 go mod、embed 和泛型稳定性都不足以支撑微服务基础能力;国内不配 GOPROXY,go mod download 会卡死在第三方包上。
Go 版本与代理必须一步到位
别用系统包管理器装的 Go(Ubuntu 的 1.18、CentOS 的 1.16 都不行)。直接去 golang.google.cn 下载 go1.21.6.linux-amd64.tar.gz(或对应平台版本),解压到 /usr/local/go,再把 /usr/local/go/bin 加进 $PATH。执行完记得 source ~/.zshrc 或 source ~/.bashrc。
代理必须立刻配好:
go env -w GO111MODULE=ongo env -w GOPROXY=https://goproxy.cn,directgo env -w GOSUMDB=sum.golang.org
验证:go version 输出必须是 go version go1.21.6 linux/amd64 或更高;go env | grep GOPROXY 应显示你刚设的地址。
立即学习“go语言免费学习笔记(深入)”;
项目结构不能从 main.go 开始
空目录下直接 go mod init yourcompany.com/order-svc 是错的起点。微服务一启动就得注册、打日志、响应健康检查——这些不是“后续加”,而是骨架。
强制建立以下目录:
-
cmd/order-svc/main.go:只做三件事——加载viper配置、初始化zap日志、调用gin.Default()或grpc.NewServer() -
internal/handler/和internal/service/:业务逻辑全放这儿,禁止跨层引用(比如 handler 直接 import model) -
configs/app.yaml:至少含server.port、log.level、consul.addr等基础项 -
api/(留空或放user.proto)和migrations/(留空)也得先建好
没这结构,后面加服务发现、日志切割、CI/CD 时你会反复重写路径和导入链。
Dockerfile 必须多阶段且禁用 CGO
别用 FROM golang:alpine 直接跑源码——镜像会带几百 MB 编译环境,且 Alpine 默认没 curl,健康检查容易失败。
标准写法:
FROM golang:1.22-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o /usr/local/bin/order-svc . <p>FROM alpine:latest RUN apk --no-cache add ca-certificates COPY --from=builder /usr/local/bin/order-svc /usr/local/bin/order-svc HEALTHCHECK --interval=10s --timeout=3s --start-period=30s --retries=3 \ CMD wget --quiet --tries=1 --spider <a href="https://www.php.cn/link/1633b2e8d8d39ecaf5fd05fd16b4ffd0">https://www.php.cn/link/1633b2e8d8d39ecaf5fd05fd16b4ffd0</a> || exit 1 CMD ["/usr/local/bin/order-svc"]
关键点:
-
CGO_ENABLED=0:避免 Alpine 缺 libc 动态库导致 panic -
GOOS=linux:本地 macOS/Windows 构建时极易漏掉,容器内直接报 “exec format error” -
HEALTHCHECK用wget而非curl,Alpine 默认不含后者 -
--start-period=30s给服务留够加载配置、连 Consul 的时间
docker-compose.yml 要模拟真实网络拓扑
本地联调不能只跑一个服务。哪怕只有 order-svc 和 consul,也要用自定义 bridge 网络,让服务名能当 DNS 解析。
示例 docker-compose.yml:
version: '3.8'
services:
consul:
image: consul:1.19
command: "agent -server -bootstrap-expect=1 -ui -client=0.0.0.0 -bind=0.0.0.0"
ports:
- "8500:8500"
<p>order-svc:
build: .
ports:</p><ul><li>"8080:8080"
environment:</li><li>CONSUL_ADDR=consul:8500
depends_on:</li><li>consul<h1>关键:同 network 才能用 consul 当 host</h1><p>networks:</p></li><li>micro-net</li></ul><p>networks:
micro-net:
driver: bridge你的 Go 代码里调用注册逻辑时,地址必须写 http://consul:8500/v1/agent/service/register,而不是 localhost 或 127.0.0.1——容器内 localhost 指自己,不是宿主机。
最后提醒一句:所有服务的 main.go 必须监听 0.0.0.0:8080,不是 127.0.0.1:8080;否则容器内健康检查和外部调用全部失败,但错误日志里几乎不报具体原因,只能靠抓包或 netstat 排查。


















