App Engine スタンダード環境から Cloud SQL への接続

このページには、App Engine スタンダード環境で動作中のサービスから Cloud SQL インスタンスに接続するための情報と例が記載されています。

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

App Engine は、大規模なウェブ アプリケーションを開発およびホスティングするための、フルマネージド型のサーバーレス プラットフォームです。アプリの開発では複数の一般的な言語、ライブラリ、フレームワークからの選択が可能で、開発したアプリのインスタンスのサーバー プロビジョニングとスケーリングは App Engine によってオンデマンドで行われます。

Cloud SQL インスタンスの設定

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

    API を有効にする

  2. Cloud SQL for MySQL インスタンスを作成します

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

App Engine スタンダード環境の構成

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

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

パブリック IP を使用して Cloud SQL インスタンスに接続できるように App Engine スタンダード環境を構成するには:

  • 上記で作成したインスタンスにパブリック IP アドレスがあることを確認します。これは、Google Cloud Console のインスタンスの [概要] ページで確認できます。パブリック IP を追加する必要がある場合は、パブリック IP の構成ページの手順をご覧ください。
  • インスタンスの INSTANCE_CONNECTION_NAME を取得します。これは、Google Cloud Console のインスタンスの [概要] ページで確認できます。また、コマンド gcloud sql instances describe [INSTANCE_NAME] を実行して確認することもできます。
  • アプリが Cloud SQL の呼び出しを認証するために使用しているサービス アカウントに、適切な Cloud SQL のロールと権限があることを確認します。
    • お使いのサービスのサービス アカウントには、次のいずれかの IAM ロールが必要です。
      • Cloud SQL Client(推奨)
      • Cloud SQL Editor
      • Cloud SQL Admin
      または、次の IAM 権限を手動で割り当てることもできます。
      • cloudsql.instances.connect
      • cloudsql.instances.get
      サービス アカウントに IAM ロールを追加する方法の詳細については、サービス アカウントへのロールの付与をご覧ください。

    デフォルトでは、アプリは App Engine サービス アカウントを使用して接続を承認します。サービス アカウント ID の形式は PROJECT_ID@appspot.gserviceaccount.com です。

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

プライベート IP

サーバーレス VPC アクセス コネクタは VPC ネットワークとの通信を処理します。 プライベート IP に直接接続するには、次のようにする必要があります。

  1. 上述で作成した Cloud SQL インスタンスにプライベート IP アドレスが割り当てられていることを確認します。プライベート IP を追加する必要がある場合は、プライベート IP の構成ページの手順をご覧ください。
  2. Cloud SQL インスタンスと同じ VPC ネットワークにサーバーレス VPC アクセス コネクタを作成します。
  3. 共有 VPC を使用している場合を除き、コネクタは、それを使用するリソースと同じプロジェクトとリージョン内に配置されている必要がありますが、異なるリージョンのリソースにトラフィックを送信できます。

    サーバーレス VPC アクセスでは、Cloud VPNVPC ネットワーク ピアリングを介して接続された VPC ネットワークとの通信がサポートされています。

    サーバーレス VPC アクセスは、レガシー ネットワークをサポートしていません。

  4. インスタンスのプライベート IP とポート 3306 を使用して接続します。

Cloud SQL への接続

App Engine スタンダード環境を構成すると、Cloud SQL インスタンスに接続できます。

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

パブリック IP パスの場合、App Engine スタンダード環境では、Unix ソケット経由で Cloud SQL Auth プロキシを使用した暗号化と接続が行われます。

Unix ソケットによる接続

正しく構成されたら、パス /cloudsql/INSTANCE_CONNECTION_NAME で環境のファイルシステムからアクセスされる Cloud SQL インスタンスの Unix ドメイン ソケットにサービスを接続できます。

INSTANCE_CONNECTION_NAME は、Google Cloud Console でインスタンスの [概要] ページで確認できます。または、次のコマンドを実行します。

gcloud sql instances describe [INSTANCE_NAME]

これらの接続は、追加構成なしで自動的に暗号化されます。

以下に示すコードサンプルは、GitHub サイトに掲載されているより詳細な例からの抜粋です。詳しく見るには、View on GitHub をクリックしてください。

Python

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

# Remember - storing secrets in plaintext is potentially unsafe. Consider using
# something like https://cloud.google.com/secret-manager/docs/overview to help keep
# secrets secret.
db_user = os.environ["DB_USER"]
db_pass = os.environ["DB_PASS"]
db_name = os.environ["DB_NAME"]
db_socket_dir = os.environ.get("DB_SOCKET_DIR", "/cloudsql")
cloud_sql_connection_name = os.environ["CLOUD_SQL_CONNECTION_NAME"]

pool = sqlalchemy.create_engine(
    # Equivalent URL:
    # mysql+pymysql://<db_user>:<db_pass>@/<db_name>?unix_socket=<socket_path>/<cloud_sql_instance_name>
    sqlalchemy.engine.url.URL.create(
        drivername="mysql+pymysql",
        username=db_user,  # e.g. "my-database-user"
        password=db_pass,  # e.g. "my-database-password"
        database=db_name,  # e.g. "my-database-name"
        query={
            "unix_socket": "{}/{}".format(
                db_socket_dir,  # e.g. "/cloudsql"
                cloud_sql_connection_name)  # i.e "<PROJECT-NAME>:<INSTANCE-REGION>:<INSTANCE-NAME>"
        }
    ),
    **db_config
)

Java

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

// Note: For Java users, the Cloud SQL JDBC Socket Factory can provide authenticated connections
// which is preferred to using the Cloud SQL Proxy with Unix sockets.
// See https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory for details.

// 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:mysql:///<DB_NAME>?cloudSqlInstance=<CLOUD_SQL_CONNECTION_NAME>&
// socketFactory=com.google.cloud.sql.mysql.SocketFactory&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:mysql:///%s", DB_NAME));
config.setUsername(DB_USER); // e.g. "root", "mysql"
config.setPassword(DB_PASS); // e.g. "my-password"

config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.mysql.SocketFactory");
config.addDataSourceProperty("cloudSqlInstance", CLOUD_SQL_CONNECTION_NAME);

// The ipTypes argument can be used to specify a comma delimited list of preferred IP types
// for connecting to a Cloud SQL instance. The argument ipTypes=PRIVATE will force the
// SocketFactory to connect with an instance's associated private IP.
config.addDataSourceProperty("ipTypes", "PUBLIC,PRIVATE");

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

// Initialize the connection pool using the configuration object.
DataSource pool = new HikariDataSource(config);

Node.js

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

const createUnixSocketPool = async config => {
  const dbSocketPath = process.env.DB_SOCKET_PATH || '/cloudsql';

  // Establish a connection to the database
  return await mysql.createPool({
    user: process.env.DB_USER, // e.g. 'my-db-user'
    password: process.env.DB_PASS, // e.g. 'my-db-password'
    database: process.env.DB_NAME, // e.g. 'my-database'
    // If connecting via unix domain socket, specify the path
    socketPath: `${dbSocketPath}/${process.env.CLOUD_SQL_CONNECTION_NAME}`,
    // Specify additional properties here.
    ...config,
  });
};

C#

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

// Equivalent connection string:
// "Server=<dbSocketDir>/<INSTANCE_CONNECTION_NAME>;Uid=<DB_USER>;Pwd=<DB_PASS>;Database=<DB_NAME>;Protocol=unix"
String dbSocketDir = Environment.GetEnvironmentVariable("DB_SOCKET_PATH") ?? "/cloudsql";
String instanceConnectionName = Environment.GetEnvironmentVariable("INSTANCE_CONNECTION_NAME");
var connectionString = new MySqlConnectionStringBuilder()
{
    // The Cloud SQL proxy provides encryption between the proxy and instance.
    SslMode = MySqlSslMode.None,
    // Remember - storing secrets in plain text is potentially unsafe. Consider using
    // something like https://cloud.google.com/secret-manager/docs/overview to help keep
    // secrets secret.
    Server = String.Format("{0}/{1}", dbSocketDir, instanceConnectionName),
    UserID = 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'
    ConnectionProtocol = MySqlConnectionProtocol.UnixSocket
};
connectionString.Pooling = true;
// Specify additional properties here.
return connectionString;

Go

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

var (
	dbUser                 = mustGetenv("DB_USER")                  // e.g. 'my-db-user'
	dbPwd                  = mustGetenv("DB_PASS")                  // e.g. 'my-db-password'
	instanceConnectionName = mustGetenv("INSTANCE_CONNECTION_NAME") // e.g. 'project:region:instance'
	dbName                 = mustGetenv("DB_NAME")                  // e.g. 'my-database'
)

socketDir, isSet := os.LookupEnv("DB_SOCKET_DIR")
if !isSet {
	socketDir = "/cloudsql"
}

var dbURI string
dbURI = fmt.Sprintf("%s:%s@unix(/%s/%s)/%s?parseTime=true", dbUser, dbPwd, socketDir, instanceConnectionName, dbName)

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

// ...

return dbPool, nil

Ruby

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

production:
  adapter: mysql2
  # Configure additional properties here.
  username: <%= ENV["DB_USER"] %>  # e.g. "my-database-user"
  password: <%= ENV["DB_PASS"] %> # e.g. "my-database-password"
  database: <%= ENV.fetch("DB_NAME") { "vote_production" } %>
  socket: "<%= ENV.fetch("DB_SOCKET_DIR") { '/cloudsql' } %>/<%= ENV["INSTANCE_CONNECTION_NAME"] %>"

PHP

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

// $username = 'your_db_user';
// $password = 'yoursupersecretpassword';
// $dbName = 'your_db_name';
// $connectionName = getenv("CLOUD_SQL_CONNECTION_NAME");
// $socketDir = getenv('DB_SOCKET_DIR') ?: '/cloudsql';

// Connect using UNIX sockets
$dsn = sprintf(
    'mysql:dbname=%s;unix_socket=%s/%s',
    $dbName,
    $socketDir,
    $connectionName
);

// Connect to the database.
$conn = new PDO($dsn, $username, $password, $conn_config);

プライベート IP

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

TCP による接続

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

Python

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

# Remember - storing secrets in plaintext is potentially unsafe. Consider using
# something like https://cloud.google.com/secret-manager/docs/overview to help keep
# secrets secret.
db_user = os.environ["DB_USER"]
db_pass = os.environ["DB_PASS"]
db_name = os.environ["DB_NAME"]
db_host = os.environ["DB_HOST"]

# Extract host and port from db_host
host_args = db_host.split(":")
db_hostname, db_port = host_args[0], int(host_args[1])

pool = sqlalchemy.create_engine(
    # Equivalent URL:
    # mysql+pymysql://<db_user>:<db_pass>@<db_host>:<db_port>/<db_name>
    sqlalchemy.engine.url.URL.create(
        drivername="mysql+pymysql",
        username=db_user,  # e.g. "my-database-user"
        password=db_pass,  # e.g. "my-database-password"
        host=db_hostname,  # e.g. "127.0.0.1"
        port=db_port,  # e.g. 3306
        database=db_name,  # e.g. "my-database-name"
    ),
    **db_config
)

Java

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

注:

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

// Note: For Java users, the Cloud SQL JDBC Socket Factory can provide authenticated connections
// which is preferred to using the Cloud SQL Proxy with Unix sockets.
// See https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory for details.

// 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:mysql:///<DB_NAME>?cloudSqlInstance=<CLOUD_SQL_CONNECTION_NAME>&
// socketFactory=com.google.cloud.sql.mysql.SocketFactory&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:mysql:///%s", DB_NAME));
config.setUsername(DB_USER); // e.g. "root", "mysql"
config.setPassword(DB_PASS); // e.g. "my-password"

config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.mysql.SocketFactory");
config.addDataSourceProperty("cloudSqlInstance", CLOUD_SQL_CONNECTION_NAME);

// The ipTypes argument can be used to specify a comma delimited list of preferred IP types
// for connecting to a Cloud SQL instance. The argument ipTypes=PRIVATE will force the
// SocketFactory to connect with an instance's associated private IP.
config.addDataSourceProperty("ipTypes", "PUBLIC,PRIVATE");

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

// Initialize the connection pool using the configuration object.
DataSource pool = new HikariDataSource(config);

Node.js

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

const createTcpPool = async config => {
  // Extract host and port from socket address
  const dbSocketAddr = process.env.DB_HOST.split(':');

  // Establish a connection to the database
  return await mysql.createPool({
    user: process.env.DB_USER, // e.g. 'my-db-user'
    password: process.env.DB_PASS, // e.g. 'my-db-password'
    database: process.env.DB_NAME, // e.g. 'my-database'
    host: dbSocketAddr[0], // e.g. '127.0.0.1'
    port: dbSocketAddr[1], // e.g. '3306'
    // ... Specify additional properties here.
    ...config,
  });
};

Go

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

var (
	dbUser    = mustGetenv("DB_USER") // e.g. 'my-db-user'
	dbPwd     = mustGetenv("DB_PASS") // e.g. 'my-db-password'
	dbTCPHost = mustGetenv("DB_HOST") // e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
	dbPort    = mustGetenv("DB_PORT") // e.g. '3306'
	dbName    = mustGetenv("DB_NAME") // e.g. 'my-database'
)

var dbURI string
dbURI = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", dbUser, dbPwd, dbTCPHost, dbPort, dbName)

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

// ...

return dbPool, nil

C#

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

            // Equivalent connection string:
            // "Uid=<DB_USER>;Pwd=<DB_PASS>;Host=<DB_HOST>;Database=<DB_NAME>;"
            var connectionString = new MySqlConnectionStringBuilder()
            {
                // The Cloud SQL proxy provides encryption between the proxy and instance.
                SslMode = MySqlSslMode.None,

                // Remember - storing secrets in plain text is potentially unsafe. Consider using
                // something like https://cloud.google.com/secret-manager/docs/overview to help keep
                // secrets secret.
                Server = Environment.GetEnvironmentVariable("DB_HOST"),   // e.g. '127.0.0.1'
                // Set Host to 'cloudsql' when deploying to App Engine Flexible environment
                UserID = 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'
            };
            connectionString.Pooling = true;
            // Specify additional properties here.
            return connectionString;

Ruby

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

development:
  adapter: mysql2
  # Configure additional properties here
  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("DB_HOST") { "127.0.0.1" }%>" # '172.17.0.1' if deployed to GAE Flex
  port: <%= ENV.fetch("DB_PORT") { 3306 }%>
  socket: "<%= ENV.fetch("DB_SOCKET_DIR") { '/cloudsql' } %>/<%= ENV["INSTANCE_CONNECTION_NAME"] %>"

PHP

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

// $username = 'your_db_user';
// $password = 'yoursupersecretpassword';
// $dbName = 'your_db_name';
// $dbHost = "127.0.0.1";

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

// Connect to the database
$conn = new PDO($dsn, $username, $password, $connConfig);

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

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

接続プール

データベース サーバー自体、または基盤となるインフラストラクチャによって、基盤となるデータベースへの接続が切断される可能性があります。これを軽減するには、接続プールと自動再接続をサポートするクライアント ライブラリを使用することをおすすめします。

接続上限

スタンダード環境で実行される App Engine の各インスタンスでは、インスタンスに対する同時接続数が最大 100 個に制限されます。PHP 5.5 アプリケーションについては、同時接続数が最大 60 個に制限されます。この上限はアプリケーション インスタンスごとに適用されます。つまり、App Engine アプリケーションの各インスタンスはデータベースに対してこれだけ多くの接続を保持できるため、スケールするにつれて、デプロイあたりの接続の合計数が増加する可能性があります。詳しくは、要素のスケーリングをご覧ください。

インスタンスごとの最大接続数は、接続プールを使用して制限できます。接続数の制限方法の詳しい例については、データベース接続の管理ページをご覧ください。

App Engine アプリケーションでは、使用状況や環境に応じてリクエストに時間制限が設けられる場合があります。詳しくは、App Engine のスタンダード環境とフレキシブル環境におけるインスタンスの管理方法をご覧ください。

API の割り当て上限

App Engine には、Cloud SQL Admin API を使用する Cloud SQL Auth Proxy を使用して接続する仕組みが用意されています。Cloud SQL Auth Proxy には API 割り当て上限が適用されます。使用される Cloud SQL Admin API の割り当ては、1 度にデプロイされる特定のサービスの App Engine インスタンス数によって構成される Cloud SQL インスタンス数の約 2 倍です。さらに App Engine アプリケーションには、App Engine の割り当てページで説明されている App Engine の割り当てと上限も適用されます。