SpringBootをKubernetes上で動かしてみる

## about
SoftwareDesign 2018/3号を読んでいてKubernetesに少し興味を持ったので試してみました。
色々ハマりどころがあるかと思いましたが、環境構築〜デプロイ、スケールまで割りとすんなりと進めることができました。

## 環境
- macOS High Sierra 10.13.3
- Kubernetes v1.8.0
- minikube v0.24.1
- VirtualBox v5.2.6 r120293

## インストール

### VirtualBox

```bash
$ brew cask install virtualbox
```

※Hish Sierraだとインストール中に止まってしまうことがあります。
その場合は`システム環境設定 > セキュリティとプライバシー`でOracleがブロックされたみたいなものが表示されているので「許可」するとインストールできます。
(スクリーンショット撮り忘れ)

### minikube

```bash
$ brew cask install minikube
```

### 動作確認

minikubeの起動

```bash
$ minikube start
Starting local Kubernetes v1.8.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.
```

VirtualBox上でminikubeが作成されて起動していることが確認できます

<img width="841" alt="スクリーンショット 2018-02-24 17.28.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/24467/5344128a-6bf6-9e02-9788-f2311220242c.png">

デプロイメントの作成

```bash
# deployment
$ kubectl run hello-minikube --image=k8s.gcr.io/echoserver:1.4 --port=8080
deployment "hello-minikube" created

$ kubectl expose deployment hello-minikube --type=NodePort
service "hello-minikube" exposed

$ kubectl get pod
NAME                              READY     STATUS    RESTARTS   AGE
hello-minikube-7844bdb9c6-88hl4   1/1       Running   0          2m
```

この状態でダッシュボードを確認してみると

```bash
# ダッシュボードの起動
$ minikube dashboard
```

デプロイメントとポッドが作成される。
<img width="1109" alt="スクリーンショット 2018-02-24 17.35.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/24467/f06872db-f992-7b43-c698-f356895c402f.png">

```bash
# URLの確認
$ minikube service hello-minikube --url

$ curl $(minikube service hello-minikube --url)
CLIENT VALUES:
client_address=172.17.0.1
command=GET
real path=/
・
・
・
```

```bash
# サービスの削除
$ kubectl delete service hello-minikube
service "hello-minikube" deleted

# デプロイメントの削除
$ kubectl delete deployment hello-minikube
deployment "hello-minikube" deleted

# minikube終了
$ minikube stop
Stopping local Kubernetes cluster...
Machine stopped.
```

## Spring BootのDocker環境を用意する

今回は公式チュートリアルの完成版を利用します。
https://spring.io/guides/gs/spring-boot-docker/

スターターをclone

```bash
$ git clone https://github.com/spring-guides/gs-spring-boot-docker.git
# 完成版を使う
$ cd gs-spring-boot-docker/complete
$ ./gradlew build docker
・
・
・
:processTestResources NO-SOURCE
:testClasses
:test
:check
:build
:dockerClean UP-TO-DATE
:dockerPrepare
:docker

BUILD SUCCESSFUL

Total time: 1 mins 37.278 secs
```

動かしてみる

```bash
$ docker images
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
springio/gs-spring-boot-docker   latest              d486fdb38288        4 minutes ago       116MB

$ docker run -p 8080:8080 -t springio/gs-spring-boot-docker
```

docker上でSpringBootが起動しました。

<img width="1107" alt="スクリーンショット 2018-02-24 21.11.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/24467/48ef6c5a-540c-d4e5-7bd8-43268d6c331e.png">

## kubernetes上で動かす

環境変数の設定

```bash
$ minikube start
$ eval $(minikube docker-env)
# この状態では一時的にローカルPCからdockerへの接続などができなくなりますが、ターミナルを再起動すれば設定が消えて元にもどります。
```

サービスの設定ファイルを以下の内容で作成する。

```kubernetes-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: hellojavakubernetes
  labels:
    app: hellojavakubernetes
    tier: backend
spec:
  type: NodePort
  ports:
    # the port that this service should serve on
  - port: 8080
  selector:
    app: hellojavakubernetes
    tier: backend
```

サービスの登録

```bash
$ kubectl create -f kubernetes-service.yaml
```

`hellojavakubernetes`サービスが登録されました。

<img width="1104" alt="スクリーンショット 2018-02-24 21.43.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/24467/40aebf6e-a144-0030-f8f2-ad6f7f3aaf87.png">

デプロイメント設定ファイルを以下の内容で作成する。

```kubernetes-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: hellojavakubernetes
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: hellojavakubernetes
        tier: backend
    spec:
      containers:
      - name: hellojavakubernetes
        image: springio/gs-spring-boot-docker
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 8080
```

デプロイしてみる。

```bash
$ kubectl create -f kubernetes-deployment.yaml
deployment "hellojavakubernetes" created

$ kubectl get deployment
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hellojavakubernetes   1         1         1            1           3m
```
`hellojavakubernetes`というデプロイメントが作成され、ポッドも作成されています。

<img width="1107" alt="スクリーンショット 2018-02-24 21.54.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/24467/8c54af54-8355-9d47-0635-17182c659ecb.png">

URLを調べる。

```bash
$ minikube service hellojavakubernetes --url
http://192.168.99.100:31830
```

表示されたURLにアクセスする
<img width="1106" alt="スクリーンショット 2018-02-24 22.04.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/24467/da74a7b9-aa56-40d9-a112-fb1fb3479759.png">

正しく表示されました。
ここまで詰まることなく進めることができました。

## アプリケーションのスケーリング

せっかくなのでスケーリングしてみます。

```bash
$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hellojavakubernetes   1         1         1            1           17h

# replicasを指定する
$ kubectl scale --replicas=2 -f kubernetes-deployment.yaml 
deployment "hellojavakubernetes" scaled

# deploymentsの数が2に増えました。
$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hellojavakubernetes   2         2         2            2           17h
```

ポッドの数が2つに増えていることがわかります。

<img width="1111" alt="スクリーンショット 2018-02-25 15.48.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/24467/821adb0f-1dcf-bc7d-0fdc-3afe539fd349.png">

続いて設定ファイルから変更してみます。
上の方で作成した`kubernetes-deployment.yaml`の`replicas`を`3`に変更します。

```bash
# 設定の適用
$ kubectl apply -f kubernetes-deployment.yaml 
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment "hellojavakubernetes" configured

$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hellojavakubernetes   3         3         3            3           17h
```

こちらも無事スケールできました。

## 後始末

終了する

```bash
$ kubectl delete service,deployment hellojavakubernetes
$ minikube stop
$ minikube delete
```

本番で運用するにはまだまだ調べることが多そうですがKubernetes自体はかなり完成されているなという印象でした。


## 参考ページ
[minikube]
https://github.com/kubernetes/minikube

[Spring Boot with Docker]
https://spring.io/guides/gs/spring-boot-docker/

[getting started]
https://www.bluefyre.io/getting-started-springboot-kubernetes/