kubernetes核心概念 service(二)
kubernetes核心概念 service(二)
service类型
- ClusterIP(可在集群内部访问)
- NodePort(可通过节点ip访问)
- LoadBalancer
- ExternalName
注意:
- Service类型决定了客户访问Service代理的方法
- Kube-proxy工作模式是service实现代理时的底层实现方式(ipvs)
- service类型-LoadBalancer
使用MetalLB/OpenELB实现LoadBalancer
- 概述:
MetalLB可以为kubernetes集群中的Service提供网络负载均衡功能。
MetalLB两大功能为:
- 地址分配,类似于DHCP,此地址是对外发布的虚拟的群集ip
- 通过群集ip访问的流量,将被负载均衡的调度到k8s群集的各个节点的service。
注:
当使用云平台(阿里云、腾讯云、AWS等)的容器服务时,我们可以通过配置service为LoadBalancer模式来绑定云平台的负载均衡器,从而实现外网的访问。
对于自建kubernetes集群我们一般使用MetalLB来实现外部流量的访问。
- 工作原理:

Metallb包含两个组件,Controller(Deployment方式部署)和Speaker(daemonset方式部署)。
具体的工作原理:
- Controller负责监听service变化,当service配置为LoadBalancer模式时,从IP池中分配相应的IP。
- Speaker则依据Service的变化,将外部流量引流到kubernetes集群node节点。
- 当业务流量通过到达指定的Node时,由Node上面运行的Kube-Proxy依据转发模式(iptables或ipvs)将流量转发到pod中。
小结:
- MetaLB负责从主机维度实现负载均衡,而pod副本间的负载均衡是通过kube-proxy实现。
- 跟NodePort模式相比较,MetalLB使群集有了客户访问的统一入口,即群集ip
- NodePort:客户访问任意节点ip,都可以访问到service,kube-proxy再通过ipvs实现pod间的调度
- MetalLB:客户通过访问的群集IP,客户请求被负载均衡的调度到任一节点service,kube-proxy再通过ipvs实现pod间的调度
- 修改kube-proxy代理模式
[root@master01 ~]# kubectl get configmap -n kube-system
NAME DATA AGE
......
kube-proxy 2 35h
[root@master01 ~]# kubectl edit configmap kube-proxy -n kube-system
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: true #严格arp,由原来的flase修改为true,原理同LVS中的DR模式关闭到群集地址的arp响应
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
logging:
flushFrequency: 0
options:
json:
infoBufferSize: "0"
verbosity: 0
metricsBindAddress: ""
mode: "ipvs" #默认为空,添加ipvs
[root@master01 ~]# kubectl rollout restart daemonset kube-proxy -n kube-system
官网安装步骤
https://metallb.universe.tf/installation/
[root@master01 ~]# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
服务器连接不了时,可在vpn连接后,浏览器中访问https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml,看到内容后复制创建文件,再kubectl apply -f metallb-native.yaml部署应用
也可以使用离线下载后的文件部署
[root@xxx ~]# docker load -i metallb-controller.tar #所有节点
[root@xxx ~]# docker load -i metallb_speaker.tar #所有节点
[root@master01 ~]# kubectl apply -f metallb-native.yaml
[root@master01 ~]# kubectl -n metallb-system get pod
NAME READY STATUS RESTARTS AGE
controller-6b9fd67ff4-rzvg2 1/1 Running 0 9m33s
speaker-8sbmc 1/1 Running 0 9m33s
speaker-9rhng 1/1 Running 0 9m33s
speaker-sfdtl 1/1 Running 0 9m33s
等待一会,可通过查看描述信息跟踪pod的运行状态,如果vpn连接时,长时间无法完成下载时,各节点重启docker
[root@master01 ~]# vim ippool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ippool
namespace: metallb-system
spec:
addresses:
- 192.168.10.240-192.168.10.250
[root@master01 ~]# kubectl apply -f ippool.yaml
如果出现错误提示:等上面pod运行起来以后再部署,若故障依旧,重启docker
Error from server (InternalError): error when creating "ippool.yaml": Internal error occurred: failed calling webhook "ipaddresspoolvalidationwebhook.metallb.io": failed to call webhook: Post "https://metallb-webhook-service.metallb-system.svc:443/validate-metallb-io-v1beta1-ipaddresspool?timeout=10s": dial tcp 10.100.143.2:443: connect: connection refused
查看地址池信息:
[root@master01 ~]# kubectl -n metallb-system get ipaddresspool
NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
ippool true false ["192.168.10.240-192.168.10.250"]
[root@master01 ~]# vim L2.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
[root@master01 ~]# kubectl apply -f L2.yaml
- 发布Service类型为LoadBalancer的应用
创建Deployment控制器类型应用nginx-metallb及service,service类型为LoadBalancer
[root@master01 ~]# vim nginx-metallb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-metallb
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-metallb1
image: nginx:1.20
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-metallb
spec:
ports:
- port: 8090
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer
[root@master01 ~]# kubectl apply -f nginx-metallb.yaml
[root@master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
headless-service ClusterIP None <none> 80/TCP 168m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 170m
nginx-metallb LoadBalancer 10.99.125.229 192.168.10.240 8090:32276/TCP 8m10s
nginx-nodeport NodePort 10.107.199.151 <none> 8060:30001/TCP 152m
在各节点上查看群集ip
[root@master01 ~]# ip a | grep 192.168.10.240
inet 192.168.10.240/32 scope global kube-ipvs0
[root@worker01 ~]# ip a | grep 192.168.10.240
inet 192.168.10.240/32 scope global kube-ipvs0
[root@worker02 ~]# ip a | grep 192.168.10.240
inet 192.168.10.240/32 scope global kube-ipvs0
[root@master01 ~]# curl http://192.168.10.240:8090
可以显示网页
Windows浏览器访问:http://192.168.10.240:8090
可以显示网页
仍然可以通过nodeIP访问服务:curl http://192.168.10.11:32276
可以显示网页
- 把集群外部的服务引入到集群内部,实现了集群内部pod和集群外部的服务进行通信
- ExternalName 类型的服务适用于外部服务使用域名的方式,缺点是不能指定端口
- 集群内的Pod会继承Node上的DNS解析规则,只要Node可以访问的服务,Pod中也可以访问到, 这就实现了集群内服务访问集群外服务
- 将公网域名引入
- 编写YAML文件
[root@master01 ~]# vim externalname.yml
apiVersion: v1
kind: Service
metadata:
name: my-externalname
namespace: default
spec:
type: ExternalName
externalName: www.baidu.com # 对应的外部域名为www.baidu.com
-
- 应用YAML文件
[root@master01 ~]# kubectl apply -f externalname.yml
-
- 查看service
[root@master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-externalname ExternalName <none> www.baidu.com <none> 18m
-
- 查看my-service的dns解析
[root@master01 ~]# kubectl -n kube-system get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 2d
[root@master01 ~]# dig -t A my-externalname.default.svc.cluster.local. @10.96.0.10
;; QUESTION SECTION:
;my-externalname.default.svc.cluster.local. IN A
;; ANSWER SECTION:
my-externalname.default.svc.cluster.local. 5 IN CNAME www.baidu.com.
www.baidu.com. 5 IN A 110.242.68.3
www.baidu.com. 5 IN A 110.242.68.4
[root@master01 ~]# kubectl run -it --image busybox -- sh
/ # nslookup www.baidu.com
Server: 10.96.0.10
Address: 10.96.0.10:53
Non-authoritative answer:
Name: www.baidu.com
Address: 39.156.70.46
Name: www.baidu.com
Address: 39.156.70.239
/ # nslookup my-externalname.default.svc.cluster.local.
Server: 10.96.0.10
Address: 10.96.0.10:53
my-externalname.default.svc.cluster.local canonical name = www.baidu.com
Name: www.baidu.com
Address: 110.242.68.3
Name: www.baidu.com
Address: 110.242.68.4
- sessionAffinity会话保持(会话粘滞)
- Session Affinity简介
会话保持(Session Affinity),有时又称粘滞会话(Sticky Sessions), 是负载均衡领域设计需要着力解决的重要问题之一,也是一个相对比较复杂的问题。
会话保持是指在负载均衡器上的一种机制,在完成负载均衡任务的同时,还负责一系列相关联的访问请求会分配到一台服务器上。
会话保持的作用:确保把来自同一客户的一个完整会话的请求转发至后台同一台服务器进行处理。
- 什么时候需要会话保持?
举个大家每天都会遇到的例子,大家在淘宝或者京东上购物时,从完成用户身份认证到浏览店铺,选择心仪商品加入购物车,一直到最后下单完成支付,需要经过很多次和服务器的交互过程才能完成整个交易。由于这几次交互过程从顺序上和逻辑上是密切相关的,服务器在进行这些交互过程的某一个交互步骤时需要一个上下文(Context),即上一次交互过程的输出,因此要求这些相关的交互过程都由一台服务器完成。
在这种情况下,假设负载均衡器仍然把这些相关交互session分散到不同的服务器实例上,就会带来很糟糕的用户体验,比如客户在浏览器上每点击一次,都会弹出登录页面。或者即使用户输入了正确的验证码,却仍然提示验证码错误。由于服务器处理实例不一样,也有可能造成客户放入购物车的物品丢失。
设置sessionAffinity为Clientip (类似nginx的ip_hash算法,lvs的sh算法)
- 创建测试用deployment、service
[root@nginx ~]# cat sessionAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-server1
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.20
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
app: nginx
[root@master01 ~]# kubectl apply -f sessionAffinity.yaml
[root@master01 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-server1-58845f75f4-9zlnw 1/1 Running 0 2m11s
nginx-server1-58845f75f4-ffqdt 1/1 Running 0 2m11s
进入pod,创建网页
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-9zlnw -- bash
root@nginx-server1-58845f75f4-9zlnw:/# echo web1 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-9zlnw:/# exit
进入pod,创建网页
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-ffqdt -- bash
root@nginx-server1-58845f75f4-ffqdt:/# echo web2 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-ffqdt:/# exit
[root@master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8m53s
nginx-svc ClusterIP 10.108.138.24 <none> 80/TCP 8m11s
[root@master01 ~]# curl 10.108.138.24
web1
[root@master01 ~]# curl 10.108.138.24
web2
- 给服务打补丁,增加会话粘滞
打补丁前查看:
[root@master01 ~]# kubectl describe service nginx-svc
...
Endpoints: 10.244.30.71:80,10.244.5.10:80
Session Affinity: None
Events: <none>
打补丁前查看:
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'
[root@master01 ~]# kubectl describe service nginx-svc
...
Endpoints: 10.244.30.71:80,10.244.5.10:80
Session Affinity: ClientIP
Events: <none>
客户端测试:
[root@master01 ~]# curl 10.108.138.24
web1
[root@master01 ~]# curl 10.108.138.24
web1
设置回sessionAffinity为None
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"None"}}'
[root@master01 ~]# kubectl describe service nginx-svc
...
Endpoints: 10.244.30.71:80,10.244.5.10:80
Session Affinity: None
Events: <none>
测试:
[root@master01 ~]# curl 10.108.138.24
web2
[root@master01 ~]# curl 10.108.138.24
web1
更多推荐
所有评论(0)