从 App Engine 柔性环境连接到 Cloud SQL

本页介绍从 App Engine 柔性环境中运行的服务连接到 Cloud SQL 实例的相关信息和示例。

Cloud SQL 是一项全代管式数据库服务,可帮助您在云端设置、维护、管理和控制关系型数据库。

App Engine 是全代管式无服务器平台,可用于大规模开发和托管 Web 应用。您可以选择多种主流的语言、库和框架来开发应用,然后让 App Engine 为您预配服务器并根据需求扩缩应用实例数量。

设置 Cloud SQL 实例

  1. 在您要从中进行连接的项目中启用 Cloud SQL API(如果您尚未执行此操作):

    启用 API

  2. 创建一个 Cloud SQL for PostgreSQL 实例

    默认情况下,Cloud SQL 会为新实例分配公共 IP 地址。您还可以选择分配专用 IP 地址。如需详细了解这两种地址的连接选项,请参阅 连接概览页面。

配置 App Engine 柔性环境

App Engine 柔性环境的配置步骤取决于您分配给 Cloud SQL 实例的 IP 地址类型。

公共 IP(默认)

要配置 App Engine 柔性环境以启用与 Cloud SQL 实例的连接,请执行以下操作:

  1. 确保上面创建的实例具有公共 IP 地址。您可以在 Google Cloud Console 中的实例概览页面验证这一点。如果您需要添加 IP 地址,请参阅配置公共 IP 页面来查看相关说明。
  2. 获取实例的 INSTANCE_CONNECTION_NAME。您可以在 Google Cloud Console 中的实例概览页面上找到它,也可以通过运行命令 gcloud sql instances describe [INSTANCE_NAME] 来获取。
  3. 确保您的应用用于对 Cloud SQL 调用进行身份验证的服务帐号具有适当的 Cloud SQL 角色和权限
    • 您的服务的服务帐号需要以下某个 IAM 角色
      • Cloud SQL Client(首选)
      • Cloud SQL Editor
      • Cloud SQL Admin
      或者,您可以手动分配以下两个 IAM 权限:
      • cloudsql.instances.connect
      • cloudsql.instances.get
      如需详细了解如何将 IAM 角色添加到服务帐号,请参阅向服务帐号授予角色

    默认情况下,应用将使用 App Engine 柔性环境服务帐号向您的连接授权。服务帐号的格式为 PROJECT_ID@appspot.gserviceaccount.com

    如果授权服务帐号与 Cloud SQL 实例分处不同的项目,则需要为这两个项目添加 Cloud SQL Admin API 和 IAM 权限。

  4. 使用最适用的选项更新项目的 app.yaml 文件。 您可以使用以英文逗号分隔的实例列表来同时指定多个选项。

    启用 Unix 网域套接字

    如需启用 Unix 网域套接字,请将以下其中一项添加到项目的 app.yaml 文件中,具体取决于您是要连接到一个还是多个实例:

    beta_settings:
      cloud_sql_instances: INSTANCE_CONNECTION_NAME
    

    beta_settings:
      cloud_sql_instances: INSTANCE_CONNECTION_NAME,INSTANCE_CONNECTION_NAME_2,...
    

    启用 TCP 端口

    如需启用本地 TCP 端口,请将以下其中一项添加到项目的 app.yaml 文件中,具体取决于您是要连接到一个还是多个实例:

    beta_settings:
      cloud_sql_instances: INSTANCE_CONNECTION_NAME=tcp:PORT
    

    beta_settings:
      cloud_sql_instances: INSTANCE_CONNECTION_NAME_1=tcp:PORT_1,INSTANCE_CONNECTION_NAME_2=tcp:PORT_2,...
    

专用 IP

为了通过专用 IP 地址连接到您的 Cloud SQL 实例,App Engine 柔性环境部署必须与您的 Cloud SQL 实例位于同一 VPC 网络中。如需了解如何为您的部署指定 VPC 网络,请参阅配置文档中有关网络设置的内容。

部署后,您的应用将能够使用实例的专用 IP 地址和端口 5432 直接连接。

连接到 Cloud SQL

配置 App Engine 柔性环境后,您可以连接到 Cloud SQL 实例。

公共 IP(默认)

对于公共 IP 路径,App Engine 柔性环境提供了加密功能,并通过 Unix 套接字使用 Cloud SQL Auth 代理进行连接。

专用 IP

使用 TCP 连接

直接使用您实例的专用 IP 地址和端口 5432 进行连接。

Python

如需了解 Web 应用环境下的此代码段,请查看 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:
    # postgresql+pg8000://<db_user>:<db_pass>@<db_host>:<db_port>/<db_name>
    sqlalchemy.engine.url.URL.create(
        drivername="postgresql+pg8000",
        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. 5432
        database=db_name  # e.g. "my-database-name"
    ),
    **db_config
)

Java

如需了解 Web 应用环境下的此代码段,请查看 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:postgresql:///<DB_NAME>?cloudSqlInstance=<CLOUD_SQL_CONNECTION_NAME>&
// socketFactory=com.google.cloud.sql.postgres.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:postgresql:///%s", DB_NAME));
config.setUsername(DB_USER); // e.g. "root", "postgres"
config.setPassword(DB_PASS); // e.g. "my-password"

config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.postgres.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

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

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

  // Establish a connection to the database
  return Knex({
    client: 'pg',
    connection: {
      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'
      host: dbSocketAddr[0], // e.g. '127.0.0.1'
      port: dbSocketAddr[1], // e.g. '5432'
    },
    // ... Specify additional properties here.
    ...config,
  });
};

Go

如需了解 Web 应用环境下的此代码段,请查看 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. '5432'
	dbName    = mustGetenv("DB_NAME") // e.g. 'my-database'
)

var dbURI string
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: %v", err)
}

// ...

return dbPool, nil

C#

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

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

                // 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.
                Host = Environment.GetEnvironmentVariable("DB_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'
            };
            connectionString.Pooling = true;
            // Specify additional properties here.
            return connectionString;

Ruby

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

development:
  adapter: postgresql
  # 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")  { 5432 }%>

PHP

如需了解 Web 应用环境下的此代码段,请查看 GitHub 上的 README

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

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

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

最佳做法和其他信息

在本地测试应用时,您可以使用 Cloud SQL Auth 代理。如需了解详细说明,请参阅快速入门:使用 Cloud SQL Auth 代理

连接池

与底层数据库的连接可能会被数据库服务器本身或底层基础架构断开。为了缓解此问题,我们建议您使用支持连接池和自动重新连接的客户端库。

连接限制

每个在标准环境中运行的 App Engine 实例与其他实例的并发连接数不能超过 100 个。对于 PHP 5.5 应用,并发连接数上限为 60 个。 此限制适用于单个应用实例。这意味着 App Engine 应用的每个实例都可以与数据库建立这么多连接,并且在扩容时,每个部署的连接总数可以随之增加。如需了解详情,请参阅扩缩元素

您可以使用连接池来限制每个实例使用的最大连接数。如需查看有关如何限制连接数的详细示例,请参阅管理数据库连接页面。

App Engine 应用受请求时间限制的约束,具体取决于使用情况和环境。如需了解详情,请参阅实例在 App Engine 标准环境标准柔性环境中的管理方式。

API 配额限制

App Engine 提供了一种使用 Cloud SQL Auth 代理进行连接的机制,该代理使用 Cloud SQL API。API 配额限制适用于 Cloud SQL Auth 代理。 使用的 Cloud SQL Admin API 配额大约是任何一次部署的特定服务的 App Engine 实例数所配置 Cloud SQL 实例数的两倍。App Engine 应用还受 App Engine 配额页面上所述的其他配额和限制的约束。