Kubernetes 集群上的粘性会话

mig*_*ira 16 cookies load-balancing kubernetes sticky-session nginx-ingress

目前,我正在尝试在 Google Cloud 上创建一个带有两个负载均衡器的 Kubernetes 集群:一个用于后端(在 Spring Boot 中),另一个用于前端(在 Angular 中),其中每个服务(负载均衡器)与 2 个副本(pod)通信. 为了实现这一点,我创建了以下入口:

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
Run Code Online (Sandbox Code Playgroud)

上面提到的入口可以使前端应用程序与后端应用程序提供的 REST API 进行通信。但是,由于后端提供的身份验证机制,我必须创建粘性会话,以便每个用户都与同一个 POD 通信。澄清一下,如果一个用户在 POD #1 中进行身份验证,POD #2 将无法识别 cookie。

为了解决这个问题,我读到Nginx-ingress设法处理这种情况,我通过此处提供的步骤进行安装:https : //kubernetes.github.io/ingress-nginx/deploy/ using Helm。

您可以在我尝试构建的架构图下方找到:

在此处输入图片说明

使用以下服务(我将只粘贴其中一项服务,另一项类似):

apiVersion: v1
kind: Service
metadata:
  name: sample-backend
spec:
  selector:
    app: sample
    tier: backend
  ports:
    - protocol: TCP
      port: 8082
      targetPort: 8082
  type: LoadBalancer
Run Code Online (Sandbox Code Playgroud)

我声明了以下入口:

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
Run Code Online (Sandbox Code Playgroud)

之后,我运行kubectl apply -f sample-nginx-ingress.yaml应用入口,它被创建并且它的状态是好的。但是,当我访问出现在“端点”列中的 URL 时,浏览器无法连接到该 URL。我做错了什么吗?

编辑 1

** 更新服务和入口配置 **

经过一些帮助,我设法通过 Ingress Nginx 访问了这些服务。在上面你有配置:

Nginx 入口

路径不应包含“ ”,这与默认的 Kubernetes 入口不同,默认 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
Run Code Online (Sandbox Code Playgroud)

服务

此外,服务不应该是“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
Run Code Online (Sandbox Code Playgroud)

但是,我仍然无法在我的 Kubernetes 集群中实现粘性会话,一旦我仍然收到 403 并且甚至没有替换 cookie 名称,所以我猜注释没有按预期工作。

Daw*_*ruk 11

我调查了这个问题,并找到了解决您问题的方法。

要实现两条路径的粘性会话,您将需要两个入口定义。

我创建了示例配置来向您展示整个过程:

重现步骤:

  • 应用入口定义
  • 创建部署
  • 创建服务
  • 创建入口
  • 测试

我假设集群已配置并且工作正常。

应用入口定义

在您的基础设施上安装 Ingress 控制器之前,请按照此Ingress 链接查找是否有任何必要的先决条件。

应用以下命令以提供所有必需的先决条件:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
Run Code Online (Sandbox Code Playgroud)

运行以下命令以应用通用配置来创建服务:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud-generic.yaml
Run Code Online (Sandbox Code Playgroud)

创建部署

以下是响应特定服务上的 Ingress 流量的 2 个示例部署:

你好.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"
Run Code Online (Sandbox Code Playgroud)

通过调用命令应用第一个部署配置:

$ kubectl apply -f hello.yaml

再见.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"
Run Code Online (Sandbox Code Playgroud)

通过调用命令应用第二个部署配置:

$ kubectl apply -f goodbye.yaml

检查部署是否正确配置了 pod:

$ kubectl get deployments

它应该显示如下内容:

NAME      READY   UP-TO-DATE   AVAILABLE   AGE
goodbye   5/5     5            5           2m19s
hello     5/5     5            5           4m57s
Run Code Online (Sandbox Code Playgroud)

创建服务

要连接到之前创建的 pod,您需要创建服务。每项服务都将分配给一个部署。以下是 2 项服务来实现这一点:

你好-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
Run Code Online (Sandbox Code Playgroud)

通过调用命令应用第一个服务配置:

$ kubectl apply -f hello-service.yaml

再见-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
Run Code Online (Sandbox Code Playgroud)

通过调用命令应用第二个服务配置:

$ 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
Run Code Online (Sandbox Code Playgroud)

创建入口

要实现粘性会话,您需要创建 2 个入口定义。

定义如下:

你好-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

Run Code Online (Sandbox Code Playgroud)

再见-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
Run Code Online (Sandbox Code Playgroud)

请更改DOMAIN.NAME 两个入口以适合您的情况。我建议查看此Ingress Sticky 会话链接。两个入口都配置为仅 HTTP 流量。

应用它们两个调用命令:

$ kubectl apply -f hello-ingress.yaml

$ kubectl apply -f goodbye-ingress.yaml

检查是否应用了两种配置:

$ kubectl get ingress

输出应该是这样的:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
Run Code Online (Sandbox Code Playgroud)

测试

打开浏览器并转到http://DOMAIN.NAME 输出应该是这样的:

Hello, world!
Version: 1.0.0
Hostname: hello-549db57dfd-4h8fb
Run Code Online (Sandbox Code Playgroud)

Hostname: hello-549db57dfd-4h8fb是 pod 的名称。刷新几次。

它应该保持不变。

要检查另一条路线是否正在工作,请转到http://DOMAIN.NAME/v2/ 输出应如下所示:

Hello, world!
Version: 2.0.0
Hostname: goodbye-7b5798f754-pbkbg
Run Code Online (Sandbox Code Playgroud)

Hostname: goodbye-7b5798f754-pbkbg是 pod 的名称。刷新几次。

它应该保持不变。

确保 cookie 不会改变打开的开发人员工具(可能是 F12)并导航到带有 cookie 的地方。您可以重新加载页面以检查它们是否没有变化。

饼干