🐳

[Kuberntes] 汎用OAuth2 Proxyをサービスの手前に置く:準備編

2022/02/06に公開

やりたいこと

サービス毎に認証の設定をするんじゃなくて、手前のReverse Proxyレイヤーで一元管理することで、認証の設定をテナント側から隠しつつ運用コストを減らしたい。

前提条件

自分たちはKubernetesのSystem Adminで、複数のテナントが1つのKubernetes Clusterを共用で使ういわゆるマルチテナント方式でサービスを提供している。

別にJenkins等のDocker imageを各テナントが自分でデプロイしても良いが、なるべくテナント側の構築/運用コストを減らしたい。マネージャー曰く「アプリエンジニアには、アプリの開発に専念してもらいたい。」

わかります。。

ひとまず、手元のMacbookで検証中。

本日のゴール

ブラウザからテスト用にあげたNginxのトップページが見える。
認証はまだ無しです。

システムアーキテクチャ図

first goal

ローカル環境構築

Tools

  • Docker Serverとしてlima
  • Kubernetes Platformとしてkind
  • Ingress GatewayとしてIstio
  • ServiceとしてNginx

lima

Exampleを参考にDocker環境を構築。
なお、docker CLI Toolは別途インストールしておいて下さい。
https://github.com/lima-vm/lima/blob/master/examples/docker.yaml

おそらく、メモリー不足になるので

メモリーを増やせる範囲で増やしておきましょう。

# default mem size is 4GiB
memory: 8GiB

Docker用のVM作成

$ limactl start ./docker.yaml
$ export DOCKER_HOST=$(limactl list docker --format 'unix://{{.Dir}}/sock/docker.sock')

kind

ブラウザから動作確認したいので http://localhost でアクセスしたら、kindのnodePort: 30080にマップする。このポートは後ほどIstio Ingress GatewayのnodePortにもマップする。

localhost:80 -> kind host:30080 -> Istio Ingress Gateway

Configrationを参考に、設定ファイルを作って、k8sクラスタ作成時にconfigとして指定する。

config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30080
    hostPort: 80
    protocol: TCP
networking:
  # WARNING: It is _strongly_ recommended that you keep this the default
  # (127.0.0.1) for security reasons. However it is possible to change this.
  apiServerAddress: "0.0.0.0"
$ kind create cluster --config /path/to/config.yaml

Istio

Ingress Gatewayの設定

公式の手順に沿って、istioctl installまで進める。

https://istio.io/latest/docs/setup/getting-started/

$ istioctl install --set profile=demo -y

Ingress GatewayのnodePortを変更する。

$ kubectl get svc -n istio-system istio-ingressgateway -o yaml > ingress-gateway.yaml
ingress-gateway.yaml
  - name: http2
    nodePort: 30080 # Change this port to 30080
    port: 80
    protocol: TCP
    targetPort: 8080
$ kubectl apply -f ingress-gateway.yaml

Gateway作る

gateway.yaml
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: default-gateway
  namespace: default
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - nginx.default.svc.macbook.local

確認用にNginxをデプロイしてみる

nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginxinc/nginx-unprivileged:1.20-alpine
        name: nginx
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
  namespace: default
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: nginx
  type: ClusterIP
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nginx
  namespace: default
spec:
  hosts:
  - nginx.default.svc.macbook.local
  gateways:
  - default-gateway
  http:
  - route:
    - destination:
        host: nginx
        port:
          number: 80

localhostでアクセスしても良いですが、後でDomain Virtualで複数のサービスを分けたいので、ローカルマシンのhostファイルにNginxのドメインを登録する。ちなみに、VirtualServiceに登録したHost名と整合性が取れていれば何でも良いです。

/etc/hosts
127.0.0.1 nginx.default.svc.macbook.local

ブラウザでアクセスできるか確認
http://nginx.default.svc.macbook.local

設定が全て完了していれば、Nginxのトップページが見えるはずです。
Nginx Top

トラブルシューティング

名前解決ができていない場合は、hostファイル
名前解決はできているけど繋がらない場合は、kindもしくはIstio Ingress GatewayのnodePortの設定
404 Not Foundが返ってくる場合は、Istioに設定したHost名とブラウザに入力したHost名がマッチしているか
500系のエラーが返ってくる場合は、Nginx Podが正しく起動しているか

それぞれ確認してみてください。

Discussion