Shohhei1126's Blog

KubernetesのNginx Ingress Controllerを使ってみたらめっちゃ便利だった話

Kubernetesのserviceで type: LoadBalancer とすると外部に公開することが出来る。

AWSの場合自動でELBが作られる(ただしRoute53までは設定できなさそう)。

ちょっとずれてるけどEXTERNAL-IPにELBのドメインが入ってる。

$ kubectl version
Client Version: version.Info{...GitVersion:"v1.7.2"...}
Server Version: version.Info{...GitVersion:"v1.7.2"...}

$ kubectl -n kube-system get svc -l k8s-app=kubernetes-dashboard -o wide
NAME                   CLUSTER-IP      EXTERNAL-IP             PORT(S)        AGE       SELECTOR
kubernetes-dashboard   100.64.26.123   ***.elb.amazonaws.com   80:31083/TCP   13d       k8s-app=kubernetes-dashboard

これはこれで便利だがService側で認証する必要があるしServiceごとにELBできるのでもったいない。

ServiceとIngress

現状ServiceはPodへのL4ロードバランサー&サービスディスカバーとみなせる。ただ Future work にはL7(HTTP)のサポートもするつもりとあるので将来変わるかも。

IngressはL7(HTTP)をサポートしたものでpathでServiceへ振り分けたり

kind: Ingress
...
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80

バーチャルホストの設定もできる。

kind: Ingress
...
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80
  - host: bar.foo.com
    http:
      paths:
      - backend:
          serviceName: s2
          servicePort: 80

Ingress Controller

Ingres自体はただの設定なので動作する実体は別途用意する必要がある。

Ingress Controllerと呼ばれてる。

公式のリポジトリを見るとNginxやHAProxyなどがある。

Ingress Annotations

CoreOSがつくってる ALB Ingress Controller も気になってるので今度別の記事にしてみる。

自分の場合Nginxに馴染みがあるし External Authentication を使いたかったで Nginx Ingress Controller を選んだ。

Nginx Ingress Controller

NGINX Ingress running in AWS を参考にしてインストール。

Yaml を見るとNginx Ingress ControllerのServiceも type: LoadBalancer と定義されていて一度すべてのリクエストを受取り定義に従ってServiceへ振り分けている。そのためELBは一つだけで済む。

ALB Ingress Controller はALBが実体となるのでServiceの定義はない。Ingressリソースの作成、変更、削除を検知してALBを作成、更新、削除だけを行っている(はず)。

TLSの設定と認証

Kubernetesを使っているとDashboardやGrafana、Kibanaなどを使うことが多い(はずな)のでそれらの認証とHTTPS化は必須。

まずはTLSのSecretリソースを作成。

$ kubectl create secret tls {secret name} --key={path to private key} --cert={path to cert}

それをIngressの設定に追加するだけ。

kind: Ingress
...
spec:
  tls:
  - hosts:
    - kibana.shohhei1126.jp
    - grafana.shohhei1126.jp
    secretName: {secret name}

認証は前述の External authentication を参考にした。

例ではGithubが使われているがサポートしてる認証プロバイダが OAuth Provider Configuration と結構あるので使い勝手はよさそう。

メインと認証用のIngressをそれぞれ用意してメインで以下のAnnotationを指定するのがポイント。

kind: Ingress
metadata:
  annotations:
    ingress.kubernetes.io/auth-signin: https://$host/oauth2/sign_in
    ingress.kubernetes.io/auth-url: https://$host/oauth2/auth
  ...

auth-url で認証されているかどうかの確認をしている。

手元で試したところ認証済みでHTTPステータスコード 202、未認証で 401 が返ってきた。

$ curl -HGET https://**.**.**/oauth2/auth -H "cookie:_oauth2_proxy=***" -I
HTTP/2 202
...

$ curl -HGET https://**.**.**/oauth2/auth -I
HTTP/2 401
...

そして未認証であれば auth-signin にリダイレクトされる。

もう一点のポイントは見ての通りクッキーによる認証なので external-auth/nginx/dashboard-ingress.yaml__INGRESS_HOST__ のようにメインと認証用で同じドメインを指定する必要がある。

kind: Ingress
metadata:
  name: external-auth-oauth2
spec:
  rules:
  - host: __INGRESS_HOST__ // 例えば grafana.shohhei1126.jp
  ...
---
kind: Ingress
metadata:
  name: oauth2-proxy
spec:
  rules:
  - host: __INGRESS_HOST__ // 例えば grafana.shohhei1126.jp
  ...

認証するアカウントを指定する場合は Email Authentication にある通り --email-domain=yourcompany.com とドメインで絞るか、ConfigMapで許可するメールアドレスのリストを作って --authenticated-emails-file={file path} と指定するといい。サンプルのままだと --email-domain=* と全許可になってしまうので注意が必要。

まとめ

結論めっちゃ便利 👍

Kubernetesってとっつきにくくて最初時間かかるけど理解してくるとめっちゃ便利やなーと。

一通り必要なものが揃ってステーブルになってるタイミングで手を付けられてるからかも。