service对外暴露你的应用
1965字约7分钟
2024-09-29
Service是什么与Service存在的意义
Service引入主要是解决Pod的动态变化,提供统一访问入口:
防止Pod失联,准备找到提供同一个服务的Pod(服务发现)
定义一组Pod的访问策略(负载均衡)
Pod与Service的关系
Service通过标签关联一组Pod
Service使用iptables或者ipvs为一组Pod提供负载均衡能力
Service定义与创建
vim service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
type: ClusterIP # 服务类型
ports:
- port: 80 # Service端口
protocol: TCP # 协议
targetPort: 80 # 容器端口
selector:
app: web # 指定关联Pod的标签
#创建service:
kubectl apply -f service.yaml
#查看service:
kubectl get service
#查看service关联一组pod的IP
kubectl get endpoints
Service三种类型
ClusterIP:集群内部使用
NodePort:对外暴露应用(集群外)
LoadBalancer:对外暴露应用,适用公有云
ClusterIP:默认,分配一个稳定的IP地址,即VIP,只能在集群内部访问。
vim service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
type: ClusterIP # 服务类型
ports:
- port: 80 # Service端口
protocol: TCP # 协议
targetPort: 80 # 容器端口
selector:
app: web # 指定关联Pod的标签
访问
kubectl apply -f service.yaml
kubectl get svc
curl 10.107.214.48 #访问集群内部暴露的service的IP及端口
NodePort:在每个节点上启用一个端口来暴露服务,可以在集群 外部访问。也会分配一个稳定内部集群IP地址。 访问地址:<任意NodeIP>: 端口范围:30000-32767
vim service-node.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
type: NodePort # 服务类型
ports:
- port: 80 # Service端口
protocol: TCP # 协议
targetPort: 80 # 容器端口
nodePort: 30009 #nodeport暴露的端口
selector:
app: web # 指定关联Pod的标签
访问
kubectl apply -f service-node.yaml
kubectl get svc
http://192.168.1.12:30009/ #访问集群外部节点IP以及暴露的端口
NodePort:会在每台Node上监听端口接收用户流量,在实际情 况下,对用户暴露的只会有一个IP和端口,那这么多台Node该使 用哪台让用户访问呢?
这时就需要前面加一个公网负载均衡器为项目提供统一访问入口了。
负载均衡器:
开源:nginx、lvs、haproxy
公有云:SLB
upstream demo {
server 192.168.0.11:30008;
server 192.168.0.12:30008;
}
upstream demo2 {
server 192.168.0.13:30009;
server 192.168.0.14:30009;
}
upstream demo3 {
server 192.168.0.15:30010;
server 192.168.0.16:30010;
}
server {
server_name a.xxx.com;
location / {
proxy_pass http://demo;
}
}
server {
server_name b.xxx.com;
location / {
proxy_pass http://demo2;
}
}
server {
server_name c.xxx.com;
location / {
proxy_pass http://demo3;
}
}
LoadBalancer:与NodePort类似,在每个节点上启用一个端口来暴 露服务。除此之外,Kubernetes会请求底层云平台(例如阿里云、腾 讯云、AWS等)上的负载均衡器,将每个Node ([NodeIP]:[NodePort])作为后端添加进去。
Service代理模式
Service的底层实现主要有iptables和ipvs二种网络模式,决定了如何转发流量
基于iptables实现负载均衡的一个过程
1、在浏览器访问 http://192.168.0.11:30009/
2.数据包经过iptables规则匹配,重定向到另一个链KUBE-SVC-LOLE4ISW44XBNF3G
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web" -m tcp --dport 30009 -j KUBE-SVC-LOLE4ISW44XBNF3G
3.一组规则,有几个pod就会创建几条规则,这里实现了负载均衡 (概率1/3,1/2,1)
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-PXRBKXV7I65SLLDB
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-4MXWCRSI3HRHILKZ
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web" -j KUBE-SEP-ODUGDMBPYLOH457E
4.使用DNAT转发到具体的pod
-A KUBE-SEP-PXRBKXV7I65SLLDB -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.169.133:80
-A KUBE-SEP-4MXWCRSI3HRHILKZ -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.36.67:80
-A KUBE-SEP-ODUGDMBPYLOH457E -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.36.68:80
针对ClusterIP实现的转发,后面与nodeport一样,回到了上面的第三步
-A KUBE-SERVICES -d 10.109.90.58/32 -p tcp -m comment --comment "default/web cluster IP" -m tcp --dport 80 -j KUBE-SVC-LOLE4ISW44XBNF3G
kubeadm方式修改ipvs模式:
kubectl edit configmaps kube-proxy -n kube-system
#搜索mode,添加ipvs,修改完保存
mode: "ipvs"
#删除node1节点proxy的pod,重新生成新的pod
kubectl delete pod kube-proxy-lzjgg -n kube-system
kubectl get pod -o wide -n kube-system
kubectl logs kube-proxy-hnw5p -n kube-system
注: 1、kube-proxy配置文件以configmap方式存储 2、如果让所有节点生效,需要重建所有节点kube-proxy pod
在node1节点上安装ipvsadm工具
yum -y install ipvsadm
ipvsadm -L -n
ip a
二进制方式修改ipvs模式:
vi kube-proxy-config.yml
mode: ipvs
ipvs:
scheduler: "rr“
systemctl restart kube-proxy
注:参考不同资料,文件名可能不同
流程包流程:客户端 ->NodePort/ClusterIP(iptables/Ipvs负载均衡规则) -> 分布在各节点Pod
查看负载均衡规则:
- iptables模式
iptables-save |grep
- ipvs模式
ipvsadm -L -n
当一个客户端访问service的时候,经过iptables/ipvs进行负载均衡,负载到后端的pod上,iptables/ipvs的规则是由kube-proxy去创建的。
当出现问题的时候,应该先检查的service的配置的是不是对的(标签端口等等),再检查kube-proxy是不是正常的,有没有创建对应的iptables/ipvs规则。
Service DNS名称
CoreDNS:是一个DNS服务器,Kubernetes默认采用,以Pod部署在集群中,CoreDNS服 务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。
CoreDNS YAML文件:
https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns/coredns
ClusterIP A记录格式:<service-name>.<namespace-name>.svc.cluster.local
示例:my-svc.my-namespace.svc.cluster.local
当我们在pod内做nslookup(dns)解析时,它会请求coredns pod,coredns里面存放了从k8smaster中获取的service对应的dns记录,就会帮你解析成对应service的IP。
Iptables VS IPVS
Iptables:
灵活,功能强大
规则遍历匹配和更新,呈线性时延
IPVS:
工作在内核态,有更好的性能
调度算法丰富:rr,wrr,lc,wlc,ip hash...
生产环境建议使用IPVS
1、创建一个deployment 副本数 3,然后滚动更新镜像版本,并记录这个更新记录,最后再回滚到上一个版本
vim web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
namespace: default
spec:
replicas: 3 # Pod副本预期数量
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web # Pod副本的标签
spec:
containers:
- name: web
image: nginx:1.15
kubectl apply -f web-deployment.yaml
#通过命令更新镜像,指定--record参数会将这条命令记录到历史版本记录中,方便回滚到对应的版本
kubectl set image deploy web-deployment web=nginx:1.16 --record
kubectl get pod -o wide
curl -I10.244.169.140 #验证是否是nginx1.16版本
kubectl rollout history deployment web-deployment #查看历史版本记录
kubectl rollout undo deployment web-deployment #默认回滚到上一个版本
kubectl get pod -o wide #查看pod的IP
curl -I 10.244.36.76 #验证是否回滚到nginx1.15版本
2、给一个应用扩容副本数为3
kubectl scale deployment web-deployment --replicas=6
kubectl get pod
3、创建一个pod,其中运行着nginx、redis、memcached 3个容器
vim nginx-redis-memcached.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-redis-memcached
namespace: default
spec:
replicas: 1 # Pod副本预期数量
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web # Pod副本的标签
spec:
containers:
- name: nginx
image: nginx
containers:
- name: redis
image: redis
containers:
- name: memcached
image: memcached
验证查看
kubectl apply -f nginx-redis-memcached.yaml
kubectl get pod
kubectl exec -it web-deployment-7c6bf5fdf8-8m2gm nginx -- bash
kubectl exec -it web-deployment-7c6bf5fdf8-8m2gm redis -- bash
kubectl exec -it web-deployment-7c6bf5fdf8-8m2gm memcached -- bash
4、给一个pod创建service,并可以通过ClusterIP/NodePort访问
vim service-node.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
type: NodePort # 服务类型
ports:
- port: 80 # Service端口
protocol: TCP # 协议
targetPort: 80 # 容器端口
nodePort: 30009 #nodeport暴露的端口
selector:
app: web # 指定关联Pod的标签
验证查看
kubectl apply -f service-node.yaml
kubectl get svc
curl -I 10.105.40.240 #访问集群内部service IP
http://192.168.0.12:30009/ #访问任意node节点IP加30009端口
5、创建deployment和service,使用busybox容器nslookup解析service
kubectl run -it dns-test --image=busybox -- sh
注:自由发挥,实现需求即可