cookies - Kubernetes 集群上的粘性会话
问题描述
目前,我正在尝试在 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
上面提到的入口可以使前端应用程序与后端应用程序提供的 REST API 进行通信。但是,由于后端提供的身份验证机制,我必须创建粘性会话,以便每个用户都与同一个 POD 进行通信。澄清一下,如果一个用户在 POD #1 中进行身份验证,则 POD #2 将无法识别 cookie。
为了解决这个问题,我读到Nginx-ingress设法处理这种情况,我通过此处提供的步骤进行安装:https ://kubernetes.github.io/ingress-nginx/deploy/使用 Helm。
您可以在下面找到我正在尝试构建的架构的图表:
使用以下服务(我将仅粘贴其中一项服务,另一项类似):
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
应用入口,它被创建并且它的状态是好的。但是,当我访问出现在“端点”列中的 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
服务
此外,服务不应该是“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
但是,我仍然无法在我的 Kubernetes 集群中实现粘性会话,一旦我仍然得到 403,甚至 cookie 名称都没有被替换,所以我猜注释没有按预期工作。
解决方案
我调查了此事,并找到了解决您问题的方法。
要为两条路径实现粘性会话,您将需要两个入口定义。
我创建了示例配置来向您展示整个过程:
重现步骤:
- 应用入口定义
- 创建部署
- 创建服务
- 创建入口
- 测试
我假设集群已配置并且工作正常。
应用入口定义
在您的基础架构上安装 Ingress 控制器之前,请按照此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 个示例部署:
你好.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
再见.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"
通过调用命令应用第二个部署配置:
$ 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
创建服务
要连接到之前创建的 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
通过调用命令应用第一个服务配置:
$ kubectl apply -f hello-service.yaml
再见服务.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
通过调用命令应用第二个服务配置:
$ 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
创建入口
要实现粘性会话,您需要创建 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
再见-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 会话链接。两个 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
是 pod 的名称。刷新几次。
它应该保持不变。
要检查另一条路线是否正在工作,请转到http://DOMAIN.NAME/v2/
输出应该是这样的:
Hello, world!
Version: 2.0.0
Hostname: goodbye-7b5798f754-pbkbg
Hostname: goodbye-7b5798f754-pbkbg
是 pod 的名称。刷新几次。
它应该保持不变。
确保 cookie 不会更改打开的开发人员工具(可能是 F12)并导航到带有 cookie 的位置。您可以重新加载页面以检查它们是否没有更改。
推荐阅读
- reactjs - 无法从 Input React (react-rails gem) 中获取值
- java - java - 如何在Java中从Mongo DB获取或检索大数据到前端?
- java - 吐司消息不可见\在android中弹出
- python-3.x - DynamoDB update_item 问题:“调用 UpdateItem 操作时:条件请求失败”(Python)
- angular - 如果 index.html 被缓存,如何使用 Angular 2 代码在任何浏览器中强制从服务器加载 index.html
- google-sheets - 如何查询单元格引用,引用单元格中的数据部分匹配?
- python - 在 Python 中同时使用 Selenium webdriver 和 Requests
- android - 如何调用 popbackstack 而不是删除 backstack 上的先前条目以便我可以再次使用它?
- django-rest-framework - UserRegistrationAPIView 应该包含一个 `querylist` 属性,或者覆盖 `get_querylist()` 方法
- c# - UWP 无法在两个应用程序之间创建 localhost 连接