התחברות מפונקציות Cloud Run

בדף הזה מופיעים מידע ודוגמאות להתחברות למופע Cloud SQL משירות שפועל בפונקציות Cloud Run.

הוראות מפורטות להפעלת אפליקציית אינטרנט לדוגמה של פונקציות Cloud Run שמחוברת ל-Cloud SQL זמינות במדריך למתחילים בנושא התחברות מפונקציות Cloud Run.

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

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

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

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

    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 ל-MySQL. מומלץ לבחור מיקום של מופע Cloud SQL באותו אזור שבו נמצא שירות Cloud Run, כדי לשפר את זמן האחזור, להימנע מחלק מהעלויות של הרשת ולהפחית את הסיכון לכשלים חוצי-אזורים.

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

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

הגדרת פונקציות Cloud Run

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

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

כדי להגדיר פונקציות Cloud Run כדי לאפשר חיבורים למופע Cloud SQL:

  • מוודאים שלמופע שנוצר למעלה יש כתובת IP ציבורית. אפשר לאשר זאת בדף Overview של המופע במסוףGoogle Cloud . אם אתם צריכים להוסיף כתובת IP ציבורית, תוכלו לעיין במאמר בנושא הגדרת כתובת IP ציבורית.
  • מקבלים את INSTANCE_CONNECTION_NAME של המופע. הערך הזה זמין:
    • בדף Overview של המופע, במסוףGoogle Cloud , או
    • מריצים את הפקודה הבאה: gcloud sql instances describe [INSTANCE_NAME]
  • מגדירים את חשבון השירות לפונקציה. אם חשבון השירות שנותן את ההרשאה שייך לפרויקט אחר מהמכונה של Cloud SQL, צריך להפעיל את Cloud SQL Admin API ולהוסיף את Cloud SQL Client תפקיד ה-IAM לשני הפרויקטים.
  • מוודאים שלחשבון השירות יש את התפקיד הזה כדי שהחשבון יוכל להתחבר ל-Cloud SQL.
  • אם אתם משתמשים ב פונקציות Cloud Run ולא בפונקציות Cloud Run (דור ראשון), אתם צריכים את ההגדרות הבאות (אפשר גם לעיין במאמר בנושא הגדרת Cloud Run):
    1. פורסים את הפונקציה.
      כשמתחילים ליצור פונקציה ב-Cloud Run במסוף Google Cloud , שירות Cloud Run הבסיסי עוד לא נוצר. אי אפשר להגדיר חיבור ל-Cloud SQL עד שהשירות הזה נוצר (על ידי פריסת פונקציית Cloud Run).
    2. במסוף Google Cloud , בפינה הימנית העליונה של הדף Function details (פרטי הפונקציה), בקטע Powered by Cloud Run (מופעל על ידי Cloud Run), לוחצים על הקישור כדי לגשת לשירות Cloud Run הבסיסי.
    3. בדף Service details של Cloud Run, בוחרים בכרטיסייה Edit and deploy new revision.
    4. פועלים לפי השלבים הרגילים (כמו בכל שינוי בהגדרות) כדי להגדיר הגדרה חדשה לחיבור Cloud SQL.
      הפעולה הזו יוצרת גרסה חדשה של Cloud Run, וגרסאות עוקבות מקבלות באופן אוטומטי את החיבור הזה ל-Cloud SQL, אלא אם משנים אותו באופן מפורש.

כתובת 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. הגדרת פונקציות Cloud Run לשימוש במחבר.
  4. מתחברים באמצעות כתובת ה-IP הפרטית והיציאה של המופע 3306.

התחברות ל-Cloud SQL

אחרי שמגדירים את פונקציות Cloud Run, אפשר להתחבר למופע Cloud SQL.

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

בנתיבי IP ציבוריים, אפשר להגדיר פונקציות Cloud Run לשימוש בשרת proxy ל-Cloud SQL Auth להצפנה בשתי דרכים:

כתובת IP פרטית

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

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

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

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

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

הערה:


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

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

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

PHP

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

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

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

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

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

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

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

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

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

מגבלות מכסת API

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

המאמרים הבאים