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


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

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

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

事前準備

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

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  4. To initialize the gcloud CLI, run the following command:

    gcloud init
  5. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the GKE API:

    gcloud services enable container.googleapis.com
  8. Install the Google Cloud CLI.

  9. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  10. To initialize the gcloud CLI, run the following command:

    gcloud init
  11. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  12. Make sure that billing is enabled for your Google Cloud project.

  13. Enable the GKE API:

    gcloud services enable container.googleapis.com
  14. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/container.admin, roles/compute.networkAdmin, roles/iam.serviceAccountUser

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
    • Replace PROJECT_ID with your project ID.
    • Replace USER_IDENTIFIER with the identifier for your user account. For example, user:myemail@example.com.

    • Replace ROLE with each individual role.

準備環境

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

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

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

  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:a 位於 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
    

後續步驟