--- description: 使用 Cloud SQL Auth proxy 從 Google Kubernetes Engine 連線至 Google Cloud SQL lang: zh --- # Connect Cloud SQL from Kubernetes Engine This [documentation](https://cloud.google.com/sql/docs/postgres/connect-kubernetes-engine) describes how to set up a connection from an application running in Google Kubernetes Engine to a Cloud SQL instance. ## Introduction 主要有兩種做法,你可以用 Cloud SQL Auth proxy (公開或私有 IP) 或使用私有 IP 直接連線。 即使你使用私有 IP 連線,搭配 Cloud SQL Auth proxy 也是較建議的做法。因為 Cloud SQL Auth proxy 提供強加密和使用 IAM 的身份驗證來保護資料庫的安全。 :::success 本篇採用第一種做法 :tada: ::: ### Prerequisites - GKE cluster,若要使用 private IP 來連線,則必須建立 [VPC-native](https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips) 叢集,且必須和 Cloud SQL 使用相同的 VPC 網路。 - Cloud SQL instance - PostgreSQL [使用者帳號](https://cloud.google.com/sql/docs/postgres/create-manage-users#creating)(或 MySQL、MS SQL) ### About Secrets 在 Kubernetes 中,[Secrets](https://cloud.google.com/kubernetes-engine/docs/concepts/secret) 是一種能安全傳遞組態細節資訊到應用程式的方式。你可以建立一個包含資料庫名稱、使用者、密碼的 Secret 並注入到應用程式作為環境變數(env vars)。 :::info 根據你的應用程式如何取得連線資訊來決定,若不是從環境變數(env vars)取得,則不需要 Secret。 ::: ## Connecting using the Cloud SQL Auth proxy Cloud SQL Auth proxy 會以 `sidecar` 容器模式加入 pod 中。它跟你的應用程式會存在於同一 pod 裡,這讓你能夠以 `localhost` 連至 Cloud SQL Auth proxy,也增加了安全性與效能。 ### Providing the service account to the Cloud SQL Auth proxy 第一步,到 IAM 建立 [Google Service Account (GSA)](https://cloud.google.com/iam/docs/service-accounts) 讓你有足夠的權限連線至 Cloud SQL。此服務帳戶需要符合以下條件: - 該專案已啟用 Cloud SQL Admin API - 擁有 [Cloud SQL Client](https://cloud.google.com/iam/docs/understanding-roles#cloudsql.client) IAM 角色(或以上) - 若使用 private IP,你必須使用存在於和 Cloud SQL 實體同樣的 VPC 的 VPC-native GKE cluster 接著,為了讓 Cloud SQL Auth proxy 能夠使用此 GSA,需要設定 GKE。有兩種做法可以達成此目的:若你使用 GKE 則選 workload identity,其他則使用 service account key file。 #### [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) 此方法讓你將 [Kubernetes Service Account (KSA)](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) 綁定至 Google Service Account (GSA)。之後,使用對應的 KSA 的應用程式就能夠存取該 GSA。 GSA 是一個在 Google Cloud 中代表你的應用程式的 IAM 身份。和 GSA 類似,Kubernetes Service Account 是在 GKE cluster 中代表你的應用程式的身份。 Workload identity 將 KSA 綁定至 GSA,讓任何使用該 KSA 的 deployments 都能以此 GSA 的身份與 Google Cloud 互動。 1. [將你的 cluster 啟用 Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_on_cluster)(可能需要加上 `--zone` 或 `--region` 參數) 2. [更改節點池的 metadata](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#option_2_node_pool_modification) 3. 建立 KSA 的 yaml 檔並使用下列指令新增此身份 `kubectl apply -f service-account.yaml` service-account.yaml 內容: ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: <YOUR-KSA-NAME> # TODO: replace name ``` 4. 啟用你剛建立的 GSA 和 KSA 之間的 IAM 綁定: ``` gcloud iam service-accounts add-iam-policy-binding \ --role="roles/iam.workloadIdentityUser" \ --member="serviceAccount:<YOUR-GCP-PROJECT>.svc.id.goog[<YOUR-K8S-NAMESPACE>/<YOUR-KSA-NAME>]" \ <YOUR-GSA-NAME>@<YOUR-GCP-PROJECT>.iam.gserviceaccount.com ``` 5. 加入 KSA 的標注(annotation)來完成綁定: ``` kubectl annotate serviceaccount \ <YOUR-KSA-NAME> \ iam.gke.io/gcp-service-account=<YOUR-GSA-NAME>@<YOUR-GCP-PROJECT>.iam.gserviceaccount.com ``` 6. 最後在 k8s object 裡指定服務帳戶。 ``` 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> ``` #### Running the Cloud SQL Auth proxy as a sidecar 官方建議使用 `sidecar` 模式(作為一個與你的應用程式共享同一個 pod 的額外容器),而不是在 cluster 裡另外運行一個 service。 在 yaml 檔的 `containers` 下將 Cloud SQL Auth proxy 新增至 pod: ```yaml - name: cloud-sql-proxy # It is recommended to use the latest version of the Cloud SQL proxy # Make sure to update on a regular schedule! image: gcr.io/cloudsql-docker/gce-proxy:latest command: - "/cloud_sql_proxy" # If connecting from a VPC-native GKE cluster, you can use the # following flag to have the proxy connect over private IP # - "-ip_address_types=PRIVATE" # Replace DB_PORT with the port the proxy should listen on # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 - "-instances=<INSTANCE_CONNECTION_NAME>=tcp:<DB_PORT>" securityContext: # The default Cloud SQL proxy image runs as the # "nonroot" user and group (uid: 65532) by default. runAsNonRoot: 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" ``` 最終結果類似: ```yaml # 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 proxy # Make sure to update on a regular schedule! image: gcr.io/cloudsql-docker/gce-proxy:latest command: - "/cloud_sql_proxy" # If connecting from a VPC-native GKE cluster, you can use the # following flag to have the proxy connect over private IP # - "-ip_address_types=PRIVATE" # Replace DB_PORT with the port the proxy should listen on # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 - "-instances=<INSTANCE_CONNECTION_NAME>=tcp:<DB_PORT>" securityContext: # The default Cloud SQL proxy image runs as the # "nonroot" user and group (uid: 65532) by default. runAsNonRoot: 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" ``` ## 延伸閱讀 - [Sidecar pattern](https://tachingchen.com/tw/blog/desigining-distributed-systems-the-sidecar-pattern-concept/) ###### tags: `gcp` `gke` `cloud-sql` `k8s` `sql`