Kubernetes 概览
Kubernetes 基本概念
Kubernetes 是一个可移植,可扩展的用于管理容器化的工作负载和服务的开源平台,它支持声明式配置和自动化。
Kubernetes 特点
- 容器平台
- 微服务平台
- 可移植的云平台等
Kubernetes 提供了一个以容器为中心的管理环境。它代表用户工作负载编排计算、网络和存储基础设施。这很大程度上提供了平台即服务(PaaS)的简易性以及基础设施即服务(IaaS)的灵活性,并且支持跨基础设施提供商的可移植性。
Kubernetes 不是什么
Kubernetes 不是一个传统的,包罗万象的 PaaS 系统。因为 Kubernetes 在容器层而不是硬件层进行操作,它提供一些和 PaaS 通用的功能,如部署、扩展、负载均衡、日志和监控。然而,Kubernetes 不是单一的,那些默认的解决方案是可选的和可插拔的。Kubernetes 为构建开发者平台提供构建模块,但在重要的地方保留用户的选择和灵活性。
Kubernetes:
- 不限制所支持应用的类型
Kubernetes 致力于支持非常多样化的工作负载,包括无状态、有状态和数据处理工作负载。如果一个应用可以在容器中运行,它应该在 Kubernetes 能运行地很好。 - 不部署源代码和构建应用
持续集成、持续交付和持续部署工作流由组织文化、偏好和技术需求所决定。 - 不提供应用层服务
中间件(消息总线)、数据处理框架(Spark)、数据库(MySQL)、缓存和作为内置服务的集群存储系统(Ceph)都是不提供的。这些组件可以运行在 Kubernetes 上,通过可移植机制(如 Open Service Broker)由运行在 Kubernetes 上的应用访问。 - 不指定日志、监控和警报解决方案
- 不提供或授权配置语言/系统
它提供了一个声明式的 API,可以通过任意形式的声明式规范作为目标。 - 不提供和采用任何全面的机器配置、维护、管理和自修复系统
此外,Kubernetes 不仅仅是一个编排系统。实际上,它消除了编排的需求。编排的技术定义是一个定义好的工作流的执行:先做 A,然后 B,然后 C。相反,Kubernetes 由一组独立的,可组合的控制过程组成,这些控制过程不断将当前状态驱动到所提供的期望状态。不管你是如何从 A 到 C 的。中心化控制也是不需要的。
Kubernetes 组件
Master 组件
Master 组件提供集群的控制平面。Master 组件做关于集群的全局决定(如调度),检测和相应集群事件(当复制控制器(replication controller)的 ‘replicas’ 字段不满足时启动一个新的 pod)。
Master 组件能在集群的任何机器上运行。
kube-apiserver
在 master 上暴露 Kubernetes API 的组件,是 Kubernetes 控制平面的前端。这个组件被设计用于水平扩展(通过部署更多的实例来进行扩展)。
etcd
一致和高度可用的键值存储,用作 Kubernetes 的所有集群数据的备份存储。
kube-scheduler
在 master 上监视没有被分配的新创建的 pod,并为它们选择一个节点来运行。
kube-controller-manager
在 master 上运行所有控制器的组件。控制器包括:
- 节点控制器:负责节点出现故障时的发现与响应
- 复制控制器:负责为系统中的每个复制控制器对象维护正确数量的pod
- 端点控制器:填充端点对象(即加入 Services 和 Pods)
- 服务账户和令牌控制器:为新命名空间创建默认账户和 API 访问令牌。
cloud-controller-manager
运行与底层云服务提供商交互的控制器。
Node 组件
Node 组件运行在任何节点上,维护运行的 pods,提供 Kubernetes 运行时环境。
kubelet
在集群中每个节点运行的代理,它确保容器运行在一个 pod 中。Kubelet 不管理不是由 Kubernetes 创建的容器。
kube-proxy
通过维护在主机上的网络规则并执行连接转发,启用Kubernetes 服务抽象。
Container Runtime
负责运行容器的软件。Kubernetes 支持一些运行时:Docker,containerd,cri-o,rktlet 和任何 Kubernetes CRI(Container Runtime Interface)的实现。
插件(Addons)
插件是实现集群特征的 pods 和 services。命名空间的插件对象在 kube-system
命名空间中创建。
DNS
尽管其它的插件并非严格需要,但是所有的 Kubernetes 集群都应该具有集群 DNS,因为许多示例都依赖它。
集群 DNS 是你环境中其它 DNS 服务器之外的一个 DNS 服务器,为 Kubernetes 服务提供 DNS 记录。
由 Kubernetes 启动的容器将在其 DNS 搜索中自动包含此 DNS 服务器。
Web UI(Dashboard)
Dashboard 是一个通用的、基于 web 的Kubernetes 集群用户界面。它允许用户管理集群中以及集群本身运行的应用程序,并对它们进行故障排除。
Container Resource Monitoring
容器资源监控记录有关中心数据库中的容器的通用时间序列度量,并提供浏览这些数据的用户界面。
Cluster-level Logging
负责将容器日志保存到具有搜索/浏览界面的中央日志存储中。
Kubernetes Objects
理解 Kubernetes 对象
Kubernetes 是 Kubernetes 系统中持续性的实体。Kubernetes 利用这些实体来表示集群的状态:
- 哪个容器化的应用在运行(并在哪个节点运行)
- 应用可用的资源
- 应用行为的策略,如重启策略,更新策略以及容错性
对象规格和状态
每个 Kubernetes 对象都包含两个嵌套的对象字段来管理对象的配置:spec 和 status。
spec 是你必须提供的,它描述了你期望的对象的状态------你想要对象拥有的特征。
status 描述了对象实际的状态,由 Kubernetes 系统提供和更新。在任何时候,Kubernetes 控制平面都会主动管理对象的实际状态来匹配你所期望的状态。
描述 Kubernetes 对象
当使用 Kubernetes API(或者通过 kubectl)来创建对象,API 请求必须在请求主体中以 JSON 的形式包含提供的信息。通常,用一个 .yaml 文件给 kubectl 提供信息。kubectl 在发出 API 请求的时候将信息转换为 JSON。
必需的字段
在用于创建 Kubernetes 对象的 .yaml 文件中,需要设置以下字段的值:
- apiVersion:你用于创建这个对象的 Kubernetes API 版本
- kind:创建对象的类型
- metadata:帮助惟一标识对象的数据,包含 name 字符串,UID 和可选的 namespace
你也需要为对象提供嵌套的 spec 字段。每个 Kubernetes 对象的 spec 是不同的,并包含特定于该对象的嵌套字段。
Kubernetes Names
所有的对象由一个 Name 和 一个 UID 明确定义。对于非惟一的用户提供的属性,Kubernetes 提供了 labels 和 annotations。
Names
一个 URL 的形式的字符串(由用户提供),如:/api/v1/pods/some-name
UIDs
一个 Kubernetes 系统生成的用于惟一标识对象的字符串。在 Kubernetes 整个生命周期创建的对象都有一个不同的 UID。目的是为了区分相似实体的不同历史事件。
Kubernetes Namespaces
Kubernetes 支持由相同物理集群支持的多个虚拟集群。这些虚拟集群称为 命名空间
什么时候使用命名空间
命名空间适用于多个团队或项目中由多个用户的环境。没必要对于分离轻微不同的资源使用多个命名空间,如相同软件的不同版本,使用 labels 来分辨相同命名空间的资源。
使用命名空间
查看命名空间
kubectl get namespaces
Kubernetes 有三个初始的命名空间:
- default:没有其它命名空间的对象的默认命名空间
- kube-system:由 Kubernetes 系统创建的对象的命名空间
- kube-public:自动创建的并且对所有用户可读的。
设置命名空间
kubectl --namespace=<namespace name> run nginx --image=nginx
kubectl --namespace=<namespace name> get pods
命名空间和 DNS
创建一个服务的时候,这个服务创建了一个相关的 DNS 入点。这个入点的形式为 <service-name>.<namespace-name>.svc.cluster.local
。
如果一个容器使用<service-name>
,它会解析到命名空间的本地服务。
标签和选择器
标签是附加到对象的键值对,例如 pods。标签是为了指明对象对用户有意义和相关的标识属性,但是不直接表明对核心系统的语义。标签可以在创建对象的时期附加到对象上,随后可以在任何时间增加和修改。每个对象都可以定义一组键值标签。对于一个给定的对象,键值必须是独一无二的。
"metadata": {
"labels": {
"key1" : "value1",
"key2" : "value2"
}
}
标签允许高效的查找和监视,并且非常适合在 UI 和 CLI 中使用。
动机
标签允许用户以松耦合的方式将组织结构映射到系统对象上,不需要客户端存储这些映射。
语法和字符集
标签是键值对。有效的标签有两个部分:一个可选的前缀和名称,通过 /
分割。名称部分是必需的,并且至多63个字符,以数字和字母开头和结尾,数字,字母,-,_ 和 . 在中间。前缀是可选的。如果指定了,前缀必须是 DNS 子域:一系列以 . 分割的 DNS 标签,总共不长于253个字符,以 / 结尾。
如果前缀没有指定,标签的键假定对用户是私有的。添加标签到终端用户的自动化系统组件(如 kube-scheduler,kube-controller-manager,kube-apiserver,kubectl 以及其他第三方自动化组件)必须指明前缀。
kubernetes.io/
和 k8s.io/
前缀为 Kubernetes 核心组件保留。
有效的标签至多是63个字符,并且必须是空的或者以数字和字母开头和结尾,数字,字母,-,_ 和 . 在中间。
标签选择器
不像名称和 UID,标签没有提供独一无二的特性。通常,我们期望许多对象带有相同的标签。
通过一个对象选择器,客户端/用户能够识别一组对象。标签选择器是 Kubernetes 中的核心分组原语。
API 现在支持两种类型的选择器:equality-based 和 set-based。标签选择器可以由多个逗号分隔的需求组成。在多个需求中,这些都必须被满足,所以逗号分隔符充当逻辑与操作符(&&
)的作用。
Equality-based requirement
Equality- 或 inequality-based 需求允许通过标签的键值进行过滤。匹配对象必须满足所有指定的标签限制,尽管它们也可能有额外的标签。允许使用三种类型的标签:=
,==
,!=
。前两个代表相等(这两个是同义的),而最后那个代表不等。;例如:
environment = production
tier != frontend
前者选择所有键为 environment
并且值为 production
的资源。后者选择所有键为 tier
并且值不为 frontend
的资源,以及所有没有 tier
键的标签的资源。上述命令等价于 environment=production,tier!=frontend
。
Equality-based 标签需求的一个应用场景是为 Pods 指定节点选择标准。例如,下面的 Pod 选择带有 “accelerator=nvidia-tesla=p100
” 标签的节点。
apiVersion: v1
kind: Pod
metadata:
name: cuda-test
spec:
containers:
- name: cuda-test
image: "k8s.gcr.io/cuda-vector-add:v0.1"
resources:
limits:
nvidia.com/gpu: 1
nodeSelector:
accelerator: nvidia-tesla-p100
Set-based requirement
Set-based 标签需求允许根据一组值过滤键。支持三种操作符:in
,notin
,exists
(只有键标识符)。例如:
environment in (production, qa)
tier notin (fronted, backend)
partition
!partition
第一个选择所有键为 environment
并且值为 production
或者 qa
的所有资源。第二个选择所有键为 tier
并且值不为 frontend
和 backend
的所有资源。第三个是选择所有包含键为 partition
的标签的资源,不检查值。第四个选择所有不包含键为 partition
的标签的资源,不检查值。同样,逗号分隔符充当与操作符(&&
)的作用。因此,过滤带有 partition
键(不管值是什么),并且 environment
不是 qa
的所有资源可以使用 partition,environment notin (qa)
。
environment=production
等价于 environment in (production)
,同样地,!-
等价于 notin
。
Set-based 需求可以和 equality-based 需求进行混用。例如:
partition in (customerA, customerB),environment!=qa
。
API
LIST 和 WATCH 过滤
LIST 和 WATCH 操作可以指定标签选择器来过滤使用查询参数返回的对象集。
- equality-based 需求:
?labelSelector=environment%3Dproduction,tier%3Dfronted
environment=production,tier=fronted
- set-based 需求:
?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29
environment in (production,qa),tier in (frontend)
两个标签选择器风格都可以通过 REST 客户端来罗列或监视资源。例如:
kubectl get pods -l environment=production,tier=frontend
或者
kubectl get pods -l 'environment in (production),tier in (frontend)'
set-based 需求更具有表达性。例如,其可以在值上实现或运算符:
kubectl get pods -l 'environment in (production,qa)'
注解
你可以使用 Kubernetes 注解来将任意非标识的元数据附加到对象上。客户端能够检索这个元数据。
附件元数据到对象上
你能够使用标签或注解将元数据附加到 Kubernetes 对象上。标签能够用于选择对象并且找到满足特定条件对象的集合。相反,注解不用于标识和选择对象。注解中的元数据可以很小,也可以很大;可以是结构化的,也可以是非结构化的;可以包含不被标签所允许的字符集。
和标签一样,注解也是键值对映射:
"metadata": {
"annotations": {
"key1": "value1",
"key2": "value2"
}
}
以下是可以在注解中记录的信息示例:
- 被声明式配置层管理的字段。将这些字段附加注解能够将它们与有客户端或服务器设置的默认值以及由自动缩放系统设置的自动生成的字段区分开来。
- 构建、发布或镜像信息,如:时间戳,发布ID,git 分支,镜像 hash,仓库地址等。
- 指向日志,监控,解析或审计存储库的指针
- 可用于调试的客户端库或工具信息,如:名称,版本和构建信息
- 用户或工具/系统来源信息,如:来自其它生态系统组件的相关对象的 URL
- 轻量级部署工具元数据,如:配置或检查点
- 电话号码,团队网站等个人信息
- 从终端用户到实现修改行为或从事非标准特性的指令
除了使用注解,也可以通过额外的数据块或目录来存储这类型的信息,但是实现共享等会更加麻烦。
语法和字符集
注解是键值对。有效的键有两个部分:可选的前缀和名称,以 / 分隔。名称部分至多63个字符,以数字和字母开头和结尾,数字,字母,-,_ 和 . 在中间。前缀是可选的。如果指定了,前缀必须是 DNS 子域:一系列以 . 分割的 DNS 标签,总共不长于253个字符,以 / 结尾。
如果省略前缀,注解的键则假定为对用户是私有的。添加注解到终端用户对象的自动化系统组件(如:kube-scheduler, kube-controller, kube-apiserver,kubectl 或其它第三方自动化组件)必须指定前缀。
kubernetes.io/
和 k8s.io/
前缀被 Kubernetes 核心组件所保留。
字段选择器
支持的字段
支持的字段选择器根据 Kubernetes 资源类型而变化。所有的资源类型都支持 metadata.name
和 metadata.namespace
字段。使用不支持的字段选择器会产生错误。
支持的操作符
可以使用 =,,!=(=和是同义的)。
kubectl get services --field-selector metadata.namespace!=default
。
链式选择器
和标签选择器和其它选择器一样,字段选择器能以逗号分隔的列表链接起来。
kubectl get pods --filed-selector=status.phase!=Running,spec.restartPolicy=Always
多种资源类型
可以在多种资源类型中使用字段选择器。下面这条命令选择所有不在 default 命名空间中的 Statefulsets 和 Services:
kubectl get statefulsets,services --filed-selector metadata.namespace!=default
推荐的标签
共享的标签和注解共享一个公共的前缀:app.kubernetes.io
。
标签
为了充分利用这些标签,它们应当应用到每个资源对象。
Key | Description | Example | Type |
---|---|---|---|
app.kubernetes.io/name | The name of the application | mysql | string |
app.kubernetes.io/instance | A unique name identifying the instance of an application | wordpress-abcxyz | string |
app.kubernetes.io/version | The current version of the application (e.g., a semantic version, revision hash, etc) | 5.7.21 | string |
app.kubernetes.io/component | The component within the architecture | database | string |
app.kubernetes.io/part-of | The name of a higher level application this one is part of | wordpress | string |
app.kubernetes.io/managedby | The tool being used to manage the operation of an application | helm | string |
例如:
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/instance: wordpress-abcxyz
app.kubernetes.io/version: "5.7.21"
app.kubernetes.io/component: database
app.kubernetes.io/part-of: wordpress
app.kubernetes.io/managed-by: helm
应用程序和应用程序实例
一个应用程序可以在一个 Kubernetes 集群上或者有时在相同的命名空间中安装一次或多次。
应用和实例的名称是被分开记录的。这使得应用程序和应用程序实例可以被识别。每个应用程序的实例必须有惟一的名称。