从 Google Kubernetes Engine 连接到 Cloud SQL

本页面介绍如何设置从 Google Kubernetes Engine (GKE) 中运行的应用到 Cloud SQL 实例的连接。

如需了解运行连接到 Cloud SQL 的 Google Kubernetes Engine 示例 Web 应用的分步说明,请参阅从 Google Kubernetes Engine 连接快速入门

Cloud SQL 是一项全代管式数据库服务,可帮助您在云端设置、维护、管理和控制关系型数据库。

Google Kubernetes Engine 是自动部署、扩缩和管理 Kubernetes 的简单方法。

关于将 Google Kubernetes Engine 连接到 Cloud SQL

如需从 Google Kubernetes Engine 中运行的应用访问 Cloud SQL 实例,您可以使用 Cloud SQL Auth 代理(具有公共或专用 IP),也可以使用专用 IP 地址直接连接。

建议使用 Cloud SQL Auth 代理连接到 Cloud SQL,即便使用专用 IP 也是如此。这是因为 Cloud SQL Auth 代理使用 IAM 提供强大的加密和身份验证,这有助于确保您的数据库的安全。

数据库连接会消耗服务器和连接应用上的资源。请始终采用最佳连接管理做法,以最大限度减少应用的占用空间,并降低超出 Cloud SQL 连接限制的可能性。 如需了解详情,请参阅管理数据库连接

准备工作

如需连接到 Cloud SQL,您必须满足以下条件:

  • 具有一个 GKE 集群,其中安装有 kubectl 命令行工具且此工具已配置成与该集群通信。

    如需获取 GKE 使用入门方面的帮助,请参阅将应用部署到 GKE 集群

    如需使用专用 IP 进行连接,GKE 集群必须是 VPC 原生集群,并与 Cloud SQL 实例所在的同一 Virtual Private Cloud (VPC) 网络建立对等互连。

  • 已创建实例。

    如需创建 Cloud SQL 实例的帮助,请参阅创建实例

  • 已在实例上配置 MySQL 用户账号。

    您的应用将使用此账号连接到数据库。如需创建用户账号的帮助,请参阅创建用户

关于 Kubernetes Secret

在 Kubernetes 中,Secret 是一种可以将配置详细信息传递给应用的安全方式。您可以创建一个 Secret,其中包含您的数据库名称、用户和密码等详细信息,您可以将其作为环境变量注入到应用中。

可以通过多种不同的方法来使用 Secret,具体取决于连接类型:

  • 数据库凭据 Secret 包括您在连接时采用的数据库用户身份以及该用户的数据库密码。
  • 如果通过 Cloud SQL Auth 代理进行连接,则可以使用 Secret 来保存服务账号的凭据文件。
  • 如果使用专用 IP 地址进行连接,则可以使用 Secret 指定 Cloud SQL 实例的专用 IP 地址。

如需查看如何使用 Secret 的完整示例,请参阅本页面后面引用的 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 代理连接到 Cloud SQL

当您使用 Cloud SQL Auth 代理进行连接时,系统会使用 sidecar 容器模式将 Cloud SQL Auth 代理添加到 pod。Cloud SQL Auth 代理容器与您的应用位于同一 pod 中,让应用能够使用 localhost 连接到 Cloud SQL Auth 代理,从而提高安全性和性能。

如需详细了解 Cloud SQL Auth 代理,请参阅 Cloud SQL Auth 代理简介。如需详细了解如何使用 pod,请参阅 Kubernetes 文档中的 Pod 概览

如需使用 Cloud SQL Auth 代理进行连接,您需要以下各项:

  1. Cloud SQL 实例的实例连接名称。

    实例连接名称可在 Google Cloud 控制台的 Cloud SQL 实例详情页面中找到,或通过 gcloud sql instances describe INSTANCE_ID 命令来获得。

  2. 对 Cloud SQL 实例具有适当权限的服务账号所关联的密钥文件的位置。

    如需了解详情,请参阅创建服务账号

  3. 已启用 Cloud SQL Admin API。

    启用 API

向 Cloud SQL Auth 代理提供服务账号

在 Google Kubernetes Engine 中运行 Cloud SQL Auth 代理的第一步是创建一个 Google 服务账号 (GSA) 来代表您的应用。建议您为每个应用创建唯一的服务账号,而不是在所有地方都使用同一服务账号。此模式更安全,因为它允许您按应用限制权限。

应用的服务账号需要满足以下条件:

  • 属于已启用 Cloud SQL Admin API 的项目
  • 已拥有您要连接到的实例所属项目的 Cloud SQL Client IAM 角色(或等效角色)
  • 如果使用专用 IP 地址进行连接,则您必须在 Cloud SQL 实例所属的 VPC 中使用 VPC 原生 GKE 集群

您需要配置 GKE 以向 Cloud SQL Auth 代理提供服务账号。为此,我们建议使用两种方法:工作负载身份服务账号密钥文件

Workload Identity

如果您使用的是 Google Kubernetes Engine,则首选方法是使用 GKE 的 Workload Identity 功能。使用此方法,您可以将 Kubernetes 服务账号 (KSA) 绑定到 Google 服务账号 (GSA)。然后,GSA 便可供使用匹配的 KSA 的应用进行访问。

Google 服务账号 (GSA) 是在 Google Cloud 中代表应用的 IAM 身份。类似地,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-NAMEYOUR-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 代理 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 Auth 代理的 pod 访问卷。

以 Sidecar 模式运行 Cloud SQL Auth 代理

我们建议以 sidecar 模式运行 Cloud SQL Auth 代理(作为与您的应用共享 pod 的其他容器)。与将代理作为单独的服务运行相比,我们建议使用以上方法,原因如下:

  • 防止 SQL 流量在本地公开;Cloud SQL Auth 代理会为传出连接提供加密,但您需要限制传入连接的公开。
  • 防止出现单点故障;每个应用对您的数据库的访问都独立于其他应用,从而提高其弹性。
  • 限制对 Cloud SQL Auth 代理的访问权限,让您可以按应用使用 IAM 权限,而不是将数据库公开给整个集群。
  • 您可以更准确地确定资源请求的范围;因为 Cloud SQL Auth 代理会根据用量以线性方式使用资源,所以此模式可让您更准确地确定资源请求的范围以匹配应用扩缩情况。

  • 将 Cloud SQL Auth 代理添加到 containers 下的 pod 配置:

    - 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.8.0
      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"
    
        # 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"

    如果您使用的是服务账号密钥,请指定 Secret 卷并在命令中添加 --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
  • 最后,配置应用以使用 127.0.0.1 通过您在命令部分中指定的任何 DB_PORT 进行连接。

完整的示例配置文件:

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
      - 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.8.0
        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"

          # 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
      - 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.8.0
        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"

          # 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 Auth 代理的情况下连接到 Cloud SQL

虽然安全性较低,但可以在不使用 Cloud SQL Auth 代理的情况下通过专用 IP 从 VPC 原生 GKE 集群连接到同一 VPC 上的 Cloud SQL 实例。

  1. 使用实例的专用 IP 地址创建 Secret:

    kubectl create secret generic <YOUR-PRIVATE-IP-SECRET> \
        --from-literal=db_host=<YOUR-PRIVATE-IP-ADDRESS>
    
  2. 接下来,确保在应用的容器中添加该 Secret:

    - name: DB_HOST
      valueFrom:
        secretKeyRef:
          name: <YOUR-PRIVATE-IP-SECRET>
          key: db_host
  3. 最后,配置应用以使用 DB_HOST 环境变量中的 IP 地址进行连接。您需要为 MySQL 使用正确的端口:3306。

完整的示例配置文件:

专用 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

问题排查

需要帮助?如需获得代理问题排查方面的帮助,请参阅 Cloud SQL Auth 代理连接问题排查,或参阅我们的 Cloud SQL 支持页面。

后续步骤