
# 通过负载均衡配置实现会话保持
#### 概念
会话保持可以确保用户在访问应用时的连续性和一致性。如果在客户端和服务器之间部署了负载均衡设备，很有可能这多个连接会被转发至不同的服务器进行处理。开启会话保持后，负载均衡会把来自同一客户端的访问请求持续分发到同一台后端云服务器上进行处理。
例如在大多数需要用户身份认证的在线系统中，一个用户需要与服务器实现多次交互才能完成一次会话。由于多次交互过程中存在连续性，如果不配置会话保持，负载均衡可能会将部分请求分配至另一个后端服务器，但由于其他后端服务器并未经过用户身份认证，则会出现用户登录失效等交互异常。
因此，在实际的部署环境中，需要根据应用环境的特点，选择适当的会话保持机制。
表1会话保持类型 
| 类型     | 说明                                      | 支持的会话保持类型                                                                                                                                                                                                                                                                                                                                                                    | 会话保持失效的场景                                                                                                                                                                                                                                                                    |
|:---|:---|:---|:---|
| 四层会话保持 | 当创建Service时，使用的协议为TCP或UDP，默认为四层会话保持。    | **源IP地址**：基于源IP地址的简单会话保持，将请求的源IP地址作为散列键（HashKey），从静态分配的散列表中找出对应的服务器。即来自同一IP地址的访问请求会被转发到同一台后端服务器上进行处理。                                                                                                                                                                                                                                                                        | - 客户端的源IP地址发生变化。  - 客户端访问请求超过会话保持时间。                        |
| 七层会话保持 | 当创建Ingress时，使用的协议为HTTP或HTTPS，默认为七层会话保持。 | - **负载均衡器cookie**：负载均衡器会根据客户端第一个请求生成一个cookie，后续所有包含这个cookie值的请求都会由同一个后端服务器处理。  - **应用程序cookie**：该选项依赖于后端应用。后端应用生成一个cookie值，后续所有包含这个cookie值的请求都会由同一个后端服务器处理。   | - 如果客户端发送请求未附带cookie，则会话保持无法生效。  - 客户端访问请求超过会话保持时间。   |
   
![](https://support.huaweicloud.com/bestpractice-cce/public_sys-resources/note_3.0-zh-cn.png)
在创建负载均衡时，分配策略选择"加权轮询算法"（即kubernetes.io/elb.lb-algorithm参数为ROUND_ROBIN）或"加权最少连接"（即kubernetes.io/elb.lb-algorithm参数为LEAST_CONNECTIONS）可配置会话保持；选择"源IP算法"（即kubernetes.io/elb.lb-algorithm参数为SOURCE_IP）时已支持基于源IP地址的会话保持，无需重复配置会话保持。
#### 四层会话保持（Service）
四层的模式下可以开启基于源IP的会话保持（基于客户端的IP进行hash路由）。
#### 在CCE Standard集群中开启四层会话保持
在CCE Standard集群中，Service开启基于源IP的会话保持需要满足以下条件：
1. Service的服务亲和级别选择"节点级别"（即Service的externalTrafficPolicy字段为Local）。
2. Service后端的应用开启反亲和，避免所有Pod均部署在同一节点。
 
**操作步骤**
1. 创建nginx工作负载。 
   实例数设置为3，通过工作负载反亲和设置Pod与自身反亲和。
   ```
   kind: Deployment
   apiVersion: apps/v1
   metadata:
     name: nginx
     namespace: default
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: nginx
     template:
       metadata:
         labels:
           app: nginx
       spec:
         containers:
           - name: container-0
             image: 'nginx:perl'
             resources:
               limits:
                 cpu: 250m
                 memory: 512Mi
               requests:
                 cpu: 250m
                 memory: 512Mi
         imagePullSecrets:
           - name: default-secret
         affinity:
           podAntiAffinity:                   # Pod与自身反亲和
             requiredDuringSchedulingIgnoredDuringExecution:
               - labelSelector:
                   matchExpressions:
                     - key: app
                       operator: In
                       values:
                         - nginx
                 topologyKey: kubernetes.io/hostname
   ```
   
   
2. 创建Service的负载均衡，以使用已有的ELB为例，配置源IP地址会话保持的YAML示例如下。 
   ```
   apiVersion: v1
   kind: Service
   metadata:
     name: svc-example
     namespace: default
     annotations:
       kubernetes.io/elb.class: union
       kubernetes.io/elb.id: *****
       kubernetes.io/elb.lb-algorithm: ROUND_ROBIN      # 加权轮询分配策略
       kubernetes.io/elb.session-affinity-mode: SOURCE_IP    # 开启源IP会话保持
   spec:
     selector: 
       app: nginx
     externalTrafficPolicy: Local    # 服务亲和级别为“节点级别”
     ports:
       - name: cce-service-0
         targetPort: 80
         nodePort: 32633
         port: 80
         protocol: TCP
     type: LoadBalancer
   ```
   
   
3. 验证四层会话保持是否开启。 
   1. 登录ELB控制台找到对应的ELB，并在ELB所在行中单击的对应监听器名称。
   
   2. 查看后端服务器组中，会话保持配置是否开启。
      图1开启四层会话保持   
      ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002027195689.png "点击放大")
      
      
   
   
   
   
 
#### 在CCE Turbo集群中开启四层会话保持
在CCE Turbo集群中，Service开启基于源IP的会话保持与ELB类型相关。
- 使用独享型ELB时，ELB可以直通Pod（即Pod直接作为ELB的后端服务器组），因此Service开启基于源IP的会话保持无需配置服务亲和及应用反亲和。
- 使用共享型ELB时，不支持开启会话保持。
**操作步骤**
- **独享型ELB场景**
  以使用已有的ELB为例，Service的负载均衡配置源IP地址会话保持的YAML示例如下。
  ```
  apiVersion: v1
  kind: Service
  metadata:
    name: svc-example
    namespace: default
    annotations:
      kubernetes.io/elb.class: performance
      kubernetes.io/elb.id: *****
      kubernetes.io/elb.lb-algorithm: ROUND_ROBIN      # 加权轮询分配策略
      kubernetes.io/elb.session-affinity-mode: SOURCE_IP    # 开启源IP会话保持
  spec:
    selector: 
      app: nginx
    externalTrafficPolicy: Cluster     # CCE Turbo集群中，使用独享型ELB对服务亲和策略无要求
    ports:
      - name: cce-service-0
        targetPort: 80
        nodePort: 32633
        port: 80
        protocol: TCP
    type: LoadBalancer
  ```
  验证四层会话保持是否开启。
  1. 登录ELB控制台找到对应的ELB，并在ELB所在行中单击的对应监听器名称。
  
  2. 查看后端服务器组中，会话保持配置是否开启。
     图2开启四层会话保持   
     ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002027195689.png "点击放大")
     
     
    
 
#### 七层会话保持（Ingress）
七层的模式下可以开启基于http cookie和app cookie的会话保持 。
#### 在CCE Standard集群中开启七层会话保持
在Ingress上开启基于cookie的会话保持需要满足以下条件：
1. Ingress对应的Service服务亲和级别选择"节点级别"（即Service的externalTrafficPolicy字段为Local）。
2. Ingress对应的应用（工作负载）应该开启与自身反亲和，避免所有Pod均部署在同一节点。
**操作步骤**
1. 创建nginx工作负载。 
   实例数设置为3，通过工作负载反亲和设置Pod与自身反亲和。
   ```
   kind: Deployment
   apiVersion: apps/v1
   metadata:
     name: nginx
     namespace: default
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: nginx
     template:
       metadata:
         labels:
           app: nginx
       spec:
         containers:
           - name: container-0
             image: 'nginx:perl'
             resources:
               limits:
                 cpu: 250m
                 memory: 512Mi
               requests:
                 cpu: 250m
                 memory: 512Mi
         imagePullSecrets:
           - name: default-secret
         affinity:
           podAntiAffinity:                   # Pod与自身反亲和
             requiredDuringSchedulingIgnoredDuringExecution:
               - labelSelector:
                   matchExpressions:
                     - key: app
                       operator: In
                       values:
                         - nginx
                 topologyKey: kubernetes.io/hostname
   ```
   
   
2. 为工作负载创建Service。本文以NodePort类型Service为例。 
   会话保持的配置需在Service的配置中进行设置，由于Ingress可以对接多个Service，因此每个Service可以有不同的会话保持配置。
   ```
   apiVersion: v1
   kind: Service
   metadata:
     name: nginx
     namespace: default
     annotations:
       kubernetes.io/elb.lb-algorithm: ROUND_ROBIN      # 加权轮询分配策略
       kubernetes.io/elb.session-affinity-mode: HTTP_COOKIE      # HTTP Cookie类型
       kubernetes.io/elb.session-affinity-option: '{"persistence_timeout":"1440"}'   # 会话保持时间，单位为分钟，取值范围为1-1440
   spec:
     selector:
       app: nginx
     ports:
       - name: cce-service-0
         protocol: TCP
         port: 80
         targetPort: 80
         nodePort: 32633            # 自定义节点端口
     type: NodePort
     externalTrafficPolicy: Local   # 服务亲和级别为“节点级别”
   ```
   还可以选择应用程序Cookie，如下所示。
   ```
   apiVersion: v1
   kind: Service
   metadata:
     name: nginx
     namespace: default
     annotations:
       kubernetes.io/elb.lb-algorithm: ROUND_ROBIN      # 加权轮询分配策略
       kubernetes.io/elb.session-affinity-mode: APP_COOKIE     # 选择应用程序Cookie
       kubernetes.io/elb.session-affinity-option: '{"app_cookie_name":"test"}'  # 应用程序Cookie名称
   spec:
     selector:
       app: nginx
     ports:
       - name: cce-service-0
         protocol: TCP
         port: 80
         targetPort: 80
         nodePort: 32633            # 自定义节点端口
     type: NodePort
     externalTrafficPolicy: Local   # 服务亲和级别为“节点级别”
   ```
   
   
3. 创建Ingress，关联Service。以下示例以使用已有的ELB为例，如需使用自动创建ELB的方式，请参考[通过Kubectl命令行添加ELB Ingress](https://support.huaweicloud.com/usermanual-cce/cce_10_0252.html)。
   
   ```
   apiVersion: networking.k8s.io/v1
   kind: Ingress 
   metadata: 
     name: ingress-test
     namespace: default
     annotations: 
       kubernetes.io/elb.class: union
       kubernetes.io/elb.port: '80'
       kubernetes.io/elb.id: *****
   spec:
     rules: 
     - host: 'www.example.com'
       http: 
         paths: 
         - path: '/'
           backend: 
             service:
               name: nginx     # Service的名称
               port: 
                 number: 80
           property:
             ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
           pathType: ImplementationSpecific
     ingressClassName: cce
   ```
   
   
4. 验证七层会话保持是否开启。 
   1. 登录ELB控制台找到对应的ELB，并在ELB所在行中单击的对应监听器名称。
   
   2. 切换至"转发策略"页签，单击后端服务器组名称，查看会话保持配置是否开启。
      图3开启七层会话保持   
      ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002027203729.png "点击放大")
      
      
   
   
   
   
 
#### 在CCE Turbo集群中开启七层会话保持
在Ingress上开启基于cookie的会话保持：
- 使用独享型ELB时，ELB可以直通Pod（即Pod直接作为ELB的后端服务器组），因此Ingress开启基于cookie的会话保持无需配置服务亲和及应用反亲和。
- 使用共享型ELB时，不支持开启会话保持。
**操作步骤**
- **独享型ELB场景**
  1. 为工作负载创建Service。CCE Turbo集群中，使用独享型ELB的Ingress需对接CLusterIP类型的Service。
     会话保持的配置需在Service的配置中进行设置，由于Ingress可以对接多个Service，因此每个Service可以有不同的会话保持配置。
     ```
     apiVersion: v1
     kind: Service
     metadata:
       name: nginx
       namespace: default
       annotations:
         kubernetes.io/elb.lb-algorithm: ROUND_ROBIN      # 加权轮询分配策略
         kubernetes.io/elb.session-affinity-mode: HTTP_COOKIE      # HTTP Cookie类型
         kubernetes.io/elb.session-affinity-option: '{"persistence_timeout":"1440"}'   # 会话保持时间，单位为分钟，取值范围为1-1440
     spec:
       selector:
         app: nginx
       ports:
         - name: cce-service-0
           protocol: TCP
           port: 80
           targetPort: 80
           nodePort: 0
       type: ClusterIP
     ```
     
  
  2. 创建Ingress，关联Service。以下示例以使用已有的ELB为例，如需使用自动创建ELB的方式，详情请参考[通过Kubectl命令行添加ELB Ingress](https://support.huaweicloud.com/usermanual-cce/cce_10_0252.html)。
     ```
     apiVersion: networking.k8s.io/v1
     kind: Ingress 
     metadata: 
       name: ingress-test
       namespace: default
       annotations: 
         kubernetes.io/elb.class: performance
         kubernetes.io/elb.port: '80'
         kubernetes.io/elb.id: *****
     spec:
       rules: 
       - host: 'www.example.com'
         http: 
           paths: 
           - path: '/'
             backend: 
               service:
                 name: nginx     # Service的名称
                 port: 
                   number: 80
             property:
               ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
             pathType: ImplementationSpecific
       ingressClassName: cce
     ```
     
  
  3. 验证七层会话保持是否开启。
     1. 登录ELB控制台找到对应的ELB，并在ELB所在行中单击的对应监听器名称。
     
     2. 切换至"转发策略"页签，单击后端服务器组名称，查看会话保持配置是否开启。
        图4开启七层会话保持   
        ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002027203729.png "点击放大")
        
        
      
   
 
