跳到主要内容

03 部署 Go 应用

Go 是部署最省心的语言:编译产物是一个静态二进制文件,不需要装运行时、不需要装依赖。配合 Docker 多阶段构建,最终镜像能小到 20MB 以内。本篇以一个 Gin 写的 API 服务为例。

1. 示例项目结构​

go-api/
├── main.go
├── go.mod
├── go.sum
├── Dockerfile
├── .dockerignore
└── compose.yaml

main.go 里准备一个健康检查接口(后面 healthcheck 要用):

package main

import "github.com/gin-gonic/gin"

func main() {
r := gin.Default()
r.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
r.GET("/api/hello", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "hello from go"})
})
r.Run(":8080")
}

2. 编写 Dockerfile(多阶段构建)​

Dockerfile
# ---------- 阶段 1:编译 ----------
FROM golang:1.22-alpine AS builder

WORKDIR /app

# 国内环境配置 Go 模块代理,加速依赖下载
ENV GOPROXY=https://goproxy.cn,direct

# 先拷贝依赖清单并下载,利用缓存:go.mod 没变就不用重新下载
COPY go.mod go.sum ./
RUN go mod download

# 再拷贝源码编译
COPY . .
# CGO_ENABLED=0:编译纯静态二进制,不依赖任何系统库,才能放进极简镜像
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o server .

# ---------- 阶段 2:运行 ----------
FROM alpine:3.20

WORKDIR /app

# 时区数据 + CA 证书(调用 https 接口必需)
RUN apk add --no-cache tzdata ca-certificates && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 只把二进制拷过来,源码、Go 工具链全部留在上一阶段
COPY --from=builder /app/server .

EXPOSE 8080
CMD ["./server"]

.dockerignore:

.dockerignore
.git
*.md
compose.yaml

对比一下:golang:1.22 完整镜像约 800MB,而这个最终镜像只有约 15MB——编译环境和运行环境分离就是多阶段构建的价值。追求极致还可以把第二阶段换成 scratch(完全空白的镜像),但排查问题时连 shell 都没有,新手建议用 alpine。

3. 编写 compose.yaml​

compose.yaml
services:
go-api:
build: .
container_name: go-api
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080" # 只监听本机,公网流量走 Nginx 反代
environment:
- GIN_MODE=release # 生产模式,关掉调试日志
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"

启动与验证:

docker compose up -d --build
docker compose ps # STATUS 应显示 healthy
curl http://127.0.0.1:8080/api/hello # {"message":"hello from go"}

Nginx 反向代理的配置和 FastAPI 篇完全一样(proxy_pass http://127.0.0.1:8080),不再重复。

4. 不用 Docker 行不行?​

行,而且 Go 是唯一「裸部署也很舒服」的语言——把二进制传上去用 systemd 管理即可:

/etc/systemd/system/go-api.service
[Unit]
Description=Go API Service
After=network.target

[Service]
ExecStart=/opt/go-api/server
Restart=always
RestartSec=3
Environment=GIN_MODE=release

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now go-api # 开机自启 + 立即启动
systemctl status go-api # 查看运行状态
journalctl -u go-api -f # 看日志

两种方式怎么选:

Docker 部署systemd 裸部署
环境一致性好,本地和服务器一个镜像依赖交叉编译目标正确
和其他容器服务协作同一网络互访方便要走宿主机端口
资源开销略高一点点几乎为零
适合场景项目里还有 MySQL/Redis 等容器单个小工具、Agent 类程序

本教程的技术栈都容器化了,推荐统一用 Docker,管理方式一致。

小结​

  • Go 编译出静态二进制(CGO_ENABLED=0),多阶段构建后镜像只有十几 MB
  • go mod download 单独一层,依赖不变就走缓存,构建飞快
  • alpine 阶段记得补 tzdata(时区)和 ca-certificates(HTTPS 调用)
  • 端口只绑 127.0.0.1,加 /health 接口配 healthcheck,和其他后端服务一个套路
  • systemd 裸部署是 Go 独有的轻量选项,单体小程序可以用

下一篇解决数据层:04-部署MySQL与Redis