K8s on Vagrant, NGINX Ingress Controller の利用


k8sクラスタ外部のトラフィックを受け入れて、負荷分散など実行しながら、ポッドへアクセスを分散させる方法です。


vagrantの仮想サーバーで、k8s v1.10のクラスタを動作させて検証した５回目の記事で、これまでの記事を列挙しておきます。

1. [Kubenetes v1.10 クラスタをVagrantで構築したメモ](https://qiita.com/MahoTakara/items/28cd766d0447140b7ae3)
1. [K8s on Vagrant, Node障害時の振る舞いについての検証記録](https://qiita.com/MahoTakara/items/9b106664492303e1ba01)
1. [K8s on Vagrant, ダッシュボードのセットアップ](https://qiita.com/MahoTakara/items/b9b1d4bdc5a3e0d6ddfb)
1. [K8s on Vagrant, NFS 永続ボリュームの利用メモ](https://qiita.com/MahoTakara/items/c07b1b3418fc9b7130f6)


## Ingressとは? 

ノード横断のポッド・ネットワーク上のサービスやアプリケーションは、プライベートIPアドレスがアサインされますから、ルーティングする事が出来ないために、インターネットのクライアントと通信することができません。 このため、Ingressは、クラスタ内のサービス（通常はHTTP）に、クラスタ外部からのアクセスを橋渡しするもので、ロードバランシング、SSL/TLS暗号の終端処理、名前ベースの仮想ホスティングを提供するものです。 図にすると次の様になります。 

![スクリーンショット 2018-04-26 11.48.13.png](https://qiita-image-store.s3.amazonaws.com/0/42829/c7d47599-cc16-f413-7912-b3a3144c0d99.png "スクリーンショット 2018-04-26 11.48.13.png")



## Ingressコントローラーの果たす役割範囲

外観的にIngressの役割が解ったので、Ingressの実装について、話を進めて行きたいと思います。IngressとIngressコントローラーと二つの言葉が出てきて混乱するのですが、この二つの言葉の違いを整理することから進めます。

次のIngressファイルは、`kubectl apply -f ingress.yaml` コマンドを使って適用します。　解説しやすくするために、行番号を付与してあります。 このIngressのYAMLを適用する事で、hello-world-svcを外部へ公開出来る様になります。

~~~ingress.yaml
     1	apiVersion: extensions/v1beta1
     2	kind: Ingress
     3	metadata:
     4	  name: hello-world-ingress
     5	  namespace: ingress-nginx   
     6	  annotations:
     7	    kubernetes.io/ingress.class: 'nginx'
     8	    nginx.org/ssl-services: 'hello-world-svc'
     9	    ingress.kubernetes.io/ssl-redirect: 'false'
    10	
    11	spec:
    12	  tls:
    13	  - hosts:
    14	    - abc.sample.com
    15	    secretName: tls-certificate
    16	  rules:
    17	  - host: abc.sample.com
    18	    http:
    19	      paths:
    20	      - path: /
    21	        backend:
    22	          serviceName: hello-world-svc
    23	          servicePort: 8080
~~~


2行目 kind: Ingress として、この定義によって、APIオブジェクトのIngressを操作する事が解ります。
6行目 annotationsは、NGINX Ingressコントローラーへ送るパラメータで、Ingressコントローラーの動作を変更する事ができます。このアノテーションの詳細は、GitHubのNGINX Ingressコントローラ [Annotaions](https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/annotations.md) に記載されています。

12行目 HTTPSに関する設定で、ドメイン名、そして、SSL/TLS暗号の証明書のシークレットを指定します。

17行目 ドメイン名 abc.sample.com でアクセスするのみが、アプリケーションのサービスに転送されます。 もし、IPアドレス直打ちでアクセスした場合は、後述のデフォルト・バックエンドサービスから応答を返します。

21行目 アプリケーションのサービス hello-world-svc を外部提供するものです。


このYAMLファイルとNGINX Ingress コントローラの関係を表したのが、次の図になります。


![スクリーンショット 2018-04-26 13.39.20.png](https://qiita-image-store.s3.amazonaws.com/0/42829/62adbcd2-e600-d827-a67f-a7608fdbf69c.png "スクリーンショット 2018-04-26 13.39.20.png")


水色のボックスで、「Ingress APIオブジェクト」が前述のingress.yaml を適用して作られるオブジェクトです。 Ingressのオブジェクトは、NGINX Ingressコントローラに指令を送り、外部からのトラフィックを、プライベートのポッド・ネットワークにアクセス用のIPアドレスを確保している水色ボックスのユーザーアプリのサービスに転送します。 そして、IngressのYAMLファイルのルールに該当し無い場合は、図中紫色のボックス 「default-backend」サービスにルーティングして、エラーメッセージ等をクライアントへ返します。


このingress.yaml を適用して作成したオブジェクトによって、NGINX Ingressコントローラに指令が送られ、アプリケーションへ要求のトラフィックが流れ込む様になります。 この内容は、`kubectl get ing` や `kubectl describe ing`として、内容を確認できます。

~~~
$ kubectl get ing
NAME                  HOSTS            ADDRESS         PORTS     AGE
hello-world-ingress   abc.sample.com   192.168.1.100   80, 443   1d

$ kubectl describe ing
Name:             hello-world-ingress
Namespace:        ingress-nginx
Address:          192.168.1.100
Default backend:  default-http-backend:80 (<none>)
TLS:
  tls-certificate terminates abc.sample.com
Rules:
  Host            Path  Backends
  ----            ----  --------
  abc.sample.com  
                  /   hello-world-svc:8080 (<none>)
Annotations:
  nginx.org/ssl-services:                            hello-world-svc
  ingress.kubernetes.io/ssl-redirect:                false
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"ingress.kubernetes.io/ssl-redirect":"false","kubernetes.io/ingress.class":"nginx","nginx.org/ssl-services":"hello-world-svc"},"name":"hello-world-ingress","namespace":"ingress-nginx"},"spec":{"rules":[{"host":"abc.sample.com","http":{"paths":[{"backend":{"serviceName":"hello-world-svc","servicePort":8080},"path":"/"}]}}],"tls":[{"hosts":["abc.sample.com"],"secretName":"tls-certificate"}]}}

  kubernetes.io/ingress.class:  nginx
Events:                         <none>
~~~


## NGINX Ingressコントローラーのセットアップ

IBM Cloud Container Service などパブリック・クラウドでは、k8sクラスタを起動する段階で、Ingressコントローラは、自動的にセットアップされるので、前述のIngressのYAMLファイルだけを提供すれば良いのですが、今回の例の様に、自前で構築するケースでは、Ingressコントローラをセットアップする必要があります。 また、HELMには、https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress が提供されているので、HELMを利用したセットアップも可能になっています。

今回は、k8s on Vagrant のシリーズとして、自前でセットアップして、基礎を学ぶという目的がありますので、[kubernetes/ingress-nginx Installation Guide](https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md) を参考にして進めていきます。 設定作業は、全く同じではなく、内容に応じて、多少変更していますので、ご了承ください。

それから、実際の設定はで、`kubectl apply -f https://github.com/kubernetes/ingress-nginx...`の形で、GitHubから直接最新のYAMLを適用するという方法も取れます。 ここでは、内容を理解する事をフォーカスするので、YAMLのリストを提示して進めます。


### NGINX Ingressコントローラーの範囲

外部へ公開するIPアドレス(VIP)の取得、ノードへのVIPアサイン、ノード停止時のVIPの他ノードへの付け替えは、NGINX Ingressコントローラの役割の範囲外となります。 このため、今回は、vagrant の仮想サーバーに、コマンドラインからifconfigでVIPをアサインして、動作を確認したいと思います。


## NGINX Ingressコントローラ インストール


### ネームスペースの作成

今回の検証用に、専用のネームスペースを作成して進めます。 次のYAMLファイルを `kubectl apply -f namespace.yaml` として適用することで、ネームスペースが作られます。 確認するには、`kubectl get ns` とすることで、作成済みのネームスペースをリストすることができます。

~~~namespace.yaml 
apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
~~~


### ネームスペースの変更

ネームスペースに対する操作は、`kubectl get all -n ingress-nginx`の様にオプションで指定できますが、毎回、オプションをセットすると、間違いの原因になりますから、 [Qiita k8s便利コマンド Namespaceを恒久的に変更する方法](https://qiita.com/MahoTakara/items/a8b204dd183fc662926e)に書いた方法を利用します。



#### (1) ネームスペース ingress-nginx の設定を作るには

~~~
$ kubectl config set-context ingress-nginx --namespace=ingress-nginx --cluster=kubernetes --user=kubernetes-adminContext 
~~~

#### (2) 作った設定に切り替えるには

~~~
$ kubectl config use-context ingress-nginx
~~~


#### (3) 元のネームスペース defaultにするには

~~~
$ kubectl config use-context kubernetes-admin@kubernetes
~~~

上記の(1)と(2)の方法で、ネームスペースを切り替えて、以下の作業を進めていきます。


### ConfigMapのインストール

ConfigMapに、パラメータを設定することで、NGINX Ingress Controller のふるまいを変更することができます。 パラメータの種類は、https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/configmap.md にあります。また、同ページのExampleに、設定例がありますので、迷わず設定できると思います。 適用は同様に `kubectl apply -f configmap.yaml` で実行します。


~~~configmap.yaml 
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: udp-services
  namespace: ingress-nginx
~~~





### デフォルト・バックエンドのインストール

後述のIngressのルール設定で、ルールに該当しないケースに応答を返すためのデプロイとサービスです。 https://github.com/kubernetes/ingress-nginx/blob/master/deploy/default-backend.yaml 適用は、`kubectl apply -f default-backend.yaml`とします。


~~~default-backend.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: default-http-backend
  namespace: ingress-nginx
  labels:
    app: default-http-backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: default-http-backend
  template:
    metadata:
      labels:
        app: default-http-backend
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: default-http-backend
        # Any image is permissible as long as:
        # 1. It serves a 404 page at /
        # 2. It serves 200 on a /healthz endpoint
        image: gcr.io/google_containers/defaultbackend:1.4
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 30
          timeoutSeconds: 5
        ports:
        - containerPort: 8080
        resources:
          limits:
            cpu: 10m
            memory: 20Mi
          requests:
            cpu: 10m
            memory: 20Mi
---
apiVersion: v1
kind: Service
metadata:
  name: default-http-backend
  namespace: ingress-nginx
  labels:
    app: default-http-backend
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: default-http-backend
~~~

#### 動作確認
サービスとポッドのアドレスを確認します。

~~~
$ kubectl get svc
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
default-http-backend   ClusterIP      10.244.28.14     <none>          80/TCP                       2d
省略

$ kubectl get pods -o wide
NAME                                        READY     STATUS    RESTARTS   AGE       IP             NODE
default-http-backend-5c6d95c48-nr8sd        1/1       Running   0          2d        10.244.2.110   k8s3
省略
~~~

先ほど起動したUbuntuのポッドから、サービス名のDNS名、ポッドのIPアドレスから、それぞれ、アクセスして得られる応答を見ます。それから、このコンテナには、livenessProbeも実装されているはずですから、それも確認します。

~~~
vagrant@k8s1:/vagrant/yaml/ingress-nginx$ kubectl exec -it ubuntu-fcdb8ff7-657bj bash

root@ubuntu-fcdb8ff7-657bj:/# curl  http://default-http-backend/;echo 
default backend - 404

root@ubuntu-fcdb8ff7-657bj:/# curl http://10.244.2.110:8080/;echo
default backend - 404

root@ubuntu-fcdb8ff7-657bj:/# curl http://10.244.2.110:8080/healthz;echo
ok

root@ubuntu-fcdb8ff7-657bj:/# curl http://default-http-backend/healthz;echo 
ok
~~~



### RBAC ロールベースアクセスコントロールの設定

この一連の k8s on vagrant の k8s v1.10 では、デフォルトで RBAC (Role Based Access Control) が有効になっているので、適用します。 

このRBACの設定は以下の４層で構成されています。

* ClusterRole - パーミッションはロールに設定され、これはクラスタ全体に適用されます。
* ClusterRoleBinding - ClusterRoleを特定のアカウントに結び付け（バインド）します。
* Role - パーミッションをロールに設定し、これは特定のネームスペースに適用されます。
* RoleBinding - ロールを特定のアカウントに結び付けます。

RBAC を nginx-ingress-controller に適用するには、コントローラーは ServiceAccountに割り当てられる必要があり、サービスアカウントは、Roles と ClusterRoles に結び付けられなければなりません。 

詳しい説明は、[GitHub Role Based Access Control (RBAC)](https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/rbac.md) を参照ください。


~~~rbac.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount
  namespace: ingress-nginx

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - "extensions"
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
        - events
    verbs:
        - create
        - patch
  - apiGroups:
      - "extensions"
    resources:
      - ingresses/status
    verbs:
      - update

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: nginx-ingress-role
  namespace: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
    resourceNames:
      # Defaults to "<election-id>-<ingress-class>"
      # Here: "<ingress-controller-leader>-<nginx>"
      # This has to be adapted if you change either parameter
      # when launching the nginx-ingress-controller.
      - "ingress-controller-leader-nginx"
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - get

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx
~~~


### NGINX Ingressコントローラーのインストール

これは、https://github.com/kubernetes/ingress-nginx/blob/master/deploy/with-rbac.yaml を元に修正したものです。

修正箇所は、以下２点です。 外部向けIPアドレスを NGINX Ingress コントローラへ導くための修正です。 

* 30行目	`- --publish-service=$(POD_NAMESPACE)/nginx-ingress-svc` の引数はロードバランサー `nginx-ingress-svc` の EXTERNAL IP アドレスを受け入れ事を指定します。
* 64行目以降 k8sのサービスのロードバランサーで、外部向けのIPアドレスのアクセスを、NGINX Ingressコントローラーへ転送します。

これも、同じ様に `kubectl apply -f ingress-controller-with-rbac.yaml' によって適用します。 問題があった時は、apply を delete に変更する事で、取り消すことができます。

~~~ingress-controller-with-rbac.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx 
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ingress-nginx
  template:
    metadata:
      labels:
        app: ingress-nginx
      annotations:
        prometheus.io/port: '10254'
        prometheus.io/scrape: 'true'
    spec:
      serviceAccountName: nginx-ingress-serviceaccount
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.13.0
          args:
            - /nginx-ingress-controller
            - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --annotations-prefix=nginx.ingress.kubernetes.io
            - --publish-service=$(POD_NAMESPACE)/nginx-ingress-svc
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
          - name: http
            containerPort: 80
          - name: https
            containerPort: 443
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress-svc
  namespace: ingress-nginx 
spec:
  type: LoadBalancer
  ports:
  - name: http
    port: 80
    targetPort: http
  - name: https
    port: 443
    targetPort: https
  selector:
    app: ingress-nginx
  externalIPs:
    - 192.168.1.100
~~~

## サービス用にIPアドレスの設定

vagrantの仮想サーバーで稼働する k8s ノード k8s2, k8s3のどちらかで、公開用IPが設定されている必要があります。 今回検証なので、コマンドを手打ちして、仮想サーバーに２つ目のIPアドレスを設定します。 

次の様にワーカーノードにログインして、192.168.1.0/24 のIPアドレスが設定されたインタフェースに、前述のロードバランサーのexternalIPと同じアドレスをセカンドIPとして設定します。 この設定は、リブートすると消えてしまうので、再起動した場合は、再設定が必要です。

~~~
$ vagrant ssh k8s2
$ sudo -s
root@k8s2:~# ifconfig enp0s8:1 192.168.1.100
~~~


これで、NGINX Ingressコントローラーの基盤の設定が完了しました。 前述の図の左半分の紫色のボックスが全部できたことになります。



### 模擬ユーザー・アプリケーションの設定

ここから、前述の図の左半分の水色のボックスの設定を進めます。単純にHello-Worldとポッド名を表示するもので、適用は、以下のリストからコピペでファイルを作って、`kubectl apply -f hello-world.yaml` で実行します。

~~~hello-world.yaml 
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: hello-world-deployment
  namespace: ingress-nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
        - image: "strm/helloworld-http"
          imagePullPolicy: Always
          name: hello-world-container
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hello-world-svc
  namespace: ingress-nginx
spec:
  type: NodePort
  ports:
     -  port: 8080
        protocol: TCP
        targetPort: 80
        nodePort: 31445
  selector:
    app: hello-world
~~~

#### 動作確認

ここで、このアプリの動作確認をしておきます。 次の様にして、サービス、デプロイメント、ポッドの３点セットを確認します。

~~~
$ kubectl get svc hello-world-svc
NAME              TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
hello-world-svc   NodePort   10.244.245.180   <none>        8080:31445/TCP   1d

$ kubectl get deploy hello-world-deployment
NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-world-deployment   1         1         1            1           1d

$ kubectl get pods -o wide
NAME                                        READY     STATUS    RESTARTS   AGE       IP             NODE
hello-world-deployment-b58876bbd-r6z86      1/1       Running   0          1d        10.244.2.112   k8s3
~~~

ubuntuのポッドを起動して、対話型でシェルを立ち上げて、curlコマンドでサービスとポッドをアクセスして、模擬アプリの動作を確認します。

~~~
$ kubectl run ubuntu -n ingress-nginx --image=ubuntu:latest -- tail -f /dev/null
$ kubectl get pods |grep ubuntu
ubuntu-fcdb8ff7-657bj                       1/1       Running   0          35s

$ kubectl exec -it ubuntu-fcdb8ff7-657bj bash
root@ubuntu-fcdb8ff7-657bj:/# apt-get update
root@ubuntu-fcdb8ff7-657bj:/# apt-get install curl
~~~


サービスへのアクセス

~~~
root@ubuntu-fcdb8ff7-657bj:/# curl http://hello-world-svc:8080/
<html><head><title>HTTP Hello World</title></head><body><h1>Hello from hello-world-deployment-b58876bbd-r6z86</h1></body></html
~~~

ポッドへのアクセス

~~~
root@ubuntu-fcdb8ff7-657bj:/# curl http://10.244.2.112/
<html><head><title>HTTP Hello World</title></head><body><h1>Hello from hello-world-deployment-b58876bbd-r6z86</h1></body></html
~~~

ポッドをアプリの応答が、サービスでアクセスできれば、模擬アプリのデプロイは完了です。



### 暗号化なしのIngress設定

SSL/TLS暗号の無いIngressの設定から試します。 以下のファイルを `kubectl apply -f ingress.yaml` で適用します。

~~~ingress.yaml 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
  namespace: ingress-nginx   
  annotations:
    kubernetes.io/ingress.class: 'nginx'

spec:
  rules:
  - host: abc.sample.com
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-world-svc
          servicePort: 8080
~~~

#### 動作確認

~~~
$ kubectl get ing -o wide
NAME                  HOSTS            ADDRESS         PORTS     AGE
hello-world-ingress   abc.sample.com   192.168.1.100   80        2d
~~~

３の方法で、アクセスのテストを試みます。 Ingressは仮想ホスト機能があるため、必ずDNSホスト名を意識したアクセスが必要になることが解ると思います。

#### 192.168.1.100へアクセスした場合

~~~
imac:~ maho$ curl http://192.168.1.100/;echo
default backend - 404
~~~


#### ヘッダーにabc.sample.comを設定した場合

~~~
imac:~ maho$ curl http://192.168.1.100/ -H 'Host: abc.sample.com'
<html><head><title>HTTP Hello World</title></head><body><h1>Hello from hello-world-deployment-b58876bbd-r6z86</h1></body></html
~~~


#### リゾルバーでアドレス解決した場合

~~~
imac:~ maho$ curl http://abc.sample.com/
<html><head><title>HTTP Hello World</title></head><body><h1>Hello from hello-world-deployment-b58876bbd-r6z86</h1></body></html
~~~



### 暗号化有りのIngress設定

自己署名の証明書を作って、HTTPSでアクセスを確認します。
次のコマンドで、秘密鍵（暗号化しない）と 証明書を一度に生成します。

~~~
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout nginx-selfsigned.key -out nginx-selfsigned.crt
Generating a 2048 bit RSA private key
............................................................+++
........................................................+++
writing new private key to 'nginx-selfsigned.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:TOKYO
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:TAKARA Ltd
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:abc.sample.com
Email Address []:
~~~

以下の様に、証明書(.crt) と 鍵(.key)が生成されます。

~~~
$ ls -la
total 8
drwxr-xr-x 1 vagrant vagrant  136 Apr 25  2018 .
drwxr-xr-x 1 vagrant vagrant  510 Apr 25 12:42 ..
-rw-r--r-- 1 vagrant vagrant 1245 Apr 25  2018 nginx-selfsigned.crt
-rw-r--r-- 1 vagrant vagrant 1708 Apr 25  2018 nginx-selfsigned.key
~~~

k8sクラスタの同ネームスペースに、TLS用のシークレットを作成します。

~~~
$ kubectl create secret tls tls-certificate --key nginx-selfsigned.key --cert nginx-selfsigned.crt 
secret "tls-certificate" created
~~~

TLS用シークレットで作成されている事を TYPE フィールドで確認します。

~~~
$ kubectl get secret
NAME                                       TYPE                                  DATA      AGE
省略
tls-certificate                            kubernetes.io/tls                     2         2m
~~~


前回からの変更点は以下です。

* 8と9行目 サービスにSSLを適用を指示
* 12〜15行目 TLS証明書と鍵のシークレットを追加 


~~~ingress-tls.yaml 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
  namespace: ingress-nginx   
  annotations:
    kubernetes.io/ingress.class: 'nginx'
    nginx.org/ssl-services: 'hello-world-svc'
    ingress.kubernetes.io/ssl-redirect: 'false'

spec:
  tls:
  - hosts:
    - abc.sample.com
    secretName: tls-certificate
  rules:
  - host: abc.sample.com
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-world-svc
          servicePort: 8080
~~~


#### アクセス確認

前回同様に、３パターンでアクセスを確認して見ました。

~~~
imac:~ maho$ curl -k https://192.168.1.100/;echo
default backend - 404

imac:~ maho$ curl -k https://192.168.1.100/ -H 'Host: abc.sample.com'
<html><head><title>HTTP Hello World</title></head><body><h1>Hello from hello-world-deployment-b58876bbd-r6z86</h1></body></html

imac:~ maho$ curl -k https://abc.sample.com/ 
<html><head><title>HTTP Hello World</title></head><body><h1>Hello from hello-world-deployment-b58876bbd-r6z86</h1></body></html
~~~

以下はブラウザからのアクセスです。

![スクリーンショット 2018-04-27 13.27.45.png](https://qiita-image-store.s3.amazonaws.com/0/42829/88cd3fbc-a4a4-b210-445c-e96e355bc33c.png "スクリーンショット 2018-04-27 13.27.45.png")


## 感想

IngressとIngressコントローラの違いが、整理できたと思います。　それから、パブリッククラウドでは、公開用IPアドレスの付与とルーティング、そして、クラウドのロードバランサーとの連携など自動的に実行されているですが、自前で作ってみると、その仕組みや役割分担が良く理解できるように思います。 

IBM Cloud Container Service(ICCS) では、Ingressコントローラはクラスタ構成時に自動的に設定されているので、DNS名や暗号鍵を設定しなくても即に利用できます。 しかし、IBM Cloud Private(ICP)では、ロードバランサーはアプライアンスを利用するか、それとも、NGINX Ingressコントローラーを立てる必要があるので、ここで確認した方法は役に立つと思います。 


# 参考資料

1. 「Kubernetes Concepts Ingress」, < https://kubernetes.io/docs/concepts/services-networking/ingress/ >, 2018/4/24
1. 「NGINX Ingress Controller」, < https://github.com/kubernetes/ingress-nginx#conventions >, 2018/4/24
1. 「kubernetesにNginx Ingress Controllerをセットアップ」, < https://qiita.com/sheepland/items/37ece5800eb6972ffd91 >, 2018/4/24