Conectarse desde el entorno estándar de App Engine

Esta página contiene información y ejemplos para conectarse a una instancia de Cloud SQL desde un servicio que se ejecuta en el entorno estándar de App Engine.

Cloud SQL es un servicio de base de datos completamente administrado que le ayuda a configurar, mantener, administrar y gestionar sus bases de datos relacionales en la nube.

App Engine es una plataforma sin servidor y totalmente administrada para desarrollar y alojar aplicaciones web a gran escala. Puedes elegir entre varios lenguajes, bibliotecas y frameworks populares para desarrollar tus aplicaciones y dejar que App Engine se encargue del aprovisionamiento de servidores y del escalado de las instancias de tus aplicaciones según la demanda.

Configurar una instancia de Cloud SQL

  1. Habilite la API de administración de Cloud SQL en el Google Cloud proyecto desde el que te estás conectando, si aún no lo has hecho:

    Enable the API

  2. Cree una instancia de Cloud SQL para PostgreSQL . Le recomendamos que elija una ubicación de instancia de Cloud SQL en la misma región que su servicio Cloud Run para mejorar la latencia, evitar costos de red y reducir el riesgo de fallos entre regiones.

    De forma predeterminada, Cloud SQL asigna una dirección IP pública a cada nueva instancia. También puede asignar una dirección IP privada. Para obtener más información sobre las opciones de conectividad para ambas instancias, consulte la página "Resumen de la conexión" .

Configurar el entorno estándar de App Engine

Los pasos para configurar el entorno estándar de App Engine dependen del tipo de dirección IP que haya asignado a su instancia de Cloud SQL.

IP pública (predeterminada)

Para configurar el entorno estándar de App Engine a fin de habilitar conexiones a una instancia de Cloud SQL mediante IP pública:

  • Asegúrese de que la instancia tenga una dirección IP pública. Puede verificarlo en la página Descripción general de su instancia en Google Cloud consola . Si necesita agregar una, consulte la página "Configuración de IP pública" para obtener instrucciones.
  • Obtenga el INSTANCE_CONNECTION_NAME de su instancia. Puede encontrar este valor en la página de descripción general de su instancia en Google Cloud consola o ejecutando el siguiente comando gcloud sql instances describe :
    gcloud sql instances describe INSTANCE_NAME
       
    Reemplace INSTANCE_NAME con el nombre de su instancia de Cloud SQL.
  • Reemplace la variable INSTANCE_NAME con el nombre de su instancia.
  • Asegúrese de que la cuenta de servicio que utiliza su aplicación para autenticar llamadas a Cloud SQL tenga el rol de IAM Cloud SQL Client .

    Para obtener instrucciones detalladas sobre cómo agregar roles de IAM a una cuenta de servicio, consulte Otorgar roles a cuentas de servicio .

De forma predeterminada, tu aplicación autorizará tus conexiones mediante una cuenta de servicio de App Engine . La identidad de la cuenta de servicio tiene el formato PROJECT_ID @appspot.gserviceaccount.com .

Si la cuenta de servicio autorizadora pertenece a un proyecto diferente al de la instancia de Cloud SQL, será necesario agregar los permisos de IAM y de la API de administración de Cloud SQL para ambos proyectos.

IP privada

Si la cuenta de servicio autorizadora pertenece a un proyecto diferente al que contiene la instancia de Cloud SQL, haga lo siguiente:

  • En ambos proyectos, habilite la API de administración de Cloud SQL.
  • Para la cuenta de servicio en el proyecto que contiene la instancia de Cloud SQL, agregue los permisos de IAM .
Un conector de acceso a VPC sin servidor utiliza direcciones IP privadas para gestionar la comunicación con su red de VPC. Para conectarse directamente con direcciones IP privadas, debe hacer lo siguiente:
  1. Asegúrese de que la instancia de Cloud SQL creada previamente tenga una dirección IP privada. Si necesita agregar una, consulte Configurar una IP privada para obtener instrucciones.
  2. Cree un conector de acceso a VPC sin servidor en la misma red de VPC que su instancia de Cloud SQL. Tenga en cuenta las siguientes condiciones:
    • A menos que estés usando VPC compartida , tu conector debe estar en el mismo proyecto y región que el recurso que lo usa, pero puede enviar tráfico a recursos en diferentes regiones.
    • El acceso a VPC sin servidor admite la comunicación con redes VPC conectadas mediante Cloud VPN y VPC Network Peering .
    • El acceso a VPC sin servidor no es compatible con redes heredadas .
  3. Configure el entorno estándar de App Engine para usar el conector.
  4. Conéctese utilizando la dirección IP privada de su instancia y el puerto 5432 .

Conectarse a Cloud SQL

Después de configurar el entorno estándar de App Engine, puedes conectarte a tu instancia de Cloud SQL.

IP pública (predeterminada)

Para las rutas de IP públicas, el entorno estándar de App Engine proporciona cifrado y se conecta mediante el proxy de autenticación de Cloud SQL de dos maneras:

IP privada

Para las rutas IP privadas, la aplicación se conecta directamente a la instancia a través de una red VPC. Este método utiliza TCP para conectarse directamente a la instancia de Cloud SQL sin usar el proxy de autenticación de Cloud SQL.

Conectarse con TCP

Conéctese utilizando la dirección IP privada de su instancia de Cloud SQL como host y el puerto 5432 .

Pitón

Para ver este fragmento en el contexto de una aplicación web, consulte el archivo README en GitHub .

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

Para ver este fragmento en el contexto de una aplicación web, consulte el archivo README en GitHub .

Nota:

  • CLOUD_SQL_CONNECTION_NAME debe representarse como <MI-PROYECTO>:<REGIÓN-DE-INSTANCIA>:<NOMBRE-DE-INSTANCIA>
  • El uso del argumento ipTypes=PRIVATE obligará a SocketFactory a conectarse con la IP privada asociada a una instancia
  • Consulte los requisitos de la versión de fábrica del socket JDBC para el archivo pom.xml aquí .


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

Para ver este fragmento en el contexto de una aplicación web, consulte el archivo README en GitHub .

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);
};

Ir

Para ver este fragmento en el contexto de una aplicación web, consulte el archivo README en GitHub .

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
}

DO#

Para ver este fragmento en el contexto de una aplicación web, consulte el archivo README en GitHub .

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;
        }
    }
}

Rubí

Para ver este fragmento en el contexto de una aplicación web, consulte el archivo README en GitHub .

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

Para ver este fragmento en el contexto de una aplicación web, consulte el archivo README en GitHub .

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;
    }
}

Mejores prácticas y otra información

Puedes usar el proxy de autenticación de Cloud SQL al probar tu aplicación localmente. Consulta la guía de inicio rápido para usar el proxy de autenticación de Cloud SQL para obtener instrucciones detalladas.

Grupos de conexiones

Las conexiones a las bases de datos subyacentes pueden perderse, ya sea por el propio servidor de bases de datos o por la infraestructura subyacente. Para mitigar esto, recomendamos usar una biblioteca cliente compatible con grupos de conexiones y reconexión automática.

Límites de conexión

Cada instancia de App Engine que se ejecuta en un entorno estándar no puede tener más de 100 conexiones simultáneas . Para las aplicaciones PHP 5.5, el límite es de 60 conexiones simultáneas . Este límite se aplica por instancia de aplicación. Esto significa que cada instancia de la aplicación de App Engine puede tener esa cantidad de conexiones a la base de datos y, a medida que escala, el número total de conexiones por implementación puede aumentar. Para obtener más información, consulte Escalado de elementos .

Puede limitar el número máximo de conexiones por instancia mediante un grupo de conexiones. Para obtener ejemplos más detallados sobre cómo limitar el número de conexiones, consulte la página "Administrar conexiones de base de datos" .

Las aplicaciones de App Engine están sujetas a límites de tiempo de solicitud según el uso y el entorno. Para obtener más información, consulte cómo se administran las instancias en los entornos estándar y flexibles de App Engine.

Límites de cuota de API

App Engine proporciona un mecanismo que se conecta mediante el proxy de autenticación de Cloud SQL, que utiliza la API de administración de Cloud SQL. Los límites de cuota de la API se aplican al proxy de autenticación de Cloud SQL. Al iniciarse la API de administración de Cloud SQL, utiliza una cuota de dos y, posteriormente, un promedio de dos por hora. La cuota predeterminada es de 180 por minuto por usuario. Las aplicaciones de App Engine también están sujetas a cuotas y límites adicionales, como se explica en la página Cuotas de App Engine .