kubenetes 中的各种概念
概念部分帮助你了解Kubernetes系统的各个部分,以及Kubernetes用来表示你的集群的抽象概念,并帮助你获得对Kubernetes工作方式的更深理解。
kubenetes 中的各种概念
概念部分帮助你了解Kubernetes系统的各个部分,以及Kubernetes用来表示你的集群的抽象概念,并帮助你获得对Kubernetes工作方式的更深理解。
Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。
Kubernetes 这个名字源于希腊语,意为“舵手”或“飞行员”。k8s 这个缩写是因为 k 和 s 之间有八个字符的关系。
传统部署时代:
早期,各个组织是在物理服务器上运行应用程序。 由于无法限制在物理服务器中运行的应用程序资源使用,因此会导致资源分配问题。 例如,如果在同一台物理服务器上运行多个应用程序, 则可能会出现一个应用程序占用大部分资源的情况,而导致其他应用程序的性能下降。 一种解决方案是将每个应用程序都运行在不同的物理服务器上, 但是当某个应用程式资源利用率不高时,剩余资源无法被分配给其他应用程式, 而且维护许多物理服务器的成本很高。
笔记:物理机部署有资源隔离不足和资源利用率不高的问题,维护成本高
虚拟化部署时代:
因此,虚拟化技术被引入了。虚拟化技术允许你在单个物理服务器的 CPU 上运行多台虚拟机(VM)。 虚拟化能使应用程序在不同 VM 之间被彼此隔离,且能提供一定程度的安全性, 因为一个应用程序的信息不能被另一应用程序随意访问。
虚拟化技术能够更好地利用物理服务器的资源,并且因为可轻松地添加或更新应用程序, 而因此可以具有更高的可扩缩性,以及降低硬件成本等等的好处。 通过虚拟化,你可以将一组物理资源呈现为可丢弃的虚拟机集群。
每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。
笔记:虚拟化技术可以解决物理机资源隔离不足和资源利用率不高的问题,维护方便。
容器部署时代:
容器类似于 VM,但是更宽松的隔离特性,使容器之间可以共享操作系统(OS)。 因此,容器比起 VM 被认为是更轻量级的。且与 VM 类似,每个容器都具有自己的文件系统、CPU、内存、进程空间等。 由于它们与基础架构分离,因此可以跨云和 OS 发行版本进行移植。
容器因具有许多优势而变得流行起来,例如:
笔记:容器更轻量级,可移植性高
https://kubernetes.io/zh-cn/docs/concepts/overview/components/
正常运行的 Kubernetes 集群所需的各种组件:
控制平面组件会为集群做出全局决策,比如资源的调度。 以及检测和响应集群事件,例如当不满足部署的 replicas 字段时, 要启动新的 pod)。
控制平面组件可以在集群中的任何节点上运行。 然而,为了简单起见,设置脚本通常会在同一个计算机上启动所有控制平面组件, 并且不会在此计算机上运行用户容器。
API 服务器是 Kubernetes 控制平面的组件, 该组件负责公开了 Kubernetes API,负责处理接受请求的工作。 API 服务器是 Kubernetes 控制平面的前端。
Kubernetes API 服务器的主要实现是 kube-apiserver。 kube-apiserver 设计上考虑了水平扩缩,也就是说,它可通过部署多个实例来进行扩缩。 你可以运行 kube-apiserver 的多个实例,并在这些实例之间平衡流量。
一致且高度可用的键值存储,用作 Kubernetes 的所有集群数据的后台数据库。
kube-scheduler 是控制平面的组件, 负责监视新创建的、未指定运行节点(node)的 Pods, 并选择节点来让 Pod 在上面运行。
调度决策考虑的因素包括单个 Pod 及 Pods 集合的资源需求、软硬件及策略约束、 亲和性及反亲和性规范、数据位置、工作负载间的干扰及最后时限。
kube-controller-manager 是控制平面的组件, 负责运行控制器进程。
从逻辑上讲, 每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。
这些控制器包括:
一个 Kubernetes 控制平面组件, 嵌入了特定于云平台的控制逻辑。 云控制器管理器(Cloud Controller Manager)允许你将你的集群连接到云提供商的 API 之上, 并将与该云平台交互的组件同与你的集群交互的组件分离开来。
cloud-controller-manager 仅运行特定于云平台的控制器。 因此如果你在自己的环境中运行 Kubernetes,或者在本地计算机中运行学习环境, 所部署的集群不需要有云控制器管理器。
与 kube-controller-manager 类似,cloud-controller-manager 将若干逻辑上独立的控制回路组合到同一个可执行文件中, 供你以同一进程的方式运行。 你可以对其执行水平扩容(运行不止一个副本)以提升性能或者增强容错能力。
下面的控制器都包含对云平台驱动的依赖:
节点组件会在每个节点上运行,负责维护运行的 Pod 并提供 Kubernetes 运行环境。
kubelet 会在集群中每个节点(node)上运行。 它保证容器(containers)都运行在 Pod 中。
kubelet 接收一组通过各类机制提供给它的 PodSpecs, 确保这些 PodSpecs 中描述的容器处于运行状态且健康。 kubelet 不会管理不是由 Kubernetes 创建的容器。
kube-proxy 是集群中每个节点(node)上所运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分。
kube-proxy 维护节点上的一些网络规则, 这些网络规则会允许从集群内部或外部的网络会话与 Pod 进行网络通信。
如果操作系统提供了可用的数据包过滤层,则 kube-proxy 会通过它来实现网络规则。 否则,kube-proxy 仅做流量转发。
容器运行环境是负责运行容器的软件。
Kubernetes 支持许多容器运行环境,例如 containerd、 CRI-O 以及 Kubernetes CRI (容器运行环境接口) 的其他任何实现。
插件使用 Kubernetes 资源(DaemonSet、 Deployment 等)实现集群功能。 因为这些插件提供集群级别的功能,插件中命名空间域的资源属于 kube-system 命名空间。
下面描述众多插件中的几种。有关可用插件的完整列表,请参见 插件(Addons)。
尽管其他插件都并非严格意义上的必需组件,但几乎所有 Kubernetes 集群都应该有集群 DNS, 因为很多示例都需要 DNS 服务。
集群 DNS 是一个 DNS 服务器,和环境中的其他 DNS 服务器一起工作,它为 Kubernetes 服务提供 DNS 记录。
Kubernetes 启动的容器自动将此 DNS 服务器包含在其 DNS 搜索列表中。
Dashboard 是 Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身, 并进行故障排除。
容器资源监控 将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中, 并提供浏览这些数据的界面。
集群层面日志机制负责将容器的日志数据保存到一个集中的日志存储中, 这种集中日志存储提供搜索和浏览接口。
https://kubernetes.io/zh-cn/docs/concepts/overview/kubernetes-api/
Kubernetes 控制面的核心是 API 服务器。 API 服务器负责提供 HTTP API,以供用户、集群中的不同部分和集群外部组件相互通信。
Kubernetes API 使你可以查询和操纵 Kubernetes API 中对象(例如:Pod、Namespace、ConfigMap 和 Event)的状态。
大部分操作都可以通过 kubectl 命令行接口或类似 kubeadm 这类命令行工具来执行, 这些工具在背后也是调用 API。不过,你也可以使用 REST 调用来访问这些 API。
Kubernetes API 服务器通过 /openapi/v2
端点提供聚合的 OpenAPI v2 规范。
Kubernetes 为 API 实现了一种基于 Protobuf 的序列化格式,主要用于集群内部通信。
特性状态: Kubernetes v1.24 [beta]
Kubernetes v1.25 提供将其 API 以 OpenAPI v3 形式发布的 beta 支持; 这一功能特性处于 beta 状态,默认被开启。
Kubernetes 对维护达到正式发布(GA)阶段的官方 API 的兼容性有着很强的承诺,通常这一 API 版本为 v1
。
有两种途径来扩展 Kubernetes API:
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/kubernetes-objects/
在 Kubernetes 系统中,Kubernetes 对象 是持久化的实体。 Kubernetes 使用这些实体去表示整个集群的状态。 比较特别地是,它们描述了如下信息:
Kubernetes 对象是“目标性记录” —— 一旦创建该对象,Kubernetes 系统将不断工作以确保该对象存在。 通过创建对象,你就是在告知 Kubernetes 系统,你想要的集群工作负载状态看起来应是什么样子的, 这就是 Kubernetes 集群所谓的 期望状态(Desired State)。
几乎每个 Kubernetes 对象包含两个嵌套的对象字段,它们负责管理对象的配置: 对象 spec(规约) 和 对象 status(状态)。 对于具有 spec 的对象,你必须在创建对象时设置其内容,描述你希望对象所具有的特征: 期望状态(Desired State)。
status 描述了对象的当前状态(Current State),它是由 Kubernetes 系统和组件设置并更新的。 在任何时刻,Kubernetes 控制平面 都一直都在积极地管理着对象的实际状态,以使之达成期望状态。
例如,Kubernetes 中的 Deployment 对象能够表示运行在集群中的应用。 当创建 Deployment 时,可能会去设置 Deployment 的 spec,以指定该应用要有 3 个副本运行。 Kubernetes 系统读取 Deployment 的 spec, 并启动我们所期望的应用的 3 个实例 —— 更新状态以与规约相匹配。 如果这些实例中有的失败了(一种状态变更),Kubernetes 系统会通过执行修正操作来响应 spec 和状态间的不一致 —— 意味着它会启动一个新的实例来替换。
笔记:spec 必须在创建对象时设置,这是期望状态(Desired State)。status 是当前状态(Current State),由 Kubernetes 系统和组件设置并更新的。
创建 Kubernetes 对象时,必须提供对象的 spec
,用来描述该对象的期望状态, 以及关于对象的一些基本信息(例如名称)。 当使用 Kubernetes API 创建对象时(直接创建,或经由 kubectl
), API 请求必须在请求本体中包含 JSON 格式的信息。 大多数情况下,你需要提供 .yaml
文件为 kubectl 提供这些信息。 kubectl
在发起 API 请求时,将这些信息转换成 JSON 格式。
在想要创建的 Kubernetes 对象所对应的 .yaml
文件中,需要配置的字段如下:
apiVersion
- 创建该对象所使用的 Kubernetes API 的版本kind
- 想要创建的对象的类别metadata
- 帮助唯一标识对象的一些数据,包括一个 name
字符串、UID
和可选的 namespace
spec
- 你所期望的该对象的状态https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/object-management/
警告: 应该只使用一种技术来管理 Kubernetes 对象。混合和匹配技术作用在同一对象上将导致未定义行为。
管理技术 | 作用于 | 建议的环境 | 支持的写者 | 学习难度 |
---|---|---|---|---|
指令式命令 | 活跃对象 | 开发项目 | 1+ | 最低 |
指令式对象配置 | 单个文件 | 生产项目 | 1 | 中等 |
声明式对象配置 | 文件目录 | 生产项目 | 1+ | 最高 |
使用指令式命令时,用户可以在集群中的活动对象上进行操作。用户将操作传给 kubectl
命令作为参数或标志。
在指令式对象配置中,kubectl 命令指定操作(创建,替换等),可选标志和 至少一个文件名。指定的文件必须包含 YAML 或 JSON 格式的对象的完整定义。
有关对象定义的详细信息,请查看 API 参考。
警告: replace
指令式命令将现有规范替换为新提供的规范,并放弃对配置文件中 缺少的对象的所有更改。此方法不应与对象规约被独立于配置文件进行更新的 资源类型一起使用。比如类型为 LoadBalancer
的服务,它的 externalIPs
字段就是独立于集群配置进行更新。
使用声明式对象配置时,用户对本地存储的对象配置文件进行操作,但是用户 未定义要对该文件执行的操作。 kubectl
会自动检测每个文件的创建、更新和删除操作。 这使得配置可以在目录上工作,根据目录中配置文件对不同的对象执行不同的操作。
说明: 声明式对象配置保留其他编写者所做的修改,即使这些更改并未合并到对象配置文件中。 可以通过使用 patch
API 操作仅写入观察到的差异,而不是使用 replace
API 操作来替换整个对象配置来实现。
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/names/
集群中的每一个对象都有一个名称来标识在同类资源中的唯一性。
每个 Kubernetes 对象也有一个 UID 来标识在整个集群中的唯一性。
比如,在同一个名字空间 中只能有一个名为 myapp-1234 的 Pod,但是可以命名一个 Pod 和一个 Deployment 同为 myapp-1234。
对于用户提供的非唯一性的属性,Kubernetes 提供了 标签(Labels)和 注解(Annotation)机制。
客户端提供的字符串,引用资源 URL 中的对象,如/api/v1/pods/some name
。
某一时刻,只能有一个给定类型的对象具有给定的名称。但是,如果删除该对象,则可以创建同名的新对象。
说明:
当对象所代表的是一个物理实体(例如代表一台物理主机的 Node)时, 如果在 Node 对象未被删除并重建的条件下,重新创建了同名的物理主机, 则 Kubernetes 会将新的主机看作是老的主机,这可能会带来某种不一致性。
很多资源类型需要可以用作 DNS 子域名的名称。
某些资源类型需要其名称遵循 RFC 1123 所定义的 DNS 标签标准。
某些资源类型需要其名称遵循 RFC 1035 所定义的 DNS 标签标准。
某些资源类型要求名称能被安全地用作路径中的片段。 换句话说,其名称不能是 .
、..
,也不可以包含 /
或 %
这些字符。
Kubernetes 系统生成的字符串,唯一标识对象。
在 Kubernetes 集群的整个生命周期中创建的每个对象都有一个不同的 UID,它旨在区分类似实体的历史事件。
Kubernetes UID 是全局唯一标识符(也叫 UUID)。 UUID 是标准化的,见 ISO/IEC 9834-8 和 ITU-T X.667。
https://github.com/kubernetes/design-proposals-archive/blob/main/architecture/identifiers.md
对Kubernetes中标识符的目标和建议进行了总结。
UID:一个非空的、不透明的、系统生成的值,保证在时间和空间上是唯一的;旨在区分类似实体的历史出现。
name: 一个非空的字符串,保证在特定时间的特定范围内是唯一的;在资源URL中使用;由客户在创建时提供,并鼓励对人友好;旨在促进单子对象的创建同位性和空间唯一性,区分不同的实体,并在操作中引用特定的实体。
rfc1035/rfc1123 label
(DNS_LABEL)。一个字母数字(a-z和0-9)字符串,最大长度为63个字符,除第一个或最后一个字符外,任何地方都允许使用’-‘字符,适合作为主机名或域名中的段。
rfc1035/rfc1123 subdomain
(DNS_SUBDOMAIN)。一个或多个小写的rfc1035/rfc1123标签,用’.‘分隔,最大长度为253个字符。
rfc4122 通用唯一标识符(universally unique identifier / UUID)。一个128位的生成值,跨时空碰撞的可能性极低,不需要中央协调。
rfc6335 port name
(IANA_SVC_NAME)。一个字母数字(a-z和0-9)字符串,最大长度为15个字符,除了第一个或最后一个字符或与另一个’-‘字符相邻外,允许在任何地方使用’-‘字符,它必须至少包含一个(a-z)字符。
当通过API创建一个对象时,必须指定一个Name字符串(一个DNS_SUBDOMAIN
)。名称必须是非空的,并且在 apiserver 中是唯一的。这可以实现幂等和空间唯一的创建操作。系统的某些部分(如副本控制器)可以连接字符串(如基本名称和随机后缀)来创建一个唯一的Name。对于生成名字不切实际的情况,一些或所有对象可以支持一个参数来自动生成名字。生成随机的名字会破坏同位素。
例子。“guestbook.user”, “backend-x4eb1”
当一个对象通过API被创建时,可以指定一个命名空间字符串(DNS_LABEL
)。根据API接收器,命名空间可能被验证(例如,apiserver可能确保命名空间实际存在)。如果没有指定命名空间,API接收器将分配一个命名空间。这种分配策略在不同的API接收器中可能有所不同(例如,apiserver可能有一个默认值,kubelet可能会生成一些半随机的东西)。
例如。“api.k8s.example.com”
在通过API接受一个对象时,该对象被分配了一个UID(一个UUID)。UID必须是非空的,并且是跨空间和时间的唯一。
例如。“01234567-89ab-cdef-0123-456789abcdef”
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/labels/
标签(Labels) 是附加到 Kubernetes 对象(比如 Pod)上的键值对。
标签旨在用于指定对用户有意义且相关的对象的标识属性,但不直接对核心系统有语义含义。 标签可以用于组织和选择对象的子集。标签可以在创建时附加到对象,随后可以随时添加和修改。 每个对象都可以定义一组键/值标签。每个键对于给定对象必须是唯一的。
标签能够支持高效的查询和监听操作,对于用户界面和命令行是很理想的。 应使用注解记录非识别信息。
标签使用户能够以松散耦合的方式将他们自己的组织结构映射到系统对象,而无需客户端存储这些映射。
与名称和 UID 不同, 标签不支持唯一性。通常,我们希望许多对象携带相同的标签。
通过标签选择算符,客户端/用户可以识别一组对象。标签选择算符是 Kubernetes 中的核心分组原语。
API 目前支持两种类型的选择算符:基于等值的和基于集合的。 标签选择算符可以由逗号分隔的多个需求组成。 在多个需求的情况下,必须满足所有要求,因此逗号分隔符充当逻辑与(&&
)运算符。
基于等值或基于不等值的需求允许按标签键和值进行过滤。 匹配对象必须满足所有指定的标签约束,尽管它们也可能具有其他标签。 可接受的运算符有 =
、==
和 !=
三种。
基于集合的标签需求允许你通过一组值来过滤键。 支持三种操作符:in
、notin
和 exists
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/namespaces/
在 Kubernetes 中,名字空间(Namespace) 提供一种机制,将同一集群中的资源划分为相互隔离的组。
名字空间适用于存在很多跨多个团队或项目的用户的场景。对于只有几到几十个用户的集群,根本不需要创建或考虑名字空间。当需要名字空间提供的功能时,请开始使用它们。
名字空间为名称提供了一个范围。资源的名称需要在名字空间内是唯一的,但不能跨名字空间。 名字空间不能相互嵌套,每个 Kubernetes 资源只能在一个名字空间中。
不必使用多个名字空间来分隔仅仅轻微不同的资源,例如同一软件的不同版本: 应该使用标签 来区分同一名字空间中的不同资源。
Kubernetes 会创建四个初始名字空间:
default
没有指明使用其它名字空间的对象所使用的默认名字空间kube-system
Kubernetes 系统创建对象所使用的名字空间kube-public
这个名字空间是自动创建的,所有用户(包括未经过身份验证的用户)都可以读取它。 这个名字空间主要用于集群使用,以防某些资源在整个集群中应该是可见和可读的。 这个名字空间的公共方面只是一种约定,而不是要求。kube-node-lease
此名字空间用于与各个节点相关的 租约(Lease)对象。 节点租期允许 kubelet 发送心跳,由此控制面能够检测到节点故障。你可以永久保存名字空间,以用于对应上下文中所有后续 kubectl 命令。
kubectl config set-context --current --namespace=<名字空间名称>
# 验证
kubectl config view --minify | grep namespace:
笔记:这个功能很实用,有时长期使用一个命名空间,每次输入 -n xxxx 好烦。
大多数 kubernetes 资源(例如 Pod、Service、副本控制器等)都位于某些名字空间中。 但是名字空间资源本身并不在名字空间中。而且底层资源, 例如节点和持久化卷不属于任何名字空间。
查看哪些 Kubernetes 资源在名字空间中,哪些不在名字空间中:
# 位于名字空间中的资源
kubectl api-resources --namespaced=true
# 不在名字空间中的资源
kubectl api-resources --namespaced=false
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/annotations/
你可以使用 Kubernetes 注解为对象附加任意的非标识的元数据。
你可以使用标签或注解将元数据附加到 Kubernetes 对象。
标签可以用来选择对象和查找满足某些条件的对象集合。
相反,注解不用于标识和选择对象。
注解中的元数据,可以很小,也可以很大,可以是结构化的,也可以是非结构化的,能够包含标签不允许的字符。
注解和标签一样,是键/值对:
"metadata": {
"annotations": {
"key1" : "value1",
"key2" : "value2"
}
}
说明: Map 中的键和值必须是字符串。 换句话说,你不能使用数字、布尔值、列表或其他类型的键或值。
注解(Annotations) 存储的形式是键/值对。有效的注解键分为两部分: 可选的前缀和名称,以斜杠(/
)分隔。 名称段是必需项,并且必须在 63 个字符以内,以字母数字字符([a-z0-9A-Z]
)开头和结尾, 并允许使用破折号(-
),下划线(_
),点(.
)和字母数字。 前缀是可选的。如果指定,则前缀必须是 DNS 子域:一系列由点(.
)分隔的 DNS 标签, 总计不超过 253 个字符,后跟斜杠(/
)。 如果省略前缀,则假定注解键对用户是私有的。 由系统组件添加的注解 (例如,kube-scheduler
,kube-controller-manager
,kube-apiserver
,kubectl
或其他第三方组件),必须为终端用户添加注解前缀。
kubernetes.io/
和 k8s.io/
前缀是为 Kubernetes 核心组件保留的。
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/field-selectors/
kubectl
命令将筛选出 status.phase
字段值为 Running
的所有 Pod:
kubectl get pods --field-selector status.phase=Running
说明: 字段选择器本质上是资源“过滤器(Filters)”。默认情况下,字段选择器/过滤器是未被应用的, 这意味着指定类型的所有资源都会被筛选出来。 这使得以下的两个 kubectl
查询是等价的:
kubectl get pods
kubectl get pods --field-selector ""
同标签和其他选择器一样, 字段选择器可以通过使用逗号分隔的列表组成一个选择链。 下面这个 kubectl
命令将筛选 status.phase
字段不等于 Running
同时 spec.restartPolicy
字段等于 Always
的所有 Pod:
kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always
你能够跨多种资源类型来使用字段选择器。 下面这个 kubectl
命令将筛选出所有不在 default
命名空间中的 StatefulSet 和 Service:
kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
笔记:原来还能这么用,汗,之前不知道,我都是一个一个查的。
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/finalizers/
TBD: 稍后再看。
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/owners-dependents/
在 Kubernetes 中,一些对象是其他对象的“属主(Owner)”。 例如,ReplicaSet 是一组 Pod 的属主。 具有属主的对象是属主的“附属(Dependent)”。
属主关系不同于一些资源使用的标签和选择算符机制。 例如,有一个创建 EndpointSlice 对象的 Service, 该 Service 使用标签来让控制平面确定,哪些 EndpointSlice 对象属于该 Service。 除开标签,每个代表 Service 所管理的 EndpointSlice 都有一个属主引用。 属主引用避免 Kubernetes 的不同部分干扰到不受它们控制的对象。
附属对象有一个 metadata.ownerReferences
字段,用于引用其属主对象。 一个有效的属主引用,包含与附属对象同在一个命名空间下的对象名称和一个 UID。 Kubernetes 自动为一些对象的附属资源设置属主引用的值, 这些对象包含 ReplicaSet、DaemonSet、Deployment、Job、CronJob、ReplicationController 等。 你也可以通过改变这个字段的值,来手动配置这些关系。 然而,通常不需要这么做,你可以让 Kubernetes 自动管理附属关系。
附属对象还有一个 ownerReferences.blockOwnerDeletion
字段,该字段使用布尔值, 用于控制特定的附属对象是否可以阻止垃圾收集删除其属主对象。 如果控制器(例如 Deployment 控制器) 设置了 metadata.ownerReferences
字段的值,Kubernetes 会自动设置 blockOwnerDeletion
的值为 true
。 你也可以手动设置 blockOwnerDeletion
字段的值,以控制哪些附属对象会阻止垃圾收集。
Kubernetes 准入控制器根据属主的删除权限控制用户访问,以便为附属资源更改此字段。 这种控制机制可防止未经授权的用户延迟属主对象的删除。
说明:
根据设计,kubernetes 不允许跨名字空间指定属主。 名字空间范围的附属可以指定集群范围的或者名字空间范围的属主。 名字空间范围的属主必须和该附属处于相同的名字空间。 如果名字空间范围的属主和附属不在相同的名字空间,那么该属主引用就会被认为是缺失的, 并且当附属的所有属主引用都被确认不再存在之后,该附属就会被删除。
dapr在创建 service 对象时,会同时创建 xxx 和 xxx-dapr 两个service,其中 xxx-dapr 就会有 ownerReferences 的设置,指向 xxx deployment:
apiVersion: v1
kind: Service
metadata:
labels:
dapr.io/enabled: "true"
name: service-a-dapr
namespace: dapr-tests
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: Deployment
name: service-a
uid: b7ffded5-c8ab-4316-a535-5d29a6ceae18 # 对应到 owner deployment 的 uid
xxx deployment 的内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
generation: 1
name: service-a
namespace: dapr-tests
uid: b7ffded5-c8ab-4316-a535-5d29a6ceae18
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/common-labels/
一组通用的标签可以让多个工具之间相互操作,用所有工具都能理解的通用方式描述对象。
除了支持工具外,推荐的标签还以一种可以查询的方式描述了应用程序。
共享标签和注解都使用同一个前缀:app.kubernetes.io
。没有前缀的标签是用户私有的。 共享前缀可以确保共享标签不会干扰用户自定义的标签。
在 Kubernetes 中,无论你的负载是由单个组件还是由多个一同工作的组件构成, 你都可以在一组 Pod 中运行它。 在 Kubernetes 中,Pod 代表的是集群上处于运行状态的一组 容器 的集合。
不过,为了减轻用户的使用负担,通常不需要用户直接管理每个 Pod。 而是使用负载资源来替用户管理一组 Pod。 这些负载资源通过配置 控制器 来确保正确类型的、处于运行状态的 Pod 个数是正确的,与用户所指定的状态相一致。
Kubernetes 提供若干种内置的工作负载资源:
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。
除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器。 你也可以在集群支持临时性容器的情况下, 为调试的目的注入临时性容器。
Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离方面, 即用来隔离容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。
Pod 类似于共享名字空间并共享文件系统卷的一组容器。
Pod 通常不是直接创建的,而是使用工作负载资源创建的。
Pod 被设计成支持形成内聚服务单元的多个协作过程(形式为容器)。 Pod 中的容器被自动安排到集群中的同一物理机或虚拟机上,并可以一起进行调度。 容器之间可以共享资源和依赖、彼此通信、协调何时以及何种方式终止自身。
Pod 天生地为其成员容器提供了两种共享资源:网络和存储。
Pod 使它的成员容器间能够进行数据共享和通信。
Pod 可以设置一组共享的存储卷。 Pod 中的所有容器都可以访问该共享卷,从而允许这些容器共享数据。
每个 Pod 都在每个地址族中获得一个唯一的 IP 地址。 Pod 中的每个容器共享网络名字空间,包括 IP 地址和网络端口。 Pod 内的容器可以使用 localhost
互相通信。 当 Pod 中的容器与 Pod 之外的实体通信时,它们必须协调如何使用共享的网络资源(例如端口)。
在同一个 Pod 内,所有容器共享一个 IP 地址和端口空间,并且可以通过 localhost
发现对方。 他们也能通过如 SystemV 信号量或 POSIX 共享内存这类标准的进程间通信方式互相通信。
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/
本页面讲述 Pod 的生命周期。 Pod 遵循预定义的生命周期,起始于 Pending
阶段, 如果至少其中有一个主要容器正常启动,则进入 Running
,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeeded
或者 Failed
阶段。
在 Kubernetes API 中,Pod 包含规约部分和实际状态部分。 Pod 对象的状态包含了一组 Pod 状况(Conditions)。 如果应用需要的话,你也可以向其中注入自定义的就绪态信息。
Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止。
Pod 也被认为是相对临时性(而不是长期存在)的实体。
Pod 会被创建、赋予一个唯一的 ID(UID), 并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。
Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单宏观概述。 该阶段并不是对容器或 Pod 状态的综合汇总,也不是为了成为完整的状态机。
Pod 阶段的数量和含义是严格定义的。
除了本文档中列举的内容外,不应该再假定 Pod 有其他的 phase
值。
取值 | 描述 |
---|---|
Pending (悬决) |
Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。 |
Running (运行中) |
Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。 |
Succeeded (成功) |
Pod 中的所有容器都已成功终止,并且不会再重启。 |
Failed (失败) |
Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。 |
Unknown (未知) |
因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。 |
说明: 当一个 Pod 被删除时,执行一些 kubectl 命令会展示这个 Pod 的状态为 Terminating
(终止)。 这个 Terminating
状态并不是 Pod 阶段之一。 Pod 被赋予一个可以体面终止的期限,默认为 30 秒。
笔记: Terminating 不是 pod 阶段之一。
容器的状态有三种:Waiting
(等待)、Running
(运行中)和 Terminated
(已终止)。
Waiting
(等待)如果容器并不处在 Running
或 Terminated
状态之一,它就处在 Waiting
状态。 处于 Waiting
状态的容器仍在运行它完成启动所需要的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl
来查询包含 Waiting
状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。
Running
(运行中)Running
状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart
回调,那么该回调已经执行且已完成。 如果你使用 kubectl
来查询包含 Running
状态的容器的 Pod 时, 你也会看到关于容器进入 Running
状态的信息。
Terminated
(已终止)处于 Terminated
状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 kubectl
来查询包含 Terminated
状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间。
如果容器配置了 preStop
回调,则该回调会在容器进入 Terminated
状态之前执行。
Pod 的 spec
中包含一个 restartPolicy
字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
restartPolicy
适用于 Pod 中的所有容器。restartPolicy
仅针对同一节点上 kubelet
的容器重启动作。当 Pod 中的容器退出时,kubelet
会按指数回退方式计算重启的延迟(10s、20s、40s、…),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet
对该容器的重启回退计时器执行重置操作。
Pod 有一个 PodStatus 对象
Kubelet 管理以下 PodCondition:
PodScheduled
:Pod 已经被调度到某节点;PodHasNetwork
:Pod 沙箱被成功创建并且配置了网络(Alpha 特性,必须被显式启用);ContainersReady
:Pod 中所有容器都已就绪;Initialized
:所有的 Init 容器都已成功完成;Ready
:Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。字段名称 | 描述 |
---|---|
type |
Pod 状况的名称 |
status |
表明该状况是否适用,可能的取值有 “True "、"False ” 或 “Unknown ” |
lastProbeTime |
上次探测 Pod 状况时的时间戳 |
lastTransitionTime |
Pod 上次从一种状态转换到另一种状态时的时间戳 |
reason |
机器可读的、驼峰编码(UpperCamelCase)的文字,表述上次状况变化的原因 |
message |
人类可读的消息,给出上次状态转换的详细信息 |
特性状态: Kubernetes v1.25 [alpha]
在 Pod 被调度到某节点后,它需要被 Kubelet 接受并且挂载所需的卷。 一旦这些阶段完成,Kubelet 将与容器运行时(使用容器运行时接口(Container Runtime Interface;CRI)) 一起为 Pod 生成运行时沙箱并配置网络。 如果启用了 PodHasNetworkCondition
特性门控, kubelet 会通过 Pod 的 status.conditions
字段中的 PodHasNetwork
状况来报告 Pod 是否达到了初始化里程碑。
https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/
你负责描述 Deployment 中的 目标状态,而 Deployment 控制器(Controller) 以受控速率更改实际状态, 使其变为期望状态。你可以定义 Deployment 以创建新的 ReplicaSet,或删除现有 Deployment, 并通过新的 Deployment 收养其资源。
https://kubernetes.io/zh-cn/docs/concepts/services-networking/
Kubernetes 强制要求所有网络设施都满足以下基本要求(从而排除了有意隔离网络的策略):
Kubernetes 的 IP 地址存在于 Pod
范围内 —— 容器共享它们的网络命名空间 —— 包括它们的 IP 地址和 MAC 地址。
Kubernetes 网络解决四方面的问题:
https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/
Service 是将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod 和一种可以访问它们的策略
定义 service 需要最基本的两个元素:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
小知识:Pod 中的端口定义是有名字的,可以在 Service 的
targetPort
属性中引用这些名称。这样可以只修改pod定义,service 这边就自动改过来了。
服务没有选择算符时,不会自动创建相应的 EndpointSlice(和旧版 Endpoint)对象。 可以通过手动添加 EndpointSlice 对象,将服务手动映射到运行该服务的网络地址和端口
Kubernetes ServiceTypes
允许指定你所需要的 Service 类型。
Type
的取值以及行为如下:
ClusterIP
:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是你没有为服务显式指定 type
时使用的默认值。NodePort
:通过每个节点上的 IP 和静态端口(NodePort
)暴露服务。 为了让节点端口可用,Kubernetes 设置了集群 IP 地址,这等同于你请求 type: ClusterIP
的服务。LoadBalancer
:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort
服务和 ClusterIP
服务上。ExternalName
:通过返回 CNAME
记录和对应值,可以将服务映射到 externalName
字段的内容(例如,foo.bar.example.com
)。 无需创建任何类型代理。特别注意: type
字段被设计为嵌套功能 - 每个级别都添加到前一个级别。
也可以使用 Ingress 来暴露自己的服务。
如果你将 type
字段设置为 NodePort
,则 Kubernetes 控制平面将在 --service-node-port-range
标志指定的范围内分配端口(默认值:30000-32767)。
如果需要特定的端口号,你可以在 nodePort
字段中指定一个值。
https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/
Ingress 是对集群中服务的外部访问进行管理的 API 对象
Ingress 暴露从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。
下面是一个将所有流量都发送到同一 Service 的简单 Ingress 示例:
Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开到 Internet 时,通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的 Service。