---
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`