# Go微服务在Kubernetes中的自动扩缩容实践:基于HPA实战指南
## 背景介绍
微服务架构下,流量波动是常态。白天和晚上访问量能差几倍,搞活动时更是几十倍的差距。手动扩容显然跟不上这个节奏。
Kubernetes的Horizontal Pod Autoscaler(HPA)就是解决这个问题的。它能根据CPU、内存这些指标自动调整Pod数量。CPU超过50%了,多加几个Pod;低了再减掉。
但实际用起来,问题不少。很多开发者会遇到HPA根本不触发、或者扩容后马上又缩回去、或者扩个没完。这些问题通常出在指标采集、阈值设置、资源限制这几个地方。
本文直接上操作,教你怎么给Go微服务配上好用的HPA。
## 问题描述
电商平台搞大促,订单服务流量几分钟内能涨好几十倍。等人工发现再扩容,黄花菜都凉了。活动结束流量降下来,Pod还跑着,白白烧钱。
定时扩容是早期做法——早上9点加一批,晚上6点减一批。问题很明显:流量不是按固定时间来的,扩早了浪费,扩晚了还是会被投诉。
HPA能根据实时负载动态调整,这是更合理的思路。
配置HPA时会遇到几个坑:
**指标不够用。** Kubernetes默认只认CPU和内存。业务上你可能想按并发连接数、队列积压量、响应时间来扩容。这就需要Prometheus Adapter来暴露自定义指标。
**参数难调。** 扩容太快会抖动,太慢又救不了急。冷却时间设多长、最大最小副本数定多少,都要根据业务特点来定。
**Go服务本身的问题。** Go程序如果有内存泄漏或者Goroutine堆积,指标会失真,HPA基于错误信息做决策,结果可想而知。
## 详细步骤
### 步骤一:部署Go微服务到Kubernetes
先写一个能跑在Kubernetes里的Go服务。关键是要暴露健康检查接口,让HPA能判断服务状态。
“`go
package main
import (
“fmt”
“math/rand”
“net/http”
“os”
“time”
)
func main() {
http.HandleFunc(“/”, handler)
http.HandleFunc(“/health”, healthHandler)
http.HandleFunc(“/ready”, readyHandler)
port := os.Getenv(“PORT”)
if port == “” {
port = “8080”
}
fmt.Printf(“Server starting on port %s\n”, port)
if err := http.ListenAndServe(“:”+port, nil); err != nil {
fmt.Fprintf(os.Stderr, “Server error: %v\n”, err)
os.Exit(1)
}
}
func handler(w http.ResponseWriter, r *http.Request) {
// 模拟业务处理
workDuration := time.Duration(50+rand.Intn(100)) * time.Millisecond
time.Sleep(workDuration)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, “OK”)
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, “healthy”)
}
func readyHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, “ready”)
}
“`
三个端点:根路径处理业务请求,health做存活探针,ready做就绪探针。生产环境里就绪探针通常要检查数据库、缓存这些依赖。
### 步骤二:创建Docker镜像
写Dockerfile:
“`dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
FROM alpine:latest
RUN apk –no-cache add ca-certificates
WORKDIR /app
COPY –from=builder /app/server .
EXPOSE 8080
CMD [“./server”]
“`
构建推送:
“`bash
docker build -t your-registry/go-hpa-demo:v1 .
docker push your-registry/go-hpa-demo:v1
“`
### 步骤三:写Kubernetes部署清单
deployment.yaml:
“`yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-hpa-demo
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: go-hpa-demo
template:
metadata:
labels:
app: go-hpa-demo
spec:
containers:
– name: app
image: your-registry/go-hpa-demo:v1
ports:
– containerPort: 8080
resources:
requests:
cpu: “100m”
memory: “128Mi”
limits:
cpu: “500m”
memory: “256Mi”
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
“`
resources配置是重点。requests是保证的最低资源,HPA根据这个算CPU利用率百分比。limits是最大可用资源,别设太低不然会影响性能。
### 步骤四:配置HPA
hpa.yaml:
“`yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: go-hpa-demo
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: go-hpa-demo
minReplicas: 2
maxReplicas: 10
metrics:
– type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
– type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
– type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
– type: Percent
value: 100
periodSeconds: 15
– type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
“`
解释一下这个配置:
– CPU超过50%或内存超过70%时扩容
– 最少2个Pod,最多10个
– 扩容立即执行,每15秒可以翻倍或加4个Pod
– 缩容有300秒稳定窗口期,比较保守,防止抖动
### 步骤五:部署到集群
“`bash
kubectl apply -f deployment.yaml
kubectl apply -f hpa.yaml
“`
检查状态:
“`bash
kubectl get hpa go-hpa-demo
kubectl get pods -l app=go-hpa-demo
“`
## 运行结果
部署完做测试。用kubectl起一个负载Pod:
“`bash
kubectl run -it –rm load-test –image=busybox — /bin/sh
# 在Pod内执行
while true; do wget -q -O- http://go-hpa-demo.default.svc.cluster.local/; done
“`
观察HPA:
“`bash
kubectl get hpa go-hpa-demo -w
“`
正常会看到这样的变化:
“`
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
go-hpa-demo Deployment/go-hpa-demo 45%/50% 2 10 2 5m
go-hpa-demo Deployment/go-hpa-demo 75%/50% 2 10 3 6m
go-hpa-demo Deployment/go-hpa-demo 90%/50% 2 10 5 7m
go-hpa-demo Deployment/go-hpa-demo 30%/50% 2 10 7 8m
go-hpa-demo Deployment/go-hpa-demo 15%/50% 2 10 5 13m
“`
流量上来时副本数从2涨到7,流量下去后经过300秒稳定期开始回落。
看详细事件:
“`bash
kubectl describe hpa go-hpa-demo
“`
输出里会有”Scaled up replica set go-hpa-demo to 5″这类记录。
## 总结
Go微服务配HPA,关键点就几个:
**资源规划要合理。** requests设低了会频繁扩容,设高了浪费。limits要够用,不然会影响性能。
**参数要调。** 流量波动大的业务可以激进扩容,流量平稳的要设长冷却时间。
**持续监控。** HPA配置完不是万事大吉,要看实际效果,发现问题及时调整。
进阶玩法是用KEDA,支持更多触发源:Prometheus指标、Redis队列长度、Kafka消费延迟等等。业务场景复杂的可以研究一下。