Terhubung dari lingkungan standar App Engine

Halaman ini berisi informasi dan contoh untuk menghubungkan ke instance Cloud SQL dari layanan yang berjalan di lingkungan standar App Engine.

Cloud SQL adalah layanan database yang terkelola sepenuhnya untuk membantu Anda menyiapkan, memelihara, mengatur, dan mengelola database relasional di cloud.

App Engine adalah platform serverless yang terkelola sepenuhnya untuk mengembangkan dan menghosting aplikasi web dalam skala besar. Anda dapat memilih dari beberapa bahasa, library, dan framework populer untuk mengembangkan aplikasi, lalu mengizinkan App Engine menangani server penyediaan dan menskalakan instance aplikasi Anda berdasarkan permintaan.

Menyiapkan instance Cloud SQL

  1. Aktifkan Cloud SQL Admin API di project Google Cloud yang menjadi sumber koneksi, jika Anda belum melakukannya:

    Enable the API

  2. Buat instance Cloud SQL untuk MySQL. Sebaiknya pilih lokasi instance Cloud SQL di region yang sama dengan layanan Cloud Run Anda untuk latensi yang lebih baik, menghindari beberapa biaya jaringan, dan mengurangi risiko kegagalan lintas region.

    Secara default, Cloud SQL menetapkan alamat IP publik ke instance baru. Anda juga memiliki opsi untuk menetapkan alamat IP pribadi. Untuk informasi selengkapnya mengenai kedua opsi konektivitas ini, lihat halaman Ringkasan Penghubung

Mengonfigurasi lingkungan standar App Engine

Langkah-langkah untuk mengonfigurasi lingkungan standar App Engine bergantung pada jenis alamat IP yang Anda tetapkan ke instance Cloud SQL.

IP Publik (default)

Untuk mengonfigurasi lingkungan standar App Engine guna mengaktifkan koneksi ke instance Cloud SQL menggunakan IP publik:

  • Pastikan instance memiliki alamat IP publik. Anda dapat memverifikasi hal ini di halaman Ringkasan untuk instance Anda di konsol Google Cloud. Jika Anda ingin menambahkan alamat IP, lihat halaman Mengonfigurasi IP publik untuk mendapatkan petunjuknya.
  • Dapatkan INSTANCE_CONNECTION_NAME untuk instance Anda. Anda dapat menemukan nilai ini di halaman Ringkasan untuk instance Anda di konsol Google Cloud atau dengan menjalankan perintah gcloud sql instances describe berikut:
    gcloud sql instances describe INSTANCE_NAME
       
    Ganti INSTANCE_NAME dengan nama instance Cloud SQL Anda.
  • Ganti variabel INSTANCE_NAME dengan nama instance Anda.
  • Pastikan akun layanan yang digunakan aplikasi Anda untuk mengautentikasi panggilan ke Cloud SQL memiliki peran dan izin Cloud SQL yang sesuai.
    • Akun layanan untuk layanan Anda memerlukan salah satu peran IAM berikut:
      • Cloud SQL Client (disarankan)
      • Cloud SQL Editor
      • Cloud SQL Admin
      Atau, Anda dapat menetapkan izin IAM berikut secara manual:
      • cloudsql.instances.connect
      • cloudsql.instances.get
      Untuk petunjuk yang lebih terperinci tentang cara menambahkan peran IAM ke akun layanan, lihat Memberikan Peran ke Akun Layanan.

    Secara default, aplikasi Anda akan mengizinkan koneksi menggunakan akun layanan App Engine. Identitas akun layanan terdapat di format PROJECT_ID@appspot.gserviceaccount.com.

    Jika ternyata akun layanan yang memberi otorisasi adalah milik project yang berbeda dengan instance Cloud SQL, maka izin Cloud SQL Admin API dan IAM perlu ditambahkan untuk kedua project tersebut.

IP Pribadi

Jika akun layanan yang memberi otorisasi merupakan bagian dari project yang berbeda dengan project yang berisi instance Cloud SQL, lakukan tindakan berikut:

  • Di kedua project, aktifkan Cloud SQL Admin API.
  • Untuk akun layanan di project yang berisi instance Cloud SQL, tambahkan izin IAM.
Konektor Akses VPC Serverless menggunakan alamat IP pribadi untuk menangani komunikasi ke jaringan VPC Anda. Untuk terhubung langsung dengan alamat IP pribadi, Anda harus melakukan hal berikut:
  1. Pastikan instance Cloud SQL yang dibuat sebelumnya memiliki alamat IP pribadi. Jika Anda perlu menambahkannya, lihat Mengonfigurasi IP pribadi untuk mendapatkan petunjuk.
  2. Buat konektor Akses VPC Serverless di jaringan VPC yang sama dengan instance Cloud SQL Anda. Perhatikan kondisi berikut:
    • Kecuali jika Anda menggunakan VPC Bersama, konektor harus berada di project dan region yang sama dengan resource yang menggunakannya. Namun, konektor dapat mengirim traffic ke resource di region yang berbeda.
    • Akses VPC Serverless mendukung komunikasi ke jaringan VPC yang terhubung menggunakan Cloud VPN dan Peering Jaringan VPC.
    • Akses VPC Serverless tidak mendukung jaringan lama.
  3. Konfigurasikan lingkungan standar App Engine untuk menggunakan konektor.
  4. Hubungkan menggunakan alamat IP pribadi instance dan port 3306.

Menghubungkan ke Cloud SQL

Setelah berhasil mengonfigurasi lingkungan standar App Engine, Anda dapat terhubung ke instance Cloud SQL.

IP Publik (default)

Untuk jalur IP publik, lingkungan standar App Engine menyediakan enkripsi dan terhubung menggunakan Proxy Auth Cloud SQL melalui dua cara:

IP Pribadi

Untuk jalur IP pribadi, aplikasi Anda terhubung langsung ke instance melalui jaringan VPC. Metode ini menggunakan TCP untuk terhubung langsung ke instance Cloud SQL tanpa menggunakan Proxy Auth Cloud SQL.

Terhubung dengan TCP

Hubungkan menggunakan alamat IP pribadi instance Cloud SQL Anda sebagai host dan port 3306.

Python

Untuk melihat cuplikan ini dalam konteks aplikasi web, lihat README di 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

Untuk melihat cuplikan ini dalam konteks aplikasi web, lihat README di GitHub.

Catatan:

  • INSTANCE_CONNECTION_NAME harus direpresentasikan sebagai <MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>
  • Menggunakan argumen ipTypes=PRIVATE akan memaksa SocketFactory untuk terhubung dengan IP pribadi yang terkait dengan sebuah instance
  • Lihat persyaratan versi factory soket JDBC untuk file pom.xml di sini .


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

Untuk melihat cuplikan ini dalam konteks aplikasi web, lihat README di 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

Untuk melihat cuplikan ini dalam konteks aplikasi web, lihat README di 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#

Untuk melihat cuplikan ini dalam konteks aplikasi web, lihat README di 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

Untuk melihat cuplikan ini dalam konteks aplikasi web, lihat README di 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

Untuk melihat cuplikan ini dalam konteks aplikasi web, lihat README di 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;
    }
}

Praktik terbaik dan informasi lainnya

Anda dapat menggunakan Proxy Auth Cloud SQL saat menguji aplikasi Anda secara lokal. Lihat panduan memulai untuk penggunaan Proxy Auth Cloud SQL untuk mendapatkan petunjuk terperinci.

Kumpulan Koneksi

Koneksi ke database pokok dapat terputus, entah oleh server database itu sendiri, atau oleh infrastruktur yang mendasarinya. Untuk mengurangi hal ini, sebaiknya gunakan library klien yang mendukung kumpulan koneksi dan koneksi ulang otomatis.

Batas Koneksi

Setiap instance App Engine yang berjalan di lingkungan standar tidak boleh memiliki lebih dari 100 koneksi konkurensi ke instance. Untuk aplikasi PHP 5.5, batasnya adalah 60 koneksi konkurensi. Batas ini berlaku per instance aplikasi. Artinya, setiap instance aplikasi App Engine dapat memiliki koneksi sebanyak itu ke database, dan seiring dengan skalanya, jumlah total koneksi per deployment dapat meningkat. Untuk informasi selengkapnya, lihat Menskalakan elemen.

Anda dapat membatasi jumlah maksimum koneksi yang digunakan per instance dengan menggunakan kumpulan koneksi. Untuk contoh yang lebih detail tentang cara membatasi jumlah koneksi, lihat halaman Mengelola koneksi database.

Aplikasi App Engine tunduk pada batas waktu permintaan, bergantung pada penggunaan dan lingkungan. Untuk mengetahui informasi selengkapnya, lihat cara instance dikelola di lingkungan standar dan fleksibel lingkungan standar App Engine.

Batas Kuota API

App Engine menyediakan mekanisme yang terhubung menggunakan Proxy Auth Cloud SQL, yang menggunakan Cloud SQL Admin API. Batas kuota API berlaku untuk Proxy Auth Cloud SQL. Saat dimulai, Cloud SQL Admin API menggunakan kuota dua dan rata-rata dua per jam setelahnya. Kuota defaultnya adalah 180 per menit per pengguna. Aplikasi App Engine juga tunduk pada kuota dan batas tambahan seperti yang dibahas di halaman Kuota App Engine.