【息抜きアウトプット】Minikubeにノード外からアクセスせよ

# はじめに

この記事でやりたいことは表題の通りです。最近はインプットが多かったので気分転換にMinikubeで遊ぶことにしました。あまり役に立つ内容ではないかもですが、やってみたら以外に苦戦したので記事にしました。

# 構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1474054/3f2b719a-05f3-9295-885c-22a12b8c83a1.png)

# Minikubeをインストールする

まずは何も考えず、EC2にログインしてDockerとMinikubeをインストールします。
インストールのshellは以下の通りです。MinikubeはDocker上で動かすとします。

```bash:install-docker.sh
#!/bin/bash

VERSION="20.10.17"
sudo yum install -y docker-${VERSION}
sudo systemctl start docker
sudo usermod -aG docker $(whoami)
```

```bash:install-minikube.sh
#!/bin/bash

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
minikube start \
--kubernetes-version=v1.25.2 \
--driver=docker
```

SSHでEC2に接続すると、`minikube kubectl`コマンドを実行できます。

```bash
[ec2-user@ip-10-0-0-193 ~]$ minikube kubectl -- get node
NAME       STATUS   ROLES           AGE     VERSION
minikube   Ready    control-plane   6m39s   v1.25.2
```

今回はクライアントから`kubectl`でアクセスできることを目指します。

※参考
https://minikube.sigs.k8s.io/docs/start/

# クライアントにkubectlをインストールする

初めにクライアントにてkubectlをインストールします。

```bash
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.25.2/bin/linux/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl
```

この時、クラスタと同じバージョンをインストールするようにします。
もしメジャーバージョンがクライアントと大きく異なっていると以下のような警告文が出て、エラーが起きる可能性があります。

```bash
WARNING: version difference between client (1.23) and server (1.25) exceeds the supported minor version skew of +/-1
```

`kubectl version`コマンドにてClientとServerのバージョンが同じであれば問題ありません。

※参考
https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/

# クライアントからのアクセスをセキュリティグループにて許可する

アクセス制限している場合はクライアントのIPアドレスとポートをセキュリティグループにて許可する必要があります。

どのポートを使っているかはkubeconfigファイルを見ればわかります。

```bash
[ec2-user@ip-10-0-0-193 ~]$ cat .kube/config | grep server
    server: https://192.168.49.2:8443
```

8443ポートを使っています。しかし、IPアドレスが違います。
IPアドレスはMinikubeコンテナのものです。コンテナ上でMinikubeを動かしているためです。

```bash
[ec2-user@ip-10-0-0-193 ~]$ docker exec minikube hostname -i
192.168.49.2
```

`kubectl`のアクセス先はkubeconfigファイルで定義されます。そのため、EC2では`kubectl`を実行できます。
しかし、クライアントからはEC2を通して、Minikubeコンテナへアクセスする用意する必要があります。
コンテナではどのようにポートが使われているか確認します。

```bash
[ec2-user@ip-10-0-0-193 ~]$ docker ps
CONTAINER ID   IMAGE                                 COMMAND                  CREATED          STATUS          PORTS                                                                                                                                  NAMES
b9eeb00837c9   gcr.io/k8s-minikube/kicbase:v0.0.36   "/usr/local/bin/entr…"   55 minutes ago   Up 55 minutes   127.0.0.1:49157->22/tcp, 127.0.0.1:49156->2376/tcp, 127.0.0.1:49155->5000/tcp, 127.0.0.1:49154->8443/tcp, 127.0.0.1:49153->32443/tcp   minikube
```

8443ポートはローカルホストの49154ポートにマッピングされていました。
そのため、以下のようにkubeconfigファイルを書き換えてもアクセスできます。

```bash
[ec2-user@ip-10-0-0-193 ~]$ cat .kube/config | grep server
    #server: https://192.168.49.2:8443
    server: https://127.0.0.1:49154
```

クライアントからもEC2の49154ポートにアクセスすればよさそうです。
セキュリティグループにて許可します。
ただし、マッピングされるポートはデフォルトでは固定ではないので注意が必要です。

※参考
https://github.com/kubernetes/minikube/issues/14364

# クライアントにてkubeconfigファイルを作成する

クライアントにてEC2にあるkubeconfigと同じようなファイルを作成します。
注意点は以下の２点です。
* k8s APIサーバーのアドレス、ポート
* クライアント証明書、鍵

サーバーとクライアントのkubeconfigファイルの違いは以下の通りです。

```bash
$ diff <サーバーのkubeconfig> ＜クライアントのkubeconfig＞
4c4
<     certificate-authority: /home/ec2-user/.minikube/ca.crt
---
>     certificate-authority: /path/to/ca.crt #クライアントのローカルにコピーしておきます。
11c11
<     server: https://192.168.49.2:8443
---
>     server: https://18.183.225.65:49154 #k8s APIサーバーのアドレス、ポートを変えておきます。
31,32c31,32
<     client-certificate: /home/ec2-user/.minikube/profiles/minikube/client.crt
<     client-key: /home/ec2-user/.minikube/profiles/minikube/client.key
---
>     client-certificate: /path/to/client.crt #クライアントのローカルにコピーしておきます。
>     client-key: /path/to/client.key #クライアントのローカルにコピーしておきます。
```

ファイルが用意来たら、さっそくクライアントから`kubectl`コマンドを実行してみます。

```bash
$ kubectl get node
The connection to the server 18.183.225.65:49154 was refused - did you specify the right host or port?
```

タイムアウトにならなかったものの、アクセス拒否されました。

# Minikubeコンテナのポートマッピングを変更する

なぜアクセス拒否になったのでしょうか。
理由はMinikubeコンテナのポートマッピングにてローカルホストを指定していたためです。（127.0.0.1:49154->8443/tcp）
そのため、ローカルホストからはアクセスできますが、外部からはできません。
マッピングはMinikube起動時にオプションで変更できます。すでにMinikubeが起動している場合は再起動が必要です。

```bash
[ec2-user@ip-10-0-0-193 ~]$ minikube start \
--kubernetes-version=v1.25.2 \
--driver=docker \
--listen-address='0.0.0.0' #add
[ec2-user@ip-10-0-0-193 ~]$ docker ps
CONTAINER ID   IMAGE                                 COMMAND                  CREATED          STATUS          PORTS                                                                                                                        NAMES
92fb641240e3   gcr.io/k8s-minikube/kicbase:v0.0.36   "/usr/local/bin/entr…"   49 seconds ago   Up 48 seconds   0.0.0.0:49157->22/tcp, 0.0.0.0:49156->2376/tcp, 0.0.0.0:49155->5000/tcp, 0.0.0.0:49154->8443/tcp, 0.0.0.0:49153->32443/tcp   minikube
```

今度こそアクセスできるか確認します。

```bash
$ kubectl get node
Unable to connect to the server: x509: certificate is valid for 192.168.49.2, 10.96.0.1, 127.0.0.1, 10.0.0.1, not 18.183.225.65
```

できませんでした。何やら証明書関連ではじかれたようです。

※参考
https://github.com/kubernetes/minikube/issues/14364
https://minikube.sigs.k8s.io/docs/commands/start/
https://minikube.sigs.k8s.io/docs/faq/#how-can-i-access-a-minikube-cluster-from-a-remote-network

# MinikubeコンテナにアクセスできるIPアドレスを指定する

クラスタにアクセスするための証明書は、EC2にてMinikube起動時に作成されました。そのため、EC2内でのみ使えるものとなっています。
これもMinikube起動時にオプションで変更できます。グローバルIPアドレスを使ってアクセスできるようにします。

```bash
[ec2-user@ip-10-0-0-193 ~]$ minikube start \
--kubernetes-version=v1.25.2 \
--driver=docker \
--listen-address='0.0.0.0' \
--apiserver-ips='18.183.225.65'
```

再作成されたファイルをクライアントに配置します。その後、`kubectl`コマンドを実行してみます。

```bash
$ kubectl get node
NAME       STATUS   ROLES           AGE     VERSION
minikube   Ready    control-plane   6m39s   v1.25.2
```

できました。これでお題達成です。

※参考
https://stackoverflow.com/questions/52915110/unable-to-connect-to-the-server-x509-certificate-is-valid-for
https://qiita.com/reoring/items/f9d2c026781bf2760077

# ※SSHポートフォワードも使う方法もある

ここまでやっていて思ったことですが、Minikubeはノード外からのアクセスに向いていないか推奨されていないと思います。
余計なポートを開けず、デフォルトから変更を少なくするのであれば、SSHポートフォワードを使った方がよいと思います。開けるのはSSHだけでよくなり、ローカルホストとして`kubectl`を実行できるのでファイルを用意する手間も減ります。

# おわりに

今回は息抜きにアウトプットしてみました。仕事でどう使うかも大事ですが、自分ならどう使うか、他の場面で使えないかを考えていくことも大切だと最近感じています。
これからも勉強していきます。