Kubernetes 1.12にIngress Controllerをインストール

昨日の[Kubernetes 1.12インストール](https://qiita.com/rk05231977/items/2c67ad47aecfd48c53ca)に引き続き、今回はそのKubernetesにIngress Controllerを導入しよう。ワーカーノード２台あるので、そいつの上にDaemonSetで。
keepalivedでHA化もしよう。

#NGINX Ingress Controllerを導入
どうもなかなかBetaが取れないIngress Controller。まあ、LoadBalancerのServiceですべてが賄えるならいらん訳だけど、Kubernetes成熟しないなあと思う一因でもある。それはとりあえず、Nginx Ingressのインストールの手順は以下。インストール手順探すのも現状ちょい手間。
https://kubernetes.github.io/ingress-nginx/deploy/

Mandatory commandでkubectl apply直接実行してもいいのだけど、今回はDaemonSetでデプロイしたいのでいったんダウンロードして加工。またhostPort 80, 443を割り当て。

```bash
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml>mandatory.yaml
vi mandatory.yaml
■"name: nginx-ingress-controller"であるDeploymentをDaemonSetに書き換え
(変更前)
251 apiVersion: extensions/v1beta1
252 kind: Deployment
253 metadata:
254   name: nginx-ingress-controller
(変更後)
251 apiVersion: extensions/v1beta1
252 kind: DaemonSet
253 metadata:
254   name: nginx-ingress-controller
---
■ReplicaSetでなくなるのでreplica行を削除
(変更前)
259 spec:
260   replicas: 1
(変更後)
259 spec:
260 #  replicas: 1
---
■hostPortを追加
(変更前)
303           ports:
304             - name: http
305               containerPort: 80
306             - name: https
307               containerPort: 443
(変更後)
303           ports:
304             - name: http
305               containerPort: 80
306               hostPort: 80
307             - name: https
308               containerPort: 443
309               hostPort: 443
---
kubectl create -f mandatory.yaml
```

ingress-nginxネームスペースにIngress Controllerがデプロイされる。

```
# kubectl get pod -n ingress-nginx
NAME                                    READY   STATUS    RESTARTS   AGE
default-http-backend-6d6985d9d4-hv9dk   1/1     Running   0          81s
nginx-ingress-controller-j6fjn          1/1     Running   0          81s
nginx-ingress-controller-pjxkc          1/1     Running   0          81s
root@m16:~#
```

#keepalivedを導入
せっかく２台のノードに１つずつIngress Controllerがいるので、keepalivedを使って２ノードのHAを構成したい。

まずは１台目のノードで以下を実行。

```bash
apt-get -y install ipvsadm keepalived
```

その１台目用の設定ファイルを作る。

```:/etc/keepalived/keepalived.conf
vrrp_instance INGRESS {
    state MASTER
    interface ens32
    virtual_router_id 50
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.0.134/24
    }
}
```
※vipのサブネット指定（/24）必要だったっけと思ったが、指定しないと同じ筐体内のVMとVIPで通信できなくなる問題があったため、ここでは指定。

keepalivedを起動。

```bash
systemctl start keepalived
```

続いて２台目のノードで以下を実行。

```bash
apt-get -y install ipvsadm keepalived
```

その２台目用の設定ファイルを作る。

```:/etc/keepalived/keepalived.conf
vrrp_instance INGRESS {
    state MASTER
    interface ens32
    virtual_router_id 50
    priority 99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.0.134/24
    }
}
```

keepalivedを起動。

```bash
systemctl start keepalived
```

#動作確認
せっかくなので[先日作ったNode.js->Mariadbのサンプルアプリ](https://qiita.com/rk05231977/items/4d670acb1272e15127d0)をデプロイし、Ingressリソースを作って動作確認。

記事中にある「# REG=＜レジストリ:ポート番号/namespace＞」のところは、DockerHub上にレポジトリを作ったので「# REG=docker.io/rk05231977」で。

また、最後の「# PROXYIP=＜kube-proxyが動作するサーバのIPアドレス＞」は、今回の環境ではVIPの「# PROXYIP=192.168.0.134」。

そしてIngressリソースを作成。以下のファイルを作り、

```my-node-ingress.yaml
kind: Ingress
metadata:
  name: my-node-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: my-node
          servicePort: 80
    host: my-node.com
```

以下のコマンドでデプロイ。

```bash
kubectl create -f my-node-ingress.yaml
```

Ingressリソースが出来ているか確認。

```
# kubectl get ingress
NAME              HOSTS         ADDRESS   PORTS   AGE
my-node-ingress   my-node.com             80      2m17s
# kubectl exec -n ingress-nginx nginx-ingress-controller-j6fjn -- grep -2 "my-node.com" /etc/nginx/nginx.conf
        ## end server _

        ## start server my-node.com
        server {
                server_name my-node.com ;

                listen 80;
--

        }
        ## end server my-node.com

        # default server, used for NGINX healthcheck and access to nginx stats
```

うん、良さそう。
以下のcurlコマンドで、VIP（今回の環境では192.168.0.134）に向けて「Host: my-node.com」ヘッダを付けて接続確認。

```
# curl -H "Host: my-node.com" 192.168.0.134
<html><body>
date: Sat Sep 29 2018 09:56:27 GMT+0000 (Coordinated Universal Time)<br/>
hostname: my-node-54d74b647-czsw5<br/>
remoteAddress: ::ffff:10.0.2.15<br/>
db:record: Success!<br/>
</html></body>
```

一応、１台ずつノードを停止して、まあ、Ingressは動作してVIPが引き継がれることも確認。

いくつか問題はあり、一つ目は、サンプル用アプリのDBがコンテナ再起動時にデータベースがなくなってしまうのでmariadb Podができるたびに`cat > my-db.sql << 'EOF'`～のコマンド実行してDB作り直さなければいけないということと、２つ目はVIPフェールオーバー時は問題ないのだけど、その後プライマリノードが起動してくるときにIngress Controllerより先にkeepalivedが起動してしまうので一時的にアプリに接続不可になる。
後者についてはkeepalivedを自動起動しないとか、起動まで30秒ぐらいdelayを掛けなければいけない。

```:/lib/systemd/system/keepalived.service
(変更前)
  8 [Service]
  9 Type=forking
(変更後)
  8 [Service]
  9 ExecStartPre=/bin/sleep 30
 10 Type=forking
```

```bash
systemctl daemon-reload
```