在Kubernetes中,Service(服务)是分布式集群架构的核心,一个Service对象拥有如下关键特征:
- 拥有一个唯一指定的名字(比如mysql-server)。
- 拥有一个虚IP(Cluster IP、Service IP或VIP)和端口号。
- 能够提供某种远程服务能力。
- 被映射到了提供这种服务能力的一组容器应用上。
Service的服务进程目前都基于Socket通信方式对外提供服务,比如Redis、Memcache、MySQL、Web Server,或者是实现了某个具体业务的一个特定的TCP Server进程。虽然一个Service通常由多个相关的服务进程来提供服务,每个服务进程都有一个独立的Endpoint(IP+Port)访问点,但Kubernetes能够让我们通过Service(虚拟Cluster IP+Service Port)连接到指定的Service上。有了Kubernetes内建的透明负载均衡和故障恢复机制,不管后端有多少服务进程,也不管某个服务进程是否会由于发生故障而重新部署到其他机器,都不会影响到我们对服务的正常调用。更重要的是这个Service本身一旦创建就不再变化,这意味着,在Kubernetes集群中,我们再也不用为了服务的IP地址变来变去的问题而头疼了。
容器提供了强大的隔离功能,所有有必要把为Service提供服务的这组进程放入容器中进行隔离。为此,Kubernetes设计了Pod对象,将每个服务进程包装到相应的Pod中,使其成为Pod中运行的一个容器(Container)。为了建立Service和Pod之间关系,Kubernetes首先给每个Pod贴上一个标签(Label),给运行MySQL的Pod贴上name=mysql标签,给运行PHP的Pod贴上name=php标签,然后给相应的Service定义标签选择器(Label Selector),比如MySQL Service的标签选择器的选择条件为name=mysql,意为该Service要作用于所有包含name=mysql Label的Pod上。这样一来,就巧妙地解决了Servive与Pod的关联问题。
说到Pod,我们这里先简单介绍其概念。首先,Pod运行在一个我们称之为节点(Node)的环境中,这个节点既可以是物理机,也可以是私有云或者公有云中的一个虚拟机,通常一个节点上运行几百个Pod;其次,每个Pod里运行着一个特殊的被称之为Pause的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,因此它们之间的通信和数据交换更为高效,在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中;最后,需要注意的是,并不是每个Pod和它里面运行的容器都能“映射”到一个Service上,只有那些提供服务(无论是对内还是对外)的一组Pod才会被“映射”成一个服务。
在集群管理方面,Kubernetes将集群中的机器划分为一个Master节点和一群工作节点(Node)。其中,在Master节点上运行着集群管理相关的一组进程kube-apiserver、kube-controller-manager和kube-scheduler,这些进程实现了这个集群的资源管理、Pod调度、弹性伸缩、安全控制、系统监控和纠错等管理功能,并且都是全自动完成的。Node作为集群中的工作节点,运行真正的应用程序,在Node上Kubernetes管理的最小运行单元是Pod。Node上运行着Kubernetes的kubelet、kube-proxy服务进程,这些服务进程负责Pod的创建、启动、监控、重启、销毁,以及实现软件模式的负载均衡器。
最后,我们再来看看传统的IT系统中服务扩容和服务升级这两个难题,以及Kubernetes所提供的全新解决思路。服务的扩容设计资源分配(选择哪个节点进行扩容)、实例部署和启动等环节,在一个复杂的业务系统中,这两个问题基本上靠人工一步步操作才得以完成,费事费力又难以保证实施质量。
在Kubernetes集群中,你只需要为需要扩容的Service关联的Pod创建一个Replication Controller(简称RC),则该Service的扩容以至于后来的Service升级等头疼问题都迎刃而解。在一个RC定义文件中包括以下3个关键信息。
- 目标Pod的定义
- 目标Pod需要运行的副本数量(Replicas)。
- 要监控的目标Pod的标签(Label)。