在云计算和容器化技术成为主流的今天,Kubernetes作为容器编排的事实标准,其部署复杂度却一直是个门槛。传统手动部署方式需要处理网络配置、存储规划、安全策略等数十个环节,一个生产级集群的搭建往往需要资深工程师数天时间。而通过Terraform这样的基础设施即代码工具,我们可以将整个部署过程自动化、标准化,实现真正的一键式集群创建。
我最近在客户现场实施了一个金融级Kubernetes集群项目,通过Terraform+Ansible的组合,将原本需要3天的手工部署压缩到20分钟完成。本文将分享这个方案的核心实现细节,包括架构设计、模块拆分以及那些只有实际踩过坑才知道的调优参数。
生产级Kubernetes集群的基础设施需要满足几个关键要求:
我们采用多AZ部署模式,核心资源包括:
hcl复制module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.14.0"
name = "prod-k8s-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = false
}
对于控制平面组件,我们选择使用kubeadm进行初始化,但通过Terraform动态生成配置模板。关键配置包括:
hcl复制data "template_file" "kubeadm_config" {
template = file("${path.module}/templates/kubeadm-config.yaml.tpl")
vars = {
kubernetes_version = "1.24.3"
pod_subnet = "192.168.0.0/16"
service_subnet = "10.96.0.0/12"
dns_domain = "cluster.local"
control_plane_endpoint = aws_lb.k8s_api.dns_name
}
}
关键提示:生产环境务必设置controlPlaneEndpoint为负载均衡DNS,这是实现控制平面高可用的前提条件。
工作节点采用节点池(Node Pool)方式管理,每个池对应特定的实例类型和工作负载类型。例如GPU节点池配置:
hcl复制resource "aws_launch_template" "gpu_nodes" {
name_prefix = "gpu-node-"
image_id = data.aws_ami.eks_optimized_gpu.id
instance_type = "p3.2xlarge"
block_device_mappings {
device_name = "/dev/xvda"
ebs {
volume_size = 100
volume_type = "gp3"
}
}
user_data = base64encode(templatefile("${path.module}/templates/gpu-node-userdata.sh", {
cluster_name = local.cluster_name
}))
}
经过性能测试,我们最终选择Calico作为CNI插件,其配置需要与VPC网段做好协调:
yaml复制apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
name: ippool-192-168
spec:
blockSize: 26
cidr: 192.168.0.0/16
ipipMode: Never
natOutgoing: true
nodeSelector: all()
实测发现:当集群规模超过200节点时,需要调整blockSize到26或更大,避免IP地址快速耗尽。
通过Terraform动态创建EBS StorageClass:
hcl复制resource "kubernetes_storage_class" "ebs_gp3" {
metadata {
name = "ebs-gp3"
}
storage_provisioner = "ebs.csi.aws.com"
volume_binding_mode = "WaitForFirstConsumer"
parameters = {
type = "gp3"
iops = "3000"
throughput = "125"
}
allow_volume_expansion = true
}
关键安全配置包括:
通过Terraform部署策略模板:
hcl复制resource "kubernetes_network_policy" "default_deny" {
metadata {
name = "default-deny"
namespace = "default"
}
spec {
pod_selector {}
policy_types = ["Ingress"]
}
}
将整个部署过程分为三个阶段,通过Terragrunt管理依赖关系:
code复制.
├── 1-infra/ # 网络基础架构
├── 2-controlplane/ # 控制平面
└── 3-worknodes/ # 工作节点
通过封装Shell脚本实现全自动部署:
bash复制#!/bin/bash
set -eo pipefail
echo "=== 阶段1:基础设施部署 ==="
terragrunt run-all apply --terragrunt-non-interactive -target-dir 1-infra
echo "=== 阶段2:控制平面初始化 ==="
terragrunt run-all apply --terragrunt-non-interactive -target-dir 2-controlplane
echo "=== 阶段3:工作节点加入 ==="
terragrunt run-all apply --terragrunt-non-interactive -target-dir 3-worknodes
echo "=== 生成kubeconfig ==="
aws eks update-kubeconfig --name ${CLUSTER_NAME}
经过压力测试得出的优化配置:
yaml复制apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
maxPods: 110
kubeAPIQPS: 50
kubeAPIBurst: 100
serializeImagePulls: false
部署时自动安装Prometheus Operator:
hcl复制resource "helm_release" "prometheus" {
name = "prometheus"
repository = "https://prometheus-community.github.io/helm-charts"
chart = "kube-prometheus-stack"
version = "35.5.1"
set {
name = "prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName"
value = "ebs-gp3"
}
}
通过Velero实现集群状态备份:
hcl复制resource "helm_release" "velero" {
name = "velero"
repository = "https://vmware-tanzu.github.io/helm-charts"
chart = "velero"
set {
name = "configuration.backupStorageLocation.bucket"
value = aws_s3_bucket.velero_backup.id
}
set {
name = "configuration.provider"
value = "aws"
}
}
| 故障现象 | 排查命令 | 解决方案 |
|---|---|---|
| Pod卡在Pending状态 | kubectl describe pod <name> |
检查资源配额和节点选择器 |
| API Server不可用 | curl -k https://<endpoint>/healthz |
检查控制平面EC2实例状态 |
| 网络跨节点不通 | calicoctl node status |
检查Calico BGP对等体状态 |
使用Fluent Bit实现结构化日志收集:
hcl复制resource "helm_release" "fluent_bit" {
name = "fluent-bit"
repository = "https://fluent.github.io/helm-charts"
chart = "fluent-bit"
set {
name = "backend.type"
value = "es"
}
set {
name = "backend.es.host"
value = aws_elasticsearch_domain.logging.endpoint
}
}
在实际部署中,我发现最大的挑战不是技术实现,而是如何平衡安全性与便利性。比如在金融客户场景下,我们需要在Terraform代码中集成Vault进行敏感信息管理,这增加了部署链路的复杂度,但换来了审计合规的通过。这种取舍在每个项目中都需要根据实际情况做出判断。