[Kubernetes]ingressの動作を確認する

#はじめに
今回はIngressの動作を確認したいと思います。Ingressは一言で言うとL7レイヤーのロードバランサ―です。
L4レイヤーでバランシングするLoadBalancerサービスと似ていますが、厳密にはサービスではなく、独立した「Ingress」リソースです。
なお、現時点で最新のV1.18では、まだBeta版になっています。
>[kubernetes.io -> Ingress](https://kubernetes.io/ja/docs/concepts/services-networking/ingress/)

#事前準備
##Podの作成
Ingressの動作確認用に以下のPod(Deployment)を作成します。

```deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx0
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-dep0
  template:
    metadata:
      labels:
        app: nginx-dep0
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-dep1
  template:
    metadata:
      labels:
        app: nginx-dep1
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-dep2
  template:
    metadata:
      labels:
        app: nginx-dep2
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
---
```
このマニフェストをapplyします。

```
$ kubectl apply -f deployment.yaml
deployment.apps/nginx0 created
deployment.apps/nginx1 created
deployment.apps/nginx2 created
```
```
$ kubectl get pod -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx0-8466d57dbc-cndw8   1/1     Running   0          43s   192.168.79.124   k8s-worker01   <none>           <none>
nginx0-8466d57dbc-pdpxn   1/1     Running   0          43s   192.168.69.215   k8s-worker02   <none>           <none>
nginx1-68d8c5cc6d-fsmt7   1/1     Running   0          43s   192.168.69.210   k8s-worker02   <none>           <none>
nginx1-68d8c5cc6d-sbcwp   1/1     Running   0          43s   192.168.79.120   k8s-worker01   <none>           <none>
nginx2-55f9dc64d5-lqq8w   1/1     Running   0          43s   192.168.69.214   k8s-worker02   <none>           <none>
nginx2-55f9dc64d5-rr25f   1/1     Running   0          43s   192.168.79.122   k8s-worker01   <none>           <none>
```

###Podに目印をつける
動作確認用にindex.htmlファイルを作成して、それぞれ「nginx0」「nginx1」「nginx2」を記載しておきます。
「nginx1」と「nginx2」はそれぞれ下位のディレクトリ配下に作成します。

```
## nginx0
$ kubectl exec -it nginx0-8466d57dbc-cndw8 /bin/bash
# echo nginx0 > /usr/share/nginx/html/index.html
# exit

## nginx1
$ kubectl exec -it nginx1-68d8c5cc6d-fsmt7 /bin/bash
# mkdir /usr/share/nginx/html/path1
# echo nginx1 >/usr/share/nginx/html/path1/index.html
# exit

## nginx2
$ kubectl exec -it nginx2-55f9dc64d5-lqq8w /bin/bash
# mkdir /usr/share/nginx/html/path2
# echo nginx2 >/usr/share/nginx/html/path2/index.html
# exit
```

##NodePortの作成
IngressのバックエンドとなるNodePortを作成します。各Pod（Deployment）に対して作成します。

```nodePort.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: node-port0
spec:
  type: NodePort
  ports:
    - name: node-port
      protocol: TCP
      port: 8080
      targetPort: 80
      nodePort: 30010
  selector:
    app: nginx-dep0
---
apiVersion: v1
kind: Service
metadata:
  name: node-port1
spec:
  type: NodePort
  ports:
    - name: node-port
      protocol: TCP
      port: 8080
      targetPort: 80
      nodePort: 30011
  selector:
    app: nginx-dep1
---
apiVersion: v1
kind: Service
metadata:
  name: node-port2
spec:
  type: NodePort
  ports:
    - name: node-port
      protocol: TCP
      port: 8080
      targetPort: 80
      nodePort: 30012
  selector:
    app: nginx-dep2
```
このマニフェストをapplyします。

```
$ kubectl apply -f nodePort.yaml
service/node-port0 created
service/node-port1 created
service/node-port2 created
$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          48d
node-port0   NodePort    10.103.174.12    <none>        8080:30010/TCP   6s
node-port1   NodePort    10.104.244.161   <none>        8080:30011/TCP   6s
node-port2   NodePort    10.102.124.27    <none>        8080:30012/TCP   6s
```

#Ingressリソースの作成
ここまでで準備ができましたので、Ingressを作成していきます。
Ingressを使用するには、「Ingressリソース」と「Ingressコントローラ」が必要になります。

マニフェストには、リクエストパスのリストが必要になります。パスに対してserviceNameとservicePortで定義されるバックエンドが関連づけられます。オプションでホスト名も設定できます。
また、デフォルトのバックエンドも設定しておいた方がよいでしょう。

>[Ingressリソース -> Ingressのルール、デフォルトのバックエンド](https://kubernetes.io/ja/docs/concepts/services-networking/ingress/#ingress%e3%83%aa%e3%82%bd%e3%83%bc%e3%82%b9)

```sampleIngress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: sample-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /path1
        backend:
          serviceName: node-port1
          servicePort: 8080
      - path: /path2
        backend:
          serviceName: node-port2
          servicePort: 8080
  backend:
    serviceName: node-port0
    servicePort: 8080
```

このマニフェストをapplyします。

```
$ kubectl apply -f sampleIngress.yaml
ingress.networking.k8s.io/simple-ingress created
$ kubectl get ingress
NAME             HOSTS         ADDRESS   PORTS   AGE
sample-ingress   foo.bar.com             80      10s
```

この時点では、「ADDRESS」は空白になっています。

#Ingressコントローラのインストール
GKEだとIngressコントローラがデフォルトでデプロイされているらしいので、以降は不要になります。（未確認）
が、今回はオンプレ（しかもPC、しかもVM）ですので、Nginx Ingressを使用します。

>[NGINX Ingress Controller -> Installation Guide](https://kubernetes.github.io/ingress-nginx/deploy/)

「Docker for Mac」の手順でインストールしていきます。
※前提として、MetalLBがインストール済みである必要があります。
　MetalLBのインストール手順は[こちら](https://qiita.com/dingtianhongjie/items/0f29e4963810c7f8eedd)を参照してください。

```
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
namespace/ingress-nginx configured
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
limitrange/ingress-nginx created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/cloud-generic.yaml
service/ingress-nginx created
```
確認します。

```
$ kubectl -n ingress-nginx get svc
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
ingress-nginx   LoadBalancer   10.102.172.38   10.20.30.150   80:31001/TCP,443:32326/TCP   39s
$ kubectl get pod -n ingress-nginx
NAME                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-7f74f657bd-8l8c6   1/1     Running   0          21m
```
Ingressコントローラがインストールされると、IngressリソースのADDRESSにIPアドレスが表示されます。

```
$ kubectl get ingresses.
NAME             HOSTS         ADDRESS        PORTS   AGE
simple-ingress   foo.bar.com   10.20.30.150   80      84m
```

#動作確認
gatewayからリクエストを送って、レスポンスを確認します。

```
$ curl http://10.20.30.150/path1/index.html -H 'Host: foo.bar.com'
nginx1
$ curl http://10.20.30.150/path2/index.html -H 'Host: foo.bar.com'
nginx2
$ curl http://10.20.30.150/ -H 'Host: foo.bar.com'
nginx0
```

ちゃんと返ってきてますね。

#まとめ
設定と動作の確認はできましたが、長年インフラの低いレイヤーしかやってませんので、L7レイヤーの動きがどうも理解できません。
ここで悩んでてもしょうがないので、先に行ってからもう一度確認してみたいと思います。