Appearance
29|后端项目部署
go-gateway 开发完成后,需要部署到服务器或容器平台。Go 程序最终通常以两种形态运行:一个二进制文件,或者一个包含二进制的容器镜像。网关作为常驻服务,适合用 systemd 管理,或用 Docker/Kubernetes 部署。部署要记录清楚四件事:二进制怎么构建,配置从哪里来,进程怎么运行,失败时从哪里看日志。
一、交叉编译
开发机可能是 Windows 或 macOS,服务器通常是 Linux。Go 支持交叉编译,在一台机器上生成另一台机器的可执行文件:
bash
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \
go build -trimpath -ldflags="-s -w" \
-o bin/go-gateway \
./cmd/gateway| 参数 | 作用 |
|---|---|
GOOS=linux | 构建 Linux 可执行文件 |
GOARCH=amd64 | x86_64 架构,ARM 机器用 arm64 |
CGO_ENABLED=0 | 静态链接,不依赖 glibc,容器里更容易运行 |
-trimpath | 去掉本机源码路径 |
-ldflags="-s -w" | 去掉符号表和调试信息,减小体积 |
二、版本注入
发布后排查问题,需要知道当前二进制来自哪个版本。在代码里留变量,构建时注入:
go
package version
var (
Version = "dev"
Commit = "unknown"
Date = "unknown"
)构建时注入:
bash
VERSION=v1.0.0
COMMIT=$(git rev-parse --short HEAD)
DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
go build \
-ldflags="-X example.com/go-gateway/internal/version.Version=$VERSION \
-X example.com/go-gateway/internal/version.Commit=$COMMIT \
-X example.com/go-gateway/internal/version.Date=$DATE" \
-o bin/go-gateway \
./cmd/gateway三、systemd 服务
ini
[Unit]
Description=Go Gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=gateway
Group=gateway
ExecStart=/usr/local/bin/go-gateway
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target启动:
bash
systemctl daemon-reload
systemctl enable --now go-gateway
systemctl status go-gateway
journalctl -u go-gateway -f四、多阶段 Docker 镜像
dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -trimpath -ldflags="-s -w" \
-o /out/go-gateway ./cmd/gateway
FROM alpine:3.20
RUN adduser -D -H -u 10001 app
USER app
WORKDIR /app
COPY --from=builder /out/go-gateway /app/go-gateway
COPY configs/ /app/configs/
EXPOSE 8080 8081
ENTRYPOINT ["/app/go-gateway"]构建和运行:
bash
docker build -t registry.example.com/ops/go-gateway:v1.0.0 .
docker run -p 8080:8080 -p 8081:8081 \
-e GATEWAY_JWT_SECRET=xxx \
registry.example.com/ops/go-gateway:v1.0.0五、Kubernetes 部署
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-gateway
namespace: gateway
spec:
replicas: 2
selector:
matchLabels:
app: go-gateway
template:
metadata:
labels:
app: go-gateway
spec:
containers:
- name: gateway
image: registry.example.com/ops/go-gateway:v1.0.0
ports:
- name: proxy
containerPort: 8080
- name: admin
containerPort: 8081
readinessProbe:
httpGet:
path: /healthz
port: proxy
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: proxy
initialDelaySeconds: 10
periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
name: go-gateway
namespace: gateway
spec:
selector:
app: go-gateway
ports:
- name: proxy
port: 80
targetPort: proxy
- name: admin
port: 8081
targetPort: admin六、发布排查
| 层级 | 现象 | 排查入口 |
|---|---|---|
| 镜像 | ImagePullBackOff | 镜像名、tag、仓库凭据 |
| 启动参数 | Pod 反复重启 | kubectl logs、配置路径 |
| 端口冲突 | bind: address already in use | 端口占用检查 |
| 探针 | Pod Running 但 NotReady | readinessProbe 路径、端口 |
| Service | 访问不通 | selector、EndpointSlice |
kubectl logs deploy/go-gateway -n gateway --previous 看上一轮退出容器的日志,定位启动失败原因。