☰
90DaysOfDevOps 第 61 天:用 Terraform 编排 Kubernetes 资源与多环境部署
2026/10/7 8:24:26 网站建设 项目流程
  • 文档/教程

【免费下载链接】90DaysOfDevOps

This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.

项目地址:https://gitcode.com/gh_mirrors/90/90DaysOfDevOps
点击查看免费下载

本文是 90DaysOfDevOps 挑战中“基础设施即代码(IaC)”章节的第 5 讲(对应仓库 2022/Days/day61.md)。前几讲我们已经用 Terraform 在 VirtualBox 中部署虚拟机(Day 59)、在本地 Docker 中部署容器(Day 60),本讲则把同一套“用代码定义期望状态”的思路延伸到 Kubernetes:通过 Terraform 的 Kubernetes Provider 在集群内创建命名空间、Deployment 和 Service,并讨论生产/预发/开发多环境编排的两种实现路径。读完本文,你将掌握用.tf配置管理集群内对象、用kubectl验证部署结果,以及在terraform workspaces与目录结构两种多环境方案之间做出取舍的完整能力。

从虚拟机到容器再到 Kubernetes:IaC 的演进脉络

在整个 IaC 章节中,核心前提始终没有变:在代码里定义目标基础设施的样子,然后交给 Terraform 去落地。Day 59 把这一前提用在 VirtualBox 虚拟机上(virtualbox.tf),Day 60 把它用在 Docker 容器上(docker.tf)。到了 Day 61,同样的前提被用于 Kubernetes 集群内部的对象。

仓库作者在文档中说明,他曾用 Terraform 在三大主流云厂商上部署 Kubernetes 集群用于演示;而本讲更进一步——不只部署集群,还要用 Terraform 直接管理集群内部的对象(命名空间、工作负载、服务等)。

两条进入 Kubernetes 的 Provider 路径

Terraform 与 Kubernetes 交互有两种官方途径:

  1. Kubernetes Provider(hashicorp/kubernetes):管理集群内的原生对象,如kubernetes_namespace、kubernetes_deployment、kubernetes_service等资源类型;
  2. Helm Provider(hashicorp/helm):用于管理 Helm Chart 的部署与生命周期,适合以 Chart 形式交付的应用。

本文演示走的是第一条路径(Kubernetes Provider),用 HCL 直接声明集群内的三类资源。

为什么不用 kubectl?

之前章节我们一直用kubectl操作集群,但在 Kubernetes 环境中引入 Terraform 有两个明确收益:

  • 统一工作流(Unified workflow):如果集群本身就是用 Terraform 部署的,那么集群内部的资源也使用同一套工具与流程,整个链路(从云资源到集群资源)只有一个编排入口;
  • 生命周期管理(Lifecycle management):Terraform 不只是“创建工具”,它基于 state 文件持续跟踪资源状态,能够统一执行变更、更新与删除,而不是散落在一条条临时命令里。

实操:用 Terraform 在 Minikube 上部署 nginx

本讲沿用 Minikube 作为本地演示集群(与 Day 55 起的 Kubernetes 章节一致)。完整配置存放在仓库 2022/Days/IaC/Kubernetes/kubernetes.tf(文档中写作Kubernetes.tf,仓库实际以小写kubernetes.tf存储)。下面逐块解读这份配置,并给出每一步的验证命令。

完整配置文件

terraform { required_providers { kubernetes = { source = "hashicorp/kubernetes" version = ">= 2.0.0" } } } provider "kubernetes" { config_path = "~/.kube/config" } resource "kubernetes_namespace" "test" { metadata { name = "nginx" } } resource "kubernetes_deployment" "test" { metadata { name = "nginx" namespace = kubernetes_namespace.test.metadata.0.name } spec { replicas = 2 selector { match_labels = { app = "MyTestApp" } } template { metadata { labels = { app = "MyTestApp" } } spec { container { image = "nginx" name = "nginx-container" port { container_port = 80 } } } } } } resource "kubernetes_service" "test" { metadata { name = "nginx" namespace = kubernetes_namespace.test.metadata.0.name } spec { selector = { app = kubernetes_deployment.test.spec.0.template.0.metadata.0.labels.app } type = "NodePort" port { node_port = 30201 port = 80 target_port = 80 } } }

配置要点逐块解读

Provider 声明与连接配置

terraform { required_providers { kubernetes = { source = "hashicorp/kubernetes" version = ">= 2.0.0" } } } provider "kubernetes" { config_path = "~/.kube/config" }
  • source = "hashicorp/kubernetes":指定官方 Kubernetes Provider,version = ">= 2.0.0"表示允许安装不低于 2.0.0 的版本(首次terraform init实际解析到的版本会记录进.terraform.lock.hcl锁文件,保证后续安装一致);
  • config_path = "~/.kube/config":指向本机 kubeconfig 文件。Minikube 生成的 kubeconfig 默认就位于该路径,Terraform 会复用其中记录的集群地址、凭据与当前上下文,因此前提是本机已存在一个可用集群(如 Minikube)且kubectl能正常访问。

命名空间资源

resource "kubernetes_namespace" "test" { metadata { name = "nginx" } }

声明一个名为nginx的命名空间,作为后续资源的逻辑隔离边界。

Deployment 资源

resource "kubernetes_deployment" "test" { metadata { name = "nginx" namespace = kubernetes_namespace.test.metadata.0.name } spec { replicas = 2 ... } }
  • namespace = kubernetes_namespace.test.metadata.0.name:这是 Terraform 的资源间引用(引用表达式),直接把上面命名空间资源的名称引用过来,Terraform 会自动建立依赖顺序——先建命名空间,再建 Deployment;
  • replicas = 2:期望运行 2 个 nginx 副本;
  • selector.match_labels与template.metadata.labels均使用app = "MyTestApp",保持标签一致才能让 ReplicaSet 正确选中 Pod;
  • container.image = "nginx":使用默认 latest 标签的官方 nginx 镜像,容器名nginx-container,监听container_port = 80。

Service 资源

resource "kubernetes_service" "test" { metadata { name = "nginx" namespace = kubernetes_namespace.test.metadata.0.name } spec { selector = { app = kubernetes_deployment.test.spec.0.template.0.metadata.0.labels.app } type = "NodePort" port { node_port = 30201 port = 80 target_port = 80 } } }
  • selector.app引用了 Deployment 模板里 Pod 的标签值(MyTestApp),Service 据此把流量路由到对应 Pod,这同样构成了资源间的隐式依赖;
  • type = "NodePort"将服务暴露到节点端口30201,容器端口80作为port与target_port。之所以选择 NodePort 而非 Ingress,是因为 Minikube 的 Docker 网络对 Ingress 的支持有限(本讲文档也明确提到了这一限制)。

分步执行与验证

第 1 步:初始化项目

在存放kubernetes.tf的新项目目录中执行:

terraform init

输出会显示 Terraform 已成功初始化,并自动下载、安装匹配>= 2.0.0的 Kubernetes Provider 插件,同时生成.terraform.lock.hcl锁文件。这一步会拉取 Provider,因此需要本机网络可达 Terraform Registry。

第 2 步:确认应用前的集群状态

执行kubectl get ns,在未 apply 之前,集群中只有default、kube-node-lease、kube-public、kube-system等系统预置命名空间,尚不存在nginx命名空间,以此证明后续资源确实由 Terraform 创建。

第 3 步:执行 apply

terraform apply

计划输出显示将新增 3 个资源(命名空间、Deployment、Service),最终以Apply complete! Resources: 3 added, 0 changed, 0 destroyed.收尾,说明三个资源全部创建成功。这与仓库 kubernetes.tf 中声明的资源一一对应。

第 4 步:验证集群内的部署结果

kubectl get ns kubectl get all -n nginx

kubectl get ns输出中新增了nginx命名空间;kubectl get all -n nginx则展示完整部署状态:

  • Pod:2 个 nginx 实例均处于 Running,就绪 1/1;
  • Service:类型为 NodePort,Cluster IP 为10.104.210.141,端口映射80:30201/TCP,与配置中的node_port = 30201一致;
  • Deployment:期望 2 个副本、就绪 2 个;
  • ReplicaSet:管理这 2 个副本,运行正常。

第 5 步:访问应用

由于 Minikube 的 Docker 网络对 Ingress 支持有限,直接访问需要做端口转发:

kubectl port-forward -n nginx svc/nginx 30201:80

然后浏览器打开http://localhost:30201/,即可看到 nginx 的默认欢迎页(Welcome to nginx!),证明由 Terraform 声明的 Service 已正确把流量转发到 Deployment 管理的 Pod。

多环境部署:workspaces 与文件结构两条路线

演示代码跑通后,自然的下一步是:如果希望**生产(production)、预发(staging)、开发(development)**三套环境外观一致、复用同一份代码,Terraform 提供两种主流做法:

方案本质
terraform workspaces在**同一个后端(backend)**内划分多个具名工作区
文件结构(目录布局)用目录隔离环境,用**模块(module)**实现复用

两种方案各有取舍,下面逐一分析。

terraform workspaces

优点

  • 上手简单:一条terraform workspace new dev即可创建新工作区,无需改动目录结构;
  • 表达式便捷:可直接使用terraform.workspace表达式引用当前工作区名称,例如用它拼接命名空间或资源名,实现“一份代码、多环境复用”;
  • 代码重复最小化:所有环境共享同一份配置,不需要复制粘贴.tf文件。

缺点

  • 易受人为错误影响:所有环境共用一个后端,误切 workspace 后执行 apply,可能把变更应用到错误环境——这恰恰违背了使用 IaC 消除人为失误的初衷;
  • 状态存于同一后端:多个环境的 state 文件存放在同一处,隔离性弱;
  • 代码库无法无歧义地表达部署配置:单从代码仓库看不出某个工作区对应哪套环境,环境与配置的对应关系靠约定而非声明。

文件结构(目录布局)

优点

  • 后端隔离:每个环境可以配置独立的 state 后端(如不同对象存储桶/路径),带来两层好处——安全性提升与人为失误概率下降,错误环境的 apply 不会触碰其他环境的 state;
  • 代码库完整反映部署状态:从目录结构即可看出 dev/staging/prod 各自的配置与差异,环境对应关系一目了然。

缺点

  • 需要多次 apply:每个环境都要单独执行一次terraform apply(或通过 CI 分别触发),不能一次覆盖全部环境;
  • 代码重复更多:目录间会存在重复配置,但可以通过模块化大幅压缩——把通用资源抽成 module,各环境目录只保留差异化参数。

如何选择

结合本讲上下文可以得出实践倾向:workspaces 适合快速起步、环境差异小、团队规模小的场景;文件结构适合对环境隔离与安全要求高的生产级场景。第 59 讲已经介绍了模块(Module)作为资源组合与复用的载体,文件结构方案的“代码重复”痛点正好可以用模块化解,这也是 Day 62(测试、工具与替代方案)继续探讨的方向。

仓库配套:从单集群演示到工程化

围绕本讲主题,仓库 IaC 目录提供了可对照学习的配套素材:

  • 2022/Days/IaC/Kubernetes/kubernetes.tf:本讲核心配置,可直接用于 Minikube 或任何kubectl可达的集群;
  • 2022/Days/IaC/Docker/docker.tf 与 2022/Days/IaC/Docker-Wordpress/docker-wordpress.tf:Day 60 的容器编排示例,展示了相同工作流在 Docker 上的应用;
  • 2022/Days/IaC/Virtualbox/virtualbox.tf:Day 59 的虚拟机示例;
  • 2022/Days/IaC/Terratest:Go 语言编写的 IaC 自动化测试示例(test/terraform_test.go及配套examples/目录),对应 Day 62 的测试章节;
  • 2022/Days/Kubernetes:Kubernetes 章节的 YAML 清单(如 nginx-stateless-demo.yaml、pacman-stateful-demo.yaml),可与本讲的.tf声明式写法对照,理解同一目标在 YAML 与 HCL 两种语法下的差异。

值得注意的工程化细节:从配置看,Kubernetes Provider 的>= 2.0.0版本约束与terraform init生成的锁文件机制,保证不同机器、不同时间执行部署时 Provider 版本一致;而 Deployment/Service 通过引用表达式串联依赖关系,让 Terraform 的定向图(DAG)自动保证创建顺序,这也是“Terraform 不只是创建工具,还能统一管理变更与删除”的实现基础。

延伸阅读

  • Day 59:用 Terraform 创建虚拟机与变量:理解 IaC 章节起点、变量注入方式(TF_VAR_、terraform.tfvars、-var)与敏感信息处理;
  • Day 60:Docker 容器、Provisioners 与模块:本讲直接的前置实践,包含 Docker Provider、local-exec/remote-exec provisioner 与模块概念;
  • Day 62:测试、工具与替代方案:本讲的后续延伸,覆盖terraform fmt/validate/plan内置校验、Terratest 自动化测试及 Pulumi 等替代方案;
  • 2022/Days/IaC:本讲所属 IaC 章节的全部示例代码目录。
  • 文档/教程

【免费下载链接】90DaysOfDevOps

This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.

项目地址:https://gitcode.com/gh_mirrors/90/90DaysOfDevOps
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询