MinikubeでNGINX Ingress Controllerを使ってクラスタ外からPodにアクセスする

# はじめに
記念すべき初投稿です。個人的な興味でkubernetes(Minikube)をさわり始めました。
kubernetesの知識が少ないため、はまりっぱなしで、はまったところを備忘録として残していきたいと思います。

# 今回のはまりどころ
- minikubeを実行しているサーバ以外からアクセスする場合はiptablesでポリシー設定が必要

# 検証環境
- Minikube実行サーバ
  - Ubuntu 24.04
  - minikube version: v1.36.0 (kubernetes version: v1.33.1)
  - IPアドレス：192.168.11.20
- アクセス端末
  - IPアドレス：192.168.11.50

![minikube-ingress.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761786/bfe69d2f-45ad-4402-97ed-6f8802b6aa41.png)

# NGINX Ingress Controllerの準備

公式のドキュメントを参考にingressコントローラーを有効化する

https://kubernetes.io/ja/docs/tasks/access-application-cluster/ingress-minikube/

まずは有効化
```
$ minikube start
$ minikube addons enable ingress
```

Hello Worldアプリは以下の内容でdeployment,service,ingressを定義してデプロイします
``` sample.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello-world
        image: "gcr.io/google-samples/hello-app:1.0"
        ports:
          - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: sample-web
spec:
  # typeは公式ではNodePortになっているが、ClusterIP(default)でも問題ない
  selector:
    app: hello  # deploymentのlabelと名前を合わせる
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sample-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: hello-world.info
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: sample-web
                port:
                  number: 80
```

内容を反映する
```
$ kubectl apply -f sample.yaml
$ kubectl get deployment,pod,svc,ingress
NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/hello-deployment   1/1     1            1           25h

NAME                                    READY   STATUS    RESTARTS   AGE
pod/hello-deployment-545875f79c-v8wzp   1/1     Running   0          25h

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   28h
service/sample-web   ClusterIP   10.102.172.70   <none>        80/TCP    25h

NAME                                        CLASS   HOSTS              ADDRESS        PORTS   AGE
ingress.networking.k8s.io/sample-ingress   nginx   hello-world.info   192.168.49.2   80      27h
```

minikube ipを確認します。作成したingressのADDRESSに出てくるIPアドレスと同じものが表示されそうです。

```
$ minikube ip
192.168.49.2
```

Minikube実行サーバで、表示されたIPを/etc/hostsに記載し、curlでingressを経由してPodにアクセスし、Podアクセスが正常にできることを確認します。

```
$ echo $(minikube ip) hello-world.info | sudo tee -a /etc/hosts
192.168.49.2 hello-world.info
$ curl http://hello-world.info
Hello, world!
Version: 1.0.0
Hostname: hello-deployment-545875f79c-v8wzp
```

# アクセス端末からのクラスタアクセス確認

まず、アクセス端末に192.168.49.2へのルートがMinikubeサーバに向くようにルートを追加します。反映させるネットマスクや恒久的に反映させる場合は環境に合わせていい感じに調整してください。

Minikubeサーバと同様にアクセス端末のhostsにも名前解決を追加し、curlでアクセスしますが、疎通がうまくいかずタイムアウトします。
```
$ sudo ip route add 192.168.49.0/24 via 192.168.11.20
$ echo $(minikube ip) hello-world.info | sudo tee -a /etc/hosts
192.168.49.2 hello-world.info
$ curl http://hello-world.info
※ここで応答なし
```

# 原因調査

Minikube実行サーバやアクセス端末でpingやtracerouteを実行し、アクセス端末から192.168.49.1(Minikube実行サーバ)までは疎通確認できるものの、minikube ip(192.168.49.2)には到達できない。Minikube実行サーバ上から192.168.49.2に到達できるため、iptablesのFORWARDチェインでDROPされているんじゃないかという仮説を立てました。（ここにたどり着く前の試行錯誤も長かったんですが、、、）

![minikube-ingress-hypothesis.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761786/7b91e460-f829-40eb-b5d9-5954d08c21a0.png)

FORWARDチェインの一番最初にminikube ip(192.168.49.2)へのアクセス許可を追加し、無事にアクセス端末からPodにアクセスできることを確認しました。

```
$ sudo iptables -I FORWARD -s 192.168.11.0/24 -d 192.168.49.2 -j ACCEPT
$ sudo iptables -nL FORWARD
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ACCEPT     0    --  192.168.11.0/24      192.168.49.2   ★これが追加されている
DOCKER-USER  0    --  0.0.0.0/0            0.0.0.0/0
DOCKER-FORWARD  0    --  0.0.0.0/0            0.0.0.0/0
LIBVIRT_FWX  0    --  0.0.0.0/0            0.0.0.0/0
LIBVIRT_FWI  0    --  0.0.0.0/0            0.0.0.0/0
LIBVIRT_FWO  0    --  0.0.0.0/0            0.0.0.0/0
```

# まとめ
- Minikube実行サーバ外からNGINX Ingress Controllerにアクセスする場合はFORWARDチェインのポリシーに許可設定を追加する
  - このあたりは、Ingressの設定もしくはIngress Controllerのvalues等でうまく反映できないものだろうか。
  - 追加するポリシーは短絡的に入れずに、もっと適切なものを入れるように考慮した方がいい可能性も非常に高い
- もちろんNW的な考慮として、minikube ip(192.168.49.2)へのルーティング設定の考慮は必要
- 別途、恒久的に反映させる設定は必要