k8s上のElasticsearchとNode-REDをingress-nginxを使ってngrokで公開する

# はじめに
(いい感じにタイトルを書けない...)

https://qiita.com/Y-Shikase/items/7668b991d4cdf5635ee5

の続きです。
「おわりに」に書いてある、

『ふと思ったのですが、ingressのエンドポイントをngrokで公開したらOpenShiftのrouterのようなものになりそうですね。ただ、kubernetes内のIngress定義やサービスの設定は事前によく考える必要がありそうです。』

を実装したものとなります。

# 環境

- metallb

https://metallb.universe.tf/installation/

```
$ kubectl get all -n metallb-system
NAME                              READY   STATUS    RESTARTS      AGE
pod/controller-85965bd49c-7sfr9   1/1     Running   6             139d
pod/speaker-4w77j                 1/1     Running   6             139d
pod/speaker-dm45j                 1/1     Running   3             43d
pod/speaker-f7vth                 1/1     Running   4 (31d ago)   139d
pod/speaker-gvhqt                 1/1     Running   8 (31d ago)   139d
pod/speaker-j5bfp                 1/1     Running   5             139d
pod/speaker-rlmdw                 1/1     Running   8 (27d ago)   139d
pod/speaker-whcw9                 1/1     Running   3 (31d ago)   139d

NAME                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/speaker   7         7         7       7            7           kubernetes.io/os=linux   139d

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           139d

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-85965bd49c   1         1         1       139d
```

- ingress-nginx

https://github.com/kubernetes/ingress-nginx

```
$ kubectl get all -n ingress-nginx
NAME                                           READY   STATUS    RESTARTS   AGE
pod/ingress-nginx-controller-fd7bb8d66-sbvz2   1/1     Running   3          38d

NAME                                         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx-controller             LoadBalancer   10.96.205.0    10.0.0.128    80:32597/TCP,443:31821/TCP   139d
service/ingress-nginx-controller-admission   ClusterIP      10.96.139.16   <none>        443/TCP                      139d

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           139d

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-fd7bb8d66   1         1         1       139d

NAME                                       COMPLETIONS   DURATION   AGE
job.batch/ingress-nginx-admission-create   1/1           4s         139d
job.batch/ingress-nginx-admission-patch    1/1           4s         139d
```

Serviceリソースの「ingress-nginx-controller」で割り当てられているEXTERNAL-IPの「10.0.0.128」を使います。
ちなみにEXTERNAL-IPが変化しないように、LoadBalancer(metallb)が提供するIPをこの1つにしています。(他にLoadBalancer使わないし...)

# ngrokの設定

コンテナイメージの作成、Deployment作成などの手順は以下の記事を参照してください。

https://qiita.com/Y-Shikase/items/7668b991d4cdf5635ee5

Configmapは以下のように、ingressのサービスのEXTERNAL-IPをホスト名(ワイルドだろう?)で指定します。(IPアドレスでもいいと思います)

```yaml:ngrok-configmap.yaml
apiVersion: v1
data:
  ngrok.yml: |
    authtoken: *****************************
    region: jp
    console_ui: false
    tunnels:
      k8s-ingress:
        proto: http
        bind_tls: true
        addr: k8s.10.0.0.128.nip.io:80
        subdomain: *****
kind: ConfigMap
metadata:
  name: ngrok-config
  namespace: default
```

# Ingressリソース例

elasticsearchのサービスは /es/ でアクセスできるよう設定します。
hostの「*****」はngrokのサブドメインになります。外部からアクセスするホスト名を指定する部分なので、間違えないようにしてください。

若干調べた記憶があるのですが、今回使用したバージョンではIngressをURL置き換えをするタイプのリバースプロキシにする場合は「annotations」を使用する必要があるようです。
※kubernetes v1.22.0でingressのイメージは、「k8s.gcr.io/ingress-nginx/controller:v1.0.0」を使ってます。

```yaml:elasticsearch-ing.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: k8s-ingress
  namespace: elastic
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1$2
spec:
  ingressClassName: "nginx"
  rules:
  - host: *****.jp.ngrok.io
    http:
      paths:
      - path: /es/(.*)
        pathType: Prefix
        backend:
          service:
            name: elasticsearch
            port:
              number: 9200
```

linebot用のNode-REDのサービスは /red/ でアクセスできるように設定します。

```yaml:nodered-ing.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: k8s-ingress
  namespace: linebot
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1$2
spec:
  ingressClassName: "nginx"
  rules:
  - host: *****.jp.ngrok.io
    http:
      paths:
      - path: /red/(.*)
        pathType: Prefix
        backend:
          service:
            name: linebot
            port:
              number: 1880
```

両方applyします。

```
$ kubectl apply -f elasticsearch-ing.yaml
$ kubectl apply -f nodered-ing.yaml
$ kubectl get ing -A
NAMESPACE   NAME          CLASS   HOSTS                 ADDRESS      PORTS   AGE
elastic     k8s-ingress   nginx   *****.jp.ngrok.io     10.0.0.128   80      109d
linebot     k8s-ingress   nginx   *****.jp.ngrok.io     10.0.0.128   80      109d
```

# 確認

elasticsearchはちゃんと /es/ で(認証あり+ngrokのSSL化)アクセスできます。

![スクリーンショット 2022-01-19 17.35.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/b1e51f40-6462-5801-99e3-bd7a1e50fb83.png)

Node-REDは /red/ で(認証あり+ngrokのSSL化)アクセスできます。
http-inノードを使用する場合、 /red/ のPrefixが既にある事を意識しなければなりません。
URLだけでなく、「名前」でPrefixの /red/ を付与するとフロー上わかりやすいかと思います。

![スクリーンショット 2022-01-19 17.34.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/cd9efb61-f1e7-c4db-25ac-72a30659e462.png)

要するに、Node-REDのhttp-inノードがリバースプロキシでPrefixが付いたりする事に対応していないだけだと思います。

# おわりに

ngrokのサブドメインを節約できたので大満足です。ちゃんと使えばkubernetesはこんなにも便利なんですよね。
IngressのリソースのAGEを見ればわかりますが、100日以上前に実装したものです。記事にするまでが長い...orz

https://twitter.com/shikasey/status/1444184141113683969?s=21