Cloud Build から接続する

このページには、Cloud Build で実行しているサービスから Cloud SQL インスタンスに接続するための情報と例が含まれています。

Cloud SQL は、クラウド内のリレーショナル データベースの設定、維持、管理に役立つフルマネージド データベース サービスです。

Cloud Build は、Google Cloud インフラストラクチャでビルドを実行するサービスです。

Cloud SQL インスタンスを設定する

  1. 接続元の Google Cloud プロジェクトで Cloud SQL Admin API を有効にします(まだ有効にしていない場合)。

    Enable the API

  2. Cloud SQL for PostgreSQL インスタンスを作成します。レイテンシを短縮して、ネットワーク コストを回避し、リージョン間の障害のリスクを軽減するには、Cloud Run サービスと同じリージョンに Cloud SQL インスタンスのロケーションを選択することをおすすめします。

    Cloud SQL は、デフォルトで新しいインスタンスにパブリック IP アドレスを割り振ります。 プライベート IP アドレスを割り当てることもできます。両方の接続オプションの詳細については、接続の概要ページをご覧ください。

Cloud Build を構成する

Cloud Build を構成する手順は、Cloud SQL インスタンスに割り当てられた IP アドレスのタイプによって異なります。

パブリック IP(デフォルト)

Cloud Build サービス アカウントCloud SQL インスタンスへの接続に必要な IAM ロールと権限があることを確認します。Cloud Build サービス アカウントは、Google Cloud コンソールの [IAM] ページにプリンシパル [YOUR-PROJECT-NUMBER]@cloudbuild.gserviceaccount.com として表示されます。

Google Cloud コンソールでこのサービス アカウントを表示するには、[Google 提供のロール付与を含める] チェックボックスをオンにします。

Cloud Build サービス アカウントに、次の IAM ロールのいずれかが必要です。

  • Cloud SQL Client(推奨)
  • Cloud SQL Admin
または、次の IAM 権限を手動で割り当てることもできます。
  • cloudsql.instances.connect
  • cloudsql.instances.get

Cloud Build サービス アカウントが Cloud SQL インスタンスとは異なるプロジェクトに属している場合、Cloud SQL Admin API と IAM の権限を両方のプロジェクトに追加する必要があります。

プライベート IP

プライベート IP 経由で Cloud SQL インスタンスに接続するには、Cloud Build が Cloud SQL インスタンスと同じ VPC ネットワークに接続されている必要があります。この構成を行うには:

  1. Cloud SQL インスタンスの VPC ネットワークとサービス プロデューサー ネットワークの間にプライベート接続を設定します。
  2. Cloud Build プライベート プールを作成します。

構成が完了すると、プールでビルドが実行されたときに、アプリケーションがインスタンスのプライベート IP アドレスとポート 5432 を使用して直接接続できるようになります。

Cloud SQL への接続

Cloud Build を構成すると、Cloud SQL インスタンスに接続できます。

パブリック IP(デフォルト)

パブリック IP パスの場合、Cloud Build は Unix ソケットと TCP ソケットの両方をサポートします。

Cloud SQL Auth Proxy を Cloud Build ステップの 1 つで使用してデータベースへの接続を許可することができます。この構成では、次の処理を行います。

  1. コンテナをビルドして、Container Registry に push します。
  2. 2 つ目のコンテナをビルドし、このときに Cloud SQL Auth Proxy バイナリをコピーします。
    • Cloud Build によってビルドされたコンテナは、レジストリに push する必要はありません。ビルドの完了時に破棄されます。
  3. 2 つ目のコンテナを使用して、Cloud SQL Auth Proxy を起動して任意の移行コマンドを実行します。
steps:
  - id: "docker-build"
    name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "${_IMAGE_NAME}", "sql-proxy/."]

  - id: "docker-push"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "${_IMAGE_NAME}"]

  - id: "docker-layer"
    name: "gcr.io/cloud-builders/docker"
    entrypoint: /bin/bash
    args:
      - '-c'
      - |
        echo "FROM $_IMAGE_NAME
        COPY --from=gcr.io/cloud-sql-connectors/cloud-sql-proxy /cloud-sql-proxy /cloudsql/cloud-sql-proxy" > Dockerfile-proxy;

        docker build -f Dockerfile-proxy -t ${_IMAGE_NAME}-proxy .

  # For TCP connections
  - id: "migrate-tcp"
    name: "${_IMAGE_NAME}-proxy"
    dir: sql-proxy
    env:
      - "DATABASE_NAME=${_DATABASE_NAME}"
      - "DATABASE_USER=${_DATABASE_USER}"
      - "DATABASE_HOST=127.0.0.1"
      - "DATABASE_PORT=${_DATABASE_PORT}"
      - "DATABASE_TYPE=${_DATABASE_TYPE}"
    secretEnv:
      - DATABASE_PASS
    entrypoint: /bin/bash
    args:
      - '-c'
      - |
        /cloudsql/cloud-sql-proxy --port ${_DATABASE_PORT} ${_INSTANCE_CONNECTION_NAME} & sleep 2;
        python migrate.py # for example

  # For Unix Socket connections
  - id: "migrate-socket"
    name: "${_IMAGE_NAME}-proxy"
    dir: sql-proxy
    env:
      - "DATABASE_NAME=${_DATABASE_NAME}"
      - "DATABASE_USER=${_DATABASE_USER}"
      - "INSTANCE_CONNECTION_NAME=${_INSTANCE_CONNECTION_NAME}"
      - "DATABASE_TYPE=${_DATABASE_TYPE}"
    secretEnv:
      - DATABASE_PASS
    entrypoint: /bin/bash
    args:
      - '-c'
      - |
        /cloudsql/cloud-sql-proxy --unix-socket /cloudsql ${_INSTANCE_CONNECTION_NAME} & sleep 2;
        if [ $_DATABASE_TYPE = 'mssql' ]; then echo "MSSQL doesn't support Unix Sockets. Skippng."; exit 0; fi;
        python migrate.py # for example.

options:
  dynamic_substitutions: true

substitutions:
  _DATABASE_USER: myuser
  _DATABASE_NAME: mydatabase
  _INSTANCE_CONNECTION_NAME: ${PROJECT_ID}:us-central1:myinstance
  _DATABASE_PORT: '5432'
  _DATABASE_TYPE: postgres
  _DATABASE_PASSWORD_KEY: database_password
  _IMAGE_NAME: gcr.io/${PROJECT_ID}/sample-sql-proxy

availableSecrets:
  secretManager:
    - versionName: projects/$PROJECT_ID/secrets/${_DATABASE_PASSWORD_KEY}/versions/latest
      env: DATABASE_PASS

この Cloud Build コードサンプルは、前述のサンプルアプリをデプロイした後にその Cloud SQL データベースを更新するための架空の migrate スクリプトを、Cloud SQL Auth Proxy と Cloud Build を使用して実行する方法を示すものです。この Cloud Build コードサンプルを実行するには、次の設定手順が必要です。

  1. sql-proxy という名前のフォルダを作成します
  2. 次のコード行を使用して、sql-proxy フォルダに Dockerfile ファイルを作成します。このファイルの内容は次のとおりです。

    FROM gcr.io/gcp-runtimes/ubuntu_20_0_4

  3. sql-proxy フォルダに cloudbuild.yaml ファイルを作成します。
  4. cloudbuild.yaml ファイルを更新します。
    1. 上記の Cloud Build サンプルコードをコピーし、cloudbuild.yaml ファイルに貼り付けます。
    2. 使用されていない接続方法のコードブロックを削除して、TCP 接続または Unix ソケット接続のいずれかを使用します。
    3. 次のプレースホルダ値を、プロジェクトで使用されている値に置き換えます。
      • mydatabase
      • myuser
      • myinstance
  5. Secret Managerdatabase_password という名前のシークレットを作成します。
  6. sql-proxy フォルダに migrate.py スクリプト ファイルを作成します。
    • このスクリプトでは、以下の例を使用して、cloudbuild.yaml ファイルに作成された次の環境変数とシークレットを参照できます。
      • os.getenv('DATABASE_NAME')
      • os.getenv('DATABASE_USER')
      • os.getenv('DATABASE_PASS')
      • os.getenv('INSTANCE_CONNECTION_NAME')
    • Bash スクリプトから同じ変数(例: migrate.sh)を参照するには、次の例を使用します。
      • $DATABASE_NAME
      • $DATABASE_USER
      • $DATABASE_PASS
      • $INSTANCE_CONNECTION_NAME
  7. 次の gcloud builds submit コマンドを実行して、Cloud SQL Auth Proxy を含むコンテナをビルドし、Cloud SQL Auth Proxy を起動して、migrate.py スクリプトを実行します。

    gcloud builds submit --config cloudbuild.yaml

プライベート IP

プライベート IP パスの場合、アプリケーションはプライベート プールを介してインスタンスに直接接続します。この方法では、Cloud SQL Auth Proxy を使用せずに、TCP を使用して Cloud SQL インスタンスに直接接続します。

TCP による接続

Cloud SQL インスタンスのプライベート IP アドレスをホストとポートの 5432 として使用して接続します。

Python

ウェブ アプリケーションのコンテキストでのこのスニペットの使用については、GitHub の README をご覧ください。

import os
import ssl

import sqlalchemy


def connect_tcp_socket() -> sqlalchemy.engine.base.Engine:
    """Initializes a TCP connection pool for a Cloud SQL instance of Postgres."""
    # Note: Saving credentials in environment variables is convenient, but not
    # secure - consider a more secure solution such as
    # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
    # keep secrets safe.
    db_host = os.environ[
        "INSTANCE_HOST"
    ]  # e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
    db_user = os.environ["DB_USER"]  # e.g. 'my-db-user'
    db_pass = os.environ["DB_PASS"]  # e.g. 'my-db-password'
    db_name = os.environ["DB_NAME"]  # e.g. 'my-database'
    db_port = os.environ["DB_PORT"]  # e.g. 5432

    pool = sqlalchemy.create_engine(
        # Equivalent URL:
        # postgresql+pg8000://<db_user>:<db_pass>@<db_host>:<db_port>/<db_name>
        sqlalchemy.engine.url.URL.create(
            drivername="postgresql+pg8000",
            username=db_user,
            password=db_pass,
            host=db_host,
            port=db_port,
            database=db_name,
        ),
        # ...
    )
    return pool

Java

このスニペットをウェブ アプリケーションのコンテキストで表示するには、GitHub の README をご覧ください。

注:

  • CLOUD_SQL_CONNECTION_NAME は <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME> のように指定する必要があります。
  • 引数 ipTypes=PRIVATE を使用すると、SocketFactory はインスタンスに関連付けられたプライベート IP を使用して接続するようになります。
  • pom.xml ファイルの JDBC ソケット ファクトリ バージョン要件については、こちらをご覧ください。


import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;

public class TcpConnectionPoolFactory extends ConnectionPoolFactory {

  // Note: Saving credentials in environment variables is convenient, but not
  // secure - consider a more secure solution such as
  // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
  // keep secrets safe.
  private static final String DB_USER = System.getenv("DB_USER");
  private static final String DB_PASS = System.getenv("DB_PASS");
  private static final String DB_NAME = System.getenv("DB_NAME");

  private static final String INSTANCE_HOST = System.getenv("INSTANCE_HOST");
  private static final String DB_PORT = System.getenv("DB_PORT");


  public static DataSource createConnectionPool() {
    // The configuration object specifies behaviors for the connection pool.
    HikariConfig config = new HikariConfig();

    // The following URL is equivalent to setting the config options below:
    // jdbc:postgresql://<INSTANCE_HOST>:<DB_PORT>/<DB_NAME>?user=<DB_USER>&password=<DB_PASS>
    // See the link below for more info on building a JDBC URL for the Cloud SQL JDBC Socket Factory
    // https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory#creating-the-jdbc-url

    // Configure which instance and what database user to connect with.
    config.setJdbcUrl(String.format("jdbc:postgresql://%s:%s/%s", INSTANCE_HOST, DB_PORT, DB_NAME));
    config.setUsername(DB_USER); // e.g. "root", "postgres"
    config.setPassword(DB_PASS); // e.g. "my-password"


    // ... Specify additional connection properties here.
    // ...

    // Initialize the connection pool using the configuration object.
    return new HikariDataSource(config);
  }
}

Node.js

このスニペットをウェブ アプリケーションのコンテキストで表示するには、GitHub の README をご覧ください。

const Knex = require('knex');
const fs = require('fs');

// createTcpPool initializes a TCP connection pool for a Cloud SQL
// instance of Postgres.
const createTcpPool = async config => {
  // Note: Saving credentials in environment variables is convenient, but not
  // secure - consider a more secure solution such as
  // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
  // keep secrets safe.
  const dbConfig = {
    client: 'pg',
    connection: {
      host: process.env.INSTANCE_HOST, // e.g. '127.0.0.1'
      port: process.env.DB_PORT, // e.g. '5432'
      user: process.env.DB_USER, // e.g. 'my-user'
      password: process.env.DB_PASS, // e.g. 'my-user-password'
      database: process.env.DB_NAME, // e.g. 'my-database'
    },
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return Knex(dbConfig);
};

Go

このスニペットをウェブ アプリケーションのコンテキストで表示するには、GitHub の README をご覧ください。

package cloudsql

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	// Note: If connecting using the App Engine Flex Go runtime, use
	// "github.com/jackc/pgx/stdlib" instead, since v5 requires
	// Go modules which are not supported by App Engine Flex.
	_ "github.com/jackc/pgx/v5/stdlib"
)

// connectTCPSocket initializes a TCP connection pool for a Cloud SQL
// instance of Postgres.
func connectTCPSocket() (*sql.DB, error) {
	mustGetenv := func(k string) string {
		v := os.Getenv(k)
		if v == "" {
			log.Fatalf("Fatal Error in connect_tcp.go: %s environment variable not set.", k)
		}
		return v
	}
	// Note: Saving credentials in environment variables is convenient, but not
	// secure - consider a more secure solution such as
	// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
	// keep secrets safe.
	var (
		dbUser    = mustGetenv("DB_USER")       // e.g. 'my-db-user'
		dbPwd     = mustGetenv("DB_PASS")       // e.g. 'my-db-password'
		dbTCPHost = mustGetenv("INSTANCE_HOST") // e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
		dbPort    = mustGetenv("DB_PORT")       // e.g. '5432'
		dbName    = mustGetenv("DB_NAME")       // e.g. 'my-database'
	)

	dbURI := fmt.Sprintf("host=%s user=%s password=%s port=%s database=%s",
		dbTCPHost, dbUser, dbPwd, dbPort, dbName)


	// dbPool is the pool of database connections.
	dbPool, err := sql.Open("pgx", dbURI)
	if err != nil {
		return nil, fmt.Errorf("sql.Open: %w", err)
	}

	// ...

	return dbPool, nil
}

C#

このスニペットをウェブ アプリケーションのコンテキストで表示するには、GitHub の README をご覧ください。

using Npgsql;
using System;

namespace CloudSql
{
    public class PostgreSqlTcp
    {
        public static NpgsqlConnectionStringBuilder NewPostgreSqlTCPConnectionString()
        {
            // Equivalent connection string:
            // "Uid=<DB_USER>;Pwd=<DB_PASS>;Host=<INSTANCE_HOST>;Database=<DB_NAME>;"
            var connectionString = new NpgsqlConnectionStringBuilder()
            {
                // Note: Saving credentials in environment variables is convenient, but not
                // secure - consider a more secure solution such as
                // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
                // keep secrets safe.
                Host = Environment.GetEnvironmentVariable("INSTANCE_HOST"),     // e.g. '127.0.0.1'
                // Set Host to 'cloudsql' when deploying to App Engine Flexible environment
                Username = Environment.GetEnvironmentVariable("DB_USER"), // e.g. 'my-db-user'
                Password = Environment.GetEnvironmentVariable("DB_PASS"), // e.g. 'my-db-password'
                Database = Environment.GetEnvironmentVariable("DB_NAME"), // e.g. 'my-database'

                // The Cloud SQL proxy provides encryption between the proxy and instance.
                SslMode = SslMode.Disable,
            };
            connectionString.Pooling = true;
            // Specify additional properties here.
            return connectionString;
        }
    }
}

Ruby

このスニペットをウェブ アプリケーションのコンテキストで表示するには、GitHub の README をご覧ください。

tcp: &tcp
  adapter: postgresql
  # Configure additional properties here.
  # Note: Saving credentials in environment variables is convenient, but not
  # secure - consider a more secure solution such as
  # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
  # keep secrets safe.
  username: <%= ENV["DB_USER"] %>  # e.g. "my-database-user"
  password: <%= ENV["DB_PASS"] %> # e.g. "my-database-password"
  database: <%= ENV.fetch("DB_NAME") { "vote_development" } %>
  host: <%= ENV.fetch("INSTANCE_HOST") { "127.0.0.1" }%> # '172.17.0.1' if deployed to GAE Flex
  port: <%= ENV.fetch("DB_PORT") { 5432 }%>

PHP

このスニペットをウェブ アプリケーションのコンテキストで表示するには、GitHub の README をご覧ください。

namespace Google\Cloud\Samples\CloudSQL\Postgres;

use PDO;
use PDOException;
use RuntimeException;
use TypeError;

class DatabaseTcp
{
    public static function initTcpDatabaseConnection(): PDO
    {
        try {
            // Note: Saving credentials in environment variables is convenient, but not
            // secure - consider a more secure solution such as
            // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
            // keep secrets safe.
            $username = getenv('DB_USER'); // e.g. 'your_db_user'
            $password = getenv('DB_PASS'); // e.g. 'your_db_password'
            $dbName = getenv('DB_NAME'); // e.g. 'your_db_name'
            $instanceHost = getenv('INSTANCE_HOST'); // e.g. '127.0.0.1' ('172.17.0.1' for GAE Flex)

            // Connect using TCP
            $dsn = sprintf('pgsql:dbname=%s;host=%s', $dbName, $instanceHost);

            // Connect to the database
            $conn = new PDO(
                $dsn,
                $username,
                $password,
                # ...
            );
        } catch (TypeError $e) {
            throw new RuntimeException(
                sprintf(
                    'Invalid or missing configuration! Make sure you have set ' .
                        '$username, $password, $dbName, and $instanceHost (for TCP mode). ' .
                        'The PHP error was %s',
                    $e->getMessage()
                ),
                $e->getCode(),
                $e
            );
        } catch (PDOException $e) {
            throw new RuntimeException(
                sprintf(
                    'Could not connect to the Cloud SQL Database. Check that ' .
                        'your username and password are correct, that the Cloud SQL ' .
                        'proxy is running, and that the database exists and is ready ' .
                        'for use. For more assistance, refer to %s. The PDO error was %s',
                    'https://cloud.google.com/sql/docs/postgres/connect-external-app',
                    $e->getMessage()
                ),
                $e->getCode(),
                $e
            );
        }

        return $conn;
    }
}

その後、Cloud Build のステップを作成して、コードを直接実行できます。

steps:
  - id: "docker-build"
    name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "${_IMAGE_NAME}", "sql-private-pool/."]

  - id: "docker-push"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "${_IMAGE_NAME}"]

  - id: "migration"
    name: "${_IMAGE_NAME}"
    dir: sql-private-pool
    env:
      - "DATABASE_NAME=mydatabase"
      - "DATABASE_USER=myuser"
      - "DATABASE_HOST=${_DATABASE_HOST}"
      - "DATABASE_TYPE=${_DATABASE_TYPE}"
    secretEnv:
      - DATABASE_PASS
    entrypoint: python   # for example
    args: ["migrate.py"] # for example

options:
  pool:
    name: projects/$PROJECT_ID/locations/us-central1/workerPools/private-pool
  dynamic_substitutions: true

substitutions:
  _DATABASE_PASSWORD_KEY: database_password
  _DATABASE_TYPE: postgres
  _IMAGE_NAME: gcr.io/${PROJECT_ID}/sample-private-pool

availableSecrets:
  secretManager:
    - versionName: projects/$PROJECT_ID/secrets/${_DATABASE_PASSWORD_KEY}/versions/latest
      env: DATABASE_PASS

この Cloud Build コードサンプルは、前述のサンプルアプリをデプロイした後にその Cloud SQL データベースを更新するための架空の移行スクリプトを、Cloud Build を使用して実行する方法を示すものです。この Cloud Build コードサンプルを実行するには、次の設定手順が必要です。

  1. sql-private-pool という名前のフォルダを作成します
  2. 次のコード行を使用して、sql-private-pool フォルダに Dockerfile ファイルを作成します。このファイルの内容は次のとおりです。

    FROM gcr.io/gcp-runtimes/ubuntu_20_0_4

  3. sql-private-pool フォルダに cloudbuild.yaml ファイルを作成します。
  4. cloudbuild.yaml ファイルを更新します。
    1. 上記の Cloud Build サンプルコードをコピーし、cloudbuild.yaml ファイルに貼り付けます。
    2. 次のプレースホルダ値を、プロジェクトで使用されている値に置き換えます。
      • mydatabase
      • myuser
      • databasehost。形式は host:port です。
  5. Secret Managerdatabase_password という名前のシークレットを作成します。
  6. sql-proxy フォルダに migrate.py スクリプト ファイルを作成します。
    • このスクリプトでは、以下の例を使用して、cloudbuild.yaml ファイルに作成された次の環境変数とシークレットを参照できます。
      • os.getenv('DATABASE_NAME')
      • os.getenv('DATABASE_USER')
      • os.getenv('DATABASE_PASS')
      • os.getenv('DATABASE_HOST')
    • Bash スクリプトから同じ変数(例: migrate.sh)を参照するには、次の例を使用します。
      • $DATABASE_NAME
      • $DATABASE_USER
      • $DATABASE_PASS
      • $DATABASE_HOST
  7. 次の gcloud builds submit コマンドを実行して、Cloud SQL Auth Proxy を含むコンテナをビルドし、Cloud SQL Auth Proxy を起動して、migrate.py スクリプトを実行します。

    gcloud builds submit --config cloudbuild.yaml

ベスト プラクティスとその他の情報

アプリケーションをローカルでテストする場合は、Cloud SQL Auth Proxy を使用できます。詳細な手順については、Cloud SQL Auth Proxy を使用するためのクイックスタートをご覧ください。

また、Docker コンテナ経由で Cloud SQL Proxy を使用してもテストできます。

データベース スキーマの移行

Cloud SQL に接続するように Cloud Build を構成すると、他のサーバーレス プラットフォームにデプロイするコードと同じコードを使用して、Cloud Build でデータベース スキーマの移行タスクを実行できます。

Secret Manager の使用

Secret Manager を使用すると、ビルドに機密情報を含めることができます。