💨

Terraformを使って、CloudRunからPublicIPを持つCloudSQLに対して、DB接続を行う

2023/10/19に公開

記事の内容

GCPのCloudSQLに対して、Public IPを付与し、CloudRunからDB接続を行う方法を解説します(Terraformを利用します)

記事を読むと得られるもの

  • PublicIPをもったCloudSQLのセットアップの仕方
  • CloudRunのセットアップの仕方
  • CloudRunとCloudSQLの接続方法
  • TerraformでCloudRunとCloudSQLを作成する方法

対象読者

  • GCPでDBを利用した構成を作りたい人
  • CloudRunを使いたい人
  • CloudSQLにPublicIPを付与して運用したい人
  • Terraformで上記構成を作りたい人

記事の長さ

5分で読めます

CloudSQLをセットアップ

まずはPublicIPを付与したCloudSQLを作成します。
以下のTerraformのコードをapplyする形で、MySQLをセットアップします。

resource "google_sql_database" "database" {
  project = var.project_id

  name     = "database"
  instance = google_sql_database_instance.instance.name
}

resource "google_sql_database_instance" "instance" {
  project = var.project_id

  name             = "instance-1"
  region           = "asia-northeast1"
  database_version = "MYSQL_8_0"
  settings {
    tier = "db-f1-micro"
  }

  deletion_protection = "true"
}

resource "google_sql_user" "users" {
  project = var.project_id

  name     = "test-user"
  instance = google_sql_database_instance.instance.name
  password = "password_1234"
}

上記のApplyが無事に成功すると、Public IP Addressを持ったCloudSQLが作成されます。
同時に、

  • id: test-user
  • password: password_1234

のユーザーも作成されますので、このid,passwordを使って、MySQLに接続を行います。

試しに接続してみる

上記で作成したMySQLに対して、実験で接続してみます。

Autorized networksに自分のグローバルIPを登録する

CloudSQLは、Authorized networksで許可されているIPアドレスの範囲からのみ、アクセスを受け付けます。デフォルト設定の場合、すべての接続がDenyされているので、現在使っているWifiのグローバルIPアドレスを登録します。

GCP CLoudSQL

この画像の例では、123.123.123.123のIPアドレスからの接続のみ許可しています。

現在使っているIPアドレスの調べ方

$ curl httpbin.org/ip
{
  "origin": "123.123.123.123"
}

上記コマンドを実行すると、現在のローカルPCが使用しているグローバルIPを調べることができます。

ローカルから接続する

Authorized networksに、現在使用しているグローバルIPを設定できたので、ローカルPCからCloud SQLに接続することができるようになりました。以下のコマンドで、接続を試みます。

$ mysql -utest-user -p -h 11.111.111.12
Enter password: <password_1234を入力>
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 902
Server version: 8.0.31-google (Google)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [database]> use database;
Database changed
MySQL [database]> CREATE TABLE users (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT);
Query OK, 0 rows affected (0.154 sec)

MySQL [database]> INSERT INTO users VALUES ();
Query OK, 1 row affected (0.023 sec)

MySQL [database]> INSERT INTO users VALUES ();
Query OK, 1 row affected (0.012 sec)

MySQL [database]> SELECT * FROM users;
+----+
| id |
+----+
|  1 |
|  2 |
+----+
2 rows in set (0.009 sec)

無事に接続できることを確認できました。
※接続テストの際に利用できるように、usersテーブルとダミーデータも一緒に作成しておきました。

これで、CloudSQLの設定は完了です。

CloudRunを作成する

CloudRun上で動作するDockerImageを作成する

CloudRunはDockerImageを動作させるサービスなので、MySQLに接続して、その結果を返すsimpleなDocker Imageを用意します。

index.js

const express = require('express');
const mysql = require('promise-mysql');
const app = express();
const port = 8080;

const createUnixSocketPool = async () => {
  return mysql.createPool({
    user: "test-user",
    password: "password_1234",
    database: "database",
    socketPath: "/cloudsql/<CloudSQLの接続名>",
  });
};

let pool;

(async () => {
  pool = await createUnixSocketPool();
})();

app.get('/', async (req, res) => {
  try {
    const connection = await pool.getConnection();
    const results = await connection.query('SELECT * FROM users');
    connection.release();
    res.send(results);
  } catch (error) {
    res.status(500).send(error.message);
  }
});

app.listen(port, () => {
  console.log(`App running on http://localhost:${port}`);
});

package.json

{
  "name": "mysql-nodejs-app",
  "version": "1.0.0",
  "description": "A Node.js app connecting to MySQL using Unix sockets",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "express": "^4.17.1",
    "promise-mysql": "^5.0.3"
  }
}

Dockerfile

# nodeのイメージを取得
FROM node:14

# アプリケーションディレクトリを作成
WORKDIR /usr/src/app

# アプリケーションの依存関係をインストール
COPY package*.json ./

RUN npm install

# アプリケーションのソースをバンドル
COPY . .

# ポート8080で実行
EXPOSE 8080
CMD [ "node", "index.js" ]

※CloudSQLの接続名の部分は、<GCP Project ID>/<リージョン名>/<CloudSQL名>に変更してください。(CloudSQLのコンソールのConnection nameの欄でも確認ができます。)

上記3ファイルを共通のディレクトリに格納し、そのディレクトリで以下コマンドを実行して、DockerImageをGCRに格納します(Project ID部分は、自分のGCPのProject IDに変更してください)

$ gcloud builds submit --tag gcr.io/<Project ID>/test

CloudRun用にCloudSQLに接続できるServiceAccountを作成する

PublicIPが付与されたCloudSQLを全ネットワークに対して公開してしまうと、誰からでもアクセスできるようになってしまうため危険です。
そのため、CloudSQLを一般公開はせずに、Cloud Runにroles/cloudsql.clientを持ったServiceAccountを付与することで、CloudRunからの接続を許可します。

resource "google_service_account" "new_account" {
  project = var.project_id
  account_id   = "test1234"
  display_name = "Test Service Account"
}

resource "google_project_iam_member" "project" {
  project = var.project_id
  role    = "roles/cloudsql.client"
  member  = "serviceAccount:${google_service_account.new_account.email}"
}

この、Terraformを実行することで、CloudSQLをClientとして利用するServiceAccountの作成ができます。

CloudRunを起動する

  • CloudRun用に作成したDockerImage
  • CloudRun用に作成したServiceAccount

を用いて、CloudRunを起動します。


resource "google_cloud_run_service" "default" {
  project = var.project_id
  name     = "test-sql"
  location = "asia-northeast1"
  template {
    spec {
      service_account_name = google_service_account.new_account.email

      containers {
        image = "gcr.io/<Project ID>/test"
      }
    }
    metadata {
      annotations = {
        "run.googleapis.com/cloudsql-instances" = "<Project ID>:asia-northeast1:instance-1"
      }
    }
  }

  traffic {
    percent         = 100
    latest_revision = true
  }
}

resource "google_cloud_run_service_iam_member" "public" {
  project = var.project_id
  service  = google_cloud_run_service.default.name
  location = "asia-northeast1"
  role     = "roles/run.invoker"
  member   = "allUsers"
}

上記がTerraformでCloudRunを設定したコードになります。
google_cloud_run_service_iam_memberallUsersを指定することで、インターネットを通して、すべてのユーザーがこのCloudRunで動作するアプリケーションにアクセスできるようになります。

また、annotation部分に、CloudSQLとの接続の作成する記載を書くことで、cloudsqlproxy経由でのCloudSQLへの接続を許可します。

ブラウザから確認する

ここまでの構築で、CloudSQLとCloud Runの実装が完了しました。最後に、CloudRunが動作するサーバーにブラウザ経由でアクセスして、正常にCloudSQLと接続できていることを確認します。

$ open $(gcloud run services describe test-sql --format 'value(status.url)' --region asia-northeast1 --platform managed)

このコマンドで、CloudRunのデフォルトURLをブラウザで開くことができます。

GCP CLoudSQL

無事、CloudSQLの内容が表示されています。

ソースコード

TerraformとCloudrun上で動作するアプリケーションのソースコードを以下のGithubの公開リポジトリに置いておきました。

https://github.com/rara-tan/zenn-cloudrun-cloudsql

note

勉強法やキャリア構築法など、エンジニアに役立つ記事をnoteで配信しています。

https://note.com/ring_belle/membership

Discussion