01 资源对象概述
Kubernetes
中的基本概念和术语大多是围绕 资源对象(Resource Object
)来说 的,而资源对象在总体上可分为以下两类:
- 某种资源的对象。例如节点
Node
、Pod
、服务Service
、存储卷Volume
。 - 与资源对象相关的事物与动作。例如标签
Label
、注解Annotation
、命名空间Namespace
、部署Deployment
、HPA
、PVC
。
资源对象一般包括几个通用属性:版本、类别(Kind
)、名称、标签、注解,如下所述。
- 版本信息:包括了此对象所属的资源组,一些资源对象的属性会随着版本的升级而变化,在定义资源对象时要特别注意这一点。
- 类别属性:用于定义资源对象的类型。
- 资源对象的名称(
Name
)、标签、注解这三个属性属于资源对象的元数据(metadata
),资源对象的名称要唯一。资源对象的标签是很重要的数据,也是Kubernetes
的一大设计特性,比如通过标签来表明资源对象的特征、类别,以及通过标签筛选不同的资源对象并实现对象之间的关联、控制或协作功能。 - 注解:可被理解为一种特殊的标签,不过更多地是与程序挂钩,通常用于实现资源对象属性的自定义扩展。
我们可以采用 YAML
或 JSON
格式声明(定义或创建)一个 Kubernetes
资源对象,每个资源对象都有自己的特定结构定义(可以理解为数据库中一个特定的表),并且统一保存在 etcd
这种非关系型数据库中,以实现最快的读写速度。此外,所有资源对象都可以通过 Kubernetes
提供的kubectl
工具(或者 API 编程调用)执行增、删、改、查等操作。
这里按照功能或用途对众多资源对象其进行分类,将其分为集群类、应用类、存储类及安全类这四大类,下面来讲解。
02 集群类
集群(Cluster
)表示一个由 Master
和 Node
组成的 Kubernetes
集群。
2.1 Master
Master
指的是集群的控制节点。在每个 Kubernetes
集群中都需要有一个或一组被称为 Master
的节点,来负责整个集群的管理和控制。Master
通常占据一个独立的服务器(在高可用部署中建议至少使用 3 台服务器),是整个集群的“大脑”,如果它发生宕机或者不可用,那么对集群内容器应用的管理都将无法实施。
在 Master
上运行着以下关键进程:
- Kubernetes API Server (kube-apiserver):提供 HTTP RESTful API 接口的主要服务,是 Kubernetes 里对所有资源进行增、删、改、查等操作的唯一入口,也是集群控制的入口进程。
- Kubernetes Controller Manager:Kubernetes 里所有资源对象的自动化控制中心,可以将其理解为资源对象的“大总管”。
- Kubernetes Scheduler:负责资源调度(Pod 调度)的进程,相当于公交公司的调度室。
- 在
Master
上通常还需要部署etcd
服务。
2.2 Node
Kubernetes
集群中除 Master
外的其他服务器被称为 Node
。Node
可以是一台物理主机,也可以是一台虚拟机。Node
是Kubernetes
集群中的工作负载节点,每个 Node
都会被 Master
分配一些工作负载(Docker
容器),当某个Node
宕机时,其上的工作负载会被 Master
自动转移到其他 Node
上。
在每个 Node
上都运行着以下关键进程:
- kubelet:负责 Pod 对应容器的创建、启停等任务,同时与 Master 密切协作,实现集群管理的基本功能。
- kube-proxy:实现
Kubernetes Service
的通信与负载均衡机制的服务。 - 容器运行时(如
Docker
) : 负责本机的容器创建和管理。
我们可以运行以下命令查看在集群中有多少个 Node:
查询node详情:
2.3 命名空间
在集群类里还有一个重要的基础概念一一命名空间,它在很多情况下用于实现多租户的资源隔离,典型的一种思路就是给每个租户都分配一个命名空间。每个命名空间都是相互独立的存在,属于不同命名空间的资源对象从逻辑上相互隔离。
在每个 Kubernetes
集群安装完成且正常运行之后,Master
会自动创建两个命名空间。
- 默认级(
default
):用户创建的资源对象如果没有指定命名空间,则被默认存放在default
命名空间中; - 系统级(
kube-system
):系统相关的资源对象如网络组件、DNS
组件、监控类组件等,都被安装在kube-system
命名空间中。
我们可以通过命名空间将集群内部的资源对象“分配”到不同的命名空间中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时能被分别管理。当给每个租户都创建一个命名空间来实现多租户的资源隔离时,还能结合 Kubernetes
的资源配额管理,限定不同租户能占用的资源,例如 CPU
使用量、内存使用量等。
命名空间的定义很简单,如下所示的 YAML
文件定义了名为development
的命名空间:
查看(注意加上-namespace
或-n
):
03 应用类
3.1 service和pod
Node、Pod与容器间的关系图如下:
Pod及周边对象:
应用类相关的资源对象主要是围绕 Service(服务)和 Pod 这两个核心对象展开的。
- Service :一般指的是无状态服务,通常由多个程序副本提供服务,在特殊情况下也可以是有状态的单实例服务,比如 MySQL 这种数据存储类的服务。
- Pod:有一个特殊的被称为“根容器”的 Pause 容器,Pause 容器对应的镜像属于 Kubernetes 平台的一部分,还包含一个或多个紧密相关的用户业务容器。
3.2 label与标签选择器
给某个资源对象定义一个 label
,就相当于给它打了一个标签,随后可以通过 Label Selector
(标签选择器)查询和筛选拥有某些 Label 的资源对象,Kubernetes 通过这种方式实现了类似 SQL 的简单又通用的对象查询机制。
写法举例:
举例图:
3.3 Pod和Deployment
Pod、Deployment和Service的关系:
前面提到,大部分 Service
都是无状态的服务,可以由多个Pod
副本实例提供服务。通常情况下,每个 Service
对应的Pod
服务实例数量都是固定的,如果一个一个地手工创建 Pod
实例,就太麻烦了,最好是用模板的思路,即提供一个 Pod
模板(Template
),然后由程序根据我们指定的模板自动创建指定数量的 Pod
实例。这就是Deployment
这个资源对象所要完成的事情了,举例:
3.4 Service和ClusterIp
Kubernetes
内部在每个 Node
上都运行了一套全局的虚拟负载均衡器,自动注入并自动实时更新集群中所有 Service
的路由表,通过 iptables
或者 IPVS
机制,把对 Service
的请求转发到其后端对应的某个 Pod
实例上,并在内部实现服务的负载均衡与会话保持机制。
不仅如此,Kubernetes
还采用了一种很巧妙又影响深远的设计一 ClusterIP
地址。
Service
一旦被创建,Kubernetes
就会自动为它分配一个全局唯一的虚拟 IP
地址,即ClusterIP
地址,而且在Service
的整个生命周期内,其 ClusterIP
地址不会发生改变,这样一来,每个服务就变成了具备唯一 IP
地址的通信节点,远程服务之间的通信问题就变成了基础的 TCP
网络通信问题。
3.5 Service外网访问
我们需要先弄明白 Kubernetes 的三种 IP,分别如下:
- Node IP: 是 Kubernetes集群中每个节点的物理网卡的 IP 地址,是一个真实存在的物理网络,所有属于这个网络的服务器都能通过这个网络直接通信。
- Pod IP: 每个 Pod 的 IP 地址,在使用 Docker 作为容器支持引擎的情况下,它是 Docker Engine 根据 dockero 网桥的 IP 地址段进行分配的,通常是一个虚拟二层网络,通过Pod IP所在的虚拟二层网络进行通信的,真实的TCP/IP 流量是通过Node IP 所在的物理网卡流出。
- Service IP: Service 的 ClusterIP 地址属于集群内的地址,无法在集群外直接使用这个地址。为了解决这个问题,Kubernetes 首先引入了 NodePort。
对于每个 Service,我们通常需要配置一个对应的负载均衡器实例来转发流量到后端的 Node 上,这的确增加了工作量及出错的概率,如下图:
NodePort 的确功能强大且通用性强,但也存在一个问题,即每个 Service 都需要在 Node 上独占一个端口,而端口又是有限的物理资源,那能不能让多个 Service 共用一个对外端口呢,这就是后来增加的 Ingress资源对象所要解决的问题。
Ingress其实只能将多个 HTTP (HTTPS)的 Service“聚合”,通过虚拟域名或者 URL Path 的特征进行路由转发功能,考虑到常见的微服务都采用了 HTTP REST 协议,所以 Ingress 这种聚合多个 Service 并将其暴露到外网的做法还是很有效的。
在一定程度上,我们可以把 Ingress 的实现机制理解为基于 Nginx 的支持虚拟主机的 HTTP 代理。下面是一个 Ingress 的实例: