GKE(Google Kubernetes Engine)を始めてみるハンズオン

# 前提

- GKE初学者である筆者が、ツールを立ち上げた作業手順に沿ったハンズオンです。
- 勉強ついでにやっていることもあって、情報が足りていないなどのご指摘は大歓迎です。
- GCPのアカウントは取得した前提で開始します。

# 環境構築

早速、環境を構築していきます。
まずは、サイドメニューからKubernetes Engineを選択します。
初めてアクセスする場合、プロジェクトの初期セットアップで数分待つことになります。

![GKE-Top.png](https://qiita-image-store.s3.amazonaws.com/0/30230/0074260a-b1f7-bea1-7459-d36fbfbd7541.png)

## クラスタの作成

準備ができたら「クラスタを作成」をクリックして、設定画面へ移動します。
ここで選択できる内容に、なかなか強烈な機能がありますが、今回は初期設定のまま進めるため、そのまま「作成」をクリックしてください。
![GKE-クラスタの作成.png](https://qiita-image-store.s3.amazonaws.com/0/30230/ecacc4a3-fa09-5cc8-a4dc-4fdaf947d7d2.png)

作成が完了するまで5分程度待ちます。以下のようになれば作成完了です。

![GKE-クラスタの作成完了.png](https://qiita-image-store.s3.amazonaws.com/0/30230/12b6f250-e55d-2598-f731-455beb6dc0eb.png)

## クラスタに接続

作成したクラスタに接続します。
接続するには、先ほどの画面で「接続」→「Cloud Shell で実行」の順でクリックするのが手っ取り早いと思います。
Cloud Shellが立ち上がって、接続用のコマンドが入力されているので、そのまま実行します。

試しにコマンドを実行してみます。

```shell-session
$ kubectl get pods
No resources found.
```

まだ何も立ち上げていないので、Podは立ち上がっていません。
Podはコンテナの集合を表すKubernetes独自の用語です。
基礎的な用語だけでも押さえておくと後々勉強が捗ると思います。
https://kubernetes.io/docs/reference/glossary/?fundamental=true

## ツールの立ち上げ

今回は[Passman](https://passman.cc/)という認証情報管理ツールを立ち上げたいという思惑があったので、ツールが動作するように設定していきます。

### 秘密情報の登録

Kubernetesを利用するメリットの一つでもありますが、APIトークンやミドルウェアのパスワードなど、バージョン管理システムに保持させたくない秘密情報を登録する仕組みとしてSecretsという機能があります。
今回はSecretsにPassmanで使用するAdminユーザーのユーザー名とパスワードを登録します。

[手動で設定する場合はbase64エンコードで設定してね](https://kubernetes.io/docs/concepts/configuration/secret/#creating-a-secret-manually)ということで、エンコードした文字列を用意します。

```shell-session
$ echo -n "your_username" | base64
eW91cl91c2VybmFtZQ==
$ echo -n "your_password" | base64
eW91cl9wYXNzd29yZA==
```

`kubectl create`を使いたいので、以下のファイルを作成します。

```yaml:secret.yml
apiVersion: v1
kind: Secret
metadata:
  name: passman
type: Opaque
data:
  admin_user: eW91cl91c2VybmFtZQ==
  admin_password: eW91cl9wYXNzd29yZA==
```

`kubectl create`を実行します。

```shell-session
$ kubectl create -f secret.yml
secret "passman" created
$ kubectl get secrets
NAME                  TYPE                                  DATA      AGE
default-token-jthk4   kubernetes.io/service-account-token   3         41m
passman               Opaque                                2         2m
```

これでSecretsにpassmanという名前で秘密情報が登録されました。

### Podの立ち上げ

次は[Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)の機能を使って、Podを立ち上げます。

まずは、Yamlの用意から。
Podに含めたいコンテナの情報と環境変数を定義しています。
HOSTNAMEは本来立ち上げるツール名を渡すところですが、便宜上、demo.example.comとしています。
この記事を読んでいてPassmanを使いたいという人は少ないだろうということで、軽くスルーしてください。

```yaml:deployment.yml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: passman
  labels:
    app: passman
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
  selector:
    matchLabels:
      app: passman
  template:
    metadata:
      labels:
        app: passman
    spec:
      containers:
      - name: passman
        image: brantje/passman-docker
        env:
          - name: HOSTNAME
            value: demo.example.com
          - name: TZ
            value: Asia/Tokyo
          - name: ADMIN_USER
            valueFrom:
              secretKeyRef:
                name: passman
                key: admin_user
          - name: ADMIN_PASSWORD
            valueFrom:
              secretKeyRef:
                name: passman
                key: admin_password
        ports:
          - containerPort: 8888
          - containerPort: 8443
        imagePullPolicy: Always
```

余談ですが、長らくapi/v1beta1となっていたapiVersionですが、Kubernetes v1.9からapp/v1に切り替わったようです。
執筆時点では、GKEのクラスタを立ち上げる際、v1.8.7がデフォルトだったため、api/v1beta1を指定しています。
GKEはMaster, Nodesのバージョンアップが容易にできること、Masterに至っては自動更新されることに留意してください。

Podsを立ち上げます。

```shell-session
$ kubectl create -f deployment.yml
deployment "passman" created
$ kubectl get pods --watch
NAME                       READY     STATUS              RESTARTS   AGE
passman-68c555f5c5-dlsm9   0/1       ContainerCreating   0          20s
passman-68c555f5c5-l4p27   0/1       ContainerCreating   0          20s
passman-68c555f5c5-dlsm9   1/1       Running   0         24s
passman-68c555f5c5-l4p27   1/1       Running   0         25s
```

-w,--watchは、更新を検知したタイミングで表示に反映してくれるオプションです。
これで、Podが立ち上がるところまで確認できました。

この状態ではアクセスする口がないので、Serviceを立ち上げます。

### Serviceの立ち上げ

先ほどまでと同様にYamlを用意します。
今回はロードバランサ経由で、それぞれのPodのコンテナポートにアクセスするよう設定しています。

```yaml:service.yml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: passman
  name: passman
spec:
  type: LoadBalancer
  selector:
    app: passman
  ports:
    - name: http
      port: 80
      targetPort: 8888
    - name: https
      port: 443
      targetPort: 8443
```

`kubectl create`コマンドを実行します。

```shell-session
$ kubectl create -f service.yml
service "passman" created
$ kubectl get svc --watch
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
kubernetes   ClusterIP      10.11.240.1     <none>        443/TCP                      1h
passman      LoadBalancer   10.11.244.209   <pending>     80:30826/TCP,443:32687/TCP   24s
passman   LoadBalancer   10.11.244.209   XXX.XXX.XXX.XXX   80:30826/TCP,443:32687/TCP   50s
```

`kubectl get svc`は、`kubectl get services`の省略形です。
LoadBalancerのExternal-IPがEndPointです。

今回、ドメインを取得していないので、/etc/hostsに定義するなどして確認します。

![GKE-Passman.png](https://qiita-image-store.s3.amazonaws.com/0/30230/bdb3ec15-1ea3-19fc-ae19-8492855f5e81.png)

Passmanがきちんと動作するまでの設定を省略していますが、コンテンツを表示できる状態で公開することができました。

# 立ち上げたPodの落とし方

Podに限りませんが、`kubectl create`で生成したものは`kubectl delete`で削除できます。
試しにDeploymentを削除してみます。

```shell-session
$ kubectl get deploy
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
passman   2         2         2            2           8m
$ kubectl delete -f deployment.yml
deployment "passman" deleted
$ kubectl get deploy
No resources found.
```

Deploymentで立ち上げたPodは、`kubectl delete`でPodを落としてもすぐに必要数起動するので、ちゃんと落ちてくれません。
Deploymentで立ち上げたPodを落としたい場合は、Deploymentごと落としたほうがよさそうです。

# 設定の編集

少しだけ設定をいじってみたいけど、Yaml書き換えてdelete/createするのはめんどくさいと思う時もあると思います。
そんなときは`kubectl edit`が便利です。

以下のコマンドを実行すると、実行中のDeploymentの定義をYamlとして表示してくれて、修正を保存するとPodに反映されるようになっています。

```
$ kubectl edit deploy passman
```

今回はYamlを書いてcreateする流れで説明しましたが、個別にコマンドで立ち上げたものをeditで表示して、それを参考にYamlを書くこともできます。

# 最後に

Kubernetesは機能がリッチで痒いところに手が届く反面、学習コストが高い・・・という誤解もありそうですが、単純な機能だけで必要最低限の導入はできたかと思います。
運用となるといろいろ詰まるところもありそうですが、そこはGKEがフォローしてくれている感があります。
私自身、まだまだ勉強中ではありますが、使えば使うほどわくわくするツールだと思います。

この部分どうなってるの？など疑問に思った内容があれば、一緒に考えてみたいので気軽にコメントいただけると嬉しいです。