web-dev-qa-db-ja.com

Kubernetesクラスターのスティッキーセッション

現在、私は2つのロードバランサーを使用してGoogle CloudでKubernetesクラスターを作成しようとしています:1つはバックエンド(Springブート)用で、もう1つはフロントエンド( Angularでは)、各サービス(ロードバランサー)は2つのレプリカ(ポッド)と通信します。それを実現するために、次のイングレスを作成しました。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: sample-ingress
spec:
  rules:
    - http:
        paths:
          - path: /rest/v1/*
            backend:
              serviceName: sample-backend
              servicePort: 8082
          - path: /*
            backend:
              serviceName: sample-frontend
              servicePort: 80

上記のIngressにより、フロントエンドアプリはREST APIがバックエンドアプリで利用可能になります。ただし、スティッキーセッション。これにより、バックエンドによって提供される認証メカニズムのために、すべてのユーザーが同じPODと通信します。1人のユーザーがPOD#1で認証すると、CookieはPOD#2で認識されません。

この問題を追い抜くために、私はNginx-ingressがこの状況に対処することができ、ここで利用可能な手順に従ってインストールしたことを読みました: https ://kubernetes.github.io/ingress-nginx/deploy/ Helmを使用。

以下に、私が構築しようとしているアーキテクチャの図を示します。

enter image description here

次のサービスを使用します(サービスの1つを貼り付けるだけで、他のサービスも同様です)。

apiVersion: v1
kind: Service
metadata:
  name: sample-backend
spec:
  selector:
    app: sample
    tier: backend
  ports:
    - protocol: TCP
      port: 8082
      targetPort: 8082
  type: LoadBalancer

そして、私は次のイングレスを宣言しました:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: sample-nginx-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: cookie
    nginx.ingress.kubernetes.io/affinity-mode: persistent
    nginx.ingress.kubernetes.io/session-cookie-hash: sha1
    nginx.ingress.kubernetes.io/session-cookie-name: sample-cookie
spec:
  rules:
    - http:
        paths:
          - path: /rest/v1/*
            backend:
              serviceName: sample-backend
              servicePort: 8082
          - path: /*
            backend:
              serviceName: sample-frontend
              servicePort: 80

その後、kubectl apply -f sample-nginx-ingress.yamlイングレスを適用するには、作成され、そのステータスはOKです。しかし、「エンドポイント」列に表示されるURLにアクセスすると、ブラウザがそのURLに接続できません。私は何か悪いことをしていますか?

編集1

**サービスとイングレス構成を更新**

いくつかの助けの後、私はなんとかIngress Nginxを介してサービスにアクセスできました。この上に設定があります:

Nginxイングレス

パスに「」を含めないでください。必要なパスをルーティングするために「」が必要なデフォルトのKubernetesイングレスとは異なります。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: sample-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "sample-cookie"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"

spec:
  rules:
    - http:
        paths:
          - path: /rest/v1/
            backend:
              serviceName: sample-backend
              servicePort: 8082
          - path: /
            backend:
              serviceName: sample-frontend
              servicePort: 80

サービス

また、サービスのタイプは「LoadBalancer」ではなく、「ClusterIP」のようにする必要があります。

apiVersion: v1
kind: Service
metadata:
  name: sample-backend
spec:
  selector:
    app: sample
    tier: backend
  ports:
    - protocol: TCP
      port: 8082
      targetPort: 8082
  type: ClusterIP

ただし、まだ403が取得され、Cookie名も置き換えられないため、Kubernetesクラスターでスティッキーセッションをまだ実行できないため、注釈が期待どおりに機能していないと思います。

3

私はこの問題を調査し、あなたの問題の解決策を見つけました。

両方のパスでスティッキーセッションを実現するには、イングレスの2つの定義が必要です

プロセス全体を示すサンプル構成を作成しました。

再現手順:

  • Ingress定義を適用する
  • 配置を作成する
  • サービスを作成する
  • Ingressを作成する
  • テスト

クラスターがプロビジョニングされ、正常に動作していると想定しています。

Ingress定義を適用する

この Ingress link に従って、インフラストラクチャにIngressコントローラーをインストールする前に、必要な前提条件があるかどうかを確認します。

以下のコマンドを適用して、すべての必須前提条件を提供します。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

以下のコマンドを実行して、一般的な構成を適用してサービスを作成します。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud-generic.yaml

配置を作成する

以下は、特定のサービスのIngressトラフィックに応答するための2つの配置例です。

hello.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  selector:
    matchLabels:
      app: hello
      version: 1.0.0
  replicas: 5
  template:
    metadata:
      labels:
        app: hello
        version: 1.0.0
    spec:
      containers:
      - name: hello
        image: "gcr.io/google-samples/hello-app:1.0"
        env:
        - name: "PORT"
          value: "50001"

次のコマンドを呼び出して、この最初のデプロイメント構成を適用します。

$ kubectl apply -f hello.yaml

goodbye.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: goodbye
spec:
  selector:
    matchLabels:
      app: goodbye
      version: 2.0.0
  replicas: 5
  template:
    metadata:
      labels:
        app: goodbye
        version: 2.0.0
    spec:
      containers:
      - name: goodbye 
        image: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50001"

次のコマンドを呼び出して、この2番目のデプロイメント構成を適用します。

$ kubectl apply -f goodbye.yaml

デプロイでポッドが正しく構成されているかどうかを確認します。

$ kubectl get deployments

それはそのようなものを示すはずです:

NAME      READY   UP-TO-DATE   AVAILABLE   AGE
goodbye   5/5     5            5           2m19s
hello     5/5     5            5           4m57s

サービスを作成する

以前に作成したポッドに接続するには、サービスを作成する必要があります。各サービスは1つのデプロイメントに割り当てられます。これを実現する2つのサービスを以下に示します。

hello-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  type: NodePort
  selector:
    app: hello
    version: 1.0.0
  ports:
  - name: hello-port
    protocol: TCP
    port: 50001
    targetPort: 50001

次のコマンドを呼び出して、最初のサービス構成を適用します。

$ kubectl apply -f hello-service.yaml

goodbye-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: goodbye-service
spec:
  type: NodePort
  selector:
    app: goodbye
    version: 2.0.0
  ports:
  - name: goodbye-port
    protocol: TCP
    port: 50001
    targetPort: 50001

次のコマンドを呼び出して、2番目のサービス構成を適用します。

$ kubectl apply -f goodbye-service.yaml

両方の構成レイアウトタイプ:NodePort

サービスが正常に作成されたかどうかを確認します。

$ kubectl get services

出力は次のようになります。

NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)           AGE
goodbye-service   NodePort    10.0.5.131   <none>        50001:32210/TCP   3s
hello-service     NodePort    10.0.8.13    <none>        50001:32118/TCP   8s

Ingressを作成する

スティッキーセッションを実現するには、2つのイングレス定義を作成する必要があります。

定義を以下に示します。

hello-ingress.yaml:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "hello-cookie"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/affinity-mode: persistent
    nginx.ingress.kubernetes.io/session-cookie-hash: sha1
spec:
  rules:
  - Host: DOMAIN.NAME
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-service
          servicePort: hello-port

goodbye-ingress.yaml:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: goodbye-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "goodbye-cookie"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/affinity-mode: persistent
    nginx.ingress.kubernetes.io/session-cookie-hash: sha1
spec:
  rules:
  - Host: DOMAIN.NAME
    http:
      paths:
      - path: /v2/
        backend:
          serviceName: goodbye-service
          servicePort: goodbye-port

両方のイングレスのDOMAIN.NAMEをケースに合わせて変更してください。 Ingress Sticky session リンクを確認することをお勧めします。両方のIngressがHTTPのみのトラフィックに設定されています。

コマンドを呼び出すそれらの両方を適用します。

$ kubectl apply -f hello-ingress.yaml

$ kubectl apply -f goodbye-ingress.yaml

両方の構成が適用されたかどうかを確認します。

$ kubectl get ingress

出力は次のようになります。

NAME              HOSTS        ADDRESS          PORTS   AGE
goodbye-ingress   DOMAIN.NAME   IP_ADDRESS      80      26m
hello-ingress     DOMAIN.NAME   IP_ADDRESS      80      26m

テスト

ブラウザを開き、http://DOMAIN.NAMEに移動します。出力は次のようになります。

Hello, world!
Version: 1.0.0
Hostname: hello-549db57dfd-4h8fb

Hostname: hello-549db57dfd-4h8fbはポッドの名前です。数回更新してください。

それは変わらないはずです。

別のルートが機能しているかどうかを確認するには、http://DOMAIN.NAME/v2/に移動します。出力は次のようになります。

Hello, world!
Version: 2.0.0
Hostname: goodbye-7b5798f754-pbkbg

Hostname: goodbye-7b5798f754-pbkbgはポッドの名前です。数回更新してください。

それは変わらないはずです。

Cookieが開いている開発者ツール(おそらくF12)を変更していないことを確認し、Cookieのある場所に移動します。ページをリロードして、変更されていないかどうかを確認できます。

Cookies

1
Dawid Kruk

Serviceの設定が間違っていると思います。削除するだけtype: LoadBalancerで、タイプはデフォルトでClusterIPになります。

LoadBalancer:クラウドプロバイダーのロードバランサーを使用して、サービスを外部に公開します。外部ロードバランサーがルーティングするNodePortおよびClusterIPサービスが自動的に作成されます。詳しくはこちらをご覧ください: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer

apiVersion: v1
kind: Service
metadata:
  name: sample-backend
spec:
  selector:
    app: sample
    tier: backend
  ports:
    - protocol: TCP
      port: 8082
      targetPort: 8082
0
Dávid Molnár