目录
Service 服务的主要作用,就是作为 Pod 的代理入口(Portal),从而代替 Pod 对外暴露一个固定的网络地址。
一、service作用
1.1 作用
我们前面所学的pod和ReplicaSet、Deployment 等,当我们有需求Pod 对外暴露一个固定的网络地址对外放一个固定的IP地址,我们这时间就要用到服务了,虽然pod、ReplicaSet、wDeployment 有IP地址,但是它并不是固定的,pod挂了,从另了个节点起一个,那么它的地址可能是变化的,而Service 服务声明的 IP 地址等信息是“终生不变”的。
Service 服务的主要作用,就是作为 Pod 的代理入口(Portal),从而代替 Pod 对外暴露一个固定的网络地址。
Service 是 Kubernetes 项目中用来将一组 Pod 暴露给外界访问的一种机制。比如,一个 Deployment 有 3 个 Pod,那么我就可以定义一个 Service。然后,用户只要能访问到这个 Service,它就能访问到某个具体的 Pod。
关于 服务详细的学习,可以看k8s官网中文services相关章节,这里就不细讲了
1.2 例子
我们通过一个例子去说明,我建立一个有3个节点的pod
1.2.1 建立deployment
mkdir -pv /disk1/myk8s
cd /disk1/myk8s/
cat>nginx-deployment.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
web: nginx18
spec:
replicas: 3
selector:
matchLabels:
web: nginx18
template:
metadata:
labels:
web: nginx18
spec:
containers:
- name: nginx
image: nginx:1.18
ports:
- containerPort: 80
EOF
cat nginx-deployment.yaml
kubectl apply -f nginx-deployment.yaml
建立之后去登陆web方式查看一下,
更新完之后,使用命令,查看一下
[root@vm82 myk8s]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deployment 3/3 3 3 4m53s nginx nginx:1.18 web=nginx18
[root@vm82 myk8s]#
#查看发现k8s自动帮pod分配了一个内部地址,这个地址并不是固定不变的,比如一个pod挂了
#从另一个节点再起一个,那地址就会变了
[root@vm82 myk8s]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-856f977dd6-9khc2 1/1 Running 0 5m1s 10.44.0.1 vm821 <none> <none>
nginx-deployment-856f977dd6-wh9bf 1/1 Running 0 5m1s 10.44.0.3 vm821 <none> <none>
nginx-deployment-856f977dd6-xppkj 1/1 Running 0 5m1s 10.44.0.2 vm821 <none> <none>
#测试是否ping通
[root@vm82 myk8s]# ping 10.44.0.1 -c 3
PING 10.44.0.1 (10.44.0.1) 56(84) bytes of data.
64 bytes from 10.44.0.1: icmp_seq=1 ttl=64 time=107 ms
64 bytes from 10.44.0.1: icmp_seq=2 ttl=64 time=6.05 ms
64 bytes from 10.44.0.1: icmp_seq=3 ttl=64 time=3.10 ms
--- 10.44.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 9ms
rtt min/avg/max/mdev = 3.095/38.847/107.400/48.489 ms
#使用curl测试是否能访问
[root@vm82 myk8s]# curl 10.44.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
发现k8s是给pod分配一个内部IP地址,但是不稳定的啊,3个,万一挂了一个pod,在另一个节点起一个pod,和挂掉的pod的名字都不一样,地址也不一样。但是我需要一个稳定的地址,所以得services上场了,在之前我们先看一下3个pod的标签,发现是一样,如下图所示:
因为是3个pod是一样的,访问那个都无所谓,所以只需要一个入口就行了,这样会实现负载效果,我可以可以去修改一下pod的nginx中的index.html内容。
kubect exec <pod名字> -c 容器名 -- 要执行的命令
kubectl exec nginx-deployment-856f977dd6-9khc2 -c nginx -- bash -c "echo '10.44.0.1 pod'>/usr/share/nginx/html/index.html"
kubectl exec nginx-deployment-856f977dd6-xppkj -c nginx -- bash -c "echo '10.44.0.2 pod'>/usr/share/nginx/html/index.html"
kubectl exec nginx-deployment-856f977dd6-wh9bf -c nginx -- bash -c "echo '10.44.0.3 pod'>/usr/share/nginx/html/index.html"
1.2.2 建立serveices
如果你不懂怎么写可以使用 kubectl expain Service 命令,或者查看官网的 services
#创建一个服务
cat>nginx-ser.yaml<<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
#查找匹配的标签的pod
web: nginx18
ports:
- protocol: TCP
#services对外端口
port: 80
#这个是容器端口
targetPort: 80
EOF
kubectl apply -f nginx-ser.yaml
ps:除了上面的port端口还有其它几种端口,可以使用以下命令查看有哪些选择
kubectl explain Services.spec.ports
ClusterIP:使用集群内的私有ip —— 这是默认值
port:为群集访问端口
targetPort:要代理的目标的容器端口,像nginx代理那样,这个是基于端口的
NodePort:除了使用cluster ip外,也将service的port映射到每个node的一个指定内部port上,映射的每个node的内部port都一样,端口号只能30000-32767,这也多了一种形式,也是 nodeIP:port 方式访问
externalIPs:如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。 通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 的端口上的流量,将会被路由到 Service 的 Endpoint 上。 externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。
这种IP只能是节点IP地址,包括master节点和node节点
建立好了,我们查看一下serveice端口
#注svc是serivces的简写,发现创建了一个nginx服务,并建立了相关IP地址
[root@vm82 myk8s]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d21h <none>
nginx ClusterIP 10.106.215.131 <none> 80/TCP 17m web=nginx18
测试一下,访问一下
#不断开执行 curl 10.106.215.131 发现内容变化了,所以是实现了负载均衡的效果
[root@vm82 myk8s]# curl 10.106.215.131
10.44.0.1 pod
[root@vm82 myk8s]# curl 10.106.215.131
10.44.0.1 pod
[root@vm82 myk8s]# curl 10.106.215.131
10.44.0.2 pod
[root@vm82 myk8s]# curl 10.106.215.131
10.44.0.1 pod
[root@vm82 myk8s]# curl 10.106.215.131
10.44.0.2 pod
[root@vm82 myk8s]# curl 10.106.215.131
10.44.0.3 pod
[root@vm82 myk8s]# curl 10.106.215.131
10.44.0.3 pod
我们也可以从web上查看的
二、Headless Services
这个很重要,得讲一下,在下一章使用statefulset需要用到这个
2.1 定义
Headless Services为无头服务的意思,即指定 Cluster IP(spec.clusterIP
)的值为 "None"
来创建 Headless
Service。
2.2 什么情况下才用Headless Services
有时不需要或不想要负载均衡,以及单独的 Service IP。,那么我们怎样访问它呢,有两个方式
第一种方式,是以 Service 的 VIP(Virtual IP,即:虚拟 IP)方式。比如:当我访问 10.0.23.1 这个 Service 的 IP 地址时,10.0.23.1 其实就是一个 VIP,它会把请求转发到该 Service 所代理的某一个 Pod 上。
第二种方式,就是以 Service 的 DNS 方式。比如:这时候,只要我访问“my-svc.my-namespace.svc.cluster.local”这条 DNS 记录,就可以访问到名叫 my-svc 的 Service 所代理的某一个 Pod。
而在第二种 Service DNS 的方式下,具体还可以分为两种处理方法:
第一种处理方法,是 Normal Service。这种情况下,你访问“my-svc.my-namespace.svc.cluster.local”解析到的,正是 my-svc 这个 Service 的 VIP,后面的流程就跟 VIP 方式一致了。
而第二种处理方法,正是 Headless Service。这种情况下,你访问“my-svc.my-namespace.svc.cluster.local”解析到的,直接就是 my-svc 代理的某一个 Pod 的 IP 地址。可以看到,这里的区别在于,Headless Service 不需要分配一个 VIP,而是可以直接以 DNS 记录的方式解析出被代理 Pod 的 IP 地址。
上面我们使用了Deployment 建立服务,如果是多个pod是负载均衡的方式 ,但是statefulset中多个pod的时候下,每个pod是不同的,有序号的,你得需要再细化,不能用负载均衡方式,也不是群集统一地址,需要为每个pod建立一个精确的地址,这时Headless Services就派上用场了。这个在下章statefulset再讲它的pod
三、几种服务类型
3.1 services几种类型
对一些应用(如 Frontend)的某些部分,可能希望通过外部Kubernetes 集群外部IP 地址暴露 Service。
Kubernetes ServiceTypes
允许指定一个需要的类型的 Service,默认是 ClusterIP
类型。
Type
的取值以及行为如下:
ClusterIP
:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的ServiceType
。NodePort
:通过每个 Node 上的 IP 和静态端口(NodePort
)暴露服务。NodePort
服务会路由到ClusterIP
服务,这个ClusterIP
服务会自动创建。通过请求<NodeIP>:<NodePort>
,可以从集群的外部访问一个NodePort
服务。LoadBalancer
:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到NodePort
服务和ClusterIP
服务。ExternalName
:通过返回CNAME
和它的值,可以将服务映射到externalName
字段的内容(例如,foo.bar.example.com
)。 没有任何类型代理被创建。
说明: 您需要 CoreDNS 1.7 或更高版本才能使用
ExternalName
类型。
3.2 类型相关拓扑图
3.2 .1 ClusterIP
客户端Pod对象访问服务端Pod对象时不会进行源地址转换:
二者在同一主机时,源地址为客户端pod地址;
二者不在同-主机时,源地址为客户端pod所在节点的flannel或cni地址。
只能在集群内部被访问
3.2.2 NodePort
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9naXRodWItYWFyb244OS5vc3MtY24tYmVpamluZy5hbGl5dW5jcy5jb20vRG9ja2VyL05vZGVQb3J0LnBuZw?x-oss-process=image/format,png)
可以被集群外部访问到,节点的请求会DNAT到Serviceip,然后再调度至 PodIP
3.2.3 LoadBalancer
需要结合公有云的LBAAS ( 需要付费) , 支持动态接入功能。
3.2.4 ExternalName
将集群外部Service引入集群内部供各客户端使用,需要设置标签选择器,并手动定义一个endpoint资源,指向外部的资源地址。
3.2.5 Headless
这是一个比较特殊的service类型,有时候,你没必要或者不需要负载均衡和一个对外提供服务的ip地址。
在这种情况下,你可以在.spec.clusterIp中定义None字段,来申明-一个Headless Service。他可以通过coredns组件内部的解析功能,以完成相关地址解析的支持作用。
此外,我们之后会讲到StatefulSet控制器,它就是基于Headless网络所构筑的。