從 Google Kubernetes Engine 連線

本頁說明如何從 Google Kubernetes Engine (GKE) 中執行的應用程式,連線至 Cloud SQL 執行個體。

如需執行連線至 Cloud SQL 的 Google Kubernetes Engine 範例網頁應用程式逐步操作說明,請參閱從 Google Kubernetes Engine 連線的快速入門指南。

Cloud SQL 是一項全代管資料庫服務,可協助您在雲端中設定、維護及管理關聯式資料庫。

Google Kubernetes Engine 可讓您輕鬆自動部署、管理 Kubernetes 及調度所需資源。

關於將 Google Kubernetes Engine 連線至 Cloud SQL

如要從 Google Kubernetes Engine 中執行的應用程式存取 Cloud SQL 執行個體,您可以使用 Cloud SQL Auth Proxy (搭配公開或私人 IP),或直接使用私人 IP 位址連線。

建議您使用 Cloud SQL Auth Proxy 連線至 Cloud SQL,即使使用私人 IP 也是如此。這是因為 Cloud SQL Auth Proxy 使用 IAM 提供強大的加密和驗證機制,有助於確保資料庫安全。

資料庫連線會耗用伺服器和連線應用程式的資源。請務必採用良好的連線管理做法,盡量減少應用程式的資源用量,並降低超出 Cloud SQL 連線限制的可能性。詳情請參閱「管理資料庫連線」。

事前準備

如要連線至 Cloud SQL,您必須具備下列條件:

  • GKE 叢集,並安裝 kubectl 指令列工具,且已設定與叢集通訊。

    如需 GKE 入門說明,請參閱「將應用程式部署至 GKE 叢集」。

    如要使用私人 IP 連線,GKE 叢集必須是 VPC 原生,且與 Cloud SQL 執行個體位於相同的虛擬私有雲 (VPC) 網路。

  • 已建立執行個體。

    如需建立 Cloud SQL 執行個體的說明,請參閱建立執行個體一文。

  • 在執行個體上設定的 SQL Server 使用者帳戶。

    應用程式會使用這個帳戶連線至資料庫。 如需建立使用者帳戶的說明,請參閱建立使用者。

關於 Kubernetes Secret

在 Kubernetes 中,Secret 是將設定詳細資料傳遞至應用程式的安全方式。您可以建立 Secret,其中包含資料庫名稱、使用者和密碼等詳細資料,並以環境變數的形式注入應用程式。

視連線類型而定,密碼有多種用途:

  • 資料庫憑證 Secret 包含您要連線的資料庫使用者名稱,以及該使用者的資料庫密碼。
  • 如要透過 Cloud SQL Auth Proxy 連線,可以使用 Secret 保存服務帳戶的憑證檔案。
  • 如果使用私人 IP 連線,可以透過 Secret 指定 Cloud SQL 執行個體的私人 IP 位址。

如需 Secrets 的完整使用範例,請參閱本頁稍後提及的 GitHub 存放區。

建立 Secret 物件

  1. 您可以使用 kubectl create secret 指令建立 Secret 物件。

    如要建立資料庫憑證 Secret,請按照下列步驟操作:

    kubectl create secret generic <YOUR-DB-SECRET> \
      --from-literal=username=<YOUR-DATABASE-USER> \
      --from-literal=password=<YOUR-DATABASE-PASSWORD> \
      --from-literal=database=<YOUR-DATABASE-NAME>
    
  2. 建立完成後,您可以在 Google Cloud 控制台的 Google Kubernetes Engine 頁面中,查看「設定」部分中的物件。

使用 Cloud SQL Auth Proxy 連線至 Cloud SQL

使用 Cloud SQL Auth Proxy 連線時,系統會使用 sidecar 容器模式,將 Cloud SQL Auth Proxy 新增至 Pod。Cloud SQL 驗證 Proxy 容器與應用程式位於同一個 Pod 中,因此應用程式可以使用 localhost 連線至 Cloud SQL 驗證 Proxy,進而提升安全性和效能。

如要進一步瞭解 Cloud SQL Auth Proxy,請參閱「關於 Cloud SQL Auth Proxy」。如要進一步瞭解如何使用 Pod,請參閱 Kubernetes 文件中的「Pod 總覽」。

如要使用 Cloud SQL Auth Proxy 連線,您需要下列項目:

  1. Cloud SQL 執行個體的執行個體連線名稱。

    您可以在 Google Cloud 控制台的 Cloud SQL 執行個體詳細資料頁面,或透過 gcloud sql instances describe INSTANCE_ID 指令取得執行個體連線名稱。

  2. 具有 Cloud SQL 執行個體適當權限的服務帳戶相關聯的金鑰檔案所在位置。

    詳情請參閱「建立服務帳戶」一文。

  3. 已啟用 Cloud SQL Admin API。

    啟用 API 時所需的角色

    如要啟用 API,您必須具備 serviceusage.services.enable 權限。如果您建立了專案,可能已透過「擁有者」角色 (roles/owner) 取得這項權限。否則,您可以透過「服務使用管理員」角色 (roles/serviceusage.serviceUsageAdmin) 取得這項權限。瞭解如何授予角色。

    啟用 API

將服務帳戶提供給 Cloud SQL Auth Proxy

如要在 Google Kubernetes Engine 中執行 Cloud SQL 驗證 Proxy,第一步是建立代表應用程式的 Google 服務帳戶 (GSA)。建議您為每個應用程式建立專屬服務帳戶,而非在所有地方使用同一個服務帳戶。這個模式可讓您依據應用程式限制權限,因此更安全。

應用程式的服務帳戶必須符合下列條件:

  • 屬於已啟用 Cloud SQL Admin API 的專案
  • 已獲授權,可擔任專案的 Cloud SQL 用戶端 IAM 角色 (或同等角色),該專案包含您要連線的執行個體
  • 如要使用私人 IP 連線,必須使用 VPC 原生 GKE 叢集,且該叢集與 Cloud SQL 執行個體位於同一個 VPC 中

您必須設定 GKE,將服務帳戶提供給 Cloud SQL Auth Proxy。建議使用兩種方式: 工作負載身分或服務帳戶金鑰檔案。

Workload Identity

如果您使用 Google Kubernetes Engine,建議使用 GKE 的Workload Identity功能。這個方法可讓您將 Kubernetes 服務帳戶 (KSA) 繫結至 Google 服務帳戶 (GSA)。應用程式隨後就能使用相符的 KSA 存取 GSA。

Google 服務帳戶 (GSA) 是 IAM 身分,代表 Google Cloud 中的應用程式。同樣地,Kubernetes 服務帳戶 (KSA) 是代表 Google Kubernetes Engine 叢集中應用程式的身分。

Workload Identity 會將 KSA 繫結至 GSA,導致任何具有該 KSA 的部署作業在與 Google Cloud 互動時,都會以 GSA 的身分進行驗證。

  1. 為叢集啟用 Workload Identity
  2. 通常每個應用程式都有自己的身分,以 KSA 和 GSA 配對表示。執行 kubectl apply -f service-account.yaml,為應用程式建立 KSA:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: <YOUR-KSA-NAME> # TODO(developer): replace these values
  3. 在 YOUR-GSA-NAME 和 YOUR-KSA-NAME 之間啟用 IAM 繫結:

    gcloud iam service-accounts add-iam-policy-binding \
    --role="roles/iam.workloadIdentityUser" \
    --member="serviceAccount:YOUR-GOOGLE-CLOUD-PROJECT.svc.id.goog[YOUR-K8S-NAMESPACE/YOUR-KSA-NAME]" \
    YOUR-GSA-NAME@YOUR-GOOGLE-CLOUD-PROJECT.iam.gserviceaccount.com
  4. 在 YOUR-KSA-NAME 中新增註解,完成繫結:

    kubectl annotate serviceaccount \
    YOUR-KSA-NAME \
    iam.gke.io/gcp-service-account=YOUR-GSA-NAME@YOUR-GOOGLE-CLOUD-PROJECT.iam.gserviceaccount.com
  5. 最後,請務必為 k8s 物件指定服務帳戶。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: <YOUR-DEPLOYMENT-NAME>
    spec:
      selector:
        matchLabels:
          app: <YOUR-APPLICATION-NAME>
      template:
        metadata:
          labels:
            app: <YOUR-APPLICATION-NAME>
        spec:
          serviceAccountName: <YOUR-KSA-NAME>

服務帳戶金鑰檔案

或者,如果無法使用 Workload Identity,建議的模式是將服務帳戶金鑰檔案掛接到 Cloud SQL Auth Proxy Pod,並使用 --credentials-file 標記。

  1. 為服務帳戶金鑰建立憑證檔案:

    gcloud iam service-accounts keys create ~/key.json \
    --iam-account=YOUR-SA-NAME@project-id.iam.gserviceaccount.com
  2. 將服務帳戶金鑰轉換為 k8s Secret:

    kubectl create secret generic YOUR-SA-SECRET \
    --from-file=service_account.json=~/key.json
  3. 在 k8s 物件的 spec: 下,將 Secret 掛接為磁碟區:

    volumes:
      - name: <YOUR-SA-SECRET-VOLUME>
        secret:
          secretName: <YOUR-SA-SECRET>
  4. 請按照下一節的說明,從 Cloud SQL 驗證 Proxy 的 Pod 存取磁碟區。

以 sidecar 模式執行 Cloud SQL 驗證 Proxy

建議您在 sidecar 模式下執行 Cloud SQL Auth Proxy (做為與應用程式共用 Pod 的額外容器)。我們建議您採用這種做法,而非以獨立服務的形式執行,原因如下:

  • 防止 SQL 流量在本地公開;Cloud SQL Auth Proxy 會加密外送連線,但您必須限制公開的連入連線。
  • 避免單點故障;每個應用程式對資料庫的存取權都彼此獨立,因此更具彈性。
  • 限制 Cloud SQL Auth Proxy 的存取權,讓您能為每個應用程式使用 IAM 權限,而不必將資料庫公開給整個叢集。
  • 可更準確地設定資源要求;由於 Cloud SQL Auth Proxy 會根據用量線性消耗資源,因此這個模式可讓您設定並要求資源,以配合應用程式的擴展。

  • 在 initContainers 下的 Pod 設定中新增 Cloud SQL Auth Proxy,除非您使用 Cloud Service Mesh 或 Istio。

    如果您使用 Cloud Service Mesh 或 Istio,請改為在 containers 區段下方新增 Cloud SQL Auth Proxy。

    initContainers

    initContainers:
      - name: cloud-sql-proxy
        restartPolicy: Always
        # It is recommended to use the latest version of the Cloud SQL Auth Proxy
        # Make sure to update on a regular schedule!
        image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.14.1
        args:
          # If connecting from a VPC-native GKE cluster, you can use the
          # following flag to have the proxy connect over private IP
          # - "--private-ip"
    
          # If you are not connecting with Automatic IAM, you can delete
          # the following flag.
          - "--auto-iam-authn"
    
          # Enable structured logging with LogEntry format:
          - "--structured-logs"
    
          # Replace DB_PORT with the port the proxy should listen on
          - "--port=<DB_PORT>"
          - "<INSTANCE_CONNECTION_NAME>"
    
        securityContext:
          # The default Cloud SQL Auth Proxy image runs as the
          # "nonroot" user and group (uid: 65532) by default.
          runAsNonRoot: true
        # You should use resource requests/limits as a best practice to prevent
        # pods from consuming too many resources and affecting the execution of
        # other pods. You should adjust the following values based on what your
        # application needs. For details, see
        # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
        resources:
          requests:
            # The proxy's memory use scales linearly with the number of active
            # connections. Fewer open connections will use less memory. Adjust
            # this value based on your application's requirements.
            memory: "2Gi"
            # The proxy's CPU use scales linearly with the amount of IO between
            # the database and the application. Adjust this value based on your
            # application's requirements.
            cpu: "1"

    containers

    - name: cloud-sql-proxy
      # It is recommended to use the latest version of the Cloud SQL Auth Proxy
      # Make sure to update on a regular schedule!
      image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.14.1
      args:
        # If connecting from a VPC-native GKE cluster, you can use the
        # following flag to have the proxy connect over private IP
        # - "--private-ip"
    
        # If you are not connecting with Automatic IAM, you can delete
        # the following flag.
        - "--auto-iam-authn"
    
        # Enable structured logging with LogEntry format:
        - "--structured-logs"
    
        # Replace DB_PORT with the port the proxy should listen on
        - "--port=<DB_PORT>"
        - "<INSTANCE_CONNECTION_NAME>"
    
      securityContext:
        # The default Cloud SQL Auth Proxy image runs as the
        # "nonroot" user and group (uid: 65532) by default.
        runAsNonRoot: true
      # You should use resource requests/limits as a best practice to prevent
      # pods from consuming too many resources and affecting the execution of
      # other pods. You should adjust the following values based on what your
      # application needs. For details, see
      # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
      resources:
        requests:
          # The proxy's memory use scales linearly with the number of active
          # connections. Fewer open connections will use less memory. Adjust
          # this value based on your application's requirements.
          memory: "2Gi"
          # The proxy's CPU use scales linearly with the amount of IO between
          # the database and the application. Adjust this value based on your
          # application's requirements.
          cpu: "1"
  • 如果您使用服務帳戶金鑰,請指定密鑰磁碟區,並在指令中加入 --credentials-file 標記:

      # This flag specifies where the service account key can be found
      - "--credentials-file=/secrets/service_account.json"
    securityContext:
      # The default Cloud SQL Auth Proxy image runs as the
      # "nonroot" user and group (uid: 65532) by default.
      runAsNonRoot: true
    volumeMounts:
      - name: <YOUR-SA-SECRET-VOLUME>
        mountPath: /secrets/
        readOnly: true
  • 最後,請設定應用程式,使用您在指令部分指定的 DB_PORT,透過 127.0.0.1 連線。

完整的設定檔範例:

Workload Identity

# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <YOUR-DEPLOYMENT-NAME>
spec:
  selector:
    matchLabels:
      app: <YOUR-APPLICATION-NAME>
  template:
    metadata:
      labels:
        app: <YOUR-APPLICATION-NAME>
    spec:
      serviceAccountName: <YOUR-KSA-NAME>
      containers:
        - name: <YOUR-APPLICATION-NAME>
          # ... other container configuration
          env:
            - name: DB_USER
              valueFrom:
                secretKeyRef:
                  name: <YOUR-DB-SECRET>
                  key: username
            - name: DB_PASS
              valueFrom:
                secretKeyRef:
                  name: <YOUR-DB-SECRET>
                  key: password
            - name: DB_NAME
              valueFrom:
                secretKeyRef:
                  name: <YOUR-DB-SECRET>
                  key: database
      initContainers:
        - name: cloud-sql-proxy
          restartPolicy: Always
          # It is recommended to use the latest version of the Cloud SQL Auth Proxy
          # Make sure to update on a regular schedule!
          image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.14.1
          args:
            # If connecting from a VPC-native GKE cluster, you can use the
            # following flag to have the proxy connect over private IP
            # - "--private-ip"

            # If you are not connecting with Automatic IAM, you can delete
            # the following flag.
            - "--auto-iam-authn"

            # Enable structured logging with LogEntry format:
            - "--structured-logs"

            # Replace DB_PORT with the port the proxy should listen on
            - "--port=<DB_PORT>"
            - "<INSTANCE_CONNECTION_NAME>"

          securityContext:
            # The default Cloud SQL Auth Proxy image runs as the
            # "nonroot" user and group (uid: 65532) by default.
            runAsNonRoot: true
          # You should use resource requests/limits as a best practice to prevent
          # pods from consuming too many resources and affecting the execution of
          # other pods. You should adjust the following values based on what your
          # application needs. For details, see
          # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
          resources:
            requests:
              # The proxy's memory use scales linearly with the number of active
              # connections. Fewer open connections will use less memory. Adjust
              # this value based on your application's requirements.
              memory: "2Gi"
              # The proxy's CPU use scales linearly with the amount of IO between
              # the database and the application. Adjust this value based on your
              # application's requirements.
              cpu: "1"

服務帳戶金鑰

# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <YOUR-DEPLOYMENT-NAME>
spec:
  selector:
    matchLabels:
      app: <YOUR-APPLICATION-NAME>
  template:
    metadata:
      labels:
        app: <YOUR-APPLICATION-NAME>
    spec:
      containers:
        - name: <YOUR-APPLICATION-NAME>
          # ... other container configuration
          env:
            - name: DB_USER
              valueFrom:
                secretKeyRef:
                  name: <YOUR-DB-SECRET>
                  key: username
            - name: DB_PASS
              valueFrom:
                secretKeyRef:
                  name: <YOUR-DB-SECRET>
                  key: password
            - name: DB_NAME
              valueFrom:
                secretKeyRef:
                  name: <YOUR-DB-SECRET>
                  key: database
      initContainers:
        - name: cloud-sql-proxy
          restartPolicy: Always
          # It is recommended to use the latest version of the Cloud SQL Auth Proxy
          # Make sure to update on a regular schedule!
          image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.14.1
          args:
            # If connecting from a VPC-native GKE cluster, you can use the
            # following flag to have the proxy connect over private IP
            # - "--private-ip"

            # If you are not connecting with Automatic IAM AuthN, you can delete
            # the following flag.
            - "--auto-iam-authn"

            # Enable structured logging with LogEntry format:
            - "--structured-logs"

            # Replace DB_PORT with the port the proxy should listen on
            - "--port=<DB_PORT>"
            - "<INSTANCE_CONNECTION_NAME>"

            # This flag specifies where the service account key can be found
            - "--credentials-file=/secrets/service_account.json"
          securityContext:
            # The default Cloud SQL Auth Proxy image runs as the
            # "nonroot" user and group (uid: 65532) by default.
            runAsNonRoot: true
          volumeMounts:
            - name: <YOUR-SA-SECRET-VOLUME>
              mountPath: /secrets/
              readOnly: true
          # Resource configuration depends on an application's requirements. You
          # should adjust the following values based on what your application
          # needs. For details, see https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
          resources:
            requests:
              # The proxy's memory use scales linearly with the number of active
              # connections. Fewer open connections will use less memory. Adjust
              # this value based on your application's requirements.
              memory: "2Gi"
              # The proxy's CPU use scales linearly with the amount of IO between
              # the database and the application. Adjust this value based on your
              # application's requirements.
              cpu: "1"
      volumes:
        - name: <YOUR-SA-SECRET-VOLUME>
          secret:
            secretName: <YOUR-SA-SECRET>

連線至 Cloud SQL,但不使用 Cloud SQL Auth Proxy

雖然安全性較低,但您可以從虛擬私有雲原生 GKE 叢集連線至同一虛擬私有雲中的 Cloud SQL 執行個體,使用私人 IP 而不透過 Cloud SQL Auth Proxy。

  1. 使用執行個體的私人 IP 位址建立密鑰:

    kubectl create secret generic <YOUR-PRIVATE-IP-SECRET> \
        --from-literal=db_host=<YOUR-PRIVATE-IP-ADDRESS>
    
  2. 接著,請務必將密鑰新增至應用程式的容器:

    - name: DB_HOST
      valueFrom:
        secretKeyRef:
          name: <YOUR-PRIVATE-IP-SECRET>
          key: db_host
  3. 最後,請設定應用程式,使用 DB_HOST 環境變數中的 IP 位址連線。您必須使用 SQL Server 的正確通訊埠:1433

完整的設定檔範例:

私人 IP

# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <YOUR-DEPLOYMENT-NAME>
spec:
  selector:
    matchLabels:
      app: <YOUR-APPLICATION-NAME>
  template:
    metadata:
      labels:
        app: <YOUR-APPLICATION-NAME>
    spec:
      containers:
      - name: <YOUR-APPLICATION-NAME>
        # ... other container configuration
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: password
        - name: DB_NAME
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: database
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: <YOUR-PRIVATE-IP-SECRET>
              key: db_host

疑難排解

需要協助嗎?如需 Proxy 疑難排解說明,請參閱「排解 Cloud SQL 驗證 Proxy 連線問題」,或前往 Cloud SQL 支援頁面。

後續步驟