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

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

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

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

הגדרת מופע של Cloud SQL

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

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

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

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

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

הגדרת סביבה רגילה של App Engine

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

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

כדי להגדיר את סביבת App Engine standard כך שתאפשר חיבורים למופע Cloud SQL באמצעות כתובת IP ציבורית:

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

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

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

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

כתובת IP פרטית

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

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

התחברות ל-Cloud SQL

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

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

בנתיבי IP ציבוריים, אפשר להגדיר את סביבת App Engine Standard כך שתשתמש בשרת ה-proxy של Cloud SQL Auth להצפנה בשתי דרכים:

כתובת IP פרטית

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

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

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

Python

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין בקובץ ה-README ב-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

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

הערה:


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

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין בקובץ ה-README ב-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);
};

Go

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין בקובץ ה-README ב-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
}

C#‎

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין בקובץ ה-README ב-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;
        }
    }
}

Ruby

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין בקובץ ה-README ב-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

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, אפשר לעיין בקובץ ה-README ב-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;
    }
}

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

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

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

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

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

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

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

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

מגבלות מכסת API

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