חיבור מסביבה רגילה של App Engine

בדף הזה מופיעים מידע ודוגמאות להתחברות למכונה של Cloud SQL משירות שפועל בסביבת ברירת המחדל ב-App Engine.

‫Cloud SQL הוא שירות מנוהל של מסד נתונים, שבעזרתו אפשר ליצור, לתחזק ולנהל מסדי נתונים רלציוניים בענן.

‫App Engine היא פלטפורמה מנוהלת ללא שרת (serverless) לפיתוח ולאירוח של אפליקציות אינטרנט בקנה מידה נרחב. אתם יכולים לבחור מבין כמה שפות, ספריות וסביבות פיתוח פופולריות כדי לפתח את האפליקציות שלכם, ואז לתת ל-App Engine לטפל בהקצאת השרתים ובהתאמה לעומס (scaling) של המכונות של האפליקציה לפי הצורך.

הגדרת מכונה של Cloud SQL

  1. מפעילים את Cloud SQL Admin API בפרויקט ב- Google Cloud שממנו מתחברים, אם עדיין לא עשיתם את זה:

    התפקידים שנדרשים כדי להפעיל ממשקי API

    כדי להפעיל ממשקי API, צריך את ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים

    להפעלת ה-API

  2. יוצרים מכונה של Cloud SQL ל-SQL Server. כדי לשפר את זמן האחזור, להימנע מעלויות מסוימות של רשתות ולהפחית את הסיכונים לכשלים בין אזורים, מומלץ לבחור מיקום למכונה של Cloud SQL באותו אזור שבו נמצא השירות של סביבת ברירת המחדל ב-App Engine.

    כברירת מחדל, Cloud SQL מקצה כתובת IP ציבורית למכונה חדשה. אפשר גם להקצות כתובת IP פרטית. למידע נוסף על אפשרויות הקישוריות של שניהם, קראו את הדף סקירה כללית על התחברות.

  3. כשיוצרים את המכונה, אפשר לבחור את ההיררכיה של אישור השרת (CA) של המכונה, ואז להגדיר את ההיררכיה בתור serverCaMode של המכונה. כדי להתחבר למכונות מאפליקציות אינטרנט בסביבת ברירת המחדל ב-App Engine, צריך לבחור באפשרות של רשות אישורים לכל מכונה (GOOGLE_MANAGED_INTERNAL_CA) כמצב רשות האישורים של השרת.

הגדרת סביבת ברירת המחדל ב-App Engine

השלבים להגדרת סביבת ברירת המחדל ב-App Engine משתנים בהתאם לסוג כתובת ה-IP שהקציתם למכונה של Cloud SQL.

כתובת IP ציבורית (ברירת מחדל)

בסביבת ברירת המחדל ב-App Engine אפשר להתחבר ל-Cloud SQL ל-SQL Server באמצעות כתובת IP ציבורית, בעזרת המחברים של Go,‏ Java ו-Python.

כדי להגדיר את סביבת ברירת המחדל ב-App Engine כך שתאפשר חיבורים למכונה של Cloud SQL באמצעות כתובת IP ציבורית:
  • מוודאים שלמכונה יש כתובת IP ציבורית. אפשר לוודא את זה בדף Overview של המכונה במסוףGoogle Cloud . אם צריך להוסיף כתובת IP, אפשר להיעזר בהוראות שבדף הגדרת כתובת IP ציבורית.
  • משיגים את INSTANCE_CONNECTION_NAME של המכונה. אפשר למצוא את הערך הזה בדף Overview של המכונה במסוףGoogle Cloud , או על ידי הרצת הפקודה הבאה של gcloud sql instances describe:
    ‫
    gcloud sql instances describe INSTANCE_NAME
       
    מחליפים את INSTANCE_NAME בשם של המכונה ב-Cloud SQL.
  • מחליפים את המשתנה INSTANCE_NAME בשם של המכונה.
  • מוודאים שלחשבון השירות שבו האפליקציה משתמשת כדי לאמת קריאות ל-Cloud SQL יש את תפקיד ה-IAM Cloud SQL Client.

    הוראות מפורטות להוספת תפקידי IAM לחשבון שירות מופיעות במאמר הקצאת תפקידים לחשבונות שירות.

חשבון השירות של App Engine שמוגדר כברירת מחדל נוצר באופן אוטומטי כשמשתמשים ב-App Engine. הזהות של חשבון השירות היא בפורמט PROJECT_ID@.

אם חשבון השירות שנותן את ההרשאה שייך לפרויקט אחר מזה של המכונה של Cloud SQL, צריך להוסיף את Cloud SQL Admin API ואת הרשאות ה-IAM לשני הפרויקטים.

כתובת IP פרטית

אם חשבון השירות המאשר שייך לפרויקט אחר מזה שמכיל את המכונה של Cloud SQL, מבצעים את הפעולות הבאות:

  • מפעילים את Cloud SQL Admin API בשני הפרויקטים.
  • מוסיפים את הרשאות ה-IAM לחשבון השירות בפרויקט שמכיל את המכונה של Cloud SQL.
המחבר של חיבור לרשת (VPC) מאפליקציית serverless משתמש בכתובות IP פרטיות כדי לטפל בתקשורת עם רשת ה-VPC. כדי להתחבר ישירות לכתובות IP פרטיות, צריך:
  1. מוודאים שלמכונה של Cloud SQL שיצרתם קודם יש כתובת IP פרטית. אם אתם צריכים להוסיף כתובת IP פרטית, תוכלו להיעזר בהוראות שבמאמר הגדרת כתובת IP פרטית.
  2. יוצרים מחבר של גישה ל-VPC ללא שרת (Serverless) באותה רשת VPC שבה נמצאת המכונה של Cloud SQL. שימו לב לתנאים הבאים:
    • אם אתם לא משתמשים ב- VPC משותף, המחבר צריך להיות באותו פרויקט ובאותו אזור כמו המשאב שמשתמש בו, אבל הוא יכול לשלוח תנועה למשאבים באזורים שונים.
    • חיבור לרשת (VPC) מאפליקציית serverless תומך בתקשורת עם רשתות VPC שמחוברות באמצעות Cloud VPN וקישור בין רשתות VPC שכנות (peering).
    • אי אפשר להשתמש בחיבור לרשת (VPC) מאפליקציית serverless ברשתות מדור קודם.
  3. מגדירים את סביבת ברירת המחדל ב-App Engine כך שתשתמש במחבר.
  4. מתחברים באמצעות כתובת ה-IP הפרטית של המכונה ויציאה 1433.

התחברות ל-Cloud SQL

אחרי שמגדירים את סביבת ברירת המחדל ב-App Engine, אפשר להתחבר למכונה של Cloud SQL.

כתובת IP ציבורית (ברירת מחדל)

בנתיבים של כתובות IP ציבוריות, סביבת ברירת המחדל ב-App Engine מספקת הצפנה ומתחברת באמצעות המחברים של Cloud SQL.

התחברות באמצעות מחברים של Cloud SQL

המחברים של Cloud SQL הם ספריות ספציפיות לשפה שמספקות הצפנה והרשאה שמבוססת על IAM כשמתחברים למכונה של Cloud SQL.

Python

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

import os

from google.cloud.sql.connector import Connector, IPTypes
import pytds

import sqlalchemy


def connect_with_connector() -> sqlalchemy.engine.base.Engine:
    """
    Initializes a connection pool for a Cloud SQL instance of SQL Server.

    Uses the Cloud SQL Python Connector package.
    """
    # 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.

    instance_connection_name = os.environ[
        "INSTANCE_CONNECTION_NAME"
    ]  # e.g. 'project:region:instance'
    db_user = os.environ.get("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'

    ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

    # initialize Cloud SQL Python Connector object
    connector = Connector(ip_type=ip_type, refresh_strategy="LAZY")

    connect_args = {}
    # If your SQL Server instance requires SSL, you need to download the CA
    # certificate for your instance and include cafile={path to downloaded
    # certificate} and validate_host=False. This is a workaround for a known issue.
    if os.environ.get("DB_ROOT_CERT"):  # e.g. '/path/to/my/server-ca.pem'
        connect_args = {
            "cafile": os.environ["DB_ROOT_CERT"],
            "validate_host": False,
        }

    def getconn() -> pytds.Connection:
        conn = connector.connect(
            instance_connection_name,
            "pytds",
            user=db_user,
            password=db_pass,
            db=db_name,
            **connect_args
        )
        return conn

    pool = sqlalchemy.create_engine(
        "mssql+pytds://",
        creator=getconn,
        # ...
    )
    return pool

Java

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

הערה:

  • הערך של CLOUD_SQL_CONNECTION_NAME צריך להיות מיוצג בתור <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>
  • כאן מפורטות הדרישות של גרסת ה-socket factory של JDBC לקובץ pom.xml.


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

public class ConnectorConnectionPoolFactory 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 INSTANCE_CONNECTION_NAME =
      System.getenv("INSTANCE_CONNECTION_NAME");
  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");

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

    // The following is equivalent to setting the config options below:
    // jdbc:sqlserver://;user=<DB_USER>;password=<DB_PASS>;databaseName=<DB_NAME>;
    // socketFactoryClass=com.google.cloud.sql.sqlserver.SocketFactory;
    // socketFactoryConstructorArg=<INSTANCE_CONNECTION_NAME>

    // 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
        .setDataSourceClassName("com.microsoft.sqlserver.jdbc.SQLServerDataSource");
    config.setUsername(DB_USER); // e.g. "root", "sqlserver"
    config.setPassword(DB_PASS); // e.g. "my-password"
    config.addDataSourceProperty("databaseName", DB_NAME);

    config.addDataSourceProperty("socketFactoryClass",
        "com.google.cloud.sql.sqlserver.SocketFactory");
    config.addDataSourceProperty("socketFactoryConstructorArg", INSTANCE_CONNECTION_NAME);

    // The Java Connector provides SSL encryption, so it should be disabled
    // at the driver level.
    config.addDataSourceProperty("encrypt", "false");

    // cloudSqlRefreshStrategy set to "lazy" is used to perform a
    // refresh when needed, rather than on a scheduled interval.
    // This is recommended for serverless environments to
    // avoid background refreshes from throttling CPU.
    config.addDataSourceProperty("cloudSqlRefreshStrategy", "lazy");

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

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

המשך

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

package cloudsql

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

	"cloud.google.com/go/cloudsqlconn"
	mssql "github.com/denisenkom/go-mssqldb"
)

type csqlDialer struct {
	dialer     *cloudsqlconn.Dialer
	connName   string
	usePrivate bool
}

// DialContext adheres to the mssql.Dialer interface.
func (c *csqlDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
	var opts []cloudsqlconn.DialOption
	if c.usePrivate {
		opts = append(opts, cloudsqlconn.WithPrivateIP())
	}
	return c.dialer.Dial(ctx, c.connName, opts...)
}

func connectWithConnector() (*sql.DB, error) {
	mustGetenv := func(k string) string {
		v := os.Getenv(k)
		if v == "" {
			log.Fatalf("Fatal Error in connect_connector.go: %s environment variable not set.\n", 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'
		instanceConnectionName = mustGetenv("INSTANCE_CONNECTION_NAME") // e.g. 'project:region:instance'
		usePrivate             = os.Getenv("PRIVATE_IP")
	)

	dbURI := fmt.Sprintf("user id=%s;password=%s;database=%s;", dbUser, dbPwd, dbName)
	c, err := mssql.NewConnector(dbURI)
	if err != nil {
		return nil, fmt.Errorf("mssql.NewConnector: %w", err)
	}
	// WithLazyRefresh() Option is used to perform refresh
	// when needed, rather than on a scheduled interval.
	// This is recommended for serverless environments to
	// avoid background refreshes from throttling CPU.
	dialer, err := cloudsqlconn.NewDialer(context.Background(), cloudsqlconn.WithLazyRefresh())
	if err != nil {
		return nil, fmt.Errorf("cloudsqlconn.NewDailer: %w", err)
	}
	c.Dialer = &csqlDialer{
		dialer:     dialer,
		connName:   instanceConnectionName,
		usePrivate: usePrivate != "",
	}

	dbPool := sql.OpenDB(c)
	if err != nil {
		return nil, fmt.Errorf("sql.Open: %w", err)
	}
	return dbPool, nil
}

Node.js

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

const {Connection} = require('tedious');
const {Connector} = require('@google-cloud/cloud-sql-connector');

// In case the PRIVATE_IP environment variable is defined then we set
// the ipType=PRIVATE for the new connector instance, otherwise defaults
// to public ip type.
const getIpType = () =>
  process.env.PRIVATE_IP === '1' || process.env.PRIVATE_IP === 'true'
    ? 'PRIVATE'
    : 'PUBLIC';

// connectWithConnector initializes a TCP connection
// to a Cloud SQL instance of SQL Server.
const connectWithConnector = 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 connector = new Connector();
  const clientOpts = await connector.getTediousOptions({
    instanceConnectionName: process.env.INSTANCE_CONNECTION_NAME,
    ipType: getIpType(),
  });
  const dbConfig = {
    // Please note that the `server` property here is not used and is only
    // defined due to a bug in the tedious driver
    // (ref: https://github.com/tediousjs/tedious/issues/1541)
    // With that in mind, do not try to change this value since it will have no
    // impact in how the connector works, this sample will be updated to remove
    // this property declaration as soon as the tedious driver bug is fixed
    server: '0.0.0.0', // e.g. '127.0.0.1'
    authentication: {
      type: 'default',
      options: {
        userName: process.env.DB_USER, // e.g. 'my-db-user'
        password: process.env.DB_PASS, // e.g. 'my-db-password'
      },
    },
    options: {
      ...clientOpts,
      // Please note that the `port` property here is not used and is only
      // defined due to a bug in the tedious driver
      // (ref: https://github.com/tediousjs/tedious/issues/1541)
      // With that in mind, do not try to change this value since it will have
      // no impact in how the connector works, this sample will be updated to
      // remove this property declaration as soon as the tedious driver bug is
      // fixed
      port: 9999,
      database: process.env.DB_NAME, // e.g. 'my-database'
      useColumnNames: true,
    },
    // ... Specify additional properties here.
    ...config,
  };

  // Establish a connection to the database.
  return new Connection(dbConfig);
};

כתובת IP פרטית

בנתיבים של כתובות IP פרטיות, האפליקציה מתחברת ישירות למכונה דרך רשת VPC. בשיטה הזו משתמשים ב-TCP כדי להתחבר ישירות למכונה של Cloud SQL בלי להשתמש ב-Cloud SQL Auth Proxy.

התחברות באמצעות TCP

מתחברים באמצעות כתובת ה-IP הפרטית של מכונת Cloud SQL כמארח וליציאה 1433.

Python

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

import os

import sqlalchemy


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

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

    return pool

Java

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

הערה:

  • הערך של CLOUD_SQL_CONNECTION_NAME צריך להיות מיוצג בתור <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>
  • השימוש בארגומנט ipTypes=PRIVATE יאלץ את SocketFactory להתחבר לכתובת ה-IP הפרטית שמשויכת למכונה
  • דרישות הגרסה של JDBC socket factory לקובץ pom.xml


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

    // Configure which instance and what database user to connect with.
    config.setJdbcUrl(
        String.format("jdbc:sqlserver://%s:%s;databaseName=%s", INSTANCE_HOST, DB_PORT, DB_NAME));
    config.setUsername(DB_USER); // e.g. "root", "sqlserver"
    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

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

const mssql = require('mssql');

// createTcpPool initializes a TCP connection pool for a Cloud SQL
// instance of SQL Server.
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 = {
    server: process.env.INSTANCE_HOST, // e.g. '127.0.0.1'
    port: parseInt(process.env.DB_PORT), // e.g. 1433
    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'
    options: {
      trustServerCertificate: true,
    },
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return mssql.connect(dbConfig);
};

המשך

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

package cloudsql

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

	_ "github.com/denisenkom/go-mssqldb"
)

// connectTCPSocket initializes a TCP connection pool for a Cloud SQL
// instance of SQL Server.
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.\n", 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. '1433'
		dbName    = mustGetenv("DB_NAME")       // e.g. 'my-database'
	)

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


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

	// ...

	return dbPool, nil
}

C#‎

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

using Microsoft.Data.SqlClient;
using System;

namespace CloudSql
{
    public class SqlServerTcp
    {
        public static SqlConnectionStringBuilder NewSqlServerTCPConnectionString()
        {
            // Equivalent connection string:
            // "User Id=<DB_USER>;Password=<DB_PASS>;Server=<INSTANCE_HOST>;Database=<DB_NAME>;"
            var connectionString = new SqlConnectionStringBuilder()
            {
                // 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.
                DataSource = 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'
                InitialCatalog = Environment.GetEnvironmentVariable("DB_NAME"), // e.g. 'my-database'

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

Ruby

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

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

PHP

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין ב-README ב-GitHub.

namespace Google\Cloud\Samples\CloudSQL\SQLServer;

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(
                'sqlsrv:server=%s;Database=%s',
                $instanceHost,
                $dbName
            );

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

        return $conn;
    }
}

שיטות מומלצות ומידע נוסף

אתם יכולים להשתמש ב-Cloud SQL Auth Proxy כשאתם בודקים את האפליקציה באופן מקומי. הוראות מפורטות מופיעות במאמר התחלה מהירה: שימוש ב-Cloud SQL Auth Proxy.

מאגרי חיבורים

יכול להיות שהחיבורים למסדי הנתונים הבסיסיים ינותקו, על ידי שרת מסד הנתונים עצמו או על ידי התשתית הבסיסית. כדי לצמצם את הבעיה, מומלץ להשתמש בספריית לקוח שתומכת במאגרי חיבורים ובחיבור מחדש באופן אוטומטי.

מגבלות על החיבורים

לכל מכונה של App Engine שפועלת בסביבה סטנדרטית יכולים להיות עד 100 חיבורים בו-זמניים למכונה. באפליקציות PHP 5.5, המגבלה היא 60 חיבורים בו-זמניים. המגבלה הזו חלה על כל מופע של אפליקציה. כלומר, לכל מכונה של אפליקציית App Engine יכול להיות מספר כזה של חיבורים למסד הנתונים, וככל שהיא תתרחב, המספר הכולל של החיבורים לכל פריסה יכול לגדול. מידע נוסף זמין במאמר שינוי קנה מידה של רכיבים.

אתם יכולים להגביל את מספר החיבורים המקסימלי לכל מכונה באמצעות מאגר חיבורים. דוגמאות מפורטות יותר להגבלת מספר החיבורים מופיעות בדף ניהול החיבורים למסד הנתונים.

באפליקציות של App Engine יש מגבלות זמן על בקשות, בהתאם לשימוש ולסביבה. מידע נוסף זמין במאמרים על ניהול מכונות בסביבת ברירת המחדל ב-App Engine standard ובסביבה הגמישה.

מגבלות המכסות של ה-API

ב-App Engine יש מנגנון שמתחבר באמצעות Cloud SQL Auth Proxy, שמשתמש ב-Cloud SQL Admin API. מגבלות המכסות של ה-API חלות על Cloud SQL Auth Proxy. כשמפעילים את Cloud SQL Admin API, הוא משתמש במכסה של שתי בקשות, ואחר כך בממוצע של שתי בקשות לשעה. מכסת ברירת המחדל היא 180 לדקה לכל משתמש. אפליקציות של App Engine כפופות גם למכסות ולמגבלות נוספות, כמו שמפורט בדף מכסות של App Engine.