1. 项目概述:Vishwakarma,一个基于Terraform的AWS自托管K8s集群构建器
如果你和我一样,长期在云原生和基础设施即代码(IaC)的领域里摸爬滚打,那么对于“快速、可靠地搭建一个生产就绪的Kubernetes集群”这件事,一定有着深刻的体会。这不仅仅是跑几条kubeadm init命令那么简单,它涉及到网络规划、节点配置、安全加固、高可用部署等一系列繁琐且容易出错的步骤。尤其是在AWS这样的公有云上,虽然EKS提供了托管方案,但成本、控制粒度以及特定的技术栈选择(比如你想用CoreOS Container Linux)往往会让我们这些工程师想要自己动手。今天要聊的Vishwakarma,就是我在这个需求下找到并深度使用过的一个非常趁手的工具。它不是一个全新的发明,而是站在了CoreOS Tectonic Installer这个巨人的肩膀上,用Terraform模块化的思想,将搭建一个高可用K8s集群的过程,变成了一个可版本化、可重复执行、且深度可定制的“声明式”操作。
简单来说,Vishwakarma是一个用HashiCorp Terraform编写的开源项目,它的核心目标是在AWS上自动化部署一个完整的、自托管的Kubernetes集群。它帮你封装了从VPC网络、堡垒机、到Kubernetes控制平面(Master)和工作节点(Worker)的所有AWS资源创建逻辑。你只需要准备好Terraform配置,运行terraform apply,然后喝杯咖啡,一个包含了etcd集群、多Master高可用、以及可配置的Worker节点组的K8s集群就准备就绪了。这对于需要快速搭建开发测试环境、构建内部PaaS平台,或者对集群底层有强控制需求的团队来说,价值巨大。它特别适合那些已经熟悉Terraform工作流,并且希望将K8s集群基础设施也纳入同一套IaC管道的DevOps工程师和平台团队。
2. 核心架构与设计思路拆解
在深入命令行之前,我们必须先理解Vishwakarma是怎么思考这个问题的。直接去操作AWS的控制台或者CLI来搭建K8s,会面临几个核心挑战:过程碎片化(几十个步骤分散在EC2、VPC、IAM、Auto Scaling等服务中)、状态难以管理(手动创建的资源删除和追溯困难)、一致性无法保证(第二次搭建很难和第一次完全一样)。Vishwakarma的解决方案,正是用Terraform模块来应对这些挑战。
2.1 模块化设计:像搭积木一样构建集群
Vishwakarma没有把所有代码写在一个巨大的.tf文件里,而是采用了高度模块化的设计。这种设计让每个核心功能块职责清晰,也方便你未来替换或升级某个部分。从项目结构看,主要包含三大核心模块:
aws/network模块:这是集群的地基。它负责创建一整个隔离的VPC环境,包括公有子网和私有子网。一个非常关键的设计是,它会在公有子网中部署一台堡垒机(Bastion Host)。所有位于私有子网内的资源(如Master节点、Worker节点)默认没有公网IP,这是出于安全最佳实践。当你需要SSH到这些私有节点进行调试或维护时,就需要先连接到这台堡垒机,再从堡垒机跳转过去。这个模块的输出(如VPC ID、子网ID)会成为其他模块的输入,确保了网络拓扑的连贯性。aws/elastikube模块:这是集群的大脑和心脏,负责构建Kubernetes控制平面。它的工作是最复杂的,主要包括:- etcd集群部署:部署一个多节点的、基于TLS加密通信的etcd v3.5+集群,作为K8s的后端存储。高可用的etcd是K8s高可用的前提。
- Master节点部署:部署多个Master节点,运行kube-apiserver, kube-controller-manager, kube-scheduler等核心组件。这些节点通常位于私有子网,通过内部负载均衡器(如AWS NLB)对外(主要是Worker节点和
kubectl)提供API Server服务,实现负载均衡和高可用。 - 引导与配置:利用CoreOS的Ignition系统进行节点初始化配置。Ignition是一种在首次启动时执行配置的声明式工具,比传统的Cloud-Init更早阶段运行,非常适合配置操作系统基础、磁盘、用户和系统单元。
aws/kube-worker模块:这是集群的肌肉,负责创建真正运行工作负载的节点。它利用AWS Auto Scaling Group(ASG)来管理一组Worker节点。你可以灵活地配置节点类型(如m5.large,c5.xlarge)、节点数量、以及最关键的一点——选择使用按需实例(On-Demand)还是竞价实例(Spot)。对于成本敏感的非核心业务,混合使用Spot实例能大幅降低成本。节点同样通过Ignition加入集群,自动配置kubelet、容器运行时(如Docker或containerd)并注册到Master。
这种“网络 -> 控制平面 -> 工作节点”的递进式模块设计,不仅逻辑清晰,也映射了terraform apply时的分步执行策略,让你可以分阶段验证和部署。
2.2 技术选型背后的“为什么”
- 为什么用Terraform?Terraform的“编写-计划-应用”范式,完美契合基础设施的声明式管理。它维护了一个状态文件,让你清楚地知道集群里有什么,避免资源泄漏。更重要的是,它与AWS Provider的成熟集成,能高效管理大量相互依赖的云资源。
- 为什么用CoreOS Container Linux?CoreOS是一个为运行容器而生的极简Linux发行版。它系统小巧、启动快、默认集成容器运行时、并且通过自动原子更新来增强安全性。虽然CoreOS项目已演进为Fedora CoreOS,但其Ignition和Container Linux的理念在Vishwakarma中依然发挥着关键作用,提供了稳定可靠的节点操作系统基础。
- 为什么支持多种CNI?网络是K8s的难点之一。Vishwakarma支持AWS VPC CNI、flannel和Cilium,覆盖了不同场景。AWS VPC CNI让Pod直接获得VPC IP,网络性能最好,与AWS其他服务(如VPC流日志、安全组)集成度高;flannel简单稳定,是经典的Overlay网络方案;Cilium则基于eBPF,提供了强大的网络策略和可观测性能力。这种可插拔的设计给了用户根据自身网络知识和需求进行选择的权利。
3. 从零开始:手把手搭建你的第一个集群
理解了架构,我们进入实战环节。假设你有一个AWS账号,并且已经配置好了具有足够权限的AWS CLI凭证(通过aws configure)。以下步骤我将结合官方指南和个人踩坑经验,为你梳理出一条清晰的路径。
3.1 前期准备:工具链与权限检查
这一步至关重要,很多后续错误都源于这里没准备好。
安装并验证Terraform (>= v1.2.0):
# 以macOS为例,使用Homebrew安装 brew tap hashicorp/tap brew install hashicorp/tap/terraform # 验证安装和版本 terraform version注意:确保版本符合要求。Terraform不同版本间Provider插件和语法可能有差异,使用项目要求的最低版本或更高版本可以避免兼容性问题。
安装kubectl (>= v1.31.1)和aws-iam-authenticator:
# 安装kubectl brew install kubernetes-cli # 安装aws-iam-authenticator (以macOS为例) brew install aws-iam-authenticator # 分别验证 kubectl version --client aws-iam-authenticator versionaws-iam-authenticator是K8s与AWS IAM集成的关键。集群创建后,你需要用它来生成访问令牌,kubectl才能通过IAM角色认证访问集群。创建EC2密钥对: 这是为了能SSH登录到堡垒机和节点。务必在你计划部署集群的AWS区域(例如
us-west-2)创建。- 登录AWS控制台,进入EC2服务,在“密钥对”页面创建新密钥对,命名为
my-vishwakarma-key,下载私钥文件(.pem格式)。 - 将私钥文件放到
~/.ssh/目录下,并设置正确的权限:mv ~/Downloads/my-vishwakarma-key.pem ~/.ssh/ chmod 400 ~/.ssh/my-vishwakarma-key.pem - 同时,你需要有对应的公钥文件。如果你是从AWS控制台创建的,通常只提供私钥下载。你可以通过以下命令从私钥生成公钥(如果尚未生成):
ssh-keygen -y -f ~/.ssh/my-vishwakarma-key.pem > ~/.ssh/my-vishwakarma-key.pub
- 登录AWS控制台,进入EC2服务,在“密钥对”页面创建新密钥对,命名为
安装jq和Python 3.7+:
brew install jq python python3 --version # 确认是3.7+ pip3 --versionjq用于在后续脚本中处理JSON输出。Python 3.7和pip则是为了支持项目中可能用于节点滚动更新的Lambda函数(如果相关模块被启用)。
3.2 获取项目与初始化配置
克隆项目并进入示例目录:
git clone https://github.com/getamis/vishwakarma.git cd vishwakarma/examples/kubernetes-cluster这个
examples/kubernetes-cluster目录包含了一个开箱即用的Terraform配置示例。我强烈建议你先基于这个例子进行实验,理解后再创建自己的配置。审视和修改
terraform.tfvars文件: 通常示例会有一个terraform.tfvars.example文件。你需要复制它并填写自己的变量。cp terraform.tfvars.example terraform.tfvars用编辑器打开
terraform.tfvars,以下是一些最关键的配置项及其解释:# 集群标识,会用于命名许多资源(如S3存储桶、EC2实例名) cluster_name = "my-first-vishwakarma-cluster" # AWS区域,确保与你创建密钥对的区域一致 aws_region = "us-west-2" # 你刚刚创建并放入~/.ssh/的密钥对名称 key_pair_name = "my-vishwakarma-key" # 你的公钥内容,用于Ignition配置节点访问 # 将下面替换为 `cat ~/.ssh/my-vishwakarma-key.pub` 的输出 public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...(你的公钥内容)" # 网络配置,通常可以先保持默认 vpc_cidr = "10.0.0.0/16" # Master节点配置 master_count = 2 # 生产环境建议至少3个以实现高可用 master_instance_type = "t3.medium" # Worker节点组配置 worker_count = 2 worker_instance_type = "t3.medium" worker_group_name = "on-demand" # 可以创建多个不同配置的worker组 # 是否启用Spot实例 worker_spot_enabled = false # 首次尝试建议关闭,避免Spot中断干扰 worker_spot_price = "" # 如果启用,这里可以指定最高出价 # Kubernetes版本 kubernetes_version = "1.31.1"实操心得:
cluster_name最好全局唯一,特别是S3存储桶名需要全球唯一。如果创建失败,提示S3桶名已存在,修改此名称即可。master_count设置为2是一个折中方案,既能提供一定的可用性(一个挂了另一个还在),又比3个节省成本。但对于严格的生产环境,3个Master是底线。初始化Terraform:
terraform init这个命令会下载项目所需的AWS Provider插件以及本地引用的模块。看到
Terraform has been successfully initialized!即表示成功。
3.3 分步构建集群
官方文档建议分步apply,这是一个非常好的实践,有利于调试和问题定位。
创建网络基础设施:
terraform apply -target=module.networkTerraform会显示执行计划,创建VPC、子网、互联网网关、NAT网关、路由表以及堡垒机。输入
yes确认。这个过程大约需要2-3分钟。创建成功后,记下输出中的bastion_public_ip,这是你后续SSH登录的入口。创建Kubernetes控制平面:
terraform apply -target=module.master这是最耗时的一步,大约需要10-15分钟。Terraform会创建Master节点、etcd节点、负载均衡器、安全组、IAM角色等大量资源。它会通过Ignition配置文件,在EC2实例首次启动时自动安装并配置所有K8s控制平面组件。
注意事项:在此期间,如果遇到错误(例如IAM权限不足、实例类型配额不够),仔细阅读错误信息。最常见的权限问题是Terraform使用的IAM角色或用户缺少特定操作权限(如创建ELB、EC2特定类型)。你需要根据错误提示,在AWS IAM中附加相应的策略。
创建工作节点:
terraform apply在创建完网络和Master之后,运行不带
-target的apply会创建配置中定义的所有剩余资源,主要是Worker节点组。这个过程也会用到Ignition,自动将Worker节点加入集群。大约需要5-10分钟。
3.4 验证集群并获取访问权限
所有步骤完成后,集群已经运行,但你本地的kubectl还不知道如何访问它。
获取kubeconfig文件: Vishwakarma会将生成的集群访问配置文件(kubeconfig)上传到一个S3存储桶中。存储桶名称格式为
<cluster_name>-<hash>。你可以从Terraform的输出中查找一个名为kubeconfig_s3_bucket或类似的输出变量,或者直接运行以下命令获取(需要jq):terraform output -json | jq -r '.kubeconfig_s3_bucket.value'假设输出是
my-first-vishwakarma-cluster-abc123。然后使用AWS CLI下载:aws s3 cp s3://my-first-vishwakarma-cluster-abc123/kubeconfig ./kubeconfig配置kubectl:
export KUBECONFIG=$(pwd)/kubeconfig # 或者永久合并到你的默认kubeconfig # mkdir -p ~/.kube # cp ./kubeconfig ~/.kube/config_vishwakarma # export KUBECONFIG=~/.kube/config:~/.kube/config_vishwakarma验证集群状态:
kubectl cluster-info kubectl get nodes -o wide你应该能看到所有Master和Worker节点,并且状态都是
Ready。如果Worker节点长时间处于NotReady,可以SSH到堡垒机,然后跳转到Worker节点上查看kubelet日志(journalctl -u kubelet -f)。配置AWS IAM身份映射: 默认的kubeconfig使用了
aws-iam-authenticator,但它需要知道哪个AWS IAM用户或角色可以映射为K8s集群内的用户/权限。你需要创建一个aws-authConfigMap。Vishwakarma可能没有自动完成这一步。一个简单的方法是,先给运行Terraform的IAM实体(用户或角色)赋予集群管理员权限。- 首先,获取你的AWS账户ID和用户名:
aws sts get-caller-identity --query Account --output text aws iam get-user --query User.UserName --output text # 如果你用的是IAM角色,可能需要其他方式获取身份信息 - 创建一个
aws-auth.yaml文件:apiVersion: v1 kind: ConfigMap metadata: name: aws-auth namespace: kube-system data: mapUsers: | - userarn: arn:aws:iam::<YOUR_AWS_ACCOUNT_ID>:user/<YOUR_IAM_USERNAME> username: admin groups: - system:masters - 应用这个配置:
kubectl apply -f aws-auth.yaml
完成后,你的
kubectl命令就应该有权限执行了。- 首先,获取你的AWS账户ID和用户名:
4. 深入核心模块与高级配置解析
搭建起来只是第一步,理解每个模块的细节才能让你真正驾驭它。
4.1aws/elastikube模块:控制平面的魔法
这个模块是精髓。我们来看看它如何实现高可用。
- etcd集群:它会在不同的私有子网中创建多个EC2实例(通常与Master节点数量一致或为奇数个),形成一个分布式etcd集群。节点间通过TLS证书进行加密通信,这些证书在Terraform运行过程中动态生成并注入Ignition配置。etcd的数据盘通常会被挂载并格式化为独立的EBS卷,便于备份和恢复。
- Master节点与负载均衡器:多个Master节点前面,会部署一个内部网络负载均衡器(NLB)。
kube-apiserver监听在NLB后面。Worker节点和kubectl都通过这个NLB的DNS名称来访问API Server。这样,任何一个Master节点宕机,NLB会自动将流量路由到健康的节点,实现了API Server层面的高可用。 - Ignition配置:这是CoreOS生态的核心。Terraform会生成一个
.ign(Ignition配置)文件,其内容是一个JSON,定义了系统drops、磁盘分区、用户、systemd服务单元等。这个文件被传递给AWS User-Data,实例启动时,Ignition进程会首先执行它,安装Docker/containerd、kubelet,下载K8s组件二进制文件,并启动所有必要的服务。整个过程无需人工干预。
4.2aws/kube-worker模块:灵活的工作节点管理
这个模块的灵活性体现在对AWS Auto Scaling Group (ASG) 和 Launch Template的深度利用上。
- 混合实例策略:通过
worker_spot_enabled和worker_spot_price等变量,你可以轻松配置一个同时包含按需实例和竞价实例的ASG。这对于批处理任务、开发环境等非核心业务能节省大量成本。ASG会负责维持你设定的期望节点数量。 - 节点标签与污点:你可以在变量中为Worker组添加自定义的K8s标签(
node_labels)和污点(node_taints)。这样,在部署应用时,可以使用nodeSelector或tolerations来精确控制Pod调度到哪些节点组上。例如,你可以创建一个带spot=true:NoSchedule污点的Spot节点组,只有明确容忍此污点的Pod才会被调度上去。 - 自定义用户数据:除了基本的Ignition配置加入集群,你还可以通过
worker_additional_ignition_config变量注入额外的Ignition配置片段,用于在节点启动时安装监控代理、日志收集器(如Fluentd)或任何你需要的自定义软件包。
4.3 网络插件选型与配置
在variables.tf或你的terraform.tfvars中,你可以找到network_plugin这个变量,可选值为amazon-vpc(AWS VPC CNI),flannel, 或cilium。
- 选择
amazon-vpc:这是与AWS集成最深的方案。每个Pod会获得一个真实的VPC IP地址。你需要确保VPC的子网有足够大的CIDR块(或者使用辅助CIDR)来容纳大量Pod。性能最好,但需要管理VPC的IP地址空间。 - 选择
flannel:经典的Overlay网络,使用VXLAN封装。Pod网络是一个独立于VPC的CIDR。配置简单,不占用VPC IP,但会引入少量的网络开销,且Pod IP在VPC内不可直接路由。 - 选择
cilium:基于eBPF的新一代方案,提供高性能和强大的网络策略、可观测性功能。选择它意味着你希望利用更先进的网络特性,但可能需要更深入的学习。配置要点:切换网络插件通常需要在集群创建之初就确定。后期更换非常麻烦,几乎等同于重建集群。所以务必根据你的应用需求(是否需要与AWS服务直接Pod通信?是否对网络性能有极致要求?)提前做好选择。
5. 运维实践、问题排查与经验分享
集群跑起来只是开始,日常运维和问题排查才是真正的战场。
5.1 节点滚动更新与集群升级
Vishwakarma通过ASG的Launch Template来管理节点镜像。当你想更新CoreOS版本或修改节点配置时:
- 修改Terraform配置中与节点相关的变量(例如
container_linux_channel从stable改为beta,或者修改Ignition配置)。 - 运行
terraform apply。Terraform会创建新的Launch Template版本。 - 手动触发ASG实例刷新:Terraform默认不会强制替换运行中的实例。你需要到AWS控制台,找到对应的Worker ASG,执行“开始实例刷新”操作,选择“滚动更新”策略,ASG会逐步用新配置的实例替换旧实例。
重要提示:对于Master节点,滚动更新要格外小心。因为etcd和K8s控制平面组件有严格的版本兼容性和启动顺序要求。建议先仔细阅读K8s官方升级文档,并考虑在维护窗口内,通过修改
master_ignition_config并逐个节点替换的方式手动操作,而不是依赖ASG自动刷新。
5.2 常见问题排查速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
terraform apply失败,提示IAM权限不足 | 执行Terraform的IAM用户/角色缺少必要权限。 | 1. 检查错误信息中明确指出的API操作(如ec2:RunInstances,iam:CreateRole)。2. 为IAM实体附加相应的AWS托管策略(如 AdministratorAccess用于测试,生产环境应遵循最小权限原则定制策略)。 |
Worker节点状态为NotReady | kubelet未能成功启动或无法连接API Server。 | 1. SSH到堡垒机,再跳转到故障Worker节点。 2. 检查kubelet服务状态: journalctl -u kubelet -f --no-pager。3. 常见原因:网络插件Pod未就绪(检查 kubectl get pods -n kube-system)、节点CIDR冲突、或kubelet证书问题。 |
kubectl命令报错Unauthorized或Forbidden | aws-authConfigMap未配置或配置错误。 | 1. 确认已创建并正确配置了aws-authConfigMap:kubectl describe configmap aws-auth -n kube-system。2. 检查映射的IAM ARN是否正确无误。 3. 确保 aws-iam-authenticator版本与集群兼容。 |
| Pod网络不通,无法跨节点通信 | 网络插件(CNI)未正确安装或配置。 | 1. 检查CNI相关的DaemonSet是否运行正常:kubectl get ds -n kube-system。2. 查看CNI Pod的日志: kubectl logs -n kube-system -l k8s-app=<cni-pod-label>。3. 检查节点路由表和安全组规则,确保放行了CNI所需的端口(如VXLAN的4789端口,或主机网络的端口)。 |
| 无法通过SSH连接堡垒机或节点 | 安全组未开放22端口,或密钥对错误。 | 1. 检查堡垒机实例关联的安全组,确保入站规则允许你的IP访问22端口。 2. 确认SSH命令使用的私钥路径和权限( chmod 400)正确。3. 通过AWS控制台的“实例连接”功能尝试连接,以排除网络问题。 |
执行terraform destroy时资源删除失败 | 有依赖资源未删除(如S3桶非空、EBS卷被挂载)。 | 1. 手动清空S3存储桶(特别是存放kubeconfig和日志的桶)。 2. 检查是否有EBS卷因“删除时终止”未勾选而残留。 3. 最彻底的方法:在AWS控制台按资源创建顺序手动删除(VPC、ELB、EC2、IAM等),最后再运行 terraform destroy。 |
5.3 生产环境部署建议与个人心得
- 状态文件远程存储:千万不要将
terraform.tfstate文件只保存在本地。使用S3后端配合DynamoDB表做状态锁是标准做法。这能保证团队协作时状态一致,并防止并发操作。在项目根目录创建backend.tf文件配置远程后端。 - 分离环境与模块复用:为开发、测试、生产环境创建不同的Terraform工作目录(或使用Terraform Workspace),并利用模块化特性,将网络、集群等配置抽象为可复用的模块,通过传递不同的变量值来区分环境。
- 秘密管理:Terraform配置中可能包含敏感信息(如证书私钥)。切勿直接写入
.tf文件。使用Terraform的sensitive变量标记,并利用AWS Secrets Manager或HashiCorp Vault来注入这些秘密。在Vishwakarma中,很多证书是在内部动态生成的,这相对安全。 - 监控与日志:集群创建后,第一时间部署监控系统(如Prometheus Operator)和日志收集方案(如EFK栈)。CoreOS节点上的
journald是查看系统和服务日志的关键工具。 - 关于成本:除了使用Spot实例,合理选择实例类型、设置ASG的伸缩策略、定期清理未使用的EBS卷和快照,都是控制AWS账单的有效手段。使用
t3系列等新一代实例类型通常性价比更高。
在我自己的使用经验里,Vishwakarma最大的优势在于它将一个极其复杂的过程标准化、代码化了。它可能不像一些全托管服务那样“一键无忧”,但它给了你完全的透明度和控制权。当你需要排查一个深层次问题时,你能清楚地知道每一个组件是如何被配置和启动的,这对于构建稳定可靠的基础设施至关重要。当然,这也意味着你需要投入更多时间去学习和理解其内部机制。不过,对于追求“基础设施即代码”和“可重复性”的团队来说,这份投入是绝对值得的。