Docker / Kubernetes お試し環境構築

## 概要

今さら Docker / Kubernetes のお試し環境を構築したときの備忘録的なメモ。


## 環境

- Windows 10 Home (Version 1909)
- VirtualBox (6.1.6)
- Docker Toolbox (19.03.1)
- Minikube (v1.9.2)
- kubectl (v1.18.0)

## 各種ツールのインストール

### VirtualBox

後述のDocker ToolboxのインストーラにもVirtualBoxは入っているが、バージョンが古いので[VirtualBox公式](https://www.virtualbox.org/)から最新版をダウンロードしてインストールする。


### Docker Toolbox

後述のMinikubeのVMにsshで繋げばDockerを使うこともできるようだが、Kubernetesが
管理するDockerイメージと開発用途のDockerイメージが混在してしまいそうだったのでDockerも入れておいた。

Docker Desktop for Windowsは現時点ではWindows 10 Homeで利用できないため、かわりに[Docker Toolbox](https://docs.docker.com/toolbox/toolbox_install_windows/)をインストールした。Windows 10 Home でもVersion 2004以降でWSL2が利用できるようになればDocker Desktopが利用できるようになるらしい。

インストール途中のコンポーネント選択では

- 「VirtualBox」のチェックがデフォルトONになっているが、このままだと古いバージョンが上書きインストールされてしまうのでON → OFF
- 「Kitematic」はGUIでDockerを操作するツールらしいが自分は使わないのでON → OFF

インストールが完了するとデスクトップに「Docker Quickstart Terminal」のショートカットができているので、これを実行すればDockerを起動できる。

初回実行時、VirtualBox上にVM(default)が作成される。

### Minikube

「[Minikubeのインストール](https://kubernetes.io/ja/docs/tasks/tools/install-minikube/)」を参考に、Minikubeのダウンロードとインストールを行う。

初回実行時、VirtualBox上にVM(minikube)が作成される。

```
 > minikube --vm-driver=virtualbox start
```

### kubectl

「[kubectlのインストールおよびセットアップ](https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/) > [Windowsへkubectlをインストールする](https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/#install-kubectl-on-windows)」から最新版のkubectl.exeをダウンロードし、環境変数 **PATH** の通るところに配置する。


## Dockerを使ってみる

### Docker Hubのアカウント取得

テスト用のDockerイメージを管理するため、[Docker Hub](https://hub.docker.com/)のアカウントを取得しておく。

### Dockerイメージの作成

Dockerfileを作成する。

```Dockerfile
FROM openjdk:latest

RUN mkdir /app
WORKDIR /app
COPY hello.jar /app

CMD ["java", "-jar", "hello.jar"]
```

本体となる hello.jar は Hello World 的な Spring Bootアプリ。お試しで動かすだけの簡単なアプリなので詳細は割愛する。

Dockerfileとhello.jarを適当なフォルダに配置して、Dockerイメージをビルドする。

```
$ dir
Dockerfile  hello.jar

$ docker build -t hello .                                                                                             Sending build context to Docker daemon  17.62MB
Step 1/5 : FROM openjdk:latest
 ---> 0ce6496aae74
Step 2/5 : RUN mkdir /app
 ---> Running in 95d7b507569b
Removing intermediate container 95d7b507569b
 ---> 72bd239b1ac9
Step 3/5 : WORKDIR /app
 ---> Running in 99b2d010dd91
Removing intermediate container 99b2d010dd91
 ---> 6996d49d91fd
Step 4/5 : COPY hello.jar /app
 ---> 6f7b6f768860
Step 5/5 : CMD ["java", "-jar", "hello.jar"]
 ---> Running in cc884d09e717
Removing intermediate container cc884d09e717
 ---> 003acb6a5f2f
Successfully built 003acb6a5f2f
Successfully tagged hello:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              003acb6a5f2f        5 seconds ago       515MB
openjdk             latest              0ce6496aae74        5 days ago          497MB
```

動作確認のため実行してみる。

```
$ docker run -p 80:8080 hello
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.6.RELEASE)

2020-04-22 08:52:45.809  INFO 1 --- [           main] satr.beta.hello.HelloApplication         : Starting HelloApplication on 991bcda59f75 with PID 1 (/app/hello.jar started by root in /app)
...
```

レスポンスが返ってくることを確認。

```
>curl http://192.168.99.101/hello
{"message":"hello"}
```

### Docker Hubへのアップロード

Kubernetesからダウンロードして使えるように、Docker Hubにアップロードする。

アップロード用にタグ作成。

```
$ docker tag 003acb6a5f2f satrbeta/hello

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              003acb6a5f2f        About an hour ago   515MB
satrbeta/hello      latest              003acb6a5f2f        About an hour ago   515MB
openjdk             latest              0ce6496aae74        5 days ago          497MB
```

Docker Hub にアップロード。

```
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: satrbeta
Password:
WARNING! Your password will be stored unencrypted in C:\Users\admin\.docker\config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

$ docker push satrbeta/hello:latest
The push refers to repository [docker.io/satrbeta/hello]
2df05793064f: Pushed                                                                                                  5cd21ef616f9: Pushed                                                                                                  873ee7cdfd93: Mounted from library/openjdk                                                                            0639bcb73dcd: Mounted from library/openjdk                                                                            bc198e3a2f79: Mounted from library/openjdk                                                                            latest: digest: sha256:02c7cf1be53d5a4b5a3ea981ac2d38ad5720ea61db02070d9c5925b414116d6d size: 1373
```

https://hub.docker.com/repository/docker/satrbeta/hello にアップロードされた。


## Kubernetes(Minikube)を使ってみる

### ネームスペース変更

作成直後は default ネームスペースを利用するようになっているので適当なネームスペースを作成して切り替えておく。

```
> kubectl create namespace hello
namespace/hello created

>kubectl config set-context minikube --namespace=hello
Context "minikube" modified.

>kubectl config get-contexts
CURRENT   NAME       CLUSTER    AUTHINFO   NAMESPACE
*         minikube   minikube   minikube   hello
```

### Deploymentの作成

Deployment用のマニフェストを用意する。

```deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: satrbeta/hello:latest
        ports:
        - containerPort: 8080
```

Deploymentを作成する。

```
>kubectl apply -f deployment.yaml
deployment.apps/hello created

>kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
hello-6d95f58998-srn2p   1/1     Running   0          30s
hello-6d95f58998-ts56z   1/1     Running   0          30s
```

### Serviceの作成

Service用のマニフェストを用意する。

```service.yaml
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
```

Serviceを作成する。

```
>kubectl apply -f service.yaml
service/hello created

>kubectl get service
NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
hello   ClusterIP   10.102.212.52   <none>        80/TCP    24s
```

### Ingressの作成

Minikubeはインストール時点ではIngressアドオンが無効になっているので有効にする。(無効のままでも作成はできたがIPアドレスが割り当たらなかった)

```
>minikube addons enable ingress
* The 'ingress' addon is enabled
```

Ingress用のマニフェストを用意する。

```ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: hello
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: hello
          servicePort: 80
```

Ingressを作成する。

```
>kubectl apply -f ingress.yaml
ingress.networking.k8s.io/hello created

>kubectl get ingress
NAME    CLASS    HOSTS   ADDRESS          PORTS   AGE
hello   <none>   *       192.168.99.100   80      46s
```

### 動作確認

cURLでAPIをたたいてみる。

```
> curl http://192.168.99.100/hello
{"message":"hello"}
```

Ingress経由でリクエストが実行できることが確認できた。