CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Terraform 基础设施即代码/课时/Terraform 与 K8s
RawBlame
课时目录12 节

Terraform 基础设施即代码

  1. 01Terraform 是什么
  2. 02HCL 语法
  3. 03init 与 Provider
  4. 04plan 与 apply
  5. 05State 管理
  6. 06变量与输出
  7. 07Module 复用
  8. 08AWS 资源示例
  9. 09Terraform 与 K8s
  10. 10CI 中的 Terraform
  11. 11Terraform vs Helm
  12. 12综合练习

Terraform 与 K8s

集群基础设施 vs 应用 Helm Chart。

30 分钟

Terraform 与 Kubernetes

这一课你将能做到

  1. 配置 Kubernetes Provider,让 Terraform 连上一个真实集群(含 EKS 集群的取凭证方式)
  2. 用 Terraform 创建 Namespace、Deployment、Service 等 K8s 对象
  3. 划清 Terraform 在 K8s 世界的适用边界,知道哪些对象该交给 Helm 或 GitOps

为什么要学

当团队把 Spring Boot 从 EC2 迁到 Kubernetes,基础设施就分成了两层:集群本身(节点、网络、插件)和集群内的对象(Deployment、Service、Ingress)。Terraform 都能管,但「能管」不代表「都该管」。现实中最常见的架构是:Terraform 建 EKS 集群和引导组件,应用清单走 Helm 或 ArgoCD。理解 Kubernetes Provider 的用法和它的脾气(apply 时序、字段漂移),才能在这种混合架构里不踩坑。

人话:Terraform 是「盖商场 + 装好公共电梯」的施工队;每家店铺(你的应用)怎么摆货架,商场物管(Helm/GitOps)另有流程。施工队可以帮头两家店铺摆,但整层都让它管就别扭了。

先建立图像

Terraform 对接 K8s 的数据流:

kubeconfig(或 EKS 数据源)
        │
        ▼
Kubernetes Provider ──► kubernetes_* 资源(声明对象的期望状态)
                     └─► helm_* 资源(下一课讲)

EKS 场景的典型分工:

Terraform:EKS 控制面 + 节点组 + 集群插件(VPC CNI、CoreDNS)
         + 少量 bootstrap 对象(命名空间、CRD)
Helm/ArgoCD:业务应用的 Deployment/Service/Ingress

跟着做

步骤 1:准备 provider

前提:有一个可用集群并配置好了 kubeconfig(本地可用 kind/minikube 练习)。

versions.tf:

terraform {
  required_version = ">= 1.7.0"

  required_providers {
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.25"
    }
  }
}

providers.tf(本地 kubeconfig):

provider "kubernetes" {
  config_path = "${pathexpand("~/.kube/config")}"
}

执行 terraform init。

步骤 2:创建命名空间

main.tf:

resource "kubernetes_namespace" "app" {
  metadata {
    name = "springboot"
    labels = {
      managed-by = "terraform"
    }
  }
}

先 plan 再 apply:

terraform plan -out=tfplan
terraform apply tfplan

之后 kubectl get ns 能看到 springboot。

步骤 3:部署 Spring Boot 应用

resource "kubernetes_deployment" "app" {
  metadata {
    name      = "springboot-app"
    namespace = kubernetes_namespace.app.metadata[0].name
  }

  spec {
    replicas = 2

    selector {
      match_labels = {
        app = "springboot"
      }
    }

    template {
      metadata {
        labels = {
          app = "springboot"
        }
      }

      spec {
        container {
          name  = "app"
          image = "你的镜像仓库/springboot-app:最新标签"

          port {
            container_port = 8080
          }

          env {
            name  = "SPRING_PROFILES_ACTIVE"
            value = "prod"
          }

          readiness_probe {
            http_get {
              path = "/actuator/health"
              port = 8080
            }
          }
        }
      }
    }
  }
}

注意 namespace = kubernetes_namespace.app.metadata[0].name:namespace 资源创建后名称从其属性拿,这样顺序和拼写都有保证。

步骤 4:暴露 Service

resource "kubernetes_service" "app" {
  metadata {
    name      = "springboot-svc"
    namespace = kubernetes_namespace.app.metadata[0].name
  }

  spec {
    selector = {
      app = "springboot"
    }

    port {
      port        = 80
      target_port = 8080
    }

    type = "ClusterIP"
  }
}

云上若要对接 ALB,一般通过 Ingress/注解或 AWS Load Balancer Controller,而不是直接用 LoadBalancer 类型——具体取决于集群方案。

步骤 5:EKS 集群的取凭证写法

当集群本身也是 Terraform 创建时,provider 不能直接读 kubeconfig,要用 EKS 数据源(注意避免循环依赖,常用两种方式):

provider "kubernetes" {
  host = aws_eks_cluster.app.endpoint

  cluster_ca_certificate = base64decode(
    aws_eks_cluster.app.certificate_authority[0].data
  )

  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args = [
      "eks", "get-token",
      "--cluster-name", aws_eks_cluster.app.name
    ]
  }
}

若节点/执行环境本身带 IAM 角色,可省略 exec 直接靠 IRSA。集群新建时建议把 provider 配置拆到独立 apply 的目录(先建集群、再部署对象),规避 provider 在初始化阶段就要访问尚不存在集群的「鸡生蛋」问题。

步骤 6:用清单资源处理已有 YAML

团队已经有一批现成 YAML,不想逐个翻译成资源块时,用 kubernetes_manifest:

resource "kubernetes_manifest" "custom" {
  manifest = yamldecode(file("${path.module}/manifests/configmap.yaml"))
}

它直接提交任意结构的对象,灵活但字段类型在不同 K8s 版本间可能变化,遇到漂移报错要用 field 块或 annotations 处理。适合少量引导对象,不适合承载整套应用发布。

步骤 7:销毁

terraform plan -destroy
terraform destroy

注意:删除 namespace 会连带删除其中所有对象;如果命名空间不是 Terraform 创建的,Terraform 只会删它登记的 Deployment/Service,不会动命名空间。

讲清楚要点

  1. Provider 连接是第一个坎:本地用 config_path;CI 中常用短时效 token(aws eks get-token),别把长期证书写进配置。
  2. Terraform 管的是「对象声明」:它不做滚动发布策略编排,Deployment 的滚动更新由 K8s 控制器完成,Terraform 只负责把新 spec 提交进去。
  3. 字段漂移会被改回:有人 kubectl edit 改了 Terraform 管的对象,下次 apply 被还原;反之 kubernetes_manifest 的 server-side 默认字段可能让 plan 永远显示差异,需要忽略特定字段。
  4. 拆分 apply 阶段:建集群(AWS 资源)和部署对象(K8s 资源)分目录或分工作区,是 EKS 项目的通行结构。
  5. 敏感配置别进 manifest:密码用 kubernetes_secret 时值会进 state;更好的做法是 External Secrets Operator 从 Secrets Manager 同步,Terraform 只建同步规则。

你可能会懵的地方

  • 直接 apply kubectl 也能做,为什么要用 Terraform? 集群引导类对象(命名空间、CRD、集群角色、插件配置)需要和集群生命周期绑定、统一审计,适合 Terraform;高频变化的业务清单交给 Helm/GitOps 更顺手。

  • 报错 dial tcp: lookup cluster endpoint? provider 连不上集群。检查 endpoint、网络/VPC(EKS 私有端点需在对应网络执行)、kubeconfig 和 token 是否过期。

  • plan 一直显示 ~ 改一些没动过的字段? 常见于 kubernetes_manifest:API server 回填了默认值。用 computed_fields 或字段管理策略忽略这些服务端计算字段。

  • Deployment 改镜像,Terraform apply 和 kubectl rollout 有何不同? 殊途同归——都是更新 Pod 模板触发滚动更新。Terraform apply 还会把这件事纳入计划审批和 state;回滚则用 kubectl rollout undo 或改回旧镜像重新 apply。

  • Helm 安装的 release 能用 Terraform 管吗? 能(helm_release 资源,下一课),但别两套系统同时管同一个 release,选一个当权威。

错法对照

错法问题正解
把 kubeconfig 证书贴进配置提交凭据泄露config_path 引用或 exec 取 token
建集群和部署对象写同一目录一把 applyprovider 初始化时集群不存在拆两阶段 apply
kubectl edit 手改 Terraform 管的对象下次被还原改 Terraform 配置重新 apply
业务应用全部用 kubernetes_manifest 管理漂移噪音大、无模板能力应用层用 Helm/GitOps
Secret 用明文 manifest 还提交仓库密钥泄露进 Git 和 stateExternal Secrets + KMS

卡点急救

  1. Unauthorized / token 失效:重新 aws eks update-kubeconfig --name 集群名,或检查执行角色在 aws-auth ConfigMap 中的映射。
  2. CRD 不存在导致 apply 失败:CRD 必须先装。调整顺序或拆分阶段:先 apply CRD(常由 Helm 提供),再 apply 依赖它的对象。
  3. apply 卡在等待 Deployment ready:kubectl describe pod 看事件(镜像拉取、探针失败、资源不足);修好后对象已存在,重新 apply 会继续等待。

面试常问

  • Terraform 在 Kubernetes 架构中通常负责什么? 托管集群(EKS/GKE)、节点池、网络插件、集群级引导对象(命名空间、CRD、RBAC);业务工作负载多由 Helm 或 GitOps(ArgoCD/Flux)发布,Terraform 通过 helm provider 做 bootstrap。

  • Terraform 管理 K8s 对象出现配置漂移怎么办? 首先禁止在 Terraform 之外手改受管对象;对服务端回填字段使用 computed_fields/字段忽略;建立漂移检测(定期 plan),发现差异走代码修复。

  • EKS 场景下 kubernetes provider 如何认证? 用集群 endpoint + CA,配合 aws eks get-token exec 插件或 IRSA 角色获取短期令牌;分阶段 apply,集群建成后再初始化 provider。

自测三问

  1. 集群本身与集群内对象为什么建议拆成两个 Terraform 阶段?
  2. 什么场景适合 kubernetes_manifest,什么场景明显不适合?
  3. 应用的数据库密码放进 K8s Secret,用 Terraform 创建有什么风险?更优方案是什么?

小结一句话

Kubernetes Provider 让 Terraform 能提交任何 K8s 对象,但它的主战场是「建集群 + 引导组件」,业务发布应让位于 Helm/GitOps,认证一律走短期凭证。

延伸

  • Kubernetes Provider 文档
  • kubernetes_manifest 资源参考
  • Provision an EKS Cluster 官方教程
  • 下一课:CI 中的 Terraform——格式化、校验、计划、工作区与漂移检测。
加载本节练习…
← 上一课AWS 资源示例下一课 →CI 中的 Terraform