使用 Terraform 建立叢集並部署工作負載

Kubernetes 叢集可為應用程式提供運算、儲存空間、網路和其他服務,類似於虛擬資料中心。在 Kubernetes 中執行的應用程式及其相關服務稱為「工作負載」

本教學課程會使用 Terraform 快速設定並執行 Google Kubernetes Engine 叢集和範例工作負載。接著,您可以在 Google Cloud 控制台中探索工作負載,然後繼續深入學習路徑,或是開始規劃及建立自己的可部署於正式環境叢集。本教學課程假設您已熟悉 Terraform。

如要在 Google Cloud 控制台中設定範例叢集和工作負載,請參閱「在 Google Cloud 控制台中建立叢集」。

事前準備

請依照下列步驟啟用 Kubernetes Engine API:

  1. 登入 Google Cloud 帳戶。如果您是 Google Cloud新手,歡迎 建立帳戶,親自評估產品在實際工作環境中的成效。新客戶還能獲得價值 $300 美元的免費抵免額,可用於執行、測試及部署工作負載。
  2. 安裝 Google Cloud CLI。

  3. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  4. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  5. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您已獲授角色,即可選取任何專案。
    • 建立專案:如要建立專案,您需要具備專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  6. 確認專案已啟用計費功能 Google Cloud

  7. 啟用 GKE API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable container.googleapis.com
  8. 安裝 Google Cloud CLI。

  9. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  10. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  11. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您已獲授角色,即可選取任何專案。
    • 建立專案:如要建立專案,您需要具備專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  12. 確認專案已啟用計費功能 Google Cloud

  13. 啟用 GKE API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable container.googleapis.com
  14. 將角色授予使用者帳戶。針對下列每個 IAM 角色,執行一次下列指令: roles/container.admin, roles/compute.networkAdmin, roles/iam.serviceAccountUser

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    更改下列內容:

    • PROJECT_ID:專案 ID。
    • USER_IDENTIFIER:使用者帳戶的 ID。 例如:myemail@example.com
    • ROLE:授予使用者帳戶的 IAM 角色。

準備環境

在本教學課程中,您將使用 Cloud Shell 管理Google Cloud上託管的資源。Cloud Shell 已預先安裝本教學課程所需的軟體,包括 TerraformkubectlGoogle Cloud CLI

  1. 在 Google Cloud 控制台中,按一下「啟用 Cloud Shell」圖示 「Activate Shell」(啟用 Shell) 按鈕,啟動 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 Provider 是一種外掛程式,可讓您使用 Terraform 管理及佈建 Google Cloud 資源。可做為 Terraform 設定與 Google Cloud API 之間的橋樑,讓您以宣告方式定義基礎架構資源,例如虛擬機器和網路。

本教學課程的叢集和範例應用程式,是在使用 Google Cloud 和 Kubernetes 供應商的兩個 Terraform 檔案中指定。

  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
    }

    這個檔案說明下列資源:

    • google_compute_network:已啟用內部 IPv6 的虛擬私有雲網路。
    • google_compute_subnetwork雙堆疊子網路
    • google_container_cluster:位於 us-central1雙堆疊 Autopilot 模式叢集deletion_protection 設定可控制是否能使用 Terraform 刪除這個叢集。如果將 deletion_protection 欄位中的值設為 false,Terraform 就能刪除叢集。詳情請參閱 google_container_cluster 參考資料
  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"
    }

    這個檔案說明下列資源:

(選用) 將應用程式公開發布到網際網路

範例的 Terraform 檔案說明具有內部 IP 位址的應用程式,該應用程式只能從與範例應用程式相同的虛擬私有雲 (VPC) 存取。如要從網際網路 (例如從筆電) 存取執行中的示範應用程式網頁介面,請先修改 Terraform 檔案來建立公開 IP 位址,再建立叢集。您可以使用 Cloud Shell 中的文字編輯器,或 Cloud Shell 編輯器來完成這項操作。

如要將示範應用程式公開發布到網際網路,請按照下列步驟操作:

  1. cluster.tf 中,將 ipv6_access_typeINTERNAL 變更為 EXTERNAL

    ipv6_access_type = "EXTERNAL"
    
  2. app.tf 中,移除 networking.gke.io/load-balancer-type 註解,設定外部負載平衡器。

     annotations = {
       "networking.gke.io/load-balancer-type" = "Internal" # Remove this line
     }
    

建立叢集並部署應用程式

  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 控制台的「Workloads」(工作負載) 頁面:

    前往「Workloads」(工作負載)

  2. 按一下 example-hello-app-deployment 工作負載。系統隨即會顯示「Pod 詳細資料」頁面。這個頁面會顯示 Pod 的相關資訊,例如註解、在 Pod 上執行的容器、公開 Pod 的服務,以及 CPU、記憶體和磁碟用量等指標。

  3. 前往 Google Cloud 控制台的「Services & Ingress」(服務和 Ingress) 頁面:

    前往「Services & Ingress」(服務與 Ingress)

  4. 按一下 example-hello-app-loadbalancer LoadBalancer 服務。系統會顯示「服務詳細資料」頁面。這個頁面會顯示 Service 的相關資訊,例如與 Service 相關聯的 Pod,以及 Service 使用的通訊埠。

  5. 在「外部端點」部分,按一下「IPv4 連結」或「IPv6 連結」,即可在瀏覽器中查看服務。輸出結果會與下列內容相似:

    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
    

後續步驟