前提


基于kubernetes部署Java项目,发现在多pod模式下,会出现登录成功但是页面无法跳转的问题,在单一pod时却可以成功登录并页面正常跳转,于是推测是cookie的问题。

网上的大部分文章提供的解决方案都是在service的配置文件中加入sessionAffinity: ClientIP,功能是选择与请求来源ip更接近的pod,这样就会固定同一个session,但是好像并不适用于我这个项目。

最终的解决当然还是要靠自己读官方的文档,ingress-nginx有大量的注释配置,官方针对这种情况已经做了说明,需要细细阅读,详见Cookie affinity

解决方案


注释nginx.ingress.kubernetes.io/affinity在Ingress的所有上游中启用和设置相似性类型。这样,请求将始终定向到同一上游服务器。Nginx唯一可用的相似性类型是cookie

如果为一个主机定义了多个Ingress nginx.ingress.kubernetes.io/affinity: cookie,并且至少一个Ingress使用,则只有Ingress使用的路径nginx.ingress.kubernetes.io/affinity将使用会话Cookie相似性。通过随机选择后端服务器,可以在主机的其他入口定义的所有路径进行负载均衡。

如果您使用Cookie affinity,则还可以使用注释nginx.ingress.kubernetes.io/session-cookie-name来指定将用于路由请求的cookie名称。 默认是创建一个名为 INGRESSCOOKIE的cookie。

注释nginx.ingress.kubernetes.io/affinity-mode定义了会话的粘性。如果将部署规模扩大,balance则将此选项设置为(默认)将重新分配一些会话,从而重新平衡服务器上的负载。将此设置为persistent不会重新平衡与新服务器的会话,因此提供了最大的粘性。

以上是官方文档的直译。

简而言之,在ingress-nginx配置中应做以下操作:

  1. 设置nginx.ingress.kubernetes.io/affinity属性,启用会话保持。

  2. 设置nginx.ingress.kubernetes.io/affinity-mode属性,设置为balance在集群扩大pod时,会自动分配一些会话到新创建的pod上,用于平衡服务器的负载;设置为persistent则永远保证用户访问pod的一致性,不会访问到其他pod。

  3. 设置nginx.ingress.kubernetes.io/session-cookie-name属性,自定义cookie名称。

可见cookie示例

对我用到了其中的三个属性进行描述:

属性名称 描述
nginx.ingress.kubernetes.io/affinity 亲和力类型,设置该属性为 cookie 来启用会话保持 仅支持设置为cookie
nginx.ingress.kubernetes.io/affinity-mode 定义会话的粘性。 进行集群的扩容时,可设置为balanced属性来重新分配某些会话,或者使用persistent来保证用户永远访问至同一个pod。 balanced (默认设置) or persistent
nginx.ingress.kubernetes.io/session-cookie-name 将要被创建的cookie名称 默认设置为 INGRESSCOOKIE,可自定义

配置文件


使用session会话保持可以用于解决多tomcat的pod下,登录由于session问题导致页面无法跳转的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-tomcat
namespace: default
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-name: "route"
spec:
tls:
- hosts:
- your.host.cn
secretName: https-secret
rules:
- host: your.host.cn
http:
paths:
- path:
backend:
serviceName: your service name
servicePort: 8280

以下为其他网友提供的解决方案:

在service的配置文件中加入sessionAffinity: ClientIP,功能是选择与请求来源ip更接近的pod,这样就会固定同一个session。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
name: tomcat
namespace: default
spec:
selector:
app: tomcat
release: canary
ports:
- name: http
targetPort: 8280
port: 8280
sessionAffinity: ClientIP