带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

释放双眼,带上耳机,听听看~!

    哈喽,大家好~进天我们核心要讲解的是Service,Service是k8s里的核心资源对象之一。k8s里的每个Service其实就是我们经常提起的微服务架构中的一个微服务,之前讲解Pod,RC等资源对象其实都是为讲Kubernetes Service做铺垫。

下图显示了Pod、RC与Service的逻辑关系。

                            带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

              k8s的Service定义了一个服务的访问入口地址,前端的应用通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与其后端Pod副本集群之间则是通过Label Selector来实现无缝对接的。RC的作用实际上是保证Service的服务能力和服务指令始终符合预期标准。

            服务之间通过TCP/IP进行通信,从而形成了强大而又灵活的弹性网格,拥有强大的分布式能力,弹性扩展能力,容错能力,程序架构也变得简单和直观许多。

k8s提供的微服务网络架构图如下:

带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

 既然每个Pod都会被分配一个单独的IP地址,而且每个Pod都提供了个了一个独立的Endpoint(Pod IP+ ContainerPort)以被客户端访问,现在多个Pod副本组成了一个集群来提供服务,那么客户端如何来访问它们呢?部署一个负载均衡器,为这组Pod开启一个对外的服务端口如8080端口,并且将这些Pod的Endpoint列表加入8080端口的转发列表,客户端就可以通过负载均衡器的对外IP地址+服务端口来访问此服务。客户端请求最后会被转发到哪个Pod,由负载均衡器的算法所决定。

    运行在Node上的kube-proxy进程其实就是一个智能的软件负载均衡器,负责把对Service的请求转发到后端的某个Pod实例上,并在内部实现服务的负载均衡与会话保持机制。

   Service没有公用一个负载均衡器的IP地址,每个Service都被分配了一个全局唯一的虚拟IP地址,这个虚拟IP被称为Cluster IP。这样一来,每个服务就变成了具备唯一IP地址的通信节点,服务调用就变成了最基础的TCP网络通信问题。

   我们知道,Pod的Endpoint地址会随着Pod的销毁和重建而发生改变,而Service一旦被创建,k8s就会自动分配一个可用的Cluster IP,而且在Service的整个生命周期累,Cluster IP不会发生改变。所以服务发现的解决方案:只要用Service的Name与Service的Cluster IP地址做一个DNS域名映射就可以完美的解决问题。

  说了这么久,下面我们动手来创建一个Service来加深对它的理解。创建一个名为tomcat-service.yaml的定义文件。


1
2
3
4
5
6
7
8
9
10
11
1apiVersion: v1
2kind: Service
3metadata:
4  name: tomcat-service
5spec:
6  ports:
7  - port: 18080
8  selector:
9    tier: frontend
10
11

上述内容定义了一个名为tomcat-service的Service,它的服务端口为8080,拥有“tier=frontend”这个Label的所有Pod实例都属于它,运行下面的命令进行创建:


1
2
1kubectl create -f tomcat-server.yaml
2

我们之前在tomat-deployment.yaml里定义的Tomcat的Pod刚好拥有这个标签,所以刚才创建的tomcat-service已经对应一个Pod实例,运行下面的明了可以查看tomcatservice的Endpoint列表,其中x.x.x.x是Pod的IP地址,端口18080是Container暴露的端口:


1
2
1kubectl get endpoints
2

带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

查看tomcat-service被分配的Cluster IP及更多的信息


1
2
1kubectl get svc tomcat-service -o yaml
2

带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

在spec.ports的定义中,具体业务进程在容器内的targetPort上提供TCP/IP接入;port属性则定义了Service的虚端口。

接下来谈谈Service的多端口问题。

     kubernetes Service支持多额Endpoint,在存在多个Endpoint的情况下,要求每个Endpoint都定义一个名称来区分。下面为Tomcat多端口的Service定义的样例:


1
2
3
4
5
6
7
8
9
10
11
12
13
1apiVersion: v1
2kind: Service
3metadata:
4  name: tomcat-service
5spec:
6  ports:
7  - port: 8080
8   name: service-port
9  - port: 8005
10   name: shutdown-port
11  selector:
12    tier: frontend
13

kubernetes的服务发现机制

   任何分布式系统都会涉及“服务发现”这个基础问题,k8s中的Service都有唯一的Cluster IP 及唯一的名称,而名称是由开发者自己定义的,部署时也没有必要改变,所以完全可以被固定在配置中。k8s通过Add-On增值包引入DNS系统,把服务名作为DNS域名,这样程序就可以直接使用服务名来见你通信连接了。k8s大部分应用都已经采用了DNS这种新心的服务发现机制,后面会详细讲解如何部署DNS系统。

外部系统访问Service的问题

为了更深入的理解和掌握k8s,我们需要弄明白Kubernetes里的3种IP,这3种IP分别如下:

◎ Node IP:Node的IP地址。
◎ Pod IP:Pod的IP地址。
◎ Cluster IP:Service的IP地址。

Node IP是K8s集群中每个节点的物理网卡的IP地址,是一个真实存在的物理网络,所有属于这个网络的服务器都能通过这个网络直接通信,不管其中是否有部分节点不属于这个k8s集群。(k8s集群外的节点访问k8s集群内的某个节点或TCP/IP服务时,都必须通过Node IP通信)

Pod IP 是每个Pod的IP地址,他是Docker Engine 根据docker0网桥的IP地址进行分配的,由于k8s要求位于不同Node上的Pod都能够批次直接通信,所以k8s里一个Pod里的容器访问另外一个Pod里的容器时,就是通过Pod IP所在的与你二层网络进行通信的,而真实的TCP/IP流量是通过Node IP 所在的物理网卡流出的。

Cluster IP 仅仅作用于k8s这个对象,并由k8s管理和分配IP地址。

Cluster IP无法被Ping,因为没有一个“实体网络对象”来响应。

Cluster IP只能结合Service Port组成一个具体的通信端口,单独的Cluster IP不具备TCP/IP通信的基础,并且它们属于Kubernetes集群这样一个封闭的空间,集群外的节点如果要访问这个通信端口,则需要做一些额外的工作。

在k8s集群內,Node Ip网,Pod IP网与Cluster IP网之间的通信,采用的是Kubernetes 自己设计的一种编程方式的特殊路由规则,与我们熟知的IP路由很大的不同。

采用NodePort解决用户访问Service的最直接,有效常见的做法如下:

1.先创建tomcat  Pod(yaml文件如下:)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1apiVersion: v1
2kind: ReplicationController
3metadata:
4  name: frontend
5spec:
6  replicas: 1
7  selector:
8    tier: frontend
9  template:
10    metadata:
11      labels:   #可以自己定义key-value
12        app: app-demo
13        tier: frontend   #前端架构
14    spec:
15      containers:
16      - name: tomcat-damo
17        image: tomcat
18        imagePullPolicy: IfNotPresent
19        ports:
20        - containerPort: 8080
21        env:
22        - name: GET_HOSTS_FROM
23          value: dns                  
24

 

2.创建tomcat server (yaml文件如下)


1
2
3
4
5
6
7
8
9
10
11
12
1apiVersion: v1
2kind: Service
3metadata:
4  name: tomcat-servie
5spec:
6  type: NodePort
7  ports:
8  - port: 8080
9    nodePort: 31002
10  selector:
11    tier: frontend
12

 

3.访问页面

带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

 

      NodePort的实现方式是在Kubernetes集群里的每个Node上都为需要外部访问的Service开启一个对应的TCP监听端口,外部系统只要用任意一个Node的IP地址+具体的NodePort端口号即可访问此服务,在任意Node上运行netstat命令,就可以看到有NodePort端口被监听:

带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

     NodePort还没有完全解决外部访问Service的所有问题,比如负载均衡问题。假如在我们的集群中有10个Node,则此时最好有一个负载均衡器,外部的请求只需访问此负载均衡器的IP地址,由负载均衡器负责转发流量到后面某个Node的NodePort上

带你玩转kubernetes-k8s(第六篇:k8s-Service概念及其实例)

 

      Load balancer组件独立于Kubernetes集群之外,通常是一个硬件的负载均衡器,或者是以软件方式实现的,例如HAProxy或者Nginx。对于每个Service,我们通常需要配置一个对应的Load balancer实例来转发流量到后端的Node上,这的确增加了工作量及出错的概率。于是Kubernetes提供了自动化的解决方案,如果我们的集群运行在谷歌的公有云GCE上,那么只要把Service的type=NodePort改为type=LoadBalancer,Kubernetes就会自动创建一个对应的Load balancer实例并返回它的IP地址供外部客户端使用。

 

 

小结:k8s中的Service资源对象的基本概念到此,我们就讲完了,下节课将给大家带来Job,Volume的相关知识。

         see you!

给TA打赏
共{{data.count}}人
人已打赏
安全运维

故障复盘的简洁框架-黄金三问

2021-9-30 19:18:23

安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索