操作场景
负载均衡( LoadBalancer )可以通过弹性负载均衡从公网访问到工作负载,与弹性IP方式相比提供了高可靠的保障,一般用于系统中需要暴露到公网的服务。
负载均衡访问方式由公网弹性负载均衡服务地址以及设置的访问端口组成,例如“10.117.117.117:80”。
在访问时从ELB过来的流量会先访问到节点,然后通过Service转发到Pod。
图 负载均衡( LoadBalancer )
在使用CCE Turbo集群 + 独享型ELB实例时,支持ELB直通Pod,使部署在容器中的业务时延降低、性能无损耗。
从集群外部访问时,从ELB直接转发到Pod;集群内部访问可通过Service转发到Pod。
图 ELB直通容器
约束与限制
- CCE中的负载均衡 ( LoadBalancer )访问类型使用弹性负载均衡 ELB提供网络访问,存在如下产品约束:
- 自动创建的ELB实例建议不要被其他资源使用,否则会在删除时被占用,导致资源残留。
- 1.15及之前版本集群使用的ELB实例请不要修改监听器名称,否则可能导致无法正常访问。
- 创建service后,如果服务亲和从集群级别切换为节点级别,连接跟踪表将不会被清理,建议用户创建service后不要修改服务亲和属性,如需修改请重新创建service。
- 当服务亲和设置为节点级别(即externalTrafficPolicy为local)时,集群内部可能使用ELB地址访问不通,具体情况请参见集群内使用ELB地址无法访问Service说明。
- l CCE Turbo集群仅支持集群级别服务亲和。
- 独享型ELB仅支持1.17及以上集群。
- 独享型ELB规格必须支持网络型(TCP/UDP),且网络类型必须支持私网(有私有IP地址)。如果需要Service支持HTTP,则独享型ELB规格需要为网络型(TCP/UDP)和应用型(HTTP/HTTPS)。
- 使用控制台创建LoadBalancer类型Service时会自动生成一个节点端口(nodeport),端口号随机。使用kubectl创建LoadBalancer类型Service时,如不指定节点端口,也会随机生成一个节点端口,端口号随机。
- 使用CCE集群时,如果LoadBalancer类型Service的服务亲和类型为集群级别(cluster),当请求进入到集群时,会使用SNAT分发到各个节点的节点端口(nodeport),不能超过节点可用的nodeport数量,而服务亲和为节点级别(local)则无此约束。使用CCE Turbo集群时,如果是使用共享型ELB依然有此约束,而独享型ELB无此约束,建议使用CCE Turbo时配合使用独享型ELB。
- 集群服务转发模式为IPVS时,不支持配置节点的IP作为Service的externalIP,会导致节点不可用。
- IPVS模式集群下,Ingress和Service使用相同ELB实例时,无法在集群内的节点和容器中访问Ingress,因为kube-proxy会在ipvs-0的网桥上挂载LB类型的Service地址,Ingress对接的ELB的流量会被ipvs-0网桥劫持。建议Ingress和Service使用不同ELB实例。
创建LoadBalancer类型Service
步骤 1 登录CCE控制台,单击集群名称进入集群。
步骤 2 在左侧导航栏中选择“服务发现”,在右上角单击“创建服务”。
步骤 3 设置参数。
- Service名称: 自定义服务名称,可与工作负载名称保持一致。
- 访问类型 :选择“负载均衡 LoadBalancer”。
- 命名空间: 工作负载所在命名空间。
- 服务亲和: 详情请参见externalTrafficPolicy(服务亲和)。
- 集群级别:集群下所有节点的IP+访问端口均可以访问到此服务关联的负载,服务访问会因路由跳转导致一定性能损失,且无法获取到客户端源IP。
- 节点级别:只有通过负载所在节点的IP+访问端口才可以访问此服务关联的负载,服务访问没有因路由跳转导致的性能损失,且可以获取到客户端源IP。
- 选择器: 添加标签,Service根据标签选择Pod,填写后单击“添加”。也可以引用已有工作负载的标签,单击“引用负载标签”,在弹出的窗口中选择负载,然后单击“确定”。
- IPv6: 默认不开启,开启后服务的集群内IP地址(ClusterIP)变为IPv6地址。该功能仅在1.15及以上版本的集群创建时开启了IPv6功能才会显示。
- 负载均衡器:
选择对接的ELB实例,仅支持与集群在同一个VPC下的ELB实例。如果没有可选的ELB实例,请单击“创建负载均衡器”跳转到ELB控制台创建。
CCE控制台支持自动创建ELB实例,在下拉框选择自动创建,填写ELB实例名称、是否公网访问(将创建 5 Mbit/s 带宽的弹性公网 IP。默认按照流量计费),独享型ELB实例还需选择可用区、子网和规格。当前仅支持自动创建网络型(TCP/UDP)独享型ELB实例。
您可以单击“编辑”配置ELB实例的参数,在弹出窗口中配置ELB实例的参数。
分配策略:可选择加权轮询算法、加权最少连接或源IP算法。
说明
加权轮询算法:根据后端服务器的权重,按顺序依次将请求分发给不同的服务器。它用相应的权重表示服务器的处理性能,按照权重的高低以及轮询方式将请求分配给各服务器,相同权重的服务器处理相同数目的连接数。常用于短连接服务,例如HTTP等服务。
加权最少连接:最少连接是通过当前活跃的连接数来估计服务器负载情况的一种动态调度算法。加权最少连接就是在最少连接数的基础上,根据服务器的不同处理能力,给每个服务器分配不同的权重,使其能够接受相应权值数的服务请求。常用于长连接服务,例如数据库连接等服务。
源IP算法:将请求的源IP地址进行Hash运算,得到一个具体的数值,同时对后端服务器进行编号,按照运算结果将请求分发到对应编号的服务器上。这可以使得对不同源IP的访问进行负载分发,同时使得同一个客户端IP的请求始终被派发至某特定的服务器。该方式适合负载均衡无cookie功能的TCP协议。
会话保持类型:默认不启用,可选择“源IP地址”。负载均衡监听是基于IP地址的会话保持,即来自同一IP地址的访问请求转发到同一台后端服务器上。
健康检查:默认不启用。此处健康检查是设置负载均衡的健康检查配置。当端口配置协议为TCP时,支持TCP和HTTP协议,当端口配置协议为UDP时,支持UDP协议。健康检查默认使用业务端口(Service的NodePort和容器端口)作为健康检查的端口;您也可以重新指定端口用于健康检查,重新制定端口会为服务增加一个名为cce-healthz的服务端口配置。
- 端口配置:
- 协议:请根据业务的协议类型选择。
- 服务端口:Service使用的端口,端口范围为1-65535。
- 容器端口:工作负载程序实际监听的端口,需用户确定。例如nginx默认使用80端口。
步骤 4 单击“确定”,创建Service。
ELB转发说明
LoadBalancer类型Service创建完后,可以在ELB控制台查看ELB实例的监听器转发规则,如下所示。
图 ELB转发说明
可以看到这个ELB实例创建了一个监听器,其后端服务器地址是Pod的IP地址,业务端口是容器端口。这是因为Pod使用了ENI或Sub-ENI,ELB会直通Pod,当有流量通过ELB请求时,会直接转发给Pod,从而访问到Pod,这跟操作场景中所述是一致的。
ELB直通容器场景(CCE Turbo + 独享型ELB实例)下,LoadBalancer类型Service创建完后,可以在ELB控制台查看ELB实例的监听器转发规则,如下所示。
图 ELB转发说明
Service使用HTTP
说明
Service使用HTTP仅v1.19.16及以上版本集群支持。
CCE控制台当前仅支持自动创建4层独享型ELB实例,此种情况下无法使用HTTP能力,在控制台创建Service使用HTTP时请选择对接已有独享型ELB实例。
请勿将Ingress与使用HTTP的Service对接同一个ELB下的同一个监听器,否则将产生端口冲突。
Service支持使用ELB的7层能力,共享型和独享型ELB都支持对接。
独享型ELB实例有如下限制:
- 对接已有的独享型ELB实例,需要 独享型ELB实例同时支持4层和7层的flavor ,否则会功能不可用。
- 使用自动创建的ELB实例,注意 同时使用独享型ELB实例的4层和7层能力 ,需要在kubernetes.io/elb.autocreate的annotation中指定4层和7层flavor。
使用ELB的7层能力时,需要添加如下annotation
- kubernetes.io/elb.protocol-port : "https:443,http:80"
protocol-port的取值需要和service的spec.ports字段中的端口对应,格式为protocol:port,port中的端口会匹配service.spec.ports中端口,并将该端口发布成对应的protocol协议。
- kubernetes.io/elb.cert-id : "17e3b4f4bc40471c86741dc3aa211379"
cert-id内容为ELB证书管理的证书ID,当protocol-port指定了https协议,ELB监听器的证书会设置为cert-id证书,当发布多个HTTPS的服务,会使用同一份证书。
配置示例如下,其中spec.ports中两个端口与kubernetes.io/elb.protocol-port中对应,443端口、80端口分别发布成HTTPS、HTTP协议。
apiVersion: v1
kind: Service
metadata:
annotations:
kubernetes.io/elb.autocreate: '
{
"type": "public",
"bandwidth_name": "cce-bandwidth-1634816602057",
"bandwidth_chargemode": "bandwidth",
"bandwidth_size": 5,
"bandwidth_sharetype": "PER",
"eip_type": "5_bgp",
"available_zone": [
"cn-north-4b"
],
"l7_flavor_name": "L7_flavor.elb.s2.small",
"l4_flavor_name": "L4_flavor.elb.s1.medium"
}'
kubernetes.io/elb.class: performance
kubernetes.io/elb.protocol-port: "https:443,http:80"
kubernetes.io/elb.cert-id: "17e3b4f4bc40471c86741dc3aa211379"
labels:
app: nginx
name: test
name: test
namespace: default
spec:
ports:
- name: cce-service-0
port: 443
protocol: TCP
targetPort: 80
- name: cce-service-1
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
version: v1
sessionAffinity: None
type: LoadBalancer
使用上面的示例创建Service,在新建的ELB实例中可以看到创建了443端口和80端口的监听器。
集群内使用ELB地址无法访问Service说明
当LoadBalancer Service设置了服务亲和为节点级别,即externalTrafficPolicy取值为Local时,在使用中可能会碰到从集群内部(节点上或容器中)使用ELB地址访问不通的情况,回显类似如下内容:
upstream connect error or disconnect/reset before headers. reset reason: connection failure
这是由于Kubernetes在创建LoadBalancer Service时,kube-proxy会把ELB的访问地址作为External-IP添加到iptables或IPVS中。如果客户端从集群内部发起访问ELB地址的请求,该地址会被认为是服务的External-IP,被kube-proxy直接转发,而不再经过集群外部的ELB。
当externalTrafficPolicy的取值为Local时,在不同容器网络模型和服务转发模式下,情况会有所不同,详情如下:
Server Client 容器隧道集群(IPVS) VPC集群(IPVS) 容器隧道集群(iptables) VPC集群(iptables) 节点访问类型Service 同节点 OK,Pod容器所在节点通,其他不通 OK,访问Pod容器所在节点通 OK,访问Pod容器所在节点通 OK,访问Pod容器所在节点通 跨节点 OK,Pod容器所在节点通,其他不通 OK,访问Pod容器所在节点通 OK,访问Pod容器所在节点通,访问本节点IP+访问端口通;其他不通 OK,访问Pod容器所在节点通,访问本节点IP+访问端口通;其他不通 同节点容器 OK,Pod容器所在节点通,其他不通 OK,访问Pod容器所在节点不通 OK,访问Pod容器所在节点通 OK,访问Pod容器所在节点不通 跨节点容器 OK,Pod容器所在节点通,其他不通 OK,访问Pod容器所在节点通 OK,访问Pod容器所在节点通 OK,访问Pod容器所在节点通 独享型负载均衡类型Service 同节点 公网通,私网不通 公网通,私网不通 公网通,私网不通 公网通,私网不通 同节点容器 公网通,私网不通 公网通,私网不通 公网通,私网不通 公网通,私网不通 nginx-ingress插件的service为Local级别独享型 同节点 公网通,私网不通 公网通,私网不通 公网通,私网不通 公网通,私网不通 同节点容器 公网通,私网不通 公网通,私网不通 公网通,私网不通 公网通,私网不通
-
( 推荐 )在集群内部访问使用Service的ClusterIP或服务域名访问。
-
将Service的externalTrafficPolicy设置为Cluster,即集群级别服务亲和。不过需要注意这会影响源地址保持。
apiVersion: v1 kind: Service metadata: annotations: kubernetes.io/elb.class: union kubernetes.io/elb.autocreate: '{"type":"public","bandwidth_name":"cce-bandwidth","bandwidth_chargemode":"bandwidth","bandwidth_size":5,"bandwidth_sharetype":"PER","eip_type":"5_bgp","name":"james"}' labels: app: nginx name: nginx spec: externalTrafficPolicy: Cluster ports: - name: service0 port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer
-
使用Service的pass-through特性,使用ELB地址访问时绕过kube-proxy,先访问ELB,经过ELB再访问到负载。
说明独享型负载均衡配置pass-through后,在工作负载同节点和同节点容器内无法通过Service访问。 -
1.15及以下老版本集群暂不支持该能力。
-
IPVS网络模式下,对接同一个ELB的Service需保持pass-through设置情况一致。
apiVersion: v1
kind: Service
metadata:
annotations:
kubernetes.io/elb.pass-through: "true"
kubernetes.io/elb.class: union
kubernetes.io/elb.autocreate: '{"type":"public","bandwidth_name":"cce-bandwidth","bandwidth_chargemode":"bandwidth","bandwidth_size":5,"bandwidth_sharetype":"PER","eip_type":"5_bgp","name":"james"}'
labels:
app: nginx
name: nginx
spec:
externalTrafficPolicy: Local
ports:
- name: service0
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer