Cloud SQL for PostgreSQL の使用

このページでは App Engine アプリケーションから Cloud SQL for PostgreSQL インスタンスに接続する方法を説明します。また、Cloud SQL に対して読み込みや書き込みを行う方法についても説明します。Cloud SQL は、Google のクラウドで稼働する SQL データベースです。

Cloud SQL の詳細については、Cloud SQL のドキュメントをご覧ください。Cloud SQL の料金と制限については、Cloud SQL の料金ページをご覧ください。App Engine アプリケーションには、App Engine の割り当ても適用されます。

始める前に

  1. GCP Console で GCP プロジェクトを作成または選択します。そのプロジェクトに App Engine アプリケーションが含まれていること、そして課金が有効になっていることを確認してください。
    App Engine に移動

    プロジェクトに App Engine アプリケーションがすでに存在し、課金が有効な場合、ダッシュボードが開きます。それ以外の場合には、プロンプトに従ってリージョンを選択し、課金を有効にします。

  2. Cloud SQL API を有効にします。

    APIを有効にする

  3. gcloud ツールを使用してアプリをデプロイする場合は、Google Cloud SDK をダウンロードしてインストールし、初期化する必要があります。
    SDK をダウンロード

    gcloud ツールがすでにインストールしてあり、その初期化時に指定した ID と異なる GCP プロジェクト ID が使われるように構成したい場合は、Cloud SDK 構成の管理をご覧ください。

Cloud SQL インスタンスの構成

Cloud SQL インスタンスを作成して構成するには、次の手順を行います。

  1. Cloud SQL for PostgreSQL のインスタンスを作成します
  2. まだ設定していない場合は、Cloud SQL インスタンスのデフォルト ユーザーのパスワードを設定します。
    gcloud sql users set-password postgres no-host --instance [INSTANCE_NAME] --password [PASSWORD]
    
  3. デフォルトのユーザーを使用して接続したくなければ、ユーザーを作成します。
  4. インスタンスの接続名を記録します。
    gcloud sql instances describe [INSTANCE_NAME]
    

    次に例を示します。

    connectionName: project1:us-central1:instance1
    

    この値は Google Cloud Platform Console の [インスタンスの詳細] ページでも確認できます。

  5. Cloud SQL インスタンスにデータベースを作成します。
    gcloud sql databases create [DATABASE_NAME] --instance=[INSTANCE_NAME]
    
    データベースの作成と管理の詳細については Cloud SQL のドキュメントをご覧ください。

ローカル環境の設定

デプロイされたアプリケーションは、App Engine ランタイム環境に組み込まれている Cloud SQL Proxy を使用して Cloud SQL インスタンスと通信します。ただし、アプリケーションをローカルでテストするには、Cloud SQL Proxy のローカルコピーを開発環境にインストールして使用する必要があります。

Cloud SQL インスタンスに対する基本的な管理タスクを実行するには、データベースの管理クライアントまたは GCP Console を使用できます。

  1. プロキシを使用してローカルマシンから接続できるように gcloud ツールを認証します。

    gcloud auth application-default login
    
  2. Cloud SQL プロキシをインストールします。

    Linux 64 ビット

    1. プロキシをダウンロードします。
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
      
    2. プロキシを実行できるようにします。
      chmod +x cloud_sql_proxy
      

    Linux 32 ビット

    1. プロキシをダウンロードします。
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
      
    2. プロキシを実行できるようにします。
      chmod +x cloud_sql_proxy
      

    macOS 64 ビット

    1. プロキシをダウンロードします。
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
      
    2. プロキシを実行できるようにします。
      chmod +x cloud_sql_proxy
      

    macOS 32 ビット

    1. プロキシをダウンロードします。
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
      
    2. プロキシを実行できるようにします。
      chmod +x cloud_sql_proxy
      

    Windows 64 ビット

    https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe を右クリックして [名前を付けてリンク先を保存] を選択し、名前を cloud_sql_proxy.exe に変更してプロキシをダウンロードします。

    Windows 32 ビット

    https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe を右クリックして [名前を付けてリンク先を保存] を選択し、名前を cloud_sql_proxy.exe に変更してプロキシをダウンロードします。
    ここにオペレーティング システムが含まれていない場合は、プロキシをソースからコンパイルすることもできます。

  3. プロキシを実行します。

    言語や環境に応じて、TCP ソケットまたは Unix ソケットのどちらかを使用してプロキシを開始できます。

    TCP ソケット

    1. [インスタンスの詳細] ページからインスタンス接続名をコピーします。
    2. サービス アカウントを使用してプロキシを認証する場合は、サービス アカウントを作成したときに作成された秘密鍵ファイルのクライアント マシン上での場所を記録しておきます。
    3. プロキシを開始します。

      考えられるプロキシ呼び出し文字列を以下にいくつか示します。

      • Cloud SDK 認証を使用する場合:
        ./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:5432
        
        指定されたポートは、ローカル データベース サーバーなどによってまだ使用されていないものである必要があります。
      • サービス アカウントと明示的なインスタンス指定を使用する場合(本番環境で推奨):
        ./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:5432 \
                          -credential_file=<PATH_TO_KEY_FILE> &
        

      プロキシ オプションの詳細については、プロキシを認証するためのオプションインスタンスを指定するためのオプションをご覧ください。

    Unix ソケット

    1. 明示的なインスタンス指定を使用する場合は、インスタンス接続名を [インスタンスの詳細] ページからコピーします。
    2. プロキシ ソケットを格納するディレクトリを作成します。
      sudo mkdir /cloudsql; sudo chmod 777 /cloudsql
    3. サービス アカウントを使用してプロキシを認証する場合は、サービス アカウントを作成したときに作成された秘密鍵ファイルのクライアント マシン上での場所を記録しておきます。
    4. 新しいターミナル ウィンドウを開き、プロキシを開始します。

      考えられるプロキシ呼び出し文字列を以下にいくつか示します。

      • サービス アカウントと明示的なインスタンス指定を使用する場合(本番環境で推奨):
        ./cloud_sql_proxy -dir=/cloudsql -instances=<INSTANCE_CONNECTION_NAME> \
                          -credential_file=<PATH_TO_KEY_FILE> &
      • Cloud SDK 認証と自動インスタンス検出を使用する場合:
        ./cloud_sql_proxy -dir=/cloudsql &

      専用のターミナルでプロキシを開始することが最善です。この場合、他のプログラムからの出力と混ざることなく出力をモニタリングできます。

      プロキシ オプションの詳細については、プロキシを認証するためのオプションインスタンスを指定するためのオプションをご覧ください。

  4. 管理クライアントを使用するには、ローカルコピーをインストールし、プロキシまたは IP アドレスを使用して接続します。

    詳細については、Cloud SQL Proxy を使用して PSQL クライアントを接続するIP アドレスを使用して PSQL クライアントを接続するをご覧ください。

接続文字列の設定とライブラリの追加

  1. ローカルテストの接続用にローカル環境を設定します。

    コードサンプルの例:

    export POSTGRES_CONNECTION="user=[USER_NAME] password=[PASSWORD] dbname=[DATABASE_NAME] sslmode=disable
    

  2. アプリをデプロイすると Cloud SQL インスタンスに接続できるようにするには、Cloud SQL からユーザー、パスワード、データベース、インスタンス接続名の各変数を、app.yaml ファイル内の関連する環境変数に追加します。

    env_variables:
      # See https://godoc.org/github.com/lib/pq
      #
      # Replace INSTANCE_CONNECTION_NAME with the same value as in the
      # beta_settings section below.
      POSTGRES_CONNECTION: "user=postgres password=pw dbname=db host=/cloudsql/INSTANCE_CONNECTION_NAME"
      #
      # If you're testing locally using the Cloud SQL proxy with TCP,
      # instead set this environment variable:
      # POSTGRES_CONNECTION="user=postgres password=pw dbname=db sslmode=disable"
  3. Cloud SQL インスタンス接続名を使用して、beta_settings セクションを app.yaml に追加します。

    beta_settings:
      cloud_sql_instances: INSTANCE_CONNECTION_NAME

  4. コマンドラインを使用して、ローカルマシンに PostgreSQL パッケージをダウンロードします。次に例を示します。

    go get -u github.com/lib/pq
    

サンプルコードの実行

次のサンプルは、訪問情報を Cloud SQL に書き込み、次に最新の 10 件の訪問情報を読み取って返します。
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

// +build go1.8

// Sample cloudsql demonstrates usage of Cloud SQL from App Engine flexible environment.
package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"google.golang.org/appengine"

	_ "github.com/lib/pq"
)

var db *sql.DB

func main() {
	// Set this in app.yaml when running in production.
	datastoreName := os.Getenv("POSTGRES_CONNECTION")

	var err error
	db, err = sql.Open("postgres", datastoreName)
	if err != nil {
		log.Fatal(err)
	}

	// Ensure the table exists.
	// Running an SQL query also checks the connection to the PostgreSQL server
	// is authenticated and valid.
	if err := createTable(); err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", handle)
	appengine.Main()
}

func createTable() error {
	stmt := `CREATE TABLE IF NOT EXISTS visits (
			timestamp  BIGINT,
			userip     VARCHAR(255)
		)`
	_, err := db.Exec(stmt)
	return err
}

func handle(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}

	// Get a list of the most recent visits.
	visits, err := queryVisits(10)
	if err != nil {
		msg := fmt.Sprintf("Could not get recent visits: %v", err)
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}

	// Record this visit.
	if err := recordVisit(time.Now().UnixNano(), r.RemoteAddr); err != nil {
		msg := fmt.Sprintf("Could not save visit: %v", err)
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}

	fmt.Fprintln(w, "Previous visits:")
	for _, v := range visits {
		fmt.Fprintf(w, "[%s] %s\n", time.Unix(0, v.timestamp), v.userIP)
	}
	fmt.Fprintln(w, "\nSuccessfully stored an entry of the current request.")
}

type visit struct {
	timestamp int64
	userIP    string
}

func recordVisit(timestamp int64, userIP string) error {
	stmt := "INSERT INTO visits (timestamp, userip) VALUES ($1, $2)"
	_, err := db.Exec(stmt, timestamp, userIP)
	return err
}

func queryVisits(limit int64) ([]visit, error) {
	rows, err := db.Query("SELECT timestamp, userip FROM visits ORDER BY timestamp DESC LIMIT $1", limit)
	if err != nil {
		return nil, fmt.Errorf("Could not get recent visits: %v", err)
	}
	defer rows.Close()

	var visits []visit
	for rows.Next() {
		var v visit
		if err := rows.Scan(&v.timestamp, &v.userIP); err != nil {
			return nil, fmt.Errorf("Could not get timestamp/user IP out of row: %v", err)
		}
		visits = append(visits, v)
	}

	return visits, rows.Err()
}

テストとデプロイ

  1. アプリケーションをローカルでテストするには、以下のコマンドを実行します。

    go run cloudsql.go
    

  2. ローカルテストの後、App Engine にアプリをデプロイします。

    gcloud app deploy
    

  3. ブラウザを起動して http://[YOUR_PROJECT_ID].appspot.com でアプリを表示するには、次のコマンドを実行します。

    gcloud app browse
    

Cloud SQL と App Engine を別々のプロジェクトで実行する

App Engine アプリケーションと Cloud SQL インスタンスが異なる Google Cloud Platform プロジェクトにある場合、サービス アカウントを使用して App Engine アプリケーションが Cloud SQL にアクセスできるようにする必要があります。

このサービス アカウントは App Engine アプリケーションを表し、Google Cloud Platform プロジェクトを作成するとデフォルトで作成されます。

  1. App Engine アプリケーションが Cloud SQL インスタンスと同じプロジェクトにある場合、このセクションをスキップし、ローカル環境の設定に進みます。それ以外の場合は、次のステップに進みます。
  2. App Engine アプリケーションに関連付けられたサービス アカウントを特定します。デフォルトの App Engine サービス アカウント名は [PROJECT-ID]@appspot.gserviceaccount.com です。

    App Engine サービス アカウントは [IAM 権限] ページで確認できます。プロジェクトは Cloud SQL インスタンスではなく、必ず App Engine アプリケーションに対して選択してください。

    [IAM 権限] ページに移動

  3. Google Cloud Platform Console の [IAM と管理] ページに移動します。

    [IAM と管理] ページに移動

  4. Cloud SQL インスタンスを含むプロジェクトを選択します。
  5. サービス アカウント名を検索します。
  6. サービス アカウントがすでに存在し、cloudsql.instances.connect 権限を含む役割がそのアカウントにある場合は、ローカル環境の設定に進みます。

    Cloud SQL ClientCloud SQL EditorCloud SQL Admin の役割はすべて、従来の EditorOwner のプロジェクト役割と同様に、必要な権限を提供します。

  7. それ以外の場合、[追加] をクリックしてサービス アカウントを追加します。
  8. [メンバーの追加] ダイアログでサービス アカウントの名前を指定し、cloudsql.instances.connect 権限を含む役割を選択します(閲覧者以外の Cloud SQL の定義済みの役割はすべて機能します)。

    あるいは、[プロジェクト] > [編集者] の順に選択して、編集者の基本的な役割を使用できますが、編集者の役割には Google Cloud Platform 全体の権限が含まれます。

    これらの役割が表示されない場合、Google Cloud Platform ユーザーに resourcemanager.projects.setIamPolicy 権限がない可能性があります。権限を確認するには、Google Cloud Platform Console の [IAM] ページにアクセスし、自分のユーザー ID を検索します。

  9. [追加] をクリックします。

    これで、指定した役割を持つサービス アカウントがリストされます。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Go の App Engine フレキシブル環境