Se connecter depuis l'environnement flexible App Engine

Cette page contient des informations et des exemples de connexion à une instance Cloud SQL à partir d'un service exécuté dans l'environnement flexible App Engine.

Cloud SQL est un service de base de données entièrement géré qui vous aide à configurer, faire la maintenance, gérer et administrer vos bases de données relationnelles dans le cloud.

App Engine est une plate-forme sans serveur entièrement gérée pour le développement et l'hébergement d'applications Web à grande échelle. Vous pouvez choisir parmi plusieurs langages, bibliothèques et frameworks courants pour développer vos applications, puis laisser App Engine se charger du provisionnement des serveurs et du scaling de vos instances d'applications en fonction de la demande.

Configurer une instance Cloud SQL

  1. Activez l'API Cloud SQL Admin dans le projet Google Cloud à partir duquel vous vous connectez, si ce n'est pas déjà fait :

    Enable the API

  2. Créez une instance Cloud SQL pour MySQL. Nous vous recommandons de choisir un emplacement d'instance Cloud SQL qui soit dans la même région que votre service Cloud Run, afin d'améliorer la latence, d'éviter certains coûts de mise en réseau et de réduire les risques de défaillance interrégionale.

    Par défaut, Cloud SQL attribue une adresse IP publique à une nouvelle instance. Vous avez également la possibilité d'attribuer une adresse IP privée. Pour en savoir plus sur les options de connectivité disponibles pour ces deux types d'adresses IP, consultez la page Présentation du processus de connexion.

Configurer l'environnement flexible App Engine

Les étapes de configuration de l'environnement flexible App Engine dépendent du type d'adresse IP que vous avez attribué à votre instance Cloud SQL.

Adresse IP publique (par défaut)

Pour configurer l'environnement flexible App Engine de manière à activer les connexions à une instance Cloud SQL, procédez comme suit :

  1. Assurez-vous que l'instance dispose d'une adresse IP publique. Vous pouvez le vérifier sur la page Présentation de votre instance dans la console Google Cloud. Si vous devez en ajouter une, consultez la page Configurer une adresse IP publique pour obtenir des instructions.
  2. Obtenez le INSTANCE_CONNECTION_NAME pour votre instance. Vous trouverez cette valeur sur la page Présentation de votre instance dans la console Google Cloud ou en exécutant la commande gcloud sql instances describe suivante:
    gcloud sql instances describe INSTANCE_NAME
       
    Remplacez INSTANCE_NAME par le nom de votre instance Cloud SQL.
  3. Assurez-vous que le compte de service utilisé par votre application pour authentifier les appels vers Cloud SQL dispose des rôles et autorisations Cloud SQL appropriés.
    • Le compte de service de votre service doit disposer de l'un des rôles IAM suivants :
      • Cloud SQL Client (rôle à privilégier)
      • Cloud SQL Editor
      • Cloud SQL Admin
      Vous pouvez également accorder manuellement les deux autorisations IAM suivantes :
      • cloudsql.instances.connect
      • cloudsql.instances.get
      Pour obtenir des instructions détaillées sur l'ajout de rôles IAM à un compte de service, consultez la page Attribuer des rôles aux comptes de service.

    Par défaut, votre application autorise vos connexions à l'aide du compte de service de l'environnement flexible App Engine. Le compte de service est au format PROJECT_ID@appspot.gserviceaccount.com.

    Si le compte de service autorisé appartient à un autre projet que celui de l'instance Cloud SQL, vous devez ajouter l'API Cloud SQL Admin et les autorisations IAM aux deux projets.

  4. Mettez à jour le fichier app.yaml de votre projet avec l'option la plus adaptée. Vous pouvez utiliser une liste d'instances séparées par des virgules pour spécifier plusieurs options à la fois.

    Activer un socket de domaine Unix

    Pour activer un socket de domaine Unix, ajoutez l'un des éléments suivants dans le fichier app.yaml de votre projet, selon que vous vous connectez à une ou plusieurs instances :

    beta_settings:
      cloud_sql_instances: INSTANCE_CONNECTION_NAME
    beta_settings:
      cloud_sql_instances: INSTANCE_CONNECTION_NAME,INSTANCE_CONNECTION_NAME_2,...

    Activer un port TCP

    Pour activer un port TCP local, ajoutez l'un des éléments suivants dans le fichier app.yaml de votre projet, selon que vous vous connectez à une ou plusieurs instances :
    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,...

Adresse IP privée

Pour pouvoir vous connecter à votre instance Cloud SQL via une adresse IP privée, vous devez déployer votre environnement flexible App Engine sur le réseau VPC hébergeant votre instance Cloud SQL. Consultez la documentation sur la configuration des paramètres réseau pour savoir comment spécifier un réseau VPC pour votre déploiement.

Une fois déployée, votre application pourra se connecter directement à l'aide de l'adresse IP privée et du port 3306 de votre instance.

Se connecter à Cloud SQL

Après avoir configuré l'environnement flexible App Engine, vous pouvez vous connecter à votre instance Cloud SQL.

Adresse IP publique (par défaut)

Pour les chemins d'accès des adresses IP publiques, l'environnement flexible App Engine fournit un chiffrement et se connecte à l'aide du proxy d'authentification Cloud SQL de trois manières :

Adresse IP privée

Se connecter avec TCP

Connectez-vous en utilisant l'adresse IP privée de votre instance Cloud SQL en tant qu'hôte et le port 3306.

Python

Pour afficher cet extrait dans le contexte d'une application Web, consultez le fichier README sur GitHub.

import os

import sqlalchemy


def connect_tcp_socket() -> sqlalchemy.engine.base.Engine:
    """Initializes a TCP connection pool for a Cloud SQL instance of MySQL."""
    # 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. 3306

    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,
            password=db_pass,
            host=db_host,
            port=db_port,
            database=db_name,
        ),
        # ...
    )
    return pool

Java

Pour afficher cet extrait dans le contexte d'une application Web, consultez le fichier README sur GitHub.

Remarque :

  • INSTANCE_CONNECTION_NAME doit être représenté au format <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>.
  • L'utilisation de l'argument ipTypes=PRIVATE force la connexion de SocketFactory à l'adresse IP privée associée à une instance.
  • Pour en savoir plus sur les exigences de version Socket Factory des sockets JDBC pour le fichier pom.xml, cliquez ici.


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

public class TcpConnectionPoolFactory extends ConnectionPoolFactory {

  // Saving credentials in environment variables is convenient, but not secure - consider a more
  // secure solution such as 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:mysql://<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:mysql://%s:%s/%s", INSTANCE_HOST, DB_PORT, DB_NAME));
    config.setUsername(DB_USER); // e.g. "root", "mysql"
    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

Pour afficher cet extrait dans le contexte d'une application Web, consultez le fichier README sur GitHub.

const mysql = require('promise-mysql');
const fs = require('fs');

// createTcpPool initializes a TCP connection pool for a Cloud SQL
// instance of MySQL.
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 = {
    host: process.env.INSTANCE_HOST, // e.g. '127.0.0.1'
    port: process.env.DB_PORT, // e.g. '3306'
    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'
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return mysql.createPool(dbConfig);
};

Go

Pour afficher cet extrait dans le contexte d'une application Web, consultez le fichier README sur GitHub.

package cloudsql

import (
	"crypto/tls"
	"crypto/x509"
	"database/sql"
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/go-sql-driver/mysql"
)

// connectTCPSocket initializes a TCP connection pool for a Cloud SQL
// instance of MySQL.
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'
		dbName    = mustGetenv("DB_NAME")       // e.g. 'my-database'
		dbPort    = mustGetenv("DB_PORT")       // e.g. '3306'
		dbTCPHost = mustGetenv("INSTANCE_HOST") // e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
	)

	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: %w", err)
	}

	// ...

	return dbPool, nil
}

C#

Pour afficher cet extrait dans le contexte d'une application Web, consultez le fichier README sur GitHub.

using MySql.Data.MySqlClient;
using System;

namespace CloudSql
{
    public class MySqlTcp
    {
        public static MySqlConnectionStringBuilder NewMysqlTCPConnectionString()
        {
            // Equivalent connection string:
            // "Uid=<DB_USER>;Pwd=<DB_PASS>;Host=<INSTANCE_HOST>;Database=<DB_NAME>;"
            var connectionString = new MySqlConnectionStringBuilder()
            {
                // 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.
                Server = Environment.GetEnvironmentVariable("INSTANCE_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'

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

        }
    }
}

Ruby

Pour afficher cet extrait dans le contexte d'une application Web, consultez le fichier README sur GitHub.

tcp: &tcp
  adapter: mysql2
  # 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") { 3306 }%>

PHP

Pour afficher cet extrait dans le contexte d'une application Web, consultez le fichier README sur GitHub.

namespace Google\Cloud\Samples\CloudSQL\MySQL;

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('mysql: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/mysql/connect-external-app',
                    $e->getMessage()
                ),
                $e->getCode(),
                $e
            );
        }

        return $conn;
    }
}

Bonnes pratiques et autres informations

Vous pouvez utiliser le proxy d'authentification Cloud SQL lorsque vous testez votre application en local. Pour obtenir des instructions détaillées, consultez le guide de démarrage rapide pour l'utilisation du proxy d'authentification Cloud SQL.

Pools de connexions

Les connexions aux bases de données sous-jacentes peuvent être supprimées, soit par le serveur de base de données lui-même, soit par l'infrastructure sous-jacente. Pour éviter cela, nous vous recommandons d'utiliser une bibliothèque cliente compatible avec les pools de connexions et la reconnexion automatique.

Limites de connexion

Chaque instance App Engine exécutée dans un environnement standard ne peut pas avoir plus de 100 connexions simultanées à une instance. Pour les applications en PHP 5.5, la limite est de 60 connexions simultanées. Cette limite s'applique à chaque instance d'application. Cela signifie que chaque instance de l'application App Engine peut posséder autant de connexions à la base de données et que le nombre total de connexions par déploiement peut augmenter. Pour plus d'informations, consultez la section Éléments de scaling.

Toutefois, vous avez la possibilité de limiter le nombre maximal de connexions par instance en utilisant un pool de connexions. Pour obtenir des exemples plus détaillés sur les techniques de limitation du nombre de connexions, consultez la page Gérer les connexions à la base de données.

Les applications App Engine sont soumises à des délais de requêtes selon l'utilisation et l'environnement. Pour en savoir plus, découvrez comment les instances sont gérées dans les environnements standard et flexible d'App Engine.

Limites de quota d'API

App Engine fournit un mécanisme permettant de se connecter à l'aide du proxy d'authentification Cloud SQL, qui utilise l'API Cloud SQL Admin. Les limites de quota d'API s'appliquent au proxy d'authentification Cloud SQL. Lorsque l'API Cloud SQL Admin démarre, elle utilise un quota de deux et une moyenne de deux par heure ensuite. Le quota par défaut est de 180 par minute et par utilisateur. Les applications App Engine sont également soumises à d'autres quotas et limites, comme indiqué sur la page Quotas d'App Engine.