1 相关概念
1.1 k8s各组件
1.1.1 控制平面组件(Control Plane Components)
- 控制平面的组件对集群做出全局决策(比如调度)
- 控制平面组件可以在集群中的任何节点上运行
1.1.1.1 kube-apiserver
- API 服务器是 Kubernetes 控制面的前端
- 水平伸缩相关
1.1.1.2 etcd
后台数据库
1.1.1.3 kube-scheduler
- 根据单个 Pod 和 Pod 集合的资源需求、硬件/软件/策略约束等因素进行调度决策。
- 决策把pod部署到那个node上
1.1.1.4 kube-controller-manager
从逻辑上讲,每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在一个进程中运行。
1.1.1.5 cloud-controller-manager
云控制器
1.1.2 Node组件
在每个节点上运行
1.1.2.1 kubelet
代理,保证容器应用都运行在pod中,确保容器运行状态健康。
1.1.2.2 kube-proxy
网络代理,与service相关。允许从集群内部或外部的网络会话与 Pod 进行网络通信
1.1.2.3 Container Runtime
容器运行环境,例如docker。
1.1.3 Addons(插件)
DNS
和Dashboard
以及Weave Scope
Dashboard 是一个 Kubernetes 的 Web 控制台界面。
Dashboard详细技巧参见这篇博客
Weave Scope
是一个图形化工具, 用于查看你的容器、Pod、服务等。请和一个 Weave Cloud
账号 一起使用, 或者自己运行 UI。
1.2 容器镜像
1.2.1 镜像拉取策略
imagePullPolicy:
IfNotPresent
只有当镜像在本地不存在时才会拉取。
Always
每当 kubelet 启动一个容器时,kubelet 会查询容器的镜像仓库, 将名称解析为一个镜像摘要。 如果 kubelet 有一个容器镜像,并且对应的摘要已在本地缓存,kubelet 就会使用其缓存的镜像; 否则,kubelet 就会使用解析后的摘要拉取镜像,并使用该镜像来启动容器。
Never
Kubelet 不会尝试获取镜像。如果镜像已经以某种方式存在本地, kubelet 会尝试启动容器;否则,会启动失败。 更多细节见提前拉取镜像。
如果想强制拉取镜像,可设为Always
策略。
1.2.2 私有镜像仓库
之前测试的时候需要把镜像资源预先拉取到本地才行,可能是因为私有仓库读取镜像时可能需要密钥
,可以通过配置节点向私有仓库进行身份验证解决。
1.2.3 容器
之前一直把容器和镜像等同,但其实容器包含镜像,还包括卷
。
1.2.4 Pod
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod (就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储
、网络
、以及怎样运行这些容器的声明。
一个pod中的多个镜像组成一个较为完整的项目服务,而不是之前混淆理解的几个pods组成一个完整服务。
Pod 在其生命周期
中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止。
容器重启策略
Pod 的 spec 中包含一个 restartPolicy
字段,其可能取值包括 Always
、OnFailure
和 Never
。默认值是 Always
。
restartPolicy 适用于 Pod 中的所有容器。restartPolicy 仅针对同一节点上 kubelet 的容器重启动作。当 Pod 中的容器退出时,kubelet 会按指数回退 方式计算重启的延迟(10s、20s、40s、…),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行 重置操作。
1.3 工作负载资源
1.3.1 Deployment
Deployment为Pod
和ReplicaSet
提供了一个声明式定义(declarative)方法。典型的应用场景包括:
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用,具体操作见官网。
- 扩容和缩容
- 暂停和继续Deployment
1.3.2 ReplicaSet
无状态服务
。
ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。即之前理解的自愈能力
,水平伸缩
。
通过Deployment来管理,不单独直接自定义。
1.3.3 StatefulSet
StatefulSet是为了解决有状态服务
的问题(对应Deployments和ReplicaSets
是为无状态服务而设计),其应用场景
包括:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
- 有序收缩,有序删除(即从N-1到0)
从上面的应用场景可以发现,StatefulSet由以下几个部分组成
:
- 用于定义网络标志(DNS domain)的Headless Service
- 用于创建PersistentVolumes的volumeClaimTemplates
- 定义具体应用的StatefulSet
注意事项
:
- 还在beta状态,需要kubernetes v1.5版本以上才支持
- 所有Pod的Volume必须使用PersistentVolume或者是管理员事先创建好
- 为了保证数据安全,删除StatefulSet时不会删除Volume StatefulSet需要一个Headless
- Service来定义DNS domain,需要在StatefulSet之前创建好 目前StatefulSet还没有feature
complete,比如更新操作还需要手动patch。
更新策略
:
OnDelete
当 StatefulSet 的 .spec.updateStrategy.type
设置为 OnDelete
时, 它的控制器将不会自动更新 StatefulSet 中的 Pod。 用户必须手动删除 Pod 以便让控制器创建新的 Pod,以此来对 StatefulSet 的 .spec.template
的变动作出反应。
RollingUpdate
RollingUpdate
更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。这是默认的更新策略。
1.3.4 DaemonSet
DaemonSet保证在每个Node上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。典型的应用包括:
-
日志收集,比如fluentd,logstash等
-
系统监控,比如Prometheus Node Exporter,collectd,New Relic agent,Ganglia gmond等
-
系统程序,比如kube-proxy, kube-dns, glusterd, ceph等
Note:被 DaemonSet 控制器创建的 Pod 能够容忍节点的不可调度属性。 DaemonSet 通常提供节点本地的服务,即使节点上的负载应用已经被腾空, 这些服务也仍需运行在节点之上。
1.3.5 Jobs
Job 会创建一个或者多个 Pods,并将继续重试 Pods 的执行,直到指定数量的 Pods 成功终止。 随着 Pods 成功结束,Job 跟踪记录成功完成的 Pods 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。
分布式训练好像比较适合这种形式,因为之前也看到很多这样处理的。
1.3.6 总结
- StatefulSet是有状态服务,区别于Deployment创建的ReplicaSet主要区别是持久化存储。
- Job需要后续深入了解,好像和分布式训练比较契合。
1.4 容器运行环境接口(CRI)
是 kubelet 和容器运行时之间通信的主要协议,通信相关。
2 API版本控制
不同的 API 版本代表着不同的稳定性和支持级别。
下面是每个级别的摘要:
-
Alpha:
- 版本名称包含 alpha(例如,v1alpha1)。
- 软件可能会有 Bug。启用某个特性可能会暴露出 Bug。 某些特性可能默认禁用。
- 对某个特性的支持可能会随时被删除,恕不另行通知。
- API 可能在以后的软件版本中以不兼容的方式更改,恕不另行通知。
- 由于缺陷风险增加和缺乏长期支持,建议该软件仅用于短期测试集群。
-
Beta:
-
版本名称包含 beta (例如, v2beta3)。
-
软件被很好的测试过。启用某个特性被认为是安全的。 特性默认开启。
-
尽管一些特性会发生细节上的变化,但它们将会被长期支持。
-
在随后的 Beta 版或稳定版中,对象的模式和(或)语义可能以不兼容的方式改变。 当这种情况发生时,将提供迁移说明。 模式更改可能需要删除、编辑和重建 API 对象。 编辑过程可能并不简单。 对于依赖此功能的应用程序,可能需要停机迁移。
-
该版本的软件不建议生产使用。 后续发布版本可能会有不兼容的变动。 如果你有多个集群可以独立升级,可以放宽这一限制。
Note: 请试用测试版特性时并提供反馈。特性完成 Beta 阶段测试后, 就可能不会有太多的变更了。
-
-
Stable:
- 版本名称如 vX,其中 X 为整数。
- 特性的稳定版本会出现在后续很多版本的发布软件中。
3 存储
3.1 卷(Volume)
Container 中的文件在磁盘上是临时存放的,这给 Container 中运行的较重要的应用程序带来一些问题。
- 问题之一是当容器崩溃时文件丢失。 kubelet 会重新启动容器,但容器会以干净的状态重启。
- 在同一 Pod 中运行多个容器并共享文件时会出现问题。
Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题。
相关知识:
- Kubernetes 支持很多类型的卷。临时卷、持久卷、投射卷、动态卷等。
- Pod 可以同时使用任意数目的卷类型。
- 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。
- 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁持久卷。 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
- 卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。
- 卷挂载在镜像中的指定路径下。 Pod 配置中的每个容器必须独立指定各个卷的挂载位置。
3.2 持久卷(Persistent Volume)
持久卷(Persistent Volume),简称PV,是集群中的资源
持久卷请求(PersistentVolumeClaim),简称PVC,是对PV资源的请求。
3.3 临时卷(Ephemeral Volume)
有些应用程序需要额外的存储,但并不关心数据在重启后仍然可用。 例如,缓存服务经常受限于内存大小,将不常用的数据转移到比内存慢、但对总体性能的影响很小的存储中。
另有些应用程序需要以文件形式注入的只读数据,比如配置数据或密钥。
临时卷就是为此类用例设计的。因为卷会遵从 Pod 的生命周期,与 Pod 一起创建和删除, 所以停止和重新启动 Pod 时,不会受持久卷在何处可用的限制。
临时卷的类型
:
- emptyDir: Pod 启动时为空,存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
- configMap、downwardAPI、 secret: 将不同类型的 Kubernetes 数据注入到 Pod 中
CSI 临时卷:类似于前面的卷类型,但由专门支持此特性 的指定 CSI 驱动程序提供通用临时卷: 它可以由所有支持持久卷的存储驱动程序提供
注:删除掉的不常见,暂不考虑
3.4 存储类(StorageClass)
好像挺关键的,但暂不了解。
4 配置
4.1 ConfigMap
ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。
-
Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
-
ConfigMap 将您的环境配置信息和 容器镜像 解耦,便于应用配置的修改。
Caution: ConfigMap 并不提供保密或者加密功能。 如果你想存储的数据是机密的,请使用 Secret, 或者使用其他第三方工具来保证你的数据的私密性,而不是用 ConfigMap。
4.2 Secret
Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。
Secret 类似于 ConfigMap 但专门用于保存机密数据。
4.3 Pod所需资源
CPU
和内存(RAM)
4.3.1 CPU 资源单位
CPU 资源的约束和请求以 “cpu” 为单位。 在 Kubernetes 中,一个 CPU 等于1 个物理 CPU 核 或者 一个虚拟核, 取决于节点是一台物理主机还是运行在某物理主机上的虚拟机。
你也可以表达带小数 CPU 的请求。 当你定义一个容器,将其 spec.containers[].resources.requests.cpu
设置为 0.5 时, 你所请求的 CPU 是你请求 1.0 CPU 时的一半。 对于 CPU 资源单位,数量 表达式 0.1 等价于表达式 100m,可以看作 “100 millicpu”。 有些人说成是“一百毫核”,其实说的是同样的事情。
4.3.2 内存资源单位
memory 的约束和请求以字节为单位。
E、P、T、G、M、k
5 调度
在 Kubernetes 中,调度 是指将 Pod 放置到合适的 Node 上,然后对应 Node 上的 Kubelet 才能够运行这些 pod。
kube-scheduler
调度流程
- 过滤。过滤阶段会将所有满足 Pod 调度需求的 Node 选出来。过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下, 这个 Node 列表包含不止一个 Node。如果这个列表是空的,代表这个 Pod 不可调度。
- 打分。打分阶段,调度器会为 Pod 从所有可调度节点中选取一个最合适的 Node。 根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。最后,kube-scheduler 会将 Pod 调度到得分最高的 Node 上。