创建 GKE 集群并使用 Terraform 部署工作负载


在本快速入门中,您将学习如何创建 Google Kubernetes Engine (GKE) Autopilot 集群并使用 Terraform 部署工作负载。

基础设施即代码 (IaC) 是一种使用代码管理和预配软件基础设施资源的做法。Terraform 是一种常用的开源 IaC 工具,支持各种 Cloud 服务,包括 GKE。作为 GKE 平台管理员,您可以使用 Terraform 标准化 Kubernetes 集群的配置并简化 DevOps 工作流。如需了解详情,请参阅 Terraform 对 GKE 的支持

目标

  • 创建 IPv6 Virtual Private Cloud (VPC) 网络
  • 创建 GKE Autopilot 集群
  • 在集群上部署工作负载
  • 使用 Service 公开工作负载

准备工作

请按照以下步骤启用 Kubernetes Engine API:

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 启用 GKE API。

    启用 API

  5. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  6. 确保您的 Google Cloud 项目已启用结算功能

  7. 启用 GKE API。

    启用 API

  8. 确保您拥有项目的以下一个或多个角色: roles/container.admin, roles/compute.networkAdmin, roles/iam.serviceAccountUser

    检查角色

    1. 在 Google Cloud 控制台中,前往 IAM 页面。

      转到 IAM
    2. 选择项目。
    3. 主账号列中,找到您的电子邮件地址所在的行。

      如果您的电子邮件地址不在此列,则表示您没有任何角色。

    4. 在您的电子邮件地址所在的行对应的角色列中,检查角色列表是否包含所需的角色。

    授予角色

    1. 在 Google Cloud 控制台中,前往 IAM 页面。

      转到 IAM
    2. 选择项目。
    3. 点击 授予访问权限
    4. 新的主账号字段中,输入您的电子邮件地址。
    5. 选择角色列表中,选择一个角色。
    6. 如需授予其他角色,请点击 添加其他角色,然后添加其他各个角色。
    7. 点击 Save(保存)。

您应该熟悉 Terraform 的基础知识。您可以使用以下资源:

准备环境

在本教程中,您将使用 Cloud Shell 来管理 Google Cloud 上托管的资源。Cloud Shell 中预安装了本教程所需的软件,包括 TerraformkubectlGoogle Cloud CLI

  1. 点击 Cloud Shell 激活图标 激活 Cloud Shell 激活 Shell 按钮,从 Google Cloud 控制台启动 Cloud Shell 会话。此操作会在 Google Cloud 控制台的底部窗格中启动会话。

    与此虚拟机关联的服务凭据会自动获取,因此您无需设置或下载服务账号密钥。

  2. 在运行命令之前,请使用以下命令在 gcloud CLI 中设置默认项目:

    gcloud config set project PROJECT_ID
    

    请将 PROJECT_ID 替换为您的项目 ID

  3. 克隆 GitHub 代码库:

    git clone https://github.com/terraform-google-modules/terraform-docs-samples.git --single-branch
    
  4. 切换到工作目录:

    cd terraform-docs-samples/gke/quickstart/autopilot
    

查看 Terraform 文件

Google Cloud 提供程序是一款插件,可让您使用 Terraform(HashiCorp 的基础设施即代码 [IaC] 工具)来管理和预配 Google Cloud 资源。它充当 Terraform 配置与 Google Cloud API 之间的桥梁,支持您以声明方式定义基础设施资源,例如虚拟机和网络。

  1. 查看 cluster.tf 文件:

    cat cluster.tf
    

    输出类似于以下内容

    resource "google_compute_network" "default" {
      name = "example-network"
    
      auto_create_subnetworks  = false
      enable_ula_internal_ipv6 = true
    }
    
    resource "google_compute_subnetwork" "default" {
      name = "example-subnetwork"
    
      ip_cidr_range = "10.0.0.0/16"
      region        = "us-central1"
    
      stack_type       = "IPV4_IPV6"
      ipv6_access_type = "INTERNAL" # Change to "EXTERNAL" if creating an external loadbalancer
    
      network = google_compute_network.default.id
      secondary_ip_range {
        range_name    = "services-range"
        ip_cidr_range = "192.168.0.0/24"
      }
    
      secondary_ip_range {
        range_name    = "pod-ranges"
        ip_cidr_range = "192.168.1.0/24"
      }
    }
    
    resource "google_container_cluster" "default" {
      name = "example-autopilot-cluster"
    
      location                 = "us-central1"
      enable_autopilot         = true
      enable_l4_ilb_subsetting = true
    
      network    = google_compute_network.default.id
      subnetwork = google_compute_subnetwork.default.id
    
      ip_allocation_policy {
        stack_type                    = "IPV4_IPV6"
        services_secondary_range_name = google_compute_subnetwork.default.secondary_ip_range[0].range_name
        cluster_secondary_range_name  = google_compute_subnetwork.default.secondary_ip_range[1].range_name
      }
    
      # Set `deletion_protection` to `true` will ensure that one cannot
      # accidentally delete this instance by use of Terraform.
      deletion_protection = false
    }

    此文件描述了以下资源:

    • 启用了内部 IPv6 的 VPC 网络。如需将应用公开到互联网,请将 ipv6_access_type 更改为 EXTERNAL。如果您进行此项更改,则还必须在下一步中移除 app.tf 文件中的 networking.gke.io/load-balancer-type 注解。
    • 双栈子网
    • 位于 us-central1双栈 Autopilot 集群
  2. 查看 app.tf 文件:

    cat app.tf
    

    输出类似于以下内容:

    data "google_client_config" "default" {}
    
    provider "kubernetes" {
      host                   = "https://${google_container_cluster.default.endpoint}"
      token                  = data.google_client_config.default.access_token
      cluster_ca_certificate = base64decode(google_container_cluster.default.master_auth[0].cluster_ca_certificate)
    
      ignore_annotations = [
        "^autopilot\\.gke\\.io\\/.*",
        "^cloud\\.google\\.com\\/.*"
      ]
    }
    
    resource "kubernetes_deployment_v1" "default" {
      metadata {
        name = "example-hello-app-deployment"
      }
    
      spec {
        selector {
          match_labels = {
            app = "hello-app"
          }
        }
    
        template {
          metadata {
            labels = {
              app = "hello-app"
            }
          }
    
          spec {
            container {
              image = "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
              name  = "hello-app-container"
    
              port {
                container_port = 8080
                name           = "hello-app-svc"
              }
    
              security_context {
                allow_privilege_escalation = false
                privileged                 = false
                read_only_root_filesystem  = false
    
                capabilities {
                  add  = []
                  drop = ["NET_RAW"]
                }
              }
    
              liveness_probe {
                http_get {
                  path = "/"
                  port = "hello-app-svc"
    
                  http_header {
                    name  = "X-Custom-Header"
                    value = "Awesome"
                  }
                }
    
                initial_delay_seconds = 3
                period_seconds        = 3
              }
            }
    
            security_context {
              run_as_non_root = true
    
              seccomp_profile {
                type = "RuntimeDefault"
              }
            }
    
            # Toleration is currently required to prevent perpetual diff:
            # https://github.com/hashicorp/terraform-provider-kubernetes/pull/2380
            toleration {
              effect   = "NoSchedule"
              key      = "kubernetes.io/arch"
              operator = "Equal"
              value    = "amd64"
            }
          }
        }
      }
    }
    
    resource "kubernetes_service_v1" "default" {
      metadata {
        name = "example-hello-app-loadbalancer"
        annotations = {
          "networking.gke.io/load-balancer-type" = "Internal" # Remove to create an external loadbalancer
        }
      }
    
      spec {
        selector = {
          app = kubernetes_deployment_v1.default.spec[0].selector[0].match_labels.app
        }
    
        ip_family_policy = "RequireDualStack"
    
        port {
          port        = 80
          target_port = kubernetes_deployment_v1.default.spec[0].template[0].spec[0].container[0].port[0].name
        }
    
        type = "LoadBalancer"
      }
    
      depends_on = [time_sleep.wait_service_cleanup]
    }
    
    # Provide time for Service cleanup
    resource "time_sleep" "wait_service_cleanup" {
      depends_on = [google_container_cluster.default]
    
      destroy_duration = "180s"
    }

    此文件描述了以下资源:

    • 具有示例容器映像的 Deployment
    • LoadBalancer 类型的 Service。该 Service 在端口 80 上公开 Deployment。如需将应用公开给互联网,请通过移除 networking.gke.io/load-balancer-type 注解来配置外部负载均衡器。

创建集群并部署应用

  1. 在 Cloud Shell 中,运行以下命令以验证 Terraform 是否可用:

    terraform
    

    输出应类似如下所示:

    Usage: terraform [global options] <subcommand> [args]
    
    The available commands for execution are listed below.
    The primary workflow commands are given first, followed by
    less common or more advanced commands.
    
    Main commands:
      init          Prepare your working directory for other commands
      validate      Check whether the configuration is valid
      plan          Show changes required by the current configuration
      apply         Create or update infrastructure
      destroy       Destroy previously-created infrastructure
    
  2. 初始化 Terraform:

    terraform init
    
  3. 规划 Terraform 配置:

    terraform plan
    
  4. 应用 Terraform 配置

    terraform apply
    

    出现提示时,输入 yes 以确认操作。此命令可能需要几分钟才能完成。输出类似于以下内容:

    Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
    

验证集群是否正常运行

执行以下操作以确认集群正常运行:

  1. 进入 Google Cloud 控制台中的工作负载页面:

    进入“工作负载”

  2. 点击 example-hello-app-deployment 工作负载。系统会显示 Pod 详情页面。此页面显示有关 Pod 的信息,例如注解、Pod 上运行的容器、公开 Pod 的服务,以及 CPU、内存和磁盘用量等指标。

  3. 进入 Google Cloud 控制台中的 Service 和 Ingress 页面。

    打开“Service 和 Ingress”

  4. 点击 example-hello-app-loadbalancer LoadBalancer Service。系统会显示 Service 详情页面。此页面显示有关 Service 的信息,例如与 Service 关联的 Pod 以及 Service 使用的端口。

  5. 外部端点部分中,点击 IPv4 linkIPv6 link 以在浏览器中查看 Service。输出类似于以下内容:

    Hello, world!
    Version: 2.0.0
    Hostname: example-hello-app-deployment-5df979c4fb-kdwgr
    

清理

为避免因本页中使用的资源导致您的 Google Cloud 账号产生费用,请按照以下步骤操作。

为避免因本页面中使用的资源导致您的 Google Cloud 账号产生费用,请按照以下步骤操作。

在 Cloud Shell 中,运行以下命令以删除 Terraform 资源:

terraform destroy --auto-approve

如果您看到类似于 The network resource 'projects/PROJECT_ID/global/networks/example-network' is already being used by 'projects/PROJECT_ID/global/firewalls/example-network-yqjlfql57iydmsuzd4ot6n5v' 的错误消息,请执行以下操作:

  1. 删除防火墙规则:

    gcloud compute firewall-rules list --filter="NETWORK:example-network" --format="table[no-heading](name)" | xargs gcloud --quiet compute firewall-rules delete
    
  2. 重新运行 Terraform 命令:

    terraform destroy --auto-approve
    

后续步骤