GCE + GCR + Docker(JIB)の覚え書き

# 概要
GCEでDockerが簡単に使えることを知ったのでやった。
KotlinでのWebアプリケーション作ってみた。

### 前提
「GCPのGCRにJIBを使ったDocker Imageをdeployして、GCEを簡単に作成する」が
「パルスのファルシのルシがパージでコクーン」という言葉を思い出したりするので、頭の整理をする

|言葉||何に使うか|
|---|---|---|
|GCP| Google Cloud Platform |Googleのクラウドサービス全体|
|GCE| Google Compute Engine |Docker Imageを動かすサーバ|
|GCR| Google Container Repository |Docker Imageを保存するレポジトリ|
|JIB| https://github.com/GoogleContainerTools/jib |Javaのアプリケーションを簡単にDockerImageにできる|

## 読んで得する人
* Java(or Kotlin)でのアプリケーションのDocker化ってどうやるの？って人
* GCPでDocker使いたいんだけどっていう人(not GKEなので注意、GCRにdeployする部分は参考になる？)

## 環境
|名前|version|
|---|---|
|Gradle|5.4.1|
|JIB|1.2.0|
|GCloud|240.0.0|
|Kotlin|1.3.31|
|Spring Boot|2.2.0.M3|

## やること
- 前準備
- JIBの設定する
- ローカルでの確認する
- GCRにdeployする
- GCEで動かす

### 前準備
GCRにdeployするので、gcloudコマンドが使えるようにしておく
https://cloud.google.com/sdk/downloads?hl=ja
このあたりを参考にインストールをする。そして最後のinit時に利用するGCPに対するログインを行う。

### JIBの設定
アプリケーションはSpringBootで適宜作っているとしてbuild.gradleに以下を追加する

```build.gradle
plugins {
    // jibのpluginの追加
    id 'com.google.cloud.tools.jib' version '1.2.0'
}

// わからないことがあれば
// https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md
// https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin
// などを見てもらうと良いかも
jib {
    to {
        image = 'gcr.io/${ログインしたGCPのプロジェクトID}/${アプリケーションの名前}' // DockerImageのpush先
        // 以前プロジェクト名と書いてましたが、、、間違い(https://cloud.google.com/container-registry/docs/overview?hl=ja の通り)
        auth {
            username = 'oauth2accesstoken' // gcrにコマンドでdeployする際に使える名前
            password = 'gcloud auth print-access-token'.execute().text.trim() // gcloudが端末に入っていること前提でのpassを作成するコマンド。おそらくGCRを使う場合はこのauthで良いと思われ
        }
    }
    from {
        image = 'openjdk:alpine' // pullしてくるImage。ここは自分の好きなものを使う
    }
    container {
        mainClass = 'jp.john.test.MainKt' // 起動のentiry point。SpringBoot + Kotlinなら main関数 が記載されているクラス
        jvmFlags = [
                '-Dspring.profiles.active=product'
        ] // SpringBootに渡したい値があればこちらを使う
        format = 'OCI' // buildしたimageの形式。よくわかっていないが、Defaultの 'Docker' よりOpenな規格のようである( https://qiita.com/mamomamo/items/ed5db2ab1555078f8a24 )
    }
}
```

普通はこれで終わり、既存部分を変更しなくて良い。以下タスクが追加されている

- jib
- jibBuildTar
- jibDockerBuild

task treeを見ればわかるが jib は基本コンパイルをしてImageに追加しているだけ。

```sh
$ ./gradlew taskTree jib
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :taskTree

------------------------------------------------------------
Root project
------------------------------------------------------------

:jib
+--- :classes
     +--- :compileJava
     |    \--- :compileKotlin
     \--- :processResources
```

## ローカルでとりあえず起動させる
ローカルでImageを作成する

```sh

$ ./gradlew jibDockerBuild

> Task :compileKotlin

> Task :jibDockerBuild
Setting image creation time to current time; your image may not be reproducible.

Containerizing application to Docker daemon as gcr.io/${ログインしたGCPのプロジェクト名}/${アプリケーションの名前}...
The base image requires auth. Trying again for openjdk:alpine...

Container entrypoint set to [java, -Dspring.profiles.active=product, -cp, /app/resources:/app/classes:/app/libs/*, jp.john.test.MainKt]

Built image to Docker daemon as gcr.io/${ログインしたGCPのプロジェクト名}/${アプリケーションの名前}
Executing tasks:
[==============================] 100.0% complete

BUILD SUCCESSFUL in 36s
3 actionable tasks: 3 executed
```

Imageができたらdockerコマンドで起動する(ポート8080でアプリケーションで起動するものとする)

```
$ docker container run --rm -it -p 8080:8080 gcr.io/${ログインしたGCPのプロジェクト名}/${アプリケーションの名前}
```

ブラウザから確認して動いたらOK

## GCRにdeployする
ここは前準備(gcloudの設定)ができていれば全く難しくない

```sh
$ ./gradlew jib
```

GCR上で作成されていたらOK（自分でレポジトリを作るなどしなくても良い）

## GCEで動かす

前にGCRにdeployできていれば全く難しくない（２回目

GCRに上がったImageをclickして「GCEにデプロイ」を選択する
<img width="179" alt="スクリーンショット 2019-06-03 0.46.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75299/43aa5b24-28c6-7ac9-0079-d049031c4563.png">

設定についてはDocker部分は全くいじらなくて良いはず。（コンテナのタグがlatestになっているはず
リージョンなどは適宜変更する。
ファイアウォールはポート8080を開けているものを指定する。（dockerで利用した-pオプションはファイアウォール対応する形になる
https://cloud.google.com/compute/docs/containers/configuring-options-to-run-containers?hl=ja#publishing_container_ports

http://${ip}:8080 に対してアクセスして対象のアプリケーションが確認できれば、OK
ファイアウォールについては、GCEの設定について説明している記事を参考にしてもらえれば。

## 補足

### deployしたimageをつかって再起動してほしいのだが？
defaultのGCEの設定で再起動するとpullするので、GCEの対象のコンテナを再起動するだけでよい。
もし指定したタグのもので再起動したい場合は、コンテナのタグをGCRの対象のタグにする。

### ローカルで動いたのに、GCE上で動かないんだが？

GCEのインスタンスにsshでの接続をして以下のコマンドを叩くと、エラーが出ていることを確認できる

```sh
$ sudo journalctl -u docker-events-collector
```

```
2019-05-23 04:11:31 +0000 [warn]: #0 Dropping 33 log message(s) error="User unauthorized to access {なんかのid}" error_code="7"
2019-05-23 04:11:36 +0000 [warn]: #0 Dropping 1 log message(s) error="User unauthorized to access {なんかのid}" error_code="7"
2019-05-23 04:11:42 +0000 [warn]: #0 Dropping 1 log message(s) error="User unauthorized to access {なんかのid}" error_code="7"
2019-05-23 04:11:48 +0000 [warn]: #0 Dropping 1 log message(s) error="User unauthorized to access {なんかのid}" error_code="7"
2019-05-23 04:11:53 +0000 [warn]: #0 Dropping 1 log message(s) error="User unauthorized to access {なんかのid}" error_code="7"
2019-05-23 04:12:00 +0000 [warn]: #0 Dropping 21 log message(s) error="User unauthorized to access {なんかのid}" error_code="7"
2019-05-23 04:12:05 +0000 [warn]: #0 Dropping 1 log message(s) error="User unauthorized to access {なんかのid}" error_code="7"
```

どうやら権限が無いようです。詰まってた人が同じようにいた。

https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/issues/295

新しく作成していたサービスアカウントに対して Monitor などに対しての権限がなかったから動かないらしい。
なのでGCEのサービスアカウントはデフォルトで用意されているらしい `{プロジェクト名}@appspot.gserviceaccount.com` を使ってやるととりあえず動く。