[Kubernetes] Service应用管理
目录
service作用
使用kubernetes集群运行工作负载时,由于Pod经常处于用后即焚状态,Pod经常被重新生成,因此 Pod对应的IP地址也会经常变化,导致无法直接访问Pod提供的服务,Kuberetes中使用了Service来解决 这一问题,即在Pod前面使用Service对Pod进行代理,无论Pod怎样变化,只要有Label,就可以让 Service能够联系上Pod,把Pod lP地址添加到Service对应的端点列表(Endpoints)实现对Pod IP跟踪, 进而实现通过Service访问Pod目的。
-
通过service为pod客户端提供访问pod方法,即可客户端访问pod入口
-
通过标签动态感知podIP地址变化等
-
防止pod失联
-
定义访问pod访问策略
-
通过label-selector相关联
-
通过Service实现Pod的负载均衡(TCP/UDP4层)
-
底层实现由kube-proxy通过userspace、iptables、ipvs三种代理模式
kube-proxy三种代理模式
-
kubernetes集群中有三层网络,一类是真实存在的,例如Node Network、Pod Network,提供真实IP地址;一类是虚拟的,例如Cluster Network或Service Network,提供虚拟IP地址,不会出现在接口上,仅会出现在Service当中
-
kube-proxy始终watch(监控)kube-apiserver上关于Service相关的资源变动状态,一旦获取相关信息kube-proxy都要把相关信息转化为当前节点之上的,能够实现Service资源调度到特定Pod之上的规则,进而实现访问Service就能够获取Pod所提供的服务
-
kube-proxy三种代理模式:userspace模式、iptables模式、ipvs模式
userspace模式
userspace 模式是 kube-proxy 使用的第一代模式,该模式在 kubernetes v1.0 版本开始支持使用。
userspace 模式的实现原理图示如下:

kube-proxy会为每个service随机监听一个端口(proxyport),并增加一条iptables规则。所以通过ClusterIP:Port访问Service的报文都redirect到proxy port,kube-proxy从它监听的proxy port收到报文以后,走round robin(默认)或是session affinity(会话亲和力,即同client IP 都走同一链路给同一pod 服务),分发给对应的 pod。
由于 userspace 模式会造成所有报文都走一遍用户态(也就是Service 请求会先从用户空间进入内核 iptables,然后再回到用户空间,由kube-proxy 完成后端 Endpoints 的选择和代理工作),需要在内核 空间和用户空间转换,流量从用户空间进出内核会带来性能损耗,所以这种模式效率低、性能不高,不 推荐使用。

iptables模式
iptables 模式是 kube-proxy使用的第二代模式,该模式在 kubernetes v1.1版本开始支持,从v1.2 版本开始成为 kube-proxy 的默认模式。
iptables 模式的负载均衡模式是通过底层 netfilter/iptables 规则来实现的,通过 informer 机制 Watch接口实时跟踪 Service 和 Endpoint 的变更事件,并触发对 iptables 规则的同步更新。
iptables 模式的实现原理图示如下:

通过图示可以发现在 iptables模式下,kube proxy只是作为 controller,而不是server,真正服务的是 内核的 netfilter,体现在用户态 的是 iptables。所以整体的效率会比 userspace 模式高。

ipvs模式
ipvs 模式被 kube-proxy采纳为第三代模式,模式在 kubernetes v1.8 版本开始引入,在 v1.9 版本中处 于 beta 阶段,在 v1.11 版本中正式开始使用。
ipvs(iP Virtual Server)实现了传输层负载均衡,也就是4层交换,作为 Linux 内核的一部分。ipvs运行在 主机上,在真实服务器前充当负载均衡器。ipvs 可以将基于 TCP和 UDP 的服务请求转发到真实服务器 上,并使真实服务器上的服务在单个IP地址上显示为虚拟服务。
ipvs 模式的实现原理图示如下:


ipvs 和 iptables 都是基于 netfilter 的,那么ipvs 模式有哪些更好的性能呢?
-
ipvs 为大型集群提供了更好的可拓展性和性能
-
ipvs 支持比 iptables 更复杂的负载均衡算法(包括:最小负载、最少连接、加权等)
-
ipvs 支持服务器健康检查和连接重试等功能
-
可以动态修改 ipset的集合,即使iptables 的规则正在使用这个集合
ipvs 依赖于 iptables。ipvs 会使用 iptables 进行包过滤、airpin-masquerade tricks(地址伪装)、SNAT 等功能,但是使用的是 iptables 的扩展ipset,并不是直接调用 iptables 来生成规则链。通过 ipset 来存 储需要 DROP 或 masquerade 的流量的源或目标地址,用于确保iptables 规则的数量是恒定的,这样我 们就不需要关心有多少 Service 或是 Pod 了。
使用 ipset 相较于 iptables有什么优点呢?iptables 是线性的数据结构,而ipset引入了带索引的数据结 构,当规则很多的时候,ipset 依然可以很高效的查找和匹配。可以将 ipset 简单理解为一个IP(段)的集 合,这个集合的内容可以是IP 地址、IP 网段、端口等,iptables 可以直接添加规则对这个“可变的集合进 行操作”,这样就可以大大减少iptables规则的数量,从而减少性能损耗。
举一个例子,如果我们要禁止成千上万个IP访问我们的服务器,如果使用 iptables 就需要一条一条的添 加规则,这样会在 iptables 中生成大量的规则:如果用ipset 就只需要将相关的IP 地址(网段)加入到 ipset 集合中,然后只需要设置少量的 iptables 规则就可以实现这个目标。
下面的表格是ipvs模式下维护的ipset表集合:

iptables与ipvs对比
iptables
-
工作在内核空间
-
优点
- 灵活,功能强大(可以在数据包不同阶段对包进行操作)
-
缺点
- 表中规则过多时,响应变慢,即规则遍历匹配和更新,呈线性延时
-
ipvs
-
工作在内核空间
-
优点
-
转发效率高
-
调度算法丰富:rr,wrr,lc,wlc,ip hash等
-
-
缺点
- 内核支持不全,低版本内核不能使用,需要升级到4.0或5.0以上。
-
使用iptables与ipvs时机
-
1.10版本之前使用iptables(1.1版本之前使用UserSpace进行转发)
-
1.11版本之后同时支持iptables与ipvs,默认使用ipvs,如果ipvs模块没有加载时,会自动降 级至iptables
service类型
-
ClusterIP
-
默认,分配一个集群内部可以访问的虚拟IP
-
NodePort
-
在每个Node上分配一个端口作为外部访问入口
-
nodePort端口范围为:30000-32767
-
LoadBalancer
-
工作在特定的Cloud Provider上,例如Google Cloud,AWS,OpenStack
-
ExternalName
-
表示把集群外部的服务引入到集群内部中来,即实现了集群内部pod和集群外部的服务进行通 信
service参数
-
port 访问service使用的端口
-
targetPort 访问 Pod中容器端口
-
nodePort 通过Node实现外网用户访问k8s集群内service(30000-32767)
service创建
Service的创建在工作中有两种方式,一是命令行创建,二是通过资源清单文件YAML文件创建。
1:ClusterIP类型
ClusterlP根据是否生成ClusterlP又可分为普通Service和Headless Service。
service两类:
- 普通service:
为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP),实现集群内的访问,。
- Headless Service
该服务不会分配Cluster IP,也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定的网络 ID来访问,DNS会将headless service的后端直接解析为pod IP列表。

ClusterIP Service
命令创建service
创建deployment类型的应用
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.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80


创建clusterIP类型service与Deployment类型应用关联
kubectl expose deployment nginx-server1 --type=ClusterIP --target-port=80 --port=80
说明:
-
expose 创建service
-
deployment.apps 控制器类型
-
nginx-server1 应用名称,也是service名称
-
--type=ClusterIP 指定service类型
-
--target-port=80 指定Pod中容器端口
-
--port=80 指定service端口
kubectl get svc
查看详情描述
kubectl describe service nginx-server1

访问clusterIP就可以看到网页内容
curl http://10.103.196.143

验证负载均衡功能
查看pod
kubectl get pod

修改nginx-server1-5b6d5cd699-mxgc2网页内容为web1
kubectl exec -it nginx-server1-5b6d5cd699-mxgc2 -- /bin/sh
/ # cd /usr/share/nginx/html
/usr/share/nginx/html # ls
50x.html index.html
/usr/share/nginx/html # echo "web1" > index.html
/usr/share/nginx/html # exit
修改nginx-server1-5b6d5cd699-vtc7b网页内容为web2
kubectl exec -it nginx-server1-5b6d5cd699-vtc7b -- /bin/sh
/ # cd /usr/share/nginx/html
/usr/share/nginx/html # ls
50x.html index.html
/usr/share/nginx/html # echo "web2" > index.html
/usr/share/nginx/html # exit
验证网页显示
curl http://10.103.196.143

通过YAML文件创建service
编写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.26-alpine
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
应用YAML
kubectl apply -f nginx_deployment.yml
验证
kubectl get svc,pod

kubectl describe service nginx-svc

kubectl get endpoints

curl http://10.108.242.7

headless service
-
普通的clusterIP service是service name解析为cluster ip,然后cluster ip对应到后面pod ip。
-
headless service是指service name直接解析为后面的pod ip
创建deployment控制器类型的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: c3
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
应用YAML文件
kubectl apply -f nginx_deployment.yml
查看
kubectl get pod

创建headless service的YAML文件
apiVersion: v1
kind: Service
metadata:
name: headless-service
namespace: default
spec:
type: ClusterIP #ClusterIP类型也是默认类型
clusterIP: None #None代表无头服务
ports: #指定service端口及容器端口
- port: 80 #service ip中的端口
protocol: TCP
targetPort: 80 #pod端口
selector: #指定后端pod标签
app: nginx
应用YAML文件
kubectl apply -f headless-service.yml
查看
kubectl get svc

kubectl get pod -o wide

kubectl get endpoints

DNS
DNS服务监视Kubernetes APl,为每一个Service创建DNS记录用于域名解析
headless service需要DNS来解决访问问题
DNS记录格式为:..svc.cluster.local.
查看kube-dns服务的IP
kubectl get pod -o wide -n kube-system | grep dns

kubectl get svc -n kube-system | grep dns

在集群主机通过DNS服务地址查找无头服务的dns解析
dig -t a headless-service.default.svc.cluster.local. @10.96.0.10

在集群内创建pod进行解析
kubectl run -it centos --image=centos:7 --image-pull-policy=IfNotPresent
curl http://headless-service.default.svc.cluster.local.

2:NodePort类型
创建YAML文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
labels:
app: nginx-app
spec:
replicas: 2
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: c2
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-app
spec:
type: NodePort
ports:
- protocol: TCP
nodePort: 31111
port: 8060
targetPort: 80
selector:
app: nginx-app
应用YAML文件
kubectl apply -f nginx_nodeport.yml
查看
kubectl get svc,pod
kubectl get deployment

直接使用浏览器访问


3:LoadBalancer
集群外访问过程
-
用户
-
域名
-
云服务提供商提供LB服务
-
NodeIP:Port(service IP)
-
Pod IP:端口

MetalLB
自建kubernetes的loadbalancer类型服务方案
MetalLB可以为kubernetes集群中的Service提供网络负载均衡功能
MetalLB两大功能为:
-
地址分配,类似于DHCP
-
外部通告,一旦MetalLB为服务分配了外部IP地址,它就需要使群集之外的网络意识到该IP在群集 中"存在"。MetalLB使用标准路由协议来实现此目的:ARP,NDP或BGP。

下载清单资源
wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
应用文件
kubectl apply -f namespace.yaml
kubectl apply -f metallb.yaml
查看
kubectl get ns
kubectl get pod -n metallb-system

问题解决:如果出现pod中有失败状态,可以在node节点中直接导入镜像文件(metallbcontroller.tar 和metallbspeaker.tar),解决镜像下载问题
可以给metallb做资源配置
kubectl get configmap -n metallb-system

准备metallb配置文件
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: | #定义了一个名为 config 的配置项,| 符号表示保留后续内容的格式
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.18.100-192.168.18.200 #与集群节点服务器处于同一网段
应用yaml文件
kubectl apply -f metallb-conf.yaml
查看
kubectl get configmap -n metallb-system

kubectl describe cm config -n metallb-system

创建nginx应用资源
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-metallb
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-metallb1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
应用yaml文件
kubectl apply -f nginx-metallb.yaml
查看
kubectl get deployment
kubectl get pod
创建service资源
apiVersion: v1
kind: Service
metadata:
name: nginx-metallb
spec:
type: LoadBalancer
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
应用yaml
kubectl apply -f lb-service.yaml
查看
kubectl get svc


使用集群节点IP也可以访问,此时端口号为31759

新版本MetalLB
1:修改kube-proxy配置文件
kubectl edit configmap -n kube-system kube-proxy
#修改41行
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs" #检查模式
ipvs:
strictARP: true #设置为true
2:使用YAML文件创建资源(需要科学上网)
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

同时也可以把YAML下载
wget https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

3:查看创建资源
kubectl get all -n metallb-system

打开官网配置

这里就和之前版本有区别
4:不需要创建configmap资源对象,而是直接使用IPAddressPool资源
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.18.200-192.168.18.209
5:应用、查看
kubectl apply -f ipaddresspool.yaml
kubectl get ipaddresspool -n metallb-system

6:创建nginx应用资源
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-metallb
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-metallb1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
应用、查看
kubectl apply -f nginx-metallb.yaml
kubectl get deployment
kubectl get pod

7:创建service资源
apiVersion: v1
kind: Service
metadata:
name: nginx-metallb
spec:
type: LoadBalancer
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
kubectl apply -f lb-service.yaml
kubectl get svc

验证查看网站

4:ExternalName
作用:
-
把集群外部的服务引入到集群内部中来,实现了集群内部pod和集群外部的服务进行通信
-
ExternalName类型的服务适用于外部服务使用域名的方式,缺点是不能指定端口
-
还有一点要注意:集群内的Pod会继承Node上的DNS解析规则。所以只要Node可以访问的服务, Pod中也可以访问到,这就实现了集群内服务访问集群外服务
公网域名引入
查看dns资源
kubectl get svc -n kube-system | grep dns

查看公网域名解析
dig -t a www.baidu.com @10.96.0.10

创建YAML
vim externelname.yml
#写入
apiVersion: v1
kind: Service
metadata:
name: my-externalname
namespace: default
spec:
type: ExternalName
externalName: www.baidu.com
应用YAML
kubectl apply -f externelname.yml
查看创建资源
kubectl get svc | grep exter

查看本地域名解析
dig -t A my-externalname.default.svc.cluster.local. @10.96.0.10

开启测试Pod来解析域名
kubectl run -it expod --image=busybox:1.28
/ # nslookup www.baidu.com #输入公网域名
/ # nslookup my-externalname.default.svc.cluster.local. #输入本地域名

不同命名空间访问
案例:实现ns1和ns2两个命名空间之间服务的访问
1:创建ns1命名空间和相关deployment,pod,service
apiVersion: v1
kind: Namespace
metadata:
name: ns1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: ns1
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: ns1 #服务名称
spec: #属于ns1命名空间
selector:
app: nginx
clusterIP: None #无头服务
ports:
- port: 80
targetPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: external-svc1
namespace: ns1 #属于ns1命名空间
spec:
type: ExternalName
externalName: svc2.ns2.svc.cluster.local #将ns2空间的svc2服务引入到ns1空间
2:应用YAML
kubectl apply -f ns1-nginx.yaml
3:查看命名空间ns1中的资源
kubectl get pods,svc -n ns1

4:使用dns:10.96.0.10解析域名,可以直接看到pod的ip
kubectl get svc -n kube-system
dig -t a svc1.ns1.svc.cluster.local. @10.96.0.10
kubectl get pods -n ns1 -o wide

5:创建ns2命名空间和相关deployment,pod,service
apiVersion: v1
kind: Namespace
metadata:
name: ns2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: ns2
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc2
namespace: ns2
spec:
selector:
app: nginx
clusterIP: None
ports:
- port: 80
protocol: TCP
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: external-svc2
namespace: ns2
spec:
type: ExternalName
externalName: svc1.ns1.svc.cluster.local
应用、查看
kubectl apply -f ns2-nginx.yaml
kubectl get pods,svc -n ns2

7:使用dns解析pod的ip
dig -t a svc2.ns2.svc.cluster.local. @10.96.0.10

kubectl get pods -n ns2 -o wide

在pod中使用域名进行访问
进入ns1中的pod,使用nslookup对ns2中的pod进行域名解析
kubectl exec -it deploy-nginx-66d785bdb5-2lwq6 -n ns1 -- /bin/sh
/ # nslookup svc1
/ # nslookup svc2.ns2.svc.cluster.local.

如果ns2中pod的ip发生变化,那么是否还能够域名正常解析
先查看ns2中pod的ip
kubectl get pods -n ns2 -o wide
再删除pod,并查看ip变化为10.244.166.138
kubectl delete pod deploy-nginx-66d785bdb5-qzw62 -n ns2
kubectl get pods -n ns2 -o wide

再次进入到ns1中pod,对ns2中pod进行域名解析
kubectl exec -it deploy-nginx-66d785bdb5-2lwq6 -n ns1 -- /bin/sh
/ # nslookup svc2.ns2.svc.cluster.local.

sessionAffinity
会话粘黏
设置sessionAffinity为clientip(类似nginx的ip_hash算法、lvs的sh算法)
创建nginx资源使用clusterip访问
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
应用YAML、查看资源
kubectl apply -f deployment-nginx-svc.yaml
kubectl get pods,svc

更新两个pod中首页内容作为鉴别区分
修改第1个pod首页内容为web1
kubectl exec -it deploy-nginx-5b6d5cd699-4sf5j -- /bin/sh
/ # cd /usr/share/nginx/html/
/usr/share/nginx/html # ls
50x.html index.html
/usr/share/nginx/html # echo "web1" > index.html
/usr/share/nginx/html # exit
修改第2个pod首页内容为web2
kubectl exec -it deploy-nginx-5b6d5cd699-st275 -- /bin/sh
/ # cd /usr/share/nginx/html/
/usr/share/nginx/html # ls
50x.html index.html
/usr/share/nginx/html # echo "web2" > index.html
/usr/share/nginx/html # exit
可以直接观测到访问clusterip使用了负载均衡
curl http://10.96.194.1
web1
curl http://10.96.194.1
web2
kubectl describe svc nginx-svc

kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'
再次查看更改结果
kubectl describe svc nginx-svc

验证访问粘黏,第1次访问哪个pod,后面就一直访问这个pod,直到失效时间
sessionAffinity机制默认失效时间为10800秒(3小时)
curl http://10.96.194.1
更多推荐


所有评论(0)