vlambda博客
学习文章列表

k8s系列第五篇~k8s资源对象-应用类资源对象(二)

上篇文章主要带大家了解了应用类资源的servicepod,本文将带大家学习应用类资源的label、标签选择器、poddeploymentserviceclusterIP

 

1、Label与标签选择器

label(标签)是kubernetes系统中的另一个核心概念,一个label是一个key=value的键值对,其中keyvalue由用户自己指定。Label可以被附加到各种资源对象上,例如nodepodservicedeployment等,一个资源对象可以定义任意数量的label,同一个label也可以被添加到任意数量的资源对象上。Label通常在资源对象定义时确定,也可以在对象创建后动态增加或删除。可以通过给指定的资源对象捆绑一个或多个不同的label来实现资源分组管理功能,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作,例如:部署不同版本的应用到不同的环境中,以及监控、分析应用等。一些常用的label示例如下:

  • 版本标签:release:stablerelease:canary

  • 环境标签:env:devenv:pro

  • 架构标签:tier:frontendtier:backend

  • 分区标签:partition:conApartition:conB

  • 质量管控标签:track:dailytrack:weekly

给资源对象定义完label后,可以通过label selector(标签选择器)查询和筛选拥有某些label的资源对象,kubernetes通过这种方式实现了类似sql的简单又通用的对象查询机制。Label select可以类比为sql语句中的where查询条件,当前有两种label selector表达式:基于等式的(equality-basedselector表达式和基于集合的(set-basedselector表达式。

      

基于等式的selector表达式采用等式类表达式匹配标签,下面是具体的例子:
  • name=tomcat,匹配所有具有name=tomcat标签的资源对象。

  • env!=pro,匹配所有不具有env=pro标签的资源对象。


基于集合的selector表达式采用集合操作类表达式匹配标签,下面是具体的例子:


  • name in (tomcat,redis),匹配所有具有name=tomcat或者name=redis标签的资源对象。

  • name not in (tomcat),匹配所有不具有name-tomcat标签的资源对象。

 

可以通过多个label selector表达式的组合来实现复杂的条件选择,多个表达式之间用”,”进行分隔,几个条件之间是“AND”的关系。

 

2、poddeployment

前面文章提到大部分service都是无状态的服务,可以由多个pod副本实例提供服务,每个service对应的pod实例数量都是固定的,我们可以用模板的思路创建指定数量的pod副本实例数量,即提供一个pod模板,然后程序根据指定的模板自动创建指定数量的pod实例,这就是deployment资源对象需要完成的事情。

 

Deployment资源定义示例:

apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deployment labels:    app: nginxspec: replicas: 3  selector: matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers: - name: nginx        image: nginx:1.14.2 ports:        - containerPort: 80

参数说明:

replicas:pod的副本数量
selector:目标pod的标签选择器
template:用于自动创建新pod副本的模板

只有一个pod副本实例时,我们是否也需要deployment来自动创建pod呢?

“需要”,因为deployment除了自动创建pod副本外,还具备“自动控制”的特性。举个列子:如果pod所在的节点发生宕机事件,kubernetes会第一时间观察到这个故障,并自动创建一个新的pod对象,将其调度到合适的节点上,kubernetes会实时监控集群中目标pod的副本数量,并且尽力与deployment中声明的replicas数量保持一致。

下图显示了poddeploymentservice的逻辑关系。

 

 

从图中可以看到,k8sservice定义了一个服务的访问入口地址,前端的应用通过这个入口地址访问其背后的一组由pod副本组成的集群实例。Service与其后端pod副本集群之间则是通过label selector实现无缝对接的,deployment用于保证service的服务能力和服务质量始终符合预期标准。

 

多个pod副本组成一个集群来提供服务,客户端如何访问他们呢?

传统的做法是部署一个负载均衡器(软件或硬件),为这组pod开启一个对外的端口(例如80端口),并且将这些Pod的endpoint的列表加入到80端口的转发列表中,客户端就可以通过负载均衡器的对外ip地址+80端口来访问此服务了。K8s也是类似的做法,k8s内部在每个node上都运行了一套全局的虚拟负载均衡器,自动注入并自动实时更新集群中所有service的路由表,通过iptables或ipvs机制,把对service的请求转发到其后端对应的某个pod实例上,并在内部实现服务的负载均衡与会话保持机制。不仅如此,k8s内部还采用了一种很巧妙又影响深远的设计----ClusterIP地址。Pod的endpoint地址会随着pod的销毁和重新创建而变化,service一旦被创建,k8s就会自动为它分配一个全局唯一的虚拟ip地址----ClusterIP地址。
K8s采用直观朴素的思路解决“服务发现”问题:只要用service的name与clusterip地址做一个dns域名映射即可。比如我们定义一个mysql service,service的名称是mydbserver,service的端口是3306,则在代码中直接通过mydbserver:3306即可访问此服务。

 

为什么ClusterIp是一种虚拟ip
ClusterIP地址仅仅作用于k8s service这个对象,用于k8s来管理和分配ip地址,与nodemaster所在的物理机网络完全无关。
因为没有一个“实体网络对象”来响应,所以ClusterIP地址无法被ping通。ClusterIp地址只能与service port组成一个具体的服务访问端口,单独的ClusterIP不具备TCP/IP通信的基础。
ClusterIP属于k8s集群这个封闭的空间,集群外的节点要访问这个通信端口号,则需要一些额外的工作。

下面是tomcat-service.yamlService定义文件:

apiVersion:v1kind:Servicemetadata:  name:tomcat-servicespec:  selector:    name:myweb  ports:    - protocol:TCP      port:8080      targetPort:8080

基本命令:

创建服务的命令:kubectl apply –f tomcat-service.yaml
查看endpoint命令:kubectl get endpoints
查看tomcat-service详细信息:kubectl get svc tomcat-service –o yaml

 

参数说明:

spec.ports.targetPort属性用来确定提供该服务的容器所暴露(Expose)的端口号,具体的业务进程在容器内的targetPort上提供TIP/IP接入。
spec.ports.port属性则定义了service的端口。如果没有指定targetPort端口,则targetPort默认和port相同。

 

service如何多个端口同时提供服务?

很多情况下service存在多个端口,多个端口提供服务。K8s service支持多个endpoint,存在多个endpoint的情况下,要求每个endpoint都定义一个名称进行区分,下面是tomcat多端口的service定义:
apiVersion:v1kind:Servicemetadata:  name:tomcat-servicespec:  selector:    name:myweb  ports:    - name:service-port      protocol:TCP      port:8080      targetPort:8080 - name:shutdown-port      protocol:TCP      port:8005 targetPort:8005