1 Service简介
一句话:pod不能被外网访问,service是访问入口。
为了适应快速的业务需求,微服务架构已经逐渐成为主流,微服务架构的应用需要有非常好的服务编排支持,k8s中的核心要素Service便提供了一套简化的服务代理和发现机制,天然适应微服务架构,任何应用都可以非常轻易地运行在k8s中而无须对架构进行改动;
Service是Kubernetes里最核心的资源对象之一,Service定义了一个服务的访问入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由Pod副本组成的集群实力。 Service与其后端Pod副本集群之间则是通过Label Selector来实现"无缝对接"。而RC的作用实际上是保证Service 的服务能力和服务质量处于预期的标准。
1.1 原理
在Kubernetes中,在受到RC调控的时候,Pod副本是变化的,对于的虚拟IP也是变化的,比如发生迁移或者伸缩的时候。这对于Pod的访问者来说是不可接受的。Kubernetes中的Service是一种抽象概念,它定义了一个Pod逻辑集合以及访问它们的策略,Service同Pod的关联同样是居于Label来完成的。Service的目标是提供一种桥梁, 它会为访问者提供一个固定访问地址,用于在访问时重定向到相应的后端,这使得非 Kubernetes原生应用程序,在无须为Kubemces编写特定代码的前提下,轻松访问后端。
Service同RC一样,都是通过Label来关联Pod的。当你在Service的yaml文件中定义了该Service的selector中的label为app:my-web,那么这个Service会将Pod-->metadata-->labeks中label为app:my-web的Pod作为分发请求的后端。当Pod发生变化时(增加、减少、重建等),Service会及时更新。这样一来,Service就可以作为Pod的访问入口,起到代理服务器的作用,而对于访问者来说,通过Service进行访问,无需直接感知Pod。
需要注意的是,Kubernetes分配给Service的固定IP是一个虚拟IP,并不是一个真实的IP,在外部是无法寻址的。真实的系统实现上,Kubernetes是通过Kube-proxy组件来实现的虚拟IP路由及转发。所以在之前集群部署的环节上,我们在每个Node上均部署了Proxy这个组件,从而实现了Kubernetes层级的虚拟转发网络。
1.2 kubernetes中的三种IP
- Node IP:Node节点IP地址
- Pod IP:Pod的IP地址
- Cluster IP:Service的IP地址
Node IP是Kubernetes集群中每个节点的物理网卡的IP地址,这是一个真实存在的物理网络,所有属于这个网络的服务器之间都能通过这个网络直接通讯,不管他们中间是否含有不属于Kubernetes集群中的节点。想Kubernetes之外的节点访问Kubernetes集群内的节点或者TCP/IP服务时,必须通过Node IP
Pod IP是每个Pod的IP地址,它是Docker Engine 根据docker0网桥的IP地址段进行分配的,通常是一个虚拟的二层网络,Kubernetes要求位于不同Node上的Pod能够彼此直接通讯,所以Kubernetes里一个Pod里的容器访问另外一个Pod里的容器,就是通过Pod IP所在的虚拟二层网络进行通信,而真实的TCP/IP流量则是通过Node IP所在的物理网卡流出
Cluster IP,它是一个虚拟IP,但更像是一个伪造的IP网络
(1)Cluster IP仅仅作用于Kubernetes
Service对象,并由Kubernetes管理和分配IP地址(来源于Cluster
IP地址池)
(2)Cluster IP无法被Ping,因为没有一个"实体网络对象"来影响
(3)在Kubernetes集群内,Node
IP、Pod
IP、Cluster
IP之间的通信,采用的是Kubernetes自己设计的特殊路由规则
1.3 Service负载均衡
#[root@k8s-master k8s]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Selector: run=nginx-deployment2 #搜索标签
Type: NodePort #转发方式
IP: 10.254.18.231#虚拟IP
Port: <unset> 80/TCP
NodePort: <unset> 30001/TCP #node暴露端口
Endpoints: 172.16.47.2:80,172.16.47.3:80,172.16.73.2:80 + 2 more... #pod
Session Affinity: None
No events.
Service的虚拟IP是由Kubernetes虚拟出来的内部网络,外部是无法寻址到的。但是有些服务又需要被外部访问到,例如web前段。这时候就需要加一层网络转发,即外网到内网的转发。Kubernetes提供了NodePort、LoadBalancer、Ingress三种方式。
NodePort,在之前的Guestbook示例中,已经延时了NodePort的用法。NodePort的原理是,Kubernetes会在每一个Node上暴露出一个端口:nodePort,外部网络可以通过(任一Node)[NodeIP]:[NodePort]访问到后端的Service。
LoadBalancer,在NodePort基础上,Kubernetes可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。该模式需要底层云平台(例如GCE)支持。
Ingress,是一种HTTP方式的路由转发机制,由Ingress Controller和HTTP代理服务器组合而成。Ingress Controller实时监控Kubernetes API,实时更新HTTP代理服务器的转发规则。HTTP代理服务器有GCE Load-Balancer、HaProxy、Nginx等开源方案。
2 Service样例
2.1 查看现有的pod和deployment标签
[root@k8s-master k8s]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINER(S) IMAGE(S) SELECTOR
nginx-deployment2-3516246156 5 5 5 19h nginx-deployment2 192.168.0.136:5000/nginx:1.15 pod-template-hash=3516246156,run=nginx-deployment2
nginx-deployment2-3766659668 0 0 0 19h nginx-deployment2 192.168.0.136:5000/nginx:latest pod-template-hash=3766659668,run=nginx-deployment2
[root@k8s-master k8s]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment2-3516246156-0x490 1/1 Running 0 18h 172.16.47.2 k8s-node-2
nginx-deployment2-3516246156-827rs 1/1 Running 0 18h 172.16.73.4 k8s-node-1
nginx-deployment2-3516246156-fsb4k 1/1 Running 0 1h 172.16.47.3 k8s-node-2
nginx-deployment2-3516246156-g2c5q 1/1 Running 0 1h 172.16.73.3 k8s-node-1
nginx-deployment2-3516246156-k09ch 1/1 Running 0 18h 172.16.73.2 k8s-node-1
[root@k8s-master k8s]#
[root@k8s-master k8s]# kubectl describe deployment nginx-deployment2 | grep Selector
Selector: run=nginx-deployment2
[root@k8s-master k8s]#
2.2 根据deployment的Selector创建svc文件并启动
[root@k8s-master k8s]# cat myweb-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
ports:
- port: 80
nodePort: 30001
selector: #标签选择器
run: nginx-deployment2
[root@k8s-master nginx]# kubectl create -f myweb-svc.yaml
service "nginx" created
2.3 查看service状态
[root@k8s-master k8s]# kubectl get svc -o wide
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes 10.254.0.1 <none> 443/TCP 3d <none>
nginx 10.254.129.3 <nodes> 80:30001/TCP 52s run=nginx-deployment2
[root@k8s-master k8s]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Selector: run=nginx-deployment2
Type: NodePort
IP: 10.254.129.3
Port: <unset> 80/TCP
NodePort: <unset> 30001/TCP
Endpoints: 172.16.47.2:80,172.16.47.3:80,172.16.73.2:80 + 2 more...
Session Affinity: None
No events.
[root@k8s-master k8s]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment2-3516246156-0x490 1/1 Running 0 19h 172.16.47.2 k8s-node-2
nginx-deployment2-3516246156-827rs 1/1 Running 0 19h 172.16.73.4 k8s-node-1
nginx-deployment2-3516246156-fsb4k 1/1 Running 0 1h 172.16.47.3 k8s-node-2
nginx-deployment2-3516246156-g2c5q 1/1 Running 0 1h 172.16.73.3 k8s-node-1
nginx-deployment2-3516246156-k09ch 1/1 Running 0 19h 172.16.73.2 k8s-node-1
[root@k8s-master k8s]#
2.4 外网访问测试
2.5 为什么是30001端口?
Service从30000开始随机分配,默认不填写,自动分配30000-32767内任意一端口
我们修改成1000端口
[root@k8s-master k8s]# cat myweb-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
ports:
- port: 80
nodePort: 1000
selector: #标签选择器
run: nginx-deployment2
[root@k8s-master k8s]#
[root@k8s-master k8s]# kubectl create -f myweb-svc.yaml
The Service "nginx" is invalid: spec.ports[0].nodePort: Invalid value: 1000: provided port is not in the valid range. The range of valid ports is 30000-32767
2.6 Svc缩容—通过修改deployment修改副本数为1
[root@k8s-master k8s]# kubectl scale deployment nginx-deployment2 --replicas=1
k8s]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment2-3516246156-k09ch 1/1 Running 0 19h 172.16.73.2 k8s-node-1
[root@k8s-master k8s]#
#只有一个节点也不影响访问的
[root@k8s-master k8s]# curl -s -I 192.168.0.138:30023| grep 200
HTTP/1.1 200 OK
[root@k8s-master k8s]# curl -s -I 192.168.0.137:30023| grep 200
HTTP/1.1 200 OK
[root@k8s-master k8s]#
2.7 Svc扩容—通过修改deployment修改副本数为6
[root@k8s-master k8s]# kubectl scale deployment nginx-deployment2 --replicas=6
deployment "nginx-deployment2" scaled
[root@k8s-master k8s]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment2-3516246156-bc7pq 1/1 Running 0 36s 172.16.73.3 k8s-node-1
nginx-deployment2-3516246156-k09ch 1/1 Running 0 19h 172.16.73.2 k8s-node-1
nginx-deployment2-3516246156-l5p51 1/1 Running 0 37s 172.16.47.3 k8s-node-2
nginx-deployment2-3516246156-llhsn 1/1 Running 0 37s 172.16.73.4 k8s-node-1
nginx-deployment2-3516246156-sgpgj 1/1 Running 0 37s 172.16.47.4 k8s-node-2
nginx-deployment2-3516246156-txf3s 1/1 Running 0 37s 172.16.47.2 k8s-node-2
[root@k8s-master k8s]#
2.8 负载均衡测试
[root@k8s-master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment2-3516246156-gjkml 1/1 Running 0 9m 172.16.73.3 k8s-node-1
nginx-deployment2-3516246156-nchs3 1/1 Running 0 9m 172.16.47.2 k8s-node-2
[root@k8s-master ~]# kubectl exec -it nginx-deployment2-3516246156-gjkml /bin/bash
root@nginx-deployment2-3516246156-gjkml:/# echo 'web01' > /usr/share/nginx/html/index.html
root@nginx-deployment2-3516246156-gjkml:/#
root@nginx-deployment2-3516246156-gjkml:/# ^C
root@nginx-deployment2-3516246156-gjkml:/# exit
[root@k8s-master ~]# kubectl exec -it nginx-deployment2-3516246156-nchs3 /bin/bash
root@nginx-deployment2-3516246156-nchs3:/# echo 'web02' > /usr/share/nginx/html/index.html
root@nginx-deployment2-3516246156-nchs3:/# ^C
root@nginx-deployment2-3516246156-nchs3:/# exit
[root@k8s-master ~]#
[root@k8s-master ~]# curl http://192.168.0.137:30023/
web01
[root@k8s-master ~]# curl http://192.168.0.137:30023/
web02
[root@k8s-master ~]# curl http://192.168.0.138:30023/
web01
[root@k8s-master ~]# curl http://192.168.0.138:30023/
web01
[root@k8s-master ~]# curl http://192.168.0.138:30023/
web02
[root@k8s-master ~]#