Google Cloud Platform with Spring Boot 2.0.0

# 概要

Google Cloud Platform(以下GCP)へSpring Bootを利用して開発したwebアプリケーションをデプロイしブラウザからアクセスできるまでを学習したまとめ記事です。
ページの前半はwebアプリケーションの実行に必要なCompute EngineやCloud SQLなどの環境構築について、後半はwebアプリケーションの開発内容となっています。

**環境**

ローカルPC

* Windows 10 Professional
* Oracle JDK 1.8.0_162
* Spring Boot 2.0.0
* MySQL 5.7.19
* Cloud SDK

GCP

* Compute Engine (Ubuntu)
    * Openjdk 1.8
* Cloud SQL (MySQL 5.7)
* Cloud Storage

**参考**

* [Google Cloud Platformのドキュメント] (https://cloud.google.com/docs/?hl=ja)

# 環境構築

環境構築は下記の順番で行いました。

1. ローカルPCにCloud SDKのインストール
1. GCPにプロジェクトの作成
1. VMインスタンス用のサービスアカウントを作成
1. Cloud Storageにバケットを作成
1. Cloud SQLにDBインスタンスを作成
1. Compute EngineにVMインスタンスを作成
1. ファイアウォールルールを追加

## AWSとの簡単な対比

AWSの経験はあったのですが、GCPは初心者なので主要サービスの対比表を作りました。

|サービス           |GCP                        |AWS        |この記事での利用   |
|:------------------|:-------------------------|:----------|:-----------------|
|コンピューティング |Compute Engine              |EC2 |Ubuntu、1インスタンス |
|データベース       |Cloud SQL                  |RDS |MySQL、1インスタンス |
|ストレージ         |Cloud Storage              |S3  |1バケットを作成 |
|ブロックストレージ |永続ディスク                 |EBS |追加利用はなし |
|ネットワーク       |Cloud Virtual Network      |VPC |ファイアウォールルールを1つ追加|
|ロードバランサ     |Cloud Load Balancing       |ELB |なし |
|CDN                |Cloud CDN                |CloudFront |なし|
|アクセス制御       |Cloud IAM                  |IAM |サービスアカウントを1つ追加|
|CLI                |Cloud SDK                |CLI |ほぼ利用せず|

## ローカルPCにCloud SDKのインストール

[Cloud SDK > ドキュメント > Cloud SDK のインストール] (https://cloud.google.com/sdk/downloads?hl=ja)

オフィシャルのドキュメントで説明されている方法のうちで、”バージョニングされたアーカイブ”を利用する方法を利用しました。
なお、この記事ではブラウザベースのGCP Consoleを利用して作業を進めたのでCloud SDKはあまり使っていません。

**インストール**

Windows版のアーカイブファイルをダウンロードし適当な場所へ展開します。
Cloud SDKの実行にはpython 2.7.xが必要なので別途インストールするか、pythonバンドル版を利用します。

展開したディレクトリにあるインストールスクリプトを実行します。
通常はインストールスクリプトがbinディレクトリを環境変数pathに追加しますが、失敗することもあるようなのでその場合は手動で設定します。

```text
> install.bat
```

### Cloud SDKの初期化

[Cloud SDK > ドキュメント > Cloud SDK の初期化] (https://cloud.google.com/sdk/docs/initializing?hl=ja)

SDKを初期化します。下記のコマンドを実行するとブラウザが立ち上がってGoogleアカウントでの認証を求められます。（コンソールベースで承認フローを開始するには--console-onlyフラグを付ければいいようです）

```text
> gcloud init
```

#### 認証されたアカウント情報の確認

認証されたアカウント情報は下記のコマンドで確認できます。Cloud SDKでは複数のアカウントを使い分けることができますが、アクティブなのは常に1つです。

```text
> gcloud auth list
        Credentialed Accounts
ACTIVE  ACCOUNT
*       ********.********.********@gmail.com

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
```

### コンポーネントの確認

[Cloud SDK > ドキュメント > SDK コンポーネントの管理] (https://cloud.google.com/sdk/docs/components?hl=ja)

Cloud SDKをインストールすると、いくつかのコンポーネントと呼ばれるコマンドラインツールが使えるようになります。主だったものはGCPを操作するgcloudツール、Cloud Storageを操作するgsutilツールがあります。

下記のコマンドでインストール／未インストールのコンポーネントを確認できます。

```text
> gcloud components list
Your current Cloud SDK version is: 194.0.0
The latest available version is: 194.0.0

+-------------------------------------------------------------------------------------------------------------+
|                                                  Components                                                 |
+---------------+------------------------------------------------------+--------------------------+-----------+
|     Status    |                         Name                         |            ID            |    Size   |
+---------------+------------------------------------------------------+--------------------------+-----------+
| Not Installed | App Engine Go Extensions                             | app-engine-go            | 153.2 MiB |
| Not Installed | Cloud Bigtable Command Line Tool                     | cbt                      |   4.2 MiB |
| Not Installed | Cloud Bigtable Emulator                              | bigtable                 |   3.7 MiB |
| Not Installed | Cloud Datalab Command Line Tool                      | datalab                  |   < 1 MiB |
| Not Installed | Cloud Datastore Emulator                             | cloud-datastore-emulator |  17.9 MiB |
| Not Installed | Cloud Datastore Emulator (Legacy)                    | gcd-emulator             |  38.1 MiB |
| Not Installed | Cloud Pub/Sub Emulator                               | pubsub-emulator          |  33.4 MiB |
| Not Installed | Emulator Reverse Proxy                               | emulator-reverse-proxy   |  14.5 MiB |
| Not Installed | Google Container Registry's Docker credential helper | docker-credential-gcr    |   2.4 MiB |
| Not Installed | gcloud Alpha Commands                                | alpha                    |   < 1 MiB |
| Not Installed | gcloud Beta Commands                                 | beta                     |   < 1 MiB |
| Not Installed | gcloud app Java Extensions                           | app-engine-java          | 118.9 MiB |
| Not Installed | gcloud app PHP Extensions                            | app-engine-php           |  19.1 MiB |
| Not Installed | gcloud app Python Extensions                         | app-engine-python        |   6.2 MiB |
| Not Installed | gcloud app Python Extensions (Extra Libraries)       | app-engine-python-extras |  27.8 MiB |
| Not Installed | kubectl                                              | kubectl                  |  12.3 MiB |
| Installed     | BigQuery Command Line Tool                           | bq                       |   < 1 MiB |
| Installed     | Cloud SDK Core Libraries                             | core                     |   7.4 MiB |
| Installed     | Cloud Storage Command Line Tool                      | gsutil                   |   3.4 MiB |
+---------------+------------------------------------------------------+--------------------------+-----------+
To install or remove components at your current SDK version [194.0.0], run:
  $ gcloud components install COMPONENT_ID
  $ gcloud components remove COMPONENT_ID

To update your SDK installation to the latest version [194.0.0], run:
  $ gcloud components update
```

新しいバージョンのSDKがリリースされている場合、下記のコマンドでアップデートすることができます。
なお、カレントディレクトリがインストールディレクトリ上だとアップデートに失敗するので注意が必要です。

```text
> gcloud components update
```

## プロジェクトの作成

webアプリケーションの実行に必要なVMインスタンス(Compute Engine)やデータベース(Cloud SQL)、ストレージ(Cloud Storage)はすべてプロジェクト内に作成します。

GCP Consoleを開き、新しいプロジェクトを作成します。

![p0.png](https://qiita-image-store.s3.amazonaws.com/0/22772/0ee0a555-6ae0-a4f1-454d-8a34149c464b.png)

プロジェクトが作成されるとプロジェクトIDが発行されるので控えておきます。
プロジェクトIDはConsoleのダッシュボードのプロジェクト情報で確認できます。

![p1.png](https://qiita-image-store.s3.amazonaws.com/0/22772/0d275f45-6dc5-2eae-b1ea-c71e56263949.png)

次にプロジェクトの課金を有効する必要がありますが無料トライアル枠が利用可能だったのでこれを利用しました。

gcloudツールでも操作できるように発行されたプロジェクトIDを設定します。

```text
> gcloud config set project <project id>
Update property [core/project].
```

### サービスアカウントの作成

[Compute Engine >ドキュメント > サービス アカウント] (https://cloud.google.com/compute/docs/access/service-accounts?hl=ja)

VMインスタンスを実行するためのサービスアカウントを作成します。
GCP Consoleの左側メニューの「IAMと権限」->「サービスアカウント」->「サービスアカウントを作成」を選択します。

一覧に表示されているアカウントはCompute Engineの利用開始時に自動的に作成されるデフォルトのサービスアカウントです（プロジェクト作成後にConsoleメニューのCompute Engineを最初に開いたときに作成されるのでタイミングによっては表示されない場合があります）。
このアカウントを使うこともできますが、このアカウントは権限の範囲が広いので必要最低限の権限を持つ専用アカウントを作成します。

「サービスアカウントを作成」をクリックして開始します。

![sa0.png](https://qiita-image-store.s3.amazonaws.com/0/22772/2d5eb2ad-5c43-ef76-dd76-910fccad0f6a.png)

「役割」をクリックして以下の役割を割り当てます。

* Compute Engine -> Compute OS ログイン
* Cloud SQL -> Cloud SQL クライアント
* ストレージ -> ストレージオブジェクト閲覧者
* ストレージ -> ストレージのオブジェクト作成者
* Error Reporting -> エラー書き込み
* Logging -> ログ書き込み

![sa1b.png](https://qiita-image-store.s3.amazonaws.com/0/22772/42bddcb5-e97e-6076-d9cf-7c324825a267.png)

ちなみに役割とは1つ以上の権限の集まりです。
たとえば上記の”ストレージオブジェクト閲覧者”という役割は、図の通り4つの権限を持っています。

![pr0.png](https://qiita-image-store.s3.amazonaws.com/0/22772/d0cd1c7a-d4c1-9ac3-85d7-19d92ecd1396.png)

作成されると一覧に表示されます。

![sa2.png](https://qiita-image-store.s3.amazonaws.com/0/22772/0ab05853-7501-abd2-4b47-e328bd8aaa6a.png)

サービスアカウントに役割を追加したい場合はGCP Consoleの「IAMと管理」->「IAM」を開きます。
ちょっとわかりずらいのですがサービスアカウントの鉛筆アイコン（どれでも）をクリックします。

ちなみにこのページに表示されている1つ目のメンバーは、Compute Engineが自動的に作成するデフォルトのメンバーです。

> Compute Engine のデフォルトのサービス アカウント
> 歴史的な理由により、すべてのプロジェクトには、このメールを使用して識別が可能な Compute Engine のデフォルトのサービス アカウントが設定されています。
> [PROJECT_NUMBER]-compute@developer.gserviceaccount.com

2つ目のメンバーはGoogleが所有している特別なアカウントです。このアカウントをユーザーが利用することはなくまた役割の変更や削除を行ってはいけません。

> Google API サービス アカウント
> デフォルトのサービス アカウントは別として、Compute Engine により有効にされたすべてのプロジェクトには、このメールを使用して識別な可能な Google API サービス アカウントが設定されています。
> [PROJECT_NUMBER]@cloudservices.gserviceaccount.com

3つ目のメンバーは私のgoogleアカウントで、役割がオーナーとなっている通り全リソースへの完全なアクセス権限を持っています。
4つ目のメンバーが今回追加したVMインスタンス実行用のメンバーです。

![sa3b.png](https://qiita-image-store.s3.amazonaws.com/0/22772/0fab13c4-86db-cff3-da49-4af647d732a7.png)

「別の役割を追加」をクリックします。既存の役割の変更や削除もできます。

![sa4b.png](https://qiita-image-store.s3.amazonaws.com/0/22772/72b73b4b-f501-2988-2743-537cf8fbff52.png)

### Cloud Storageにバケットを作成する

ローカルでビルドしたjarファイルを置くためのバケットを作成します。
GCP Consoleの左側メニューの「Storage」->「ブラウザ」->「新しいバケットを作成」を選択します。

「バケットを作成」ボタンをクリックして開始します。

![s0.png](https://qiita-image-store.s3.amazonaws.com/0/22772/9f041d3a-cddf-9212-ab6c-45b3f765c0b3.png)

デフォルトのストレージクラスは「Regional」を選択しました。jarファイルを一時的に置くだけなので「Nearline」や「Coldline」でも構わないと思いましたが、これらは早期削除（最小保存期間前に削除）すると課金が発生するようなので止めました。

![s1.png](https://qiita-image-store.s3.amazonaws.com/0/22772/74322177-9b20-95eb-f965-b5dd95eed7d4.png)

**ストレージクラスの特性**

2018年3月時点の特性です。

* Multi-Regional
    * 世界中から頻繁にアクセスされるデータを保存
    * 地理的な冗長性を維持
* Regional
    * 頻繁にアクセスされるデータを保存
    * 特定のリージョンのロケーションにデータを保存
* Nearline
    * 低コストで持続時間の長いストレージサービス
    * 読み取りまたは変更を月に1回程度しか行わないデータに適している
    * 最小保存期間は30日
* Coldline
    * 保存期間が長く、保存コストが非常に安いストレージサービス
    * 年に1回程度しかアクセスしないデータに最適な選択肢
    * 最小保存期間は90日

バケットが作成されると一覧に表示されます。

![s2.png](https://qiita-image-store.s3.amazonaws.com/0/22772/dbcb2e60-eaf9-6834-39b9-7d4735bfdaf2.png)

動作確認用に適当なファイルをアップロードしておきます。

図のようにバケット毎に権限を編集することも可能です。
先ほど作成したVMインスタンス用のサービスアカウントに”ストレージのオブジェクト閲覧者”と”ストレージのオブジェクト作成者”を割り当てたので、このバケットの権限にそのサービスアカウントが表示されています。

![s3.png](https://qiita-image-store.s3.amazonaws.com/0/22772/221c2e58-7481-3488-d9e9-28a3e4118461.png)


### Cloud SQLにDBインスタンスを作成

webアプリケーションが利用するデータベースのDBインスタンス(MySQL 5.7)を作成します。
GCP Consoleの左側メニューから「SQL」を選択します。

「インスタンスを作成」ボタンをクリックして開始します。

![db0.png](https://qiita-image-store.s3.amazonaws.com/0/22772/c1726613-13f2-d8ca-6275-08460833df19.png)

データベースエンジンにMySQLを選択します。

![db1.png](https://qiita-image-store.s3.amazonaws.com/0/22772/2b9c7c47-8d08-bc3f-6eb8-3492bfb70e75.png)

第2世代を選択します。

![db2.png](https://qiita-image-store.s3.amazonaws.com/0/22772/3c7cf186-95c7-e00d-e925-83c7ab4d7eda.png)

インスタンスIDやパスワードを入力します。続いて設定オプションをクリックします。

![db3.png](https://qiita-image-store.s3.amazonaws.com/0/22772/b2918706-5bff-af0b-9f2c-0eff5685ea40.png)

設定オプションのフラグの追加である程度のコンフィグレーションが可能です。

![db31.png](https://qiita-image-store.s3.amazonaws.com/0/22772/7c06dea0-c841-d5a7-ddcb-935d3fc4c812.png)

フラグは選択式で予め用意された項目しか(少なくともGCP Console上からは)設定できないようです。

![db31b.png](https://qiita-image-store.s3.amazonaws.com/0/22772/9fc83d99-dcb6-3e1b-ed02-b667b234a623.png)

マシンタイプとストレージの設定を下図のようにしました。選択したマシンタイプは開発向けのもっとも性能の低いタイプです。

![db32.png](https://qiita-image-store.s3.amazonaws.com/0/22772/4debf283-c78a-39e8-c998-a64254b3c9a6.png)

インスタンスが作成されると一覧に表示されます。画面に表示されている”インスタンス接続名”は後ほど使うので控えておきます。

![db4.png](https://qiita-image-store.s3.amazonaws.com/0/22772/1e1bd917-cc06-f26c-cedb-edb5b7a96921.png)

#### Google Cloud SQL APIの有効化

VMインスタンスからMySQLへ接続するために”Google Cloud SQL API”を有効にする必要があります。
この図はすでにAPIを有効にした状態のもので、最初は表示されていませんでした。
上に”Google Cloud SQL”が表示されていますが、これが有効になっていても接続はできません。
APIを有効にするには「APIとサービスの有効化」をクリックします。

![a0b.png](https://qiita-image-store.s3.amazonaws.com/0/22772/a77afa29-4956-c5f3-dc44-b7c6f3589f96.png)

検索フィールドに”Google Cloud SQL”と入力して検索すると「Google Cloud SQL API」が表示されると思います。

![a1.png](https://qiita-image-store.s3.amazonaws.com/0/22772/80e4b404-96ab-73cd-314a-1d9664246b97.png)

「有効にする」をクリックして有効化します。

![a3.png](https://qiita-image-store.s3.amazonaws.com/0/22772/dd69d22f-ac2b-0859-7415-fa43bab2d7f1.png)

### Compute EngineにVMインスタンスを作成する

webアプリケーションを実行するVMインスタンスを作成します。
GCP Consoleの左側メニューから「Compute Engine」-> 「VMインスタンス」を選択します。

「作成」ボタンをクリックして開始します。

![vm0.png](https://qiita-image-store.s3.amazonaws.com/0/22772/ddd67aa1-cefe-728b-c244-22bc93c891e7.png)

作成したいVMインスタンスのスペックを入力します。

![vm1b.png](https://qiita-image-store.s3.amazonaws.com/0/22772/21689342-c175-f1f2-8e90-db46cd50fc25.png)

追加の設定で起動スクリプトを入力

![vm2.png](https://qiita-image-store.s3.amazonaws.com/0/22772/21476229-7519-880f-f767-3df77cd19a63.png)

**起動スクリプトの内容**

起動スクリプトにはインスタンス起動直後に行いたい初期化処理などを記述できます。
この例ではopenjdk、mysql-client、google-fluentdのインストールを行っています。
コメントアウトしていますが、メタデータサーバーからメタデータを取得して環境変数にセットするということもできます。

```bash
#! /bin/bash

set -e
set -v

# Talk to the metadata server to get the project id
#export PROJECTID=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google")
#export BUCKET=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/attributes/MY_BUCKET" -H "Metadata-Flavor: Google")

#echo "Project ID: ${PROJECTID}  Bucket: ${BUCKET}"

# Install dependencies from apt
sudo apt-get update
sudo apt-get --only-upgrade install -yq google-cloud-sdk
sudo apt-get install -yq openjdk-8-jdk

# Make Java8 the default
sudo update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java

# MySQL
sudo apt-get install -yq mysql-client

# Install logging monitor. The monitor will automatically pickup logs sent to syslog.
curl -sSO "https://dl.google.com/cloudagents/install-logging-agent.sh"
sudo bash install-logging-agent.sh

echo "Startup Complete"
```

ネットワーキングのネットワークタグに"web-app"と入力します。このタグはこのあとに行うファイアウォールルールの追加で使用します。
最後に「作成」ボタンをクリックます。

![vm6.png](https://qiita-image-store.s3.amazonaws.com/0/22772/52b108d7-02e2-74e3-fb6b-fed4571aee51.png)

VMインスタンスが作成されると一覧に表示されます。外部IPにアクセスするとこのVMインスタンスにアクセスできます。ただしエフェメラル(一時的な)IPアドレスです。別途静的IPアドレスを予約して割り当てることもできます。

![vm3.png](https://qiita-image-store.s3.amazonaws.com/0/22772/dd07ffc8-88da-76d5-c42c-88c69495c025.png)

#### SSHで接続する

接続のSSHプルダウンから「gcloudコマンドを表示」を選択します。

![vm4.png](https://qiita-image-store.s3.amazonaws.com/0/22772/a713d051-b07c-c794-fb4c-f24c5ff56cfb.png)

接続に必要なgcloudコマンドラインが表示されます。

![vm5b.png](https://qiita-image-store.s3.amazonaws.com/0/22772/150ef9f4-d1a1-a9f9-84b9-adeb07c02a1d.png)

図に表示されているコマンドラインをWindowsのプロンプトから実行すると、terminalソフトが自動的に立ち上がりVMインスタンスに接続します。

```text
> gcloud compute --project "project-********" ssh --zone "us-east1-b" "web-app-instance-1"
```

VMインスタンスには既にCloud SDKがインストールされています。

```bash
$ gcloud components list
Your current Cloud SDK version is: 194.0.0
The latest available version is: 194.0.0

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                  Components                                                 │
├───────────────┬──────────────────────────────────────────────────────┬──────────────────────────┬───────────┤
│     Status    │                         Name                         │            ID            │    Size   │
├───────────────┼──────────────────────────────────────────────────────┼──────────────────────────┼───────────┤
│ Not Installed │ App Engine Go Extensions                             │ app-engine-go            │ 151.9 MiB │
│ Not Installed │ Cloud Bigtable Command Line Tool                     │ cbt                      │   4.5 MiB │
│ Not Installed │ Cloud Bigtable Emulator                              │ bigtable                 │   3.7 MiB │
│ Not Installed │ Cloud Datalab Command Line Tool                      │ datalab                  │   < 1 MiB │
│ Not Installed │ Cloud Datastore Emulator                             │ cloud-datastore-emulator │  17.9 MiB │
│ Not Installed │ Cloud Datastore Emulator (Legacy)                    │ gcd-emulator             │  38.1 MiB │
│ Not Installed │ Cloud Pub/Sub Emulator                               │ pubsub-emulator          │  33.4 MiB │
│ Not Installed │ Emulator Reverse Proxy                               │ emulator-reverse-proxy   │  14.5 MiB │
│ Not Installed │ Google Container Local Builder                       │ container-builder-local  │   3.8 MiB │
│ Not Installed │ Google Container Registry\'s Docker credential helper│ docker-credential-gcr    │   3.3 MiB │
│ Not Installed │ gcloud app Java Extensions                           │ app-engine-java          │ 118.9 MiB │
│ Not Installed │ gcloud app PHP Extensions                            │ app-engine-php           │           │
│ Not Installed │ gcloud app Python Extensions                         │ app-engine-python        │   6.2 MiB │
│ Not Installed │ gcloud app Python Extensions (Extra Libraries)       │ app-engine-python-extras │  27.8 MiB │
│ Not Installed │ kubectl                                              │ kubectl                  │  12.3 MiB │
│ Installed     │ BigQuery Command Line Tool                           │ bq                       │   < 1 MiB │
│ Installed     │ Cloud SDK Core Libraries                             │ core                     │   7.4 MiB │
│ Installed     │ Cloud Storage Command Line Tool                      │ gsutil                   │   3.4 MiB │
│ Installed     │ gcloud Alpha Commands                                │ alpha                    │   < 1 MiB │
│ Installed     │ gcloud Beta Commands                                 │ beta                     │   < 1 MiB │
└───────────────┴──────────────────────────────────────────────────────┴──────────────────────────┴───────────┘
To install or remove components at your current SDK version [194.0.0], run:
  $ gcloud components install COMPONENT_ID
  $ gcloud components remove COMPONENT_ID

To update your SDK installation to the latest version [194.0.0], run:
  $ gcloud components update
```

Javaのバージョンを確認

```bash
$ java -version
openjdk version "1.8.0_162"
OpenJDK Runtime Environment (build 1.8.0_162-8u162-b12-1~deb9u1-b12)
OpenJDK 64-Bit Server VM (build 25.162-b12, mixed mode)
```

MySQL Clientのバージョンを確認

```bash
$ mysql --version
mysql  Ver 15.1 Distrib 10.1.26-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
```

#### Loggingの確認

IAMで割り当てた”ログ書き込み”とstartup-scriptでインストールしたgoogle-fluentdが有効に機能しているか確認します。

```bash
$ ps -aux | grep google-fluentd
```

確認用のログを書き込みます。
Consoleの「Logging」->「ログ」を開き、このVMインスタンスのログに下記のメッセージがあるか確認します。

```bash
$ logger "test log message"
```

#### VMインスタンスからMySQLにアクセスする

[Cloud SQL > ドキュメント > MySQL > MySQLクライアントをCompute Engineから接続する] (https://cloud.google.com/sql/docs/mysql/connect-compute-engine?hl=ja)

Compute EngineのVMインスタンスからCloud SQLのDBインスタンスに接続する方法はいくつかありますが、この記事ではcloud_sql_proxyを利用しました。

cloud_sql_proxyをインストールします。

```bash
$ wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
$ chmod +x cloud_sql_proxy
```

TCPソケットでプロキシを起動します。instancesに指定する文字列は”インスタンス接続名”です。

```bash
$ ./cloud_sql_proxy -instances=project-********:us-east1:mysql-********-********=tcp:3306 &
[1] 1415
2018/03/28 05:03:00 Listening on 127.0.0.1:3306 for project-********:us-east1:mysql-********-*********
2018/03/28 05:03:00 Ready for new connections
```

MySQLクライアントで接続できるか確認します。

```bash
$ mysql -h 127.0.0.1 -u root -p
Enter password:
2018/03/28 05:03:20 New connection for "project-********:us-east1:mysql-********-*********"
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 178
Server version: 5.7.14-google-log (Google)

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

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

MySQL [(none)]>
```

##### デモ用データベース

webアプリケーションで利用するデータベースを作成します。

```sql
CREATE DATABASE IF NOT EXISTS demo_db
  CHARACTER SET = utf8mb4
  COLLATE = utf8mb4_general_ci;
```

```sql
CREATE USER IF NOT EXISTS 'demo_user'@'%'
  IDENTIFIED BY 'demo_pass'
  PASSWORD EXPIRE NEVER;

GRANT ALL ON demo_db.* TO 'demo_user'@'%';
```

```sql
DROP TABLE IF EXISTS memo;

CREATE TABLE IF NOT EXISTS memo (
  id BIGINT AUTO_INCREMENT,
  title VARCHAR(255) NOT NULL,
  description TEXT NOT NULL,
  done BOOLEAN NOT NULL DEFAULT FALSE,
  updated TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id)
)
ENGINE = INNODB,
CHARACTER SET = utf8mb4,
COLLATE utf8mb4_general_ci;
```

```sql
INSERT INTO memo (id, title, description, done, updated) VALUES
  (1, 'memo shopping', 'memo1 description', false, '2018-01-04 12:01:00'),
  (2, 'memo job', 'memo2 description', false, '2018-01-04 13:02:10'),
  (3, 'memo private', 'memo3 description', false, '2018-01-04 14:03:21'),
  (4, 'memo job', 'memo4 description', false, '2018-01-04 15:04:32'),
  (5, 'memo private', 'memo5 description', false, '2018-01-04 16:05:43'),
  (6, 'memo travel', 'memo6 description', false, '2018-01-04 17:06:54'),
  (7, 'memo travel', 'memo7 description', false, '2018-01-04 18:07:05'),
  (8, 'memo shopping', 'memo8 description', false, '2018-01-04 19:08:16'),
  (9, 'memo private', 'memo9 description', false, '2018-01-04 20:09:27'),
  (10,'memo hospital', 'memoA description', false, '2018-01-04 21:10:38')
;
```

demo_userでログインできることを確認します。

```bash
$ mysql -h 127.0.0.1 -D demo_db -u demo_user -p
```

##### ローカルPC(Windows)から接続する

**gcloudを使って接続する**

MySQL Clientの代わりにgcloudツールでもDBインスタンスに接続できます。このときに使用する情報はDBインスタンスのIDで、インスタンス接続名ではありません。

```text
> gcloud sql connect <db instance id> -u root
Whitelisting your IP for incoming connection for 5 minutes...done.
Connecting to database with SQL user [root].Enter password: ********
```

**cloud_sql_proxyを使って接続する**

[Cloud SQL > ドキュメント > MySQL > ローカルテストにプロキシを使用する場合のクイックスタート] (https://cloud.google.com/sql/docs/mysql/quickstart-proxy-test?hl=ja)

Windows版のcloud_sql_proxyが提供されています。
接続方法はVMインスタンスからの接続と同じです。

```text
> cloud_sql_proxy_x64.exe -instances=project-********:us-east1:mysql-********=tcp:3306
```

#### VMインスタンスからストレージにアクセスする

gsutilツールを利用してバケットのオブジェクトが表示されるか確認します。

```bash
$ gsutil ls gs://<my_bucket_name>
gs://<my_bucket_name>/test.txt
```

バケットからファイルをダウンロードできるか確認します。

```bash
$ gsutil cp gs://<my_bucket_name>/test.txt .
Copying gs://<my_bucket_name>/test.txt...
/ [1 files][    6.0 B/    6.0 B]
Operation completed over 1 objects/6.0 B.
```

バケットへファイルをアップロードできるか確認します。

```bash
$ echo "test" > test2.xt
$ gsutil test2.txt gs://<my_bucket_name>
Copying file://test2.txt [Content-Type=text/plain]...
/ [1 files][    6.0 B/    6.0 B]
Operation completed over 1 objects/6.0 B.
```

### ファイアウォールルールを追加

webアプリケーションはポート9000番をlistenするので9000番を通過させるルールを追加します。
GCP Consoleの左側メニューの「VPCネットワーク」->「ファイアウォール ルール」を選択します。

「ファイアウォール ルールを作成」をクリックして開始します。

![f0.png](https://qiita-image-store.s3.amazonaws.com/0/22772/ab6414b5-5ae4-7d00-385c-d57f1a8a39cd.png)

ターゲットタグには、VMインスタンス作成時に設定したネットワークタグを入力します。タグを指定することでこのルールを適用する対象を決定します。

![f1.png](https://qiita-image-store.s3.amazonaws.com/0/22772/5086c7e2-1797-136f-e474-b904c1f076ab.png)


# GCPで実行するwebアプリケーション

Spring Bootを利用して開発したwebアプリケーションをVMインスタンスで実行する手順は次のように考えています。

ローカルPC上でビルドしてjarファイルを生成

```
> mvn clean package
```

生成したjarファイルをバケットへアップロード

```
> gsutil cp .\target\demo-gcp-spring2-0.0.1-SNAPSHOT.jar gs://<my_bucket_name>
```

バケットからVMインスタンスにjarファイルをダウンロード

```
$ gsutil cp gs://<my_bucket_name>/demo-gcp-spring2-0.0.1-SNAPSHOT.jar .
```

VMインスタンス上でjarファイルを実行

```
$ java -jar demo-gcp-spring2-0.0.1-SNAPSHOT.jar
```

ブラウザでアクセス

```
http://<VMインスタンスの外部IP>:9000/<アプリケーションAPI>
```

**jarファイルの送信**

[Compute Engine >ドキュメント > インスタンスへのファイルの転送] (https://cloud.google.com/compute/docs/instances/transfer-files?hl=ja)

VMインスタンスへjarファイルを送信するのにバケットを経由していますが、gcloud compute scpコマンドを利用する方法もあります。

```text
> gcloud compute scp <local_file_name> <instance_id>:/tmp
```


## アプリケーションの仕様

memoテーブルのデータを1件または複数件をjsonで返すREST APIです。

### 1件取得するAPI

```
/app/memo/{id}
```

**レスポンスの例**

```json
{
    "id": 1,
    "title": "memo shopping",
    "description": "memo1 description",
    "done": false,
    "updated": "2018-01-04T12:01:00"
}
```

### 複数件取得するAPI

```
/app/memo/list?size=3
```

**レスポンスの例**

```json
[
    {
        "id": 1,
        "title": "memo shopping",
        "description": "memo1 description",
        "done": false,
        "updated": "2018-01-04T12:01:00"
    },
    {
        "id": 2,
        "title": "memo job",
        "description": "memo2 description",
        "done": false,
        "updated": "2018-01-04T13:02:10"
    },
    {
        "id": 3,
        "title": "memo private",
        "description": "memo3 description",
        "done": false,
        "updated": "2018-01-04T14:03:21"
    }
]
```

# 補足

## Cloud Storage JSON API

[Cloud Storage >ドキュメント > Google Cloud Storage JSON API の概要] (https://cloud.google.com/storage/docs/json_api/?hl=ja)

VMインスタンスからcurlを使ってバケットの情報を取得する方法です。APIの認証はOAuth 2.0を使います。

認証に必要なアクセストークンを取得します。
このトークンはVMインスタンスのサービスアカウントから出力したものです。

```bash
$ gcloud auth list
                             Credentialed Accounts
ACTIVE  ACCOUNT
*       compute-engine-web-application@project-********.iam.gserviceaccount.com

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
```

```bash
$ gcloud auth print-access-token
<access_token>
```

Authorizationヘッダーに取得したアクセストークンを指定します。
この`/b/<bucket>/o`JSON APIは\<bucket\>で指定したバケットのオブジェクトの一覧を返します。

```bash
$ curl 'https://www.googleapis.com/storage/v1/b/<bucket>/o' \
  -H 'Authorization: Bearer <access_token>' \
  -H 'Accept: application/json' \
  --compressed
```