4. 基础设施即代码入门
在持续交付体系中,Elasticsearch 集群不应通过控制台手工点击创建,而应以代码形式声明并纳入版本控制。基础设施即代码(IaC)的核心价值在于:集群拓扑、节点规格、存储、网络与安全策略都成为可审查、可回滚、可复现的声明式配置。本节以 Terraform 为主线,同时对照 CloudFormation 的等价表达,说明如何定义一套可交付的 Elasticsearch 集群及其依赖资源。
一、先厘清依赖关系,再写资源声明
一个可用的 Elasticsearch 集群并非孤立资源,它依赖一组前置条件:VPC 与子网划分、安全组规则、IAM 角色与策略、KMS 密钥(用于静态加密)、CloudWatch 日志组,以及节点所用的实例配置。IaC 工具通过“资源引用”自动推导依赖顺序,因此我们只需声明“谁引用谁”,而不必手工编排创建次序。下图给出本节示例中资源之间的依赖拓扑与数据流方向。
二、Terraform 资源声明示例
下面给出一个精简但可运行的 Terraform 片段,覆盖 VPC、子网、安全组与 Elasticsearch 域。示例参数为教学假设值,实际使用时需按区域与容量规划调整。
resource "aws_vpc" "es_vpc" {
cidr_block = "10.20.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = { Name = "es-iac-vpc" }
}
resource "aws_subnet" "es_subnet" {
count = 3
vpc_id = aws_vpc.es_vpc.id
cidr_block = cidrsubnet(aws_vpc.es_vpc.cidr_block, 8, count.index)
availability_zone = element(["ap-southeast-1a","ap-southeast-1b","ap-southeast-1c"], count.index)
tags = { Name = "es-subnet-${count.index}" }
}
resource "aws_security_group" "es_sg" {
name = "es-iac-sg"
vpc_id = aws_vpc.es_vpc.id
ingress {
from_port = 9200
to_port = 9200
protocol = "tcp"
cidr_blocks = ["10.20.0.0/16"]
}
ingress {
from_port = 9300
to_port = 9300
protocol = "tcp"
self = true
}
}
resource "aws_elasticsearch_domain" "es" {
domain_name = "es-iac-demo"
elasticsearch_version = "7.10"
cluster_config {
instance_type = "r6g.xlarge.search"
instance_count = 3
dedicated_master_enabled = true
dedicated_master_type = "m6g.large.search"
dedicated_master_count = 3
zone_awareness_enabled = true
zone_awareness_config { availability_zone_count = 3 }
}
ebs_options {
ebs_enabled = true
volume_type = "gp3"
volume_size = 100
}
vpc_options {
subnet_ids = aws_subnet.es_subnet[*].id
security_group_ids = [aws_security_group.es_sg.id]
}
encrypt_at_rest { enabled = true }
node_to_node_encryption { enabled = true }
domain_endpoint_options {
enforce_https = true
tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
}
tags = { Environment = "dev", ManagedBy = "terraform" }
}
output "es_endpoint" {
value = aws_elasticsearch_domain.es.endpoint
}
关键点在于:vpc_options 引用了子网与安全组资源,Terraform 据此自动建立依赖图,先建网络再建域;zone_awareness_config 的可用区数量必须与子网数量一致,否则 apply 阶段会报错。这类约束正是 IaC 在计划阶段就能暴露的问题。
三、CloudFormation 的等价表达
若团队使用 CloudFormation,可用 AWS::Elasticsearch::Domain 资源类型表达同一集群,并通过 Ref 与 Fn::GetAtt 建立引用。与 Terraform 的差异在于:CloudFormation 使用 JSON/YAML 模板,依赖通过 DependsOn 或隐式引用推导,回滚由栈机制自动完成。两者在语义上等价,选择取决于团队既有工具链与状态管理偏好。
terraform plan 或 CloudFormation 变更集作为发布流水线的强制门禁。计划输出中若出现“销毁并重建”Elasticsearch 域,必须人工确认,因为域重建会导致数据丢失与服务中断。
四、状态管理与变更安全
Terraform 的远程状态应存放在带版本控制与加密的 S3 后端,并启用 DynamoDB 锁表防止并发 apply。状态文件包含集群端点、ARN 等敏感信息,不应提交到代码仓库。对于 Elasticsearch 域,以下字段属于“不可变或高风险”属性:domain_name、elasticsearch_version 的大版本升级、vpc_options 的子网变更。修改这些字段可能触发重建,应在变更前通过 lifecycle { prevent_destroy = true } 加以保护。
| 变更类型 | 典型字段 | 影响 | 建议 |
|---|---|---|---|
| 就地更新 | instance_count、ebs volume_size | 滚动扩容,服务不中断 | 可直接 apply |
| 蓝绿替换 | instance_type | 节点逐个替换 | 低峰期执行 |
| 重建风险 | domain_name、子网列表 | 域重建,数据丢失 | prevent_destroy + 人工审批 |
五、验证与交付闭环
apply 完成后,应通过输出值验证集群可达性。例如使用 curl -XGET https://${es_endpoint}/_cluster/health 检查返回的 status 是否为 green 或 yellow,并确认 number_of_nodes 与声明一致。若状态为 red,优先检查安全组是否放行 9200、子网路由是否可达。将这些验证脚本纳入流水线,即可实现“代码提交 → plan → 审批 → apply → 健康检查”的完整交付闭环,使 Elasticsearch 集群的创建与变更真正具备可重复性与可审计性。