kubernetesにNginx Ingress Controllerをセットアップ

追記:
https://github.com/kubernetes/ingress-nginx/tree/master/deploy のセットアップ手順のほうがいいと思う。

--- 

minikubeで試しました。

# Step1: 動かすアプリケーションのPod, Serviceを作成

```yaml:hello-world-deploy.yml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: hello-world-deployment
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
        - image: "strm/helloworld-http"
          imagePullPolicy: Always
          name: hello-world-container
          ports:
            - containerPort: 80
```

```yaml:hello-world-service.yml
apiVersion: v1
kind: Service
metadata:
  name: hello-world-svc
spec:
  type: NodePort
  ports:
     -  port: 8080
        protocol: TCP
        targetPort: 80
  selector:
    app: hello-world
```

# Step2: Nginx Ingress Controllerから使用されるdefault backendの作成

Ingressのルーティング設定に該当しないリクエストを流す先(fall back)としてdefault backendを作成する。
default backendは以下の2つが必要となる。

* `/` にアクセスした場合404 pageを返す
* `/healthz` にアクセスした場合http status 200を返す

```yaml:default-backend-deploy.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: default-http-backend
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: default-http-backend
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: default-http-backend
        # Any image is permissable 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.0
        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
```

```yaml:default-backend-svc.yml
kind: Service
apiVersion: v1
metadata:
  name: default-http-backend
spec:
  type: ClusterIP
  selector:
    app: default-http-backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
```

# Step3: NginxのためのSSL設定をする

自己署名証明書を作成する。
作成するSSL certificateの`common name`にはingressに設定するhost nameを指定すること。

```
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout nginx-selfsigned.key -out nginx-selfsigned.crt
openssl dhparam -out dhparam.pem 2048

kubectl create secret tls tls-certificate --key nginx-selfsigned.key --cert nginx-selfsigned.crt

kubectl create secret generic tls-dhparam --from-file=dhparam.pem
```

# Step4: Nginx Ingress Controllerの設定


```yaml:nginx-controller-deploy.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-ingress-controller
spec:
  replicas: 1
  revisionHistoryLimit: 3
  template:
    metadata:
      labels:
        k8s-app: nginx-ingress-lb
    spec:
      containers:
        - args:
            - /nginx-ingress-controller
            - "--default-backend-service=$(POD_NAMESPACE)/default-http-backend"
            - "--default-ssl-certificate=$(POD_NAMESPACE)/tls-certificate"
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: "gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.5"
          imagePullPolicy: Always
          livenessProbe:
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            timeoutSeconds: 5
          name: nginx-ingress-controller
          ports:
            - containerPort: 80
              name: http
              protocol: TCP
            - containerPort: 443
              name: https
              protocol: TCP
          volumeMounts:
            - mountPath: /etc/nginx-ssl/dhparam
              name: tls-dhparam-vol
      terminationGracePeriodSeconds: 60
      volumes:
        - name: tls-dhparam-vol
          secret:
            secretName: tls-dhparam
```

externalIPsにnodeのIPを指定する

```yaml:nginx-controller-svc.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress
spec:
  ports:
  - name: http
    port: 80
    targetPort: http
  - name: https
    port: 443
    targetPort: https
  selector:
    k8s-app: nginx-ingress-lb
  externalIPs:
    - 192.168.99.100
```

# Step5: Ingressの設定

```yaml:ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.org/ssl-services: "hello-world-svc"
    ingress.kubernetes.io/ssl-redirect: "false"
spec:
  tls:
    - hosts:
      - api.sample.com
      secretName: tls-certificate
  rules:
  - host: api.sample.com
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-world-svc
          servicePort: 8080
```

# 参考サイト

* [快適な kubernetes オンプレミス環境を構築する(5. nginx-ingress-controllerを使ったIngress環境のセットアップ)](https://qiita.com/kaishuu0123/items/031f071b970e3be5666b)
* [
[Kubernetes] オンプレでも GKE Like な Ingress を使うために 自作 Ingress Controller を実装してみた](https://adtech.cyberagent.io/techblog/archives/3758)
* [Setting up Nginx Ingress on Kubernetes](https://medium.com/@gokulc/setting-up-nginx-ingress-on-kubernetes-2b733d8d2f45)
  * 上の記事は、minikubeのingress addonを有効にしているおかげでたまたまnginx ingress controllerが動いているようにみれるが、実際は動いていない。
上の記事のsecret部分だけは参考になる。