别再手搓环境了:聊聊我们是怎么用 Terraform + Helm 做内部服务模板化的
做过几年运维或者 DevOps 的朋友,大概率都有过这种经历:
新项目上线,流程是这样的:
- 建 Kubernetes Namespace
- 写 Deployment YAML
- 配 Service
- 配 Ingress
- 配 ConfigMap
- 配数据库
- 配 Redis
- 配监控
- 配日志
忙完一圈,突然发现:
80% 的工作都是重复的。
更要命的是,不同项目的人写的 YAML 还不一样。
有人这样写:
resources:
limits:
cpu: "500m"
有人这样写:
resources:
limits:
cpu: "0.5"
还有人根本不写资源限制。
于是时间一长,公司 Kubernetes 集群就变成了:
YAML 垃圾场。
后来我们痛定思痛做了一件事:
内部服务模板化(Service Template)。
核心思路其实很简单:
Terraform 管基础设施,Helm 管应用模板。
今天就聊聊这个实践。
一、为什么一定要做服务模板化
先说句很实在的话:
DevOps 最大的敌人其实不是技术,而是重复劳动。
很多公司所谓的“自动化”,其实只是:
人工 + 文档
比如:
步骤1:创建Namespace
步骤2:复制deployment.yaml
步骤3:修改镜像
这不叫自动化。
这叫:
手工流水线。
真正的自动化应该是:
terraform apply
然后环境 + 应用直接起来。
这就是模板化的价值。
二、整体架构设计
我们当时的架构大概是这样:
开发者
│
│ git push
▼
CI/CD
│
▼
Terraform
(基础设施)
│
▼
Helm
(应用模板)
│
▼
Kubernetes
职责划分非常清晰:
| 工具 | 负责什么 |
|---|---|
| Terraform | 云资源 / 集群资源 |
| Helm | 应用部署 |
| Kubernetes | 运行服务 |
一句话总结:
Terraform 管“地”,Helm 管“房子”。
三、Terraform:统一基础设施模板
先说 Terraform。
我们先把所有服务需要的基础设施模板化。
比如一个服务通常需要:
Namespace
ServiceAccount
数据库
Redis
S3 Bucket
Terraform 模块可以这样写:
module "service_base" {
source = "./modules/service_base"
service_name = var.service_name
env = var.env
}
模块内部大概这样:
resource "kubernetes_namespace" "service" {
metadata {
name = var.service_name
}
}
Redis 示例:
resource "aws_elasticache_cluster" "redis" {
cluster_id = "${var.service_name}-redis"
engine = "redis"
node_type = "cache.t3.micro"
}
这样一个服务上线只需要:
service_name = "order-service"
env = "prod"
Terraform 就会自动创建:
namespace
redis
数据库
存储
基础设施一键完成。
四、Helm:真正的应用模板
Terraform 解决了基础设施问题。
接下来就是应用部署。
这部分 Helm 非常适合。
我们设计了一个 标准 Helm Chart 模板。
目录结构大概是这样:
service-template
├── Chart.yaml
├── values.yaml
└── templates
├── deployment.yaml
├── service.yaml
├── ingress.yaml
Deployment 模板示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {
{
.Values.service.name }}
spec:
replicas: {
{
.Values.replicaCount }}
template:
spec:
containers:
- name: app
image: {
{
.Values.image.repository }}:{
{
.Values.image.tag }}
resources:
limits:
cpu: {
{
.Values.resources.limits.cpu }}
memory: {
{
.Values.resources.limits.memory }}
values.yaml:
service:
name: order-service
replicaCount: 2
image:
repository: company/order-service
tag: latest
resources:
limits:
cpu: "500m"
memory: "512Mi"
这样一个服务部署只需要:
helm install order-service ./service-template
五、模板化真正的关键:约束,而不是自由
很多团队做模板化最后都会失败。
原因只有一个:
模板不强制执行。
开发可以随便写 YAML。
结果时间一长:
模板 A
模板 B
模板 C
整个系统又乱了。
所以我们当时做了一件比较“狠”的事情:
禁止直接提交 Kubernetes YAML。
所有服务必须走:
Helm Template
CI 会检查:
if raw_yaml_detected
then
build_fail
fi
这样所有服务部署都必须使用模板。
慢慢整个公司就统一了。
六、模板化带来的三个巨大好处
这套体系跑了一段时间之后,好处非常明显。
1 新服务上线速度
以前:
1-2天
现在:
30分钟
开发只需要写:
values.yaml
剩下全部自动完成。
2 运维成本下降
以前:
每个服务配置不一样。
现在:
所有服务结构一致。
排查问题的时候:
deployment
service
ingress
都一模一样。
3 平台能力可以统一升级
比如要加:
sidecar
日志采集
service mesh
只需要改:
Helm 模板
所有服务自动升级。
这才是平台化的真正价值。
七、模板化的终极形态:Internal Developer Platform
很多公司做到最后都会走到一个方向:
IDP(Internal Developer Platform)
开发者不再接触:
Terraform
Helm
Kubernetes
而是只写:
service: order-service
language: go
database: mysql
cache: redis
平台自动生成:
Terraform
Helm
CI
监控
日志
一键部署。
这其实就是很多大厂在做的:
平台工程(Platform Engineering)。
最后说点我的真实感受
这些年做运维,我最大的感触其实是:
运维的终极目标是“消灭运维”。
不是裁员那种消灭。
而是:
让系统自己运行。
真正好的平台应该是这样的:
开发只管写代码:
git push
服务就自动上线。
不用申请服务器
不用写 YAML
不用找运维