文章目录
一、Service类型
1. ClusterIP类型
如上图所示,ClusterIP把客户端的请求通过负载均衡路由到集群后端的pod中,ClusterIP类型的service主要在每个node节点上使用ipvs,将发到ClusterIP service端口的数据,转发到后端pod的kube-proxy中,然后kube-proxy内部实现负载均衡方法,查询到ClusterIP service下对应的pod的地址和端口,进而把数据转发给对应pod的地址和端口。
k8s实现上述数据请求转发的原理如下图所示:
当执行kubectl create 命令后,向apiServer发送了创建ClusterIp service的命令,然后apiServer把创建后的数据存储到etcd中;
每一个node节点都有一个kube-proxy进程,该进程负责监控etcd的变化,即感知service的变化,然后把路由规则写入到pod中的ipvs规则中,ipvs使用NAT技术把流量转发至pod中。
应用示例如下:
首先建立一个deployment.yaml用于部署多个pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: mydeployment
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: stabel
template:
metadata:
labels:
app: myapp
release: stabel
spec:
containers:
- name: myapp
image: mynginx:v0.3
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
然后创建一个ClusterIp service,实现负载均衡
apiVersion: v1
kind: Service
metadata:
name: myservice
namespace: default
spec:
type: ClusterIP
selector:
app: myapp
release: stabel
ports:
- name: http
port: 8080
targetPort: 80
分别创建资源如下:
#创建development
[root@k8s-master01 cluster_work]# kubectl apply -f deployment.yaml
deployment.apps/mydeployment created
#创建service
[root@k8s-master01 cluster_work]# kubectl apply -f cluster_service.yaml
service/myservice created
#查询pod及IP
[root@k8s-master01 cluster_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-67667dddf9-gbl8c 1/1 Running 0 15s 10.244.2.99 k8s-node02 <none> <none>
mydeployment-67667dddf9-nzzxc 1/1 Running 0 15s 10.244.1.102 k8s-node01 <none> <none>
mydeployment-67667dddf9-tj896 1/1 Running 0 15s 10.244.2.98 k8s-node02 <none> <none>
#查询创建的myservice,集群地址为10.107.4.138
[root@k8s-master01 cluster_work]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2m12s
myservice ClusterIP 10.107.4.138 <none> 8080/TCP 8s
#请求service
[root@k8s-master01 cluster_work]# curl 10.107.4.138:8080
hello lzj, this is version 3
通过上述命令,已经请求到服务,下面通过ipvsadm -Ln查看一下路由规则,发现10.107.4.138:8080路由到了10.244.2.99:80、10.244.2.98:80、10.244.1.102:80
I
2、NodePort类型
NodePort类型的服务,在创建Service的时候将服务类型设置NodePort即可。设置服务类型为NodePort时,集群会在每个节点上打开一个端口,可以通过节点的IP+节点端口访问节点,然后节点把流量重定向到集群的Service服务,最后通过集群的IP+集群端口,负债均衡到后端的Pod应用。当服务类型设置为NodePort时,外部流量不仅可以通过集群IP+端口访问后端Pod应用,还可以通过节点的Ip+端口访问集群服务,然后通过集群服务负载到后端Pod应用中。
示例如下,deployment继续用上面的mydeployment,下面创建NodePort类型的yaml文件nodeport.yaml
apiVersion: v1 #版本
kind: Service #资源类型
metadata:
name: mynodeport #service资源的名字
namespace: default #资源的名称空间
spec:
type: NodePort #服务类型NodePort
selector: #pod标签选择器
app: myapp
release: stabel
ports:
- name: http #端口名称别名
port: 8080 #集群对外暴露的端口,通过该端口可以访问集群
targetPort: 80 #pod端口
nodePort: 31463 #集群节点端口,通过该端口可以访问集群服务
#创建服务
[root@k8s-master01 cluster_work]# kubectl apply -f nodeport.yaml
service/mynodeport created
#查询服务,mynodeport即为新创建的服务
[root@k8s-master01 cluster_work]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d23h
mynodeport NodePort 10.106.33.216 <none> 8080:31463/TCP 16s
#通过节点IP+节点暴露端口访问服务
[root@k8s-master01 cluster_work]# curl 192.168.137.100:31463
hello lzj, this is version 3
[root@k8s-master01 cluster_work]# curl 192.168.137.10:31463
hello lzj, this is version 3
[root@k8s-master01 cluster_work]# curl 192.168.137.20:31463
hello lzj, this is version 3
#通过集群IP+集群端口访问后端pod应用
[root@k8s-master01 cluster_work]# curl 10.106.33.216:8080
hello lzj, this is version 3
3. ExternalName类型服务
service集群可以将集群外部的服务暴露给集群内部的pod,当pod访问集群外部的服务时只需要访问service服务即可,当外部的服务地址变化时,只需要重新把外部服务的地址绑定在service,在service中创建endpoit即可。如下图所示
上述服务即为Service中的ExternalName类型服务,在创建服务资源时需要将type设置为ExternalName。如下yaml所示
apiVersion: v1
kind: Service
metadata:
name: external-svc-endpoint
spec:
type: ExternalName
externalName: www.baidu.com
ports:
- name: http
port: 80
当服务创建完成后,集群内的pod可以通过external-svc-endpoint.default.svc.cluster.local域名访问www.baidu.com,这样pod就直接访问到了外部的服务。
4、Headless服务
上述创建Cluster Service,客户端访问Cluster Service后端的pod服务时,先访问Cluster IP,然后Cluster IP负载到后端的pod。但如果客户端访问pod时不需要通过Cluster Ip,而是直接访问到后端的pod,通过本节的headless服务即可实现该功能。headless为无头服务,即把ClusterIp字段设置为None即可。客户端访问后端pod时,可以通过coreDNS查找pod的IP,可以由多个pod。coreDNS会返回多个pod的IP,然后客户端直接链接到后端的pod。客户端访问后端pod时,如果有多个pod,客户端只能通过轮询后端pod的方式进行访问,没有其它负载方式。
4.1 创建headless无头服务
创建headless时只需把clusterIP字段设置成None,其它保持与Cluster IP类型的服务保持一致。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-dp
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
spec:
clusterIP: None #无头服务
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
通过yaml文件创建Deployment和Service后,查看headless服务,发现已经创建了三个访问点Endpoints: 10.244.2.215:80,10.244.2.216:80,10.244.2.217:80
,正是三个pod的地址和端口。
[root@k8s-master01 headless_work]# kubectl describe service nginx-headless
Name: nginx-headless
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-headless","namespace":"default"},"spec":{"clusterIP":"None"...
Selector: app=nginx
Type: ClusterIP
IP: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.215:80,10.244.2.216:80,10.244.2.217:80 + 1 more...
Session Affinity: None
Events: <none>
4.2 无头服务发现未就绪pod
客户端访问后端pod服务时,通过coreDNS解析pod的地址后,提供给客户端进行访问,
只需在service.spec.publishNotReadyAddresses字段设置true值,表示pod未准备就绪的也添加到coreDNS解析的列表中,该字段默认false,表示未准备就绪的pod不会添加到coreDNS解析列表,客户端是请求不到未准备就绪的pod。
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
spec:
clusterIP: None
publishNotReadyAddresses: true #未准备就绪的pod添加到DNS解析列表中,未就绪的pod也就开始提供服务了
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx