Google Kubernetes Engine からの接続

このページでは、Google Kubernetes Engine で実行中のアプリケーションから Cloud SQL インスタンスへの接続を設定する方法について説明します。

はじめに

Google Kubernetes Engine で実行中のアプリケーションから Cloud SQL インスタンスにアクセスするには、Cloud SQL Proxy(パブリック IP またはプライベート IP)を使用するか、プライベート IP アドレスを使用して直接接続します。

プライベート IP を使用する場合でも、Cloud SQL Proxy を使用して Cloud SQL に接続することをおすすめします。これは、プロキシによって IAM を使用した強力な暗号化と認証を使用できるためです。IAM を使用するとデータベースを安全に保つのに有効です。

データベース接続は、サーバーと接続元アプリケーションのリソースを消費します。アプリケーションのフットプリントを最小限に抑え、Cloud SQL の接続制限を超える可能性を少なくするには、常に適切な接続管理方法を採用してください。詳細については、データベース接続の管理をご覧ください。

始める前に

Cloud SQL に接続するには、次に挙げるものが必要です。

  • kubectl コマンドライン ツールがインストールされ、クラスタと通信するように構成された GKE クラスタ。

    GKE の使用開始方法については、クイックスタートをご覧ください。

    プライベート IP を使用して接続するには、GKE クラスタは VPC ネイティブであり、Cloud SQL インスタンスと同じ VPC ネットワーク内にあることが必要です。

  • 作成されたインスタンス

    Cloud SQL インスタンスの作成方法については、インスタンスを作成するをご覧ください。

  • MySQL のユーザー アカウントがインスタンスで構成済みであること。

    アプリケーションはこのアカウントを使用してデータベースに接続します。ユーザー アカウントの作成方法については、ユーザーを作成するをご覧ください。

Secret について

Kubernetes では、Secret は構成の詳細をアプリケーションに渡す安全な方法です。アプリケーションに環境変数として挿入できるデータベース名、ユーザー、パスワードなどの詳細を含む Secret を作成できます。

接続タイプに応じて、Secret を使用するには、さまざまな方法があります。

  • データベース認証情報の Secret には、接続するデータベースのユーザーの名前とユーザーのデータベースのパスワードが含まれます。
  • プロキシを使用して接続する場合、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. オブジェクトを作成すると、Cloud Console の Google Kubernetes Engine ページの [構成] セクションでオブジェクトを表示できます。

Cloud SQL Proxy を使用した接続

Cloud SQL Proxy を使用して接続する場合、Cloud SQL Proxy は sidecar コンテナ パターンを使用して Pod に追加されます。プロキシ コンテナはアプリケーションと同じ Pod にあるため、アプリケーションは localhost を使用してプロキシに接続できます。これにより、セキュリティとパフォーマンスが向上します。詳細については、こちらをご覧ください。

Cloud SQL Proxy の詳細については、Cloud SQL Proxy についてをご覧ください。Pod の操作の詳細については、Kubernetes ドキュメントの Pod の概要をご覧ください。

Cloud SQL Proxy を使用して接続するには、次に挙げるものが必要です。

  1. Cloud SQL インスタンスのインスタンス接続名。

    インスタンスの接続名は、Cloud Console の [Cloud SQL インスタンスの詳細] ページ、または gcloud sql instances describe コマンドを実行して確認できます。

  2. Cloud SQL インスタンスの適切な権限を持つサービス アカウントに関連付けられたキーファイルの場所。

    詳細については、サービス アカウントの作成をご覧ください。

  3. Cloud SQL Admin API が有効化されていること。

    API を有効にする

プロキシへのサービス アカウントの提供

Google Kubernetes Engine で Cloud SQL Proxy を実行するには、まず、アプリケーションを表すサービス アカウントを作成します。どこでも同じサービス アカウントを使用するのではなく、各アプリケーションに固有のサービス アカウントを作成することをおすすめします。このモデルは、アプリケーションごとに権限を制限できるため、より安全です。

アプリケーション用のサービス アカウントは、次の条件を満たす必要があります。

  • Cloud SQL Admin API が有効になっているプロジェクトに所属している
  • 接続するインスタンスを含むプロジェクトについて、Cloud SQL Client IAM ロール(または同等の権限)が付与されている
  • プライベート IP を使用して接続する場合は、Cloud SQL インスタンスと同じ VPC で VPC ネイティブ GKE クラスタを使用する必要があります。

Cloud SQL Proxy にサービス アカウントを提供するように GKE を構成する必要があります。これを行う方法として、Workload Identity またはサービス アカウント キー ファイルの 2 つをおすすめします。

Workload Identity

Google Kubernetes Engine を使用している場合は、GKE の Workload Identity 機能を使用する方法をおすすめします。この方法では、Kubernetes サービス アカウント(KSA)を Google サービス アカウント(GSA)にバインドできます。これにより、一致する KSA を使用するアプリケーションに GSA がアクセスできるようになります。

Google サービス アカウント(GSA)は、Google Cloud で自身のアプリケーションを表す IAM ID です。同様に、Kubernetes サービス アカウント(KSA)は、Google Kubernetes Engine クラスタ内で自身のアプリケーションを表す ID です。

Workload Identity は KSA を GSA にバインドし、Google Cloud とのやり取りでは、その KSA を含むデプロイメントに GSA として認証させます。

  1. クラスタの Workload Identity を有効にします
  2. 通常、それぞれのアプリケーションには固有の ID があり、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-GCP-PROJECT>.svc.id.goog[<YOUR-K8S-NAMESPACE>/<YOUR-KSA-NAME>]" \
      <YOUR-GSA-NAME>@<YOUR-GCP-PROJECT>.iam.gserviceaccount.com
    
  4. YOUR-KSA-NAME にアノテーションを追加して、バインドを完了します。

    kubectl annotate serviceaccount \
       <YOUR-KSA-NAME> \
       iam.gke.io/gcp-service-account=<YOUR-GSA-NAME>@<YOUR-GCP-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 プロキシ Pod にマウントし、-credential_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. Secret を K8s オブジェクトの spec: の下に Volume としてマウントします。

    volumes:
    - name: <YOUR-SA-SECRET-VOLUME>
      secret:
        secretName: <YOUR-SA-SECRET>
    
  4. 次のセクションの手順に従って、プロキシの Pod から Volume にアクセスします。

プロキシをサイドカーとして実行する

プロキシを sidecar パターン(Pod をアプリケーションと共有する追加のコンテナとして)で実行することをおすすめします。次のいくつかの理由から、これを個別のサービスとして実行するよりも、この方法をおすすめします。

  • SQL トラフィックがローカルに公開されることを防ぎます。プロキシは送信接続を暗号化しますが、受信接続の公開を制限する必要があります。
  • 単一障害点を回避します。各アプリケーションのデータベースへのアクセスは他のアプリケーションから独立しているため、復旧しやすくなります。
  • プロキシへのアクセスを制限し、データベースをクラスタ全体に公開するのではなく、アプリケーションごとに IAM 権限を使用できるようにします。
  • リソース リクエストをより正確にスコープできます。プロキシはリソースを使用量に比例して消費するため、このパターンでは、アプリケーションのスケーリングに合わせてリソースをより正確にスコープおよびリクエストできます。
  1. Cloud SQL プロキシを containers: の下の Pod 構成に追加します。

    - 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:1.17
      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

    サービス アカウント キーを使用している場合は、Secret Volume を指定し、コマンドに -credential_file フラグを追加します。

      # This flag specifies where the service account key can be found
      - "-credential_file=/secrets/service_account.json"
    securityContext:
      # The default Cloud SQL 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
  2. 最後に、コマンド セクションで指定したどちらの DB_PORT でも、127.0.0.1 を使用して接続するようにアプリケーションを構成します。

構成ファイルの完全な例:

Workload Identity を使用したプロキシ

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:1.17
        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

サービス アカウント キーを使用したプロキシ

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 proxy
        # Make sure to update on a regular schedule!
        image: gcr.io/cloudsql-docker/gce-proxy:1.17
        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>"

          # This flag specifies where the service account key can be found
          - "-credential_file=/secrets/service_account.json"
        securityContext:
          # The default Cloud SQL 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
      volumes:
      - name: <YOUR-SA-SECRET-VOLUME>
        secret:
          secretName: <YOUR-SA-SECRET>

Cloud SQL Proxy を使用しない接続

それほど安全ではありませんが、VPC ネイティブの GKE クラスタから同じ VPC 上の Cloud SQL インスタンスに、プロキシを使用せずにプライベート IP を使用して接続できます。

  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

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 Proxy 接続のトラブルシューティングをご覧ください。または、Cloud SQL のサポートページをご覧ください。

次のステップ