Kubernetes浅浅入门

个人学习记录文档,欢迎补充

前言

个人学习的浅显入门,供基础知识了解,会逐步补充该笔记。

可参考图形化界面在线演示网站kuboard,进行跟进学习。

云原生

云原生是一种构建和运行在云环境中的应用程序的方法论和技术栈。旨在充分利用云计算的优势,如弹性、可扩展性和高可用性,并支持快速迭代和部署。

云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。我们可以将云原生理解为以容器技术为载体、基于微服务架构思想的一套技术体系和方法论。

Kubernetes 是 CNCF 托管的第一个开源项目。因此现在提到云原生,往往我们都把它与kubernetes联系起来。

特征

云原生应用程序通常具有以下特征:

  1. 容器化:将应用程序及其依赖项打包为容器镜像,以实现环境一致性和轻量级部署。
  2. 微服务架构:将应用程序拆分为小而自治的服务单元,每个服务专注于特定的业务功能,并可以独立开发、测试、部署和扩展。
  3. 动态编排和自动化管理:使用容器编排工具(如Kubernetes)来自动化应用程序的部署、伸缩、容错和调度等管理操作。
  4. 持续交付和持续部署:通过自动化流水线和工具链,实现快速、可靠和频繁的软件交付和部署。

云原生技术栈包括容器技术(如Docker)、容器编排平台(如Kubernetes)、微服务框架(如Spring Cloud)、服务网格(如Istio)、持续交付工具(如Jenkins、GitLab)等。这些技术共同为构建和管理云原生应用程序提供了支持。

云原生的好处包括更高的灵活性、可伸缩性和可靠性,更快的交付速度和部署效率,以及更低的运维成本。它适用于各种规模的应用程序,从小型的单体应用到大规模的分布式系统。

部署策略

现在,使用面向服务的架构和微服务方式,开发者可以设计模块化的代码库。这允许他们同时在代码库中不同的地方编写和部署代变更。

然而现如今产品团队会选择更频繁的将产品发布到生产环境,导致数月或者数年的发布周期变得越来越短。

不过缩短部署周期的业务优势狠明显:

  • 缩短上市时间
  • 客户可以在更短的时间内获得产品价值
  • 客户的反馈也会更快的到达产品团队,这意味着团队可以更快的迭代特性和修复问题
  • 开发人员的整体士气会上升

所以为了应对这些挑战,应用和基础设施团队应该设计和采用适合的部署策略,有:

“大爆炸”部署
  • 这是一种传统的部署方式,其中新版本的软件会一次性全面替换旧版本。
  • 风险较高,因为如果新版本有问题,可能会影响所有用户。
  • 通常用于小型应用或在没有足够资源进行更复杂部署策略的情况下。
滚动部署
  • 在这种策略中,新版本的软件是逐步部署到服务器集群中的。
  • 每次只更新一部分服务器,确保始终有一部分服务器在运行旧版本,以保持服务的连续性。
  • 可以减少停机时间,但如果新版本有问题,可能需要回滚。
蓝绿部署
  • 蓝绿部署涉及同时维护两个生产环境,一个运行当前版本(蓝色),另一个准备新版本(绿色)。
  • 一旦新版本准备就绪,可以快速切换流量到新环境,从而减少停机时间。
红黑部署
  • 红黑部署是蓝绿部署的一个变种,通常用于分布式系统。
  • 它通过逐步将运行旧版本的单元(红色)替换为运行新版本的单元(黑色)来实现平滑过渡。
A/B 部署
  • A/B 测试是一种将用户随机分配到两个或多个不同版本的策略,用于测试新功能或更改的效果。
  • 它允许团队比较不同版本的性能,以确定哪个版本更优。
灰度发布/金丝雀发布
  • 金丝雀发布是一种渐进式的部署策略,其中一小部分用户(“金丝雀”)首先接收到新版本的软件。
  • 如果这部分用户没有遇到问题,新版本会逐步推广到更多用户。
  • 这种方法有助于及早发现并解决新版本中的问题,减少对所有用户的影响。

简介

Kubernetes 是一个开源的容器编排引擎和容器集群管理工具,用来对容器化应用进行自动化部署、 扩缩和管理。

它可以提供:

  • 服务发现和负载均衡

    Kubernetes 可以使用 DNS 名称或自己的 IP 地址来曝露容器。 如果进入容器的流量很大Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。

  • 存储编排

    允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等

  • 自动部署和回滚

    你可以使用 Kubernetes 描述已部署容器的所需状态, 它可以以受控的速率将实际状态更改为期望状态。 例如,你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。也可以是方便的实现金丝雀部署(canary deployment )。

  • 自动完成装箱计算

    为 Kubernetes 提供许多节点组成的集群,在这个集群上运行容器化的任务。 告诉 Kubernetes 每个容器需要多少 CPU 和内存 (RAM)。 Kubernetes 可以将这些容器按实际情况调度到你的节点上,以最佳方式利用你的资源。

  • 自我修复

    Kubernetes 将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端。

  • 密钥与配置管理

    Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。

前情提要

本地开发环境中搭建一个多节点的Kubernetes集群非常麻烦,如果你只想练手学习,你可以使用:

  • Minikube:它是一个可以本地运行的单机版kubernetes,方便我们学习Kubernetes和调试程序。

    安装Minikube需要使用Docker或虚拟机。推荐使用Docker。

    运行环境:

    • 至少2核
    • 内存不低于2GB
    • 硬盘空闲空间不低于20GB
    • 联网环境
    • Docker(或虚拟机)
  • K3s:它是一个轻量级的、完全兼容的 Kubernetes 发行版本。非常适合初学者。

    K3s将所有 Kubernetes 控制平面组件都封装在单个二进制文件和进程中,文件大小<100M,占用资源更小,且包含了kubernetes运行所需要的部分外部依赖和本地存储提供程序。

    K3s提供了离线安装包,安装起来非常方便,可以避免安装过程中遇到各种网络资源访问问题。

    K3s特别适用于边缘计算、物联网、嵌入式和ARM移动端场景。

    提示:

    K3s完全兼容Kubernetes,二者的操作是一样的,使用k3s完全满足我们学习Kubernetes的要求。

并且,我们需要个能与Kubernetes进行交互的工具。

kubectl 是一个 Kubernetes 生态系统中的客户端的命令行工具,用于与 Kubernetes API 服务器交互,执行各种集群管理任务,如部署应用、扩展服务、查看日志等。它提供了一种方便的方式来创建、配置和监控 Kubernetes 资源对象。

kubectl 是开发者和运维人员与 Kubernetes 集群交互的主要方式,但它本身不是运行在 Kubernetes 集群中的组件。

概念

概念部分帮助你了解 Kubernetes 系统的各个部分以及 Kubernetes 用来表示集群的抽象概念, 并帮助你更深入地理解 Kubernetes 是如何工作的。

对象

以下的对象和概念是 Kubernetes 集群的基础,它们共同构成了 Kubernetes 的生态系统,使得容器化应用程序的部署、管理和扩展变得更加容易和可靠

什么是对象

Kubernetes对象指的是Kubernetes系统的持久化实体,所有这些对象合起来,代表了你集群的实际情况,包括PodServiceDeploymentConfigMapSecret等资源类型。

一个Kubernetes对象代表着用户的一个意图,一旦您创建了一个Kubernetes对象,Kubernetes将持续工作,以尽量实现此用户的意图。通过创建对象,你本质上是在告知 Kubernetes 系统,你想要的集群工作负载状态看起来应是什么样子的, 这就是 Kubernetes 集群所谓的期望状态(Desired State)

常规的应用里,我们把应用程序的数据存储在数据库中,Kubernetes将该数据以Kubernetes对象的形式通过 api server存储在 etcd 中

在这些 应用程序的数据 / Kubernetes对象 中,描述了:

  • 哪些容器化应用正在运行(以及在哪些节点上运行)
  • 集群中对应用程序可用的资源
  • 关于应用运行时行为的策略,例如,重启策略、升级策略、容错策略
  • 其他Kubernetes管理应用程序时所需要的信息

对象规约(Spec)与状态(Status)

每一个 Kubernetes 对象都包含了两个重要的字段:

  • spec 必须在创建对象时设置其内容,描述你希望对象所具有的特征,即: 期望状态(Desired State)
  • status 描述了对象的当前状态(Current State),它是由 Kubernetes 系统和组件设置并更新的

在 Kubernetes 中,控制器(kube-controller-manager)是实现这种状态管理的关键组件,这些控制器通过 Kubernetes API 服务器获取当前资源的实际状态,并采取措施来纠正任何偏差,从而实现期望状态。

例如,Deployment 控制器会确保指定数量的 Pod 副本始终运行,而 Service 控制器会管理服务的端点和负载均衡。

目标状态 vs 当前状态

Kubernetes 使用了 云原生(cloud-native)的视角来看待系统,并且可以持续应对变化。您的集群在运行的过程中,任何时候都有可能发生突发事件,而控制器(kube-controller-manager)则自动地修正这些问题。这就意味着,本质上,您的集群永远不会达到一个稳定不变的状态。

这种通过控制器监控集群状态并利用负反馈原理不断接近目标状态的系统,相较于那种完成安装后就不再改变的系统,是一种更高级的系统形态,尤其是在您将运行一个大规模的复杂集群的情况下。

操作对象

操作 Kubernetes 对象,无论是创建、修改或者删除,都需要使用 Kubernetes API

而操作对象的工具kubectl ,能够支持三种对象管理方式:

  • 指令式命令,作用于单个对象

    用户将操作传给 kubectl 命令作为参数或标志。

    1
    kubectl create deployment nginx --image nginx
  • 指令式对象配置,作用于单个文件

    使用描述了k8s对象yaml文件来操作 Kubernetes 对象。

    1
    kubectl create -f nginx.yaml
  • 声明式对象配置,作用于文件目录

    支持对目录中的描述了k8s对象的文件进行操作,并自动检测每个文件的操作类型(增删改查)

    1
    2
    kubectl diff -f configs/
    kubectl apply -f configs/

关于每种对象管理的优缺点的讨论,可参见 Kubernetes 对象管理

核心资源对象

下面将进行初步的介绍,在初步了解他们的概念、定义和彼此之间的关联后,再进行深一步的学习。

Node(节点)

定义:是一个运行着Kubernetes节点软件的物理机器或虚拟机。

Node是Kubernetes集群中的工作节点,由Kubernetes控制平面管理,负责运行Pod中的容器并提供运行环境

提供的运行环境有:kubelet、kube-proxy、continer runtime。该部分详细内容见架构章节


Pod(容器组)

定义:是Kubernetes中最小的可调度单元,一个Pod就是一个或者多个应用容器的组合。

它创建了一个容器的运行环境,在这个环境中容器可以共享一些资源,比如网络、存储和运行时的一些配置等等。

Kubernetes为Pod提供分配了IP地址,但Pod并不是稳定的实体

它们非常容易被创建或者销毁,会导致IP地址会发生变化


Service / svc(服务)

定义:将一组运行相同应用程序的Pod封装成一个公开的网络服务,并为其提供相同的DNS名,该服务通过一个统一的入口来访问。

Service内部可以实现不同Pod之间的负载均衡。

当部署应用程序时,可能会创建多个Pod实例,每个实例都运行相同的应用程序。这些Pod可以被视为一组,因为它们提供相同的服务或功能。

Service通过标签选择器(Label Selector)来识别它应该管理哪些Pod。标签选择器是一组标签规则,用于匹配Pod的标签。只有匹配这些标签的Pod才会被视为Service的一部分。

通过服务的 IP 地址访问数据库(有点像路由器和反向代理),即使Pod的 IP 地址发生了变化,Service的 IP 地址也不会发生变化,Service会自动将请求转发到其它健康的Pod上。


Ingress / ing(入口)

定义:管理从 集群外部 访问 集群内部服务 的入口和方式,将外部请求路由到集群内部的Service

可以通过Ingress配置不同的转发规则,从而根据不同的规则来访问不同的Service以及Service所对应的Pod

  1. URL路由规则配置
  2. 负载均衡、流量分割、流量限制

还可以通过Ingress来配置域名,这样就可以从集群外部使用域名和访问Service

  1. HTTPS配置

  2. 基于名字的虚拟托管(NBVH)

允许在单个Ingress资源中定义多个不同的域名(hostnames),每个域名都指向不同的服务


ConfigMap / cm(配置映射)

定义:将配置信息以键值对的形式明文封装,注入到Pod的环境变量或挂载到文件系统中,在应用程序中读取和使用。

当数据库的地址和端口发生变化的时候,只需要修改ConfigMap对象中的配置信息,*然后重新加载Pod*,不需要重新编译和部署应用程序


Secret(密钥)

定义:将配置信息以键值对的形式密文封装,用于封装敏感信息。

可以使用ConfigMap来存储应用程序的非敏感配置,同时使用Secret来存储敏感配置。

配合使用来管理应用程序的不同配置需求。


Volume / vol(卷)

定义:将一些持久化存储的资源挂载到集群中的本地磁盘上,或者挂载到集群外部的远程存储上(比如 OSS)

卷是独立于容器之外的一块存储区域,通过挂载(Mount)的方式供Pod中的容器使用。

实现了数据的持久化存储,避免随着Pod的销毁/重启导致其中的数据也跟着消失。

卷还分为临时卷、持久卷、投射卷,其中大有文章。该部分详细内容见卷章节


Namespace / ns(命名空间)

定义:是一种资源隔离机制, 将同一集群中的资源划分为相互隔离的组, 以便进行分类、 筛选和管理。

同一命名空间内的资源名称要唯一,但跨命名空间时没有这个要求。

  • 命名空间作用域仅针对带有名字空间的对象,例如DeploymentService等。

  • 这种作用域对集群访问的对象不适用,例如StorageClassNodePersistentVolume等。

Kubernetes 会创建四个初始命名空间:

  • default:默认的命名空间,不可删除,未指定命名空间的对象都会被分配到default中。

  • kube-system:Kubernetes 系统对象(控制平面和Node组件)所使用的命名空间。

  • kube-public:自动创建的公共命名空间,所有用户(包括未经过身份验证的用户)都可以读取它。

    通常我们约定,将整个集群中公用的可见和可读的资源放在这个空间中。

  • kube-node-lease租约(Lease)对象使用的命名空间。每个节点都有一个关联的 lease 对象,lease 是一种轻量级资源。lease对象通过发送心跳,检测集群中的每个节点是否发生故障。


Endpoint / ep

定义:存储在etcd中, 用来记录一个Service对应的所有Pod的访问地址。

Service配置selector, Endpoint Controller端点控制器才会自动创建对应的Endpoint对象;

控制器

Deployment / deploy(部署)

定义:管理无状态应用Pod的部署和扩缩。

将一个或者多个Pod组合在一起,简化应用程序的部署和更新操作,还可以副本控制(多副本)、自动扩缩容、滚动升级/更新等

无状态应用:指在任何时候,应用实例之间没有持久化数据存储,每个实例都是独立且相同的。该应用不依赖于特定的服务器或环境状态,可以自由地在任何服务器上运行和迁移。

例如:Web 服务器、RESTful API 服务等。

DeploymentPod之间还有一个中间层ReplicaSet,用来管理Pod的副本数量

  • ReplicaSet / rs(副本集):用来管理运行Pod的副本数量,确保任何时间都有指定数量的Pod副本在运行
    1. ReplicaSet并不用我们手动创建,而是通过Deployment来完成各种配置和管理
    2. ReplicaSet使用标签选择器(Label Selector)来识别和管理Pod。只有匹配特定标签的Pod才会被ReplicaSet管理。

StatefulSet / sts(有状态应用集)

定义:管理有状态应用Pod的部署和扩缩

功能与Deployment类似,并且它还保证了每个副本都有自己稳定的网络标识符和持久化存储。

有状态应用:指应用实例需要持久化数据存储,每个实例可能维护特定的状态信息。

例如:数据库系统、具有用户会话状态的 Web 应用、消息队列、分布式缓存系统等。

特殊情况:Redis 是一个内存中的数据结构存储,用作数据库、缓存或消息代理。Redis 的数据通常存储在内存中,而不是持久化存储中。这意味着如果 Redis 服务重启或Pod重新调度,存储在内存中的数据可能会丢失。

即使使用 StatefulSet 部署 Redis,如果数据仅存储在 Redis 的内存中,而不是持久化存储中,那么在Pod重启或重新调度时,数据仍然会丢失。这是因为StatefulSet只能保证存储卷的持久性,而不能保证应用程序数据的持久性。数据持久性需要应用程序本身支持持久化,例如通过将数据写入磁盘或使用持久化存储机制。

对于这些不需要 Kubernetes 管理的有状态应用,或者需要特殊处理以确保数据持久性的应用程序,更加通用和简单的方式是选择在集群外单独部署。这样可以避免 Kubernetes 集群的复杂性,并允许使用专门的存储解决方案和运维策略来管理这些应用。


DaemonSet / ds

定义:确保全部(或者某些)节点上运行一个Pod的副本。

当有节点加入集群时, 也会为他们新增一个Pod

当有节点从集群移除时, 这些Pod也会被回收。

删除DaemonSet将会删除它创建的所有Pod

架构

Kubernetes 是典型的 Master-Worker 架构, Master Node 负责管理整个集群,Worker Node 负责运行应用程序和服务。

一个Kubernetes集群至少包含一个控制平面(control plane),以及一个或多个工作节点(worker node)。

  • 控制平面(Control Plane) : 控制平面负责管理工作节点和维护集群状态。所有任务分配都来自于控制平面。

    控制平面包含了很多组件,见下

  • 工作节点(Worker Node) : 工作节点负责执行控制平面分配的请求任务,运行实际的应用和工作负载。

    为了对外提供服务,每个 Node 上都会包含三个组件,kubelet、kube-proxy 和 container runtime。

核心组件

按照如上架构,可以归类为 控制平面 和 工作节点 的组件。

Kubernetes有:kube-apiserver、kube-scheduler、kube-controller-manager、etcd、kubelet、kube-proxy等组件。

image-20240825183347410

kube-apiserver / api(API 服务器)

定义:处理所有来自用户、内部组件和外部工具的 RESTful 请求,包括资源的增删改查操作。

apiserver就像一个集群的网关,是整个系统的入口,所有的请求都会先经过它,再由它分发给不同的组件进行处理。

除了提供 API 接口之外,apiserver 还负责对所有对象的增删改查等操作进行认证、授权和访问控制。

apiserver 接收到请求时会先验证请求的合法性,验证通过之后才会将请求转发给 Scheduler 处理。


kube-scheduler / sched(调度器)

定义:负责监控集群中所有节点的资源使用情况,然后根据调度策略将Pod调度到合适的节点上运行。

会考虑容器集的资源需求(例如 CPU 或内存)以及集群的运行状况。

调度器会试图优化集群资源的利用,确保资源不会过度集中,同时也考虑到应用程序的性能和可靠性需求。

调度策略:比如新增一个新Pod时,将Pod调度到空闲资源最多的节点上


kube-controller-manager / c-m(控制器管理器)

定义:负责管理和调整集群中各种对象(如NodePodService)的状态,运行在主节点上。

它通过 Kubernetes API 服务器获取当前状态,并根据这些状态信息执行操作,以确保集群的实际状态符合用户的期望状态。

它实际运行集群,它包括多个不同的控制器,有:

  • 节点控制器(Node Controller):负责在节点出现故障时进行通知和响应
  • 任务控制器(Job Controller):监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成
  • 端点控制器(Endpoints Controller):填充端点(Endpoints)对象(即加入ServicePod
  • 服务帐户和令牌控制器(Service Account & Token Controllers):为新的命名空间创建默认帐户和 API 访问令牌

该控制器管理器将多个控制器功能合而为一,降低了程序的复杂性


etcd

定义:高可用键-值存储系统,用于存储配置数据和集群状态信息,用作 Kubernetes 所有集群数据的后台数据库。

每新增或者崩掉一个Pod,这些信息都会被记录到 etcd 中,使用命令行查询集群状态时就是通过 etcd 来获取的。

etcd 一般只存储集群中应用程序的状态信息,不存储应用程序的数据


kubelet

定义:运行在每个节点上的 “节点代理”,负责管理和维护每个节点上的容器和Pod,确保它们按照预期运行。

kubelet 在集群中每个节点node上运行,基于 PodSpec 来工作。每个 PodSpec 是一个描述 Pod 的 YAML 或 JSON 对象。

kubelet 接受通过各种机制(主要是通过 apiserver)提供的一组 PodSpec,并确保这些 PodSpec 中描述的容器处于运行状态且运行状况良好。

它保证了容器都运行在Pod中,并且会定期从 apiserver 组件接收新的或者修改后的Pod规范,同时会监控工作节点的运行情况,然后将信息汇报给 apiserver。

  • kube-controller-manager 负责集群级别的控制逻辑和资源管理

  • kubelet 负责节点级别的容器和 Pod 管理

它们共同工作,确保 Kubernetes 集群的正常运行和资源的高效调度。kube-controller-manager 通过 API 服务器获取集群状态信息并做出全局决策,而 kubelet 则在每个节点上执行这些决策,确保容器和 Pod 按照预期运行。


kube-proxy / k-proxy(网络代理)

定义:负责为Pod对象提供网络代理和负载均衡服务。

可以维护节点网络规则和转发流量,实现从集群内部或外部的网络与Pod进行网络通信


cloud-controller-manager / c-c-m

定义:云控制器管理器,允许你将你的集群连接到云提供商的 API 之上, 并将与该云平台交互的组件同与你的集群交互的组件分离开来。

可选组件,如果在自己的环境中运行 Kubernetes,或者在本地计算机中运行学习环境, 所部署的集群不需要有云控制器管理器。


container runtime

定义:负责运行容器的软件。

负责拉取容器镜像、创建容器、启动或者停止容器等等,所有的容器都需要通过 container runtime 来运行,所以每个节点上都需要安装 container runtime。

Kubernetes支持许多容器运行环境,例如 containerd、docker或者其他实现了 Kubernetes CRI (容器运行环境接口)的容器。

由于kubernetes从V1.24版本开始默认使用containerd,需要修改containerd的配置文件,才能让Pod的镜像使用镜像加速器。

配置文件路径一般为/etc/containerd/config.toml,详见阿里云镜像加速

核心组件与对象之间的关联

了解完Kubernetes的核心组件和资源对象后可以发现,组件和资源对象之间存在许多关联性。

这里大致对组件与资源对象的强弱关联进行整理分类一下,这种分类并不是绝对的,集群中的许多组件和资源对象之间存在复杂的交互。

以下是控制平面组件与资源对象的关联:

  1. kube-apiserver
    • 直接关联资源对象:所有 Kubernetes 资源对象,因为它是 API 服务器,处理所有资源对象的 CRUD 操作。
    • 包括 ConfigMapSecret,都通过 kube-apiserver 进行 CRUD 操作(创建、读取、更新、删除)
  2. kube-scheduler
    • 直接关联资源对象:Pod
    • 调度器负责将Pod分配到合适的节点上。
  3. kube-controller-manager
    • 直接关联资源对象:NodePodDeploymentReplicaSetServiceEndpointNamespace
    • 控制器管理器运行多个控制器,每个控制器负责特定的资源对象。
  4. etcd
    • 直接关联资源对象:所有 Kubernetes 资源对象,包括 ConfigMapSecret
    • etcd 作为 Kubernetes 的键值存储,存储集群状态。
  5. kubelet
    • 直接关联资源对象:PodNode
    • kubelet 负责管理节点上的容器Pod
  6. kube-proxy
    • 直接关联资源对象:ServiceEndpoint
    • kube-proxy 负责实现 Kubernetes 服务的网络代理。

容器运行时接口(CRI)

我们知道了Kubelet是运行在每个节点Node上,用于管理和维护Pod容器的状态。当你需要在集群中的每个节点上都有一个可以正常工作的容器运行时, kubelet 会启动 Pod 及其容器。

而容器运行时接口(CRI)是 kubelet容器运行时之间通信的主要协议。它将Kubelet与容器运行时解耦,理论上,实现了CRI接口的容器引擎,都可以作为 Kubernetes 的容器运行时。

Kubernetes 容器运行时接口(Container Runtime Interface;CRI)定义了主要 gRPC 协议, 用于节点组件 kubelet容器运行时之间的通信。

CRI 是一个插件接口,这个接口允许 Kubernetes 与不同的容器运行时(如 Docker、containerd、CRI-O 等)进行交互,而无需对 Kubernetes 的核心组件进行修改或重新编译。CRIctl命令用于镜像的发布导出等操作,该命令与docker的功能非常相似。

  • 解耦合:容器运行时与 Kubernetes 核心组件(如 kubelet)之间的通信是通过 CRI 接口进行的。这意味着,如果你想要更换或升级容器运行时,你不需要修改 Kubernetes 核心代码或重新编译它。这种解耦合使得 Kubernetes 能够更容易地支持多种容器运行时。
  • 维护和升级:当需要对容器运行时进行维护或升级时,你可以独立于 Kubernetes 核心组件进行。这减少了系统更新的复杂性,并允许更快地采用新的容器运行时特性。
  • 兼容性:CRI 确保了不同容器运行时与 Kubernetes 的兼容性,即使它们的内部实现可能不同。这样,Kubernetes 用户可以选择最适合他们需求的容器运行时,而不必担心与 Kubernetes 的兼容性问题。

工作负载

在了解了基本的名词概念之后,本文会介绍他们的功能

Pod

概述

Pod是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

它是一组(一个或多个)容器; 这些容器共享存储、网络、以及如何运行这些容器的规约。

Pod的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和其他的隔离资源。 在Pod的上下文中,每个独立的应用可能会进一步实施隔离。

Pod模板

控制器通常使用 Pod模板(Pod Template) 来替我们创建Pod并管理它们。

创建Pod时,我们可以在 Pod模板 中定义Pod中运行容器的环境变量。

文档:环境变量

Pod模板和描述 Kubernetes 对象的 YAML 文件是相关但不同的概念:

  • Pod模板是定义在 Kubernetes 控制器对象中的一个部分,用于指导控制器如何创建和管理 Pod。

  • 而描述 Kubernetes 对象的 YAML 文件是一个完整的配置文件,可以包含 Pod模板以及其他 Kubernetes 对象的定义。

Pod存储

一个Pod可以设置一组共享的存储卷。Pod中的所有容器都可以访问该共享卷,从而允许这些容器共享数据。

卷还允许Pod中的持久数据保留下来,即使其中的容器需要重新启动。

Pod网络

  • 每个Pod都在每个地址族中获得一个唯一的 IP 地址。

  • Pod中的每个容器共享网络名字空间,包括 IP 地址和网络端口。

  • Pod内的容器可以使用 localhost 互相通信。

  • Pod中的容器与 Pod 之外的实体通信时,它们会协调如何使用共享的网络资源(例如端口)。

在同一个Pod内,所有容器共享一个 IP 地址和端口空间,并且可以通过 localhost 发现对方。 他们也能通过如 SystemV 信号量或 POSIX 共享内存这类标准的进程间通信方式互相通信。

不同Pod中的容器的 IP 地址互不相同,如果没有特殊配置,就无法通过 OS 级 IPC 进行通信。 如果某容器希望与运行于其他Pod中的容器通信,可以通过 IP 联网的方式实现。

控制器

Pod是 Kubernetes 中最小的调度单元,但它本身并不能自愈。如果一个 Pod 所在的 Node (节点)出现故障,或者调度程序自身出现故障,Pod 将被删除;同理,当因为节点资源不够或节点维护而驱逐 Pod 时,Pod 也将被删除。

所以,我们应该始终通过创建 控制器 来创建Pod,而不是直接创建Pod

控制器可以提供如下特性:

  • 水平扩展(运行 Pod 的多个副本)

  • rollout(版本更新)

  • self-healing(故障恢复)

    例如:当一个节点出现故障,控制器可以自动地在另一个节点调度一个配置完全一样的 Pod,以替换故障节点上的 Pod。

Deployments

Deployment 是最常用的用于部署无状态服务的方式。Deployment 控制器使得我们能够以声明的方式更新 Pod(容器组)和 ReplicaSet(副本集)。

下面简单的描述一下Deployments的配置示例,对于详细场景下的用例请看:官方文档国内参考文档

创建一个管理了 3 个 Nginx 服务的 Pod 副本,每个 Pod 都运行 Nginx 镜像 1.14.2 并监听端口 80。通过标签 app: nginx,Deployment 能够识别和管理这些 Pod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1  # 指定 Kubernetes API 的版本
kind: Deployment # 定义资源类型为 Deployment
metadata: # 包含了资源的元数据,如名称、标签、注解等。
name: nginx-deployment # 为 Deployment 指定名称
labels: # 定义标签
app: nginx # 标识属于同一应用的资源
spec: # 定义期望的状态
replicas: 3 # 指定 Deployment 应维护的 Pod 副本数量
selector: # 定义选择器,用于识别属于该 Deployment 的 Pod
matchLabels:
app: nginx # 选择器匹配具有相同标签的 Pod
template: # 定义 Pod 模板
metadata:
labels:
app: nginx # Pod 模板的标签,确保 Pod 能被 Deployment 选择器匹配
spec: # 定义期望的状态
containers:
- name: nginx # 定义容器名称
image: nginx:1.14.2 # 指定容器使用的镜像及其版本
ports:
- containerPort: 80 # 定义容器内部应该暴露的端口

StatefulSet

StatefulSet 是用来管理有状态应用的工作负载 API 对象。它对于需要满足以下一个或多个需求的应用程序很有价值:

  • 稳定、唯一的网络标识(dnsname)
  • 每个Pod始终对应各自的存储路径(PersistantVolumeClaimTemplate)
  • 按顺序地增加副本、减少副本,并在减少副本时执行清理
  • 按顺序自动地执行滚动更新

下面简单的描述一下StatefulSet的配置示例,对于详细场景下的用例请看:官方文档国内参考文档

定义一个 StatefulSet,用于管理具有确定顺序和唯一网络标识的 Pod 副本集。每个 Pod 都运行 Nginx 镜像,并暴露 80 端口。此外,每个 Pod 都挂载一个名为 www 的存储卷,用于存储 Web 内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: apps/v1  # 指定 Kubernetes API 的版本
kind: StatefulSet # 定义资源类型为 StatefulSet
metadata:
name: web # 为 StatefulSet 指定名称
spec:
selector: # 定义选择器,用于识别属于该 StatefulSet 的 Pod
matchLabels:
app: nginx # 选择器匹配具有相同标签的 Pod
serviceName: "nginx" # 服务名称,StatefulSet 中的 Pod 通过这个服务名进行通信
replicas: 3 # 指定 StatefulSet 应维护的 Pod 副本数量,默认值是 1
minReadySeconds: 10 # Pod 就绪后至少等待的时间,用于健康检查,默认值是 0
template: # 定义 Pod 模板
metadata:
labels:
app: nginx # Pod 模板的标签,确保 Pod 能被 StatefulSet 选择器匹配
spec:
terminationGracePeriodSeconds: 10 # Pod 终止前的宽限期,用于优雅关闭
containers:
- name: nginx # 定义容器名称
image: registry.k8s.io/nginx-slim:0.24 # 指定容器使用的镜像及其版本
ports:
- containerPort: 80 # 定义容器内部应该暴露的端口
name: web # 端口名称
volumeMounts: # 定义卷挂载
- name: www # 卷名称
mountPath: /usr/share/nginx/html # 卷挂载在该容器内部的路径
volumeClaimTemplates: # 定义存储卷声明模板
- metadata:
name: www # 卷名称
spec:
accessModes: [ "ReadWriteOnce" ] # 卷的访问模式
storageClassName: "my-storage-class" # 存储类别
resources:
requests:
storage: 1Gi # 存储请求大小

DaemonSet

DaemonSet 控制器确保所有(或一部分)的节点都运行了一个指定的 Pod 副本。

  • 每当向集群中添加一个节点时,指定的 Pod 副本也将添加到该节点上
  • 当节点从集群中移除时,Pod 也就被垃圾回收了
  • 删除一个 DaemonSet 可以清理所有由其创建的 Pod

下面简单的描述一下StatefulSet的配置示例,对于详细场景下的用例请看:官方文档国内参考文档

定义一个 DaemonSet,用于在集群的每个节点上部署一个名为 fluentd-elasticsearch 的 Pod以日志收集。

Pod 内部运行一个名为 fluentd-elasticsearch 的容器,使用 fluent/fluentd-kubernetes-daemonset:v1.7.1-debian-syslog-1.0 镜像。

这个容器被配置为限制最多使用 200Mi 内存,并请求 100m CPU 和 200Mi 内存资源。它挂载了两个宿主机的目录:/var/log/var/lib/docker/containers,分别用于访问节点上的日志文件和 Docker 容器日志。

此外,为了避免在 master 节点上运行,配置了对应的容忍(toleration):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
apiVersion: apps/v1  # 指定 Kubernetes API 的版本
kind: DaemonSet # 定义资源类型为 DaemonSet,用于在每个节点上运行一个 Pod 的副本
metadata:
name: fluentd-elasticsearch # 为 DaemonSet 指定名称
namespace: kube-system # 指定 DaemonSet 所在的命名空间
labels:
k8s-app: fluentd-logging # 定义标签,用于标识属于同一应用的资源。与app类似
spec:
selector:
matchLabels:
name: fluentd-elasticsearch # 选择器匹配具有相同标签的 Pod
template:
metadata:
labels:
name: fluentd-elasticsearch # Pod 模板的标签,确保 Pod 能被 DaemonSet 选择器匹配
spec:
tolerations:
- key: node-role.kubernetes.io/master # 指定容忍的污点
effect: NoSchedule # 容忍效果,这里表示不在 master 节点上调度
containers:
- name: fluentd-elasticsearch # 定义容器名称
image: fluent/fluentd-kubernetes-daemonset:v1.7.1-debian-syslog-1.0 # 指定容器使用的镜像及其版本
resources:
limits:
memory: 200Mi # 容器内存使用上限
requests:
cpu: 100m # 容器 CPU 请求量
memory: 200Mi # 容器内存请求量
volumeMounts: # 定义卷挂载
- name: varlog # 卷名称
mountPath: /var/log # 卷挂载路径,容器内部的日志目录
- name: varlibdockercontainers # 卷名称
mountPath: /var/lib/docker/containers # 卷挂载路径,Docker 容器日志目录
readOnly: true # 挂载为只读
terminationGracePeriodSeconds: 30 # Pod 终止前的宽限期,用于优雅关闭
volumes: # 定义卷
- name: varlog # 卷名称
hostPath: # 使用宿主机上的路径作为卷
path: /var/log # 宿主机上的日志目录
- name: varlibdockercontainers # 卷名称
hostPath: # 使用宿主机上的路径作为卷
path: /var/lib/docker/containers # 宿主机上的 Docker 容器日志目录

管理Kubernetes工作负载对象

指令式管理/命令

使用指令式命令时,用户可以在集群中的活动对象上进行操作。用户将操作传给 kubectl 命令作为参数或标志。

创建(Create)

创建一个名为my-pod的 Pod,运行nginx镜像。

1
kubectl create pod my-pod --image=nginx
查看(Get)

列出当前命名空间下所有的 Pod。

1
kubectl get pods

配置项:

-f:指定一个包含 Kubernetes 对象定义的文件,用于创建资源。

1
kubectl create -f my-pod.yaml
更新(Update)

更新名为my-deployment的 Deployment,设置新的副本数为 4。

1
kubectl scale deployment my-deployment --replicas=4
删除(Delete)

删除名为my-pod的 Pod。

1
kubectl delete pod my-pod
编辑(Edit)

编辑名为my-service的 Service 资源。

1
kubectl edit service my-service
应用补丁(Apply Patch)

为名为my-deployment的 Deployment 应用 JSON 格式的补丁,更新镜像版本。

1
kubectl patch deployment my-deployment -p '{"spec":{"template":{"spec":{"containers":[{"name":"my-container","image":"nginx:1.17"}]}}}}'
描述(Describe)

描述名为my-pod的 Pod 的详细状态和相关信息。

1
kubectl describe pod my-pod

配置项:

--all-namespaces:显示所有命名空间的资源信息。

1
kubectl describe pods --all-namespaces
日志(Logs)

查看名为my-pod的 Pod 的容器日志。

1
kubectl logs my-pod

配置项:

--since:显示自某个时间点以来的日志。

1
kubectl logs my-pod --since=1h
端口转发(Port-forward)

将本地的 8080 端口转发到 Pod 的 80 端口。

1
kubectl port-forward my-pod 8080:80
集群信息(Cluster Info)

显示集群的相关信息。

1
kubectl cluster-info

声明式对象配置/配置文件

Kubernetes 使用 YAML 文件来描述 Kubernetes 对象,这些对象代表了集群状态的各个方面。

然而对象有很多类型,每种类型都有其特定的属性和配置选项,这些属性和配置选项在 YAML 文件中以标签(键值对)的形式出现。标签有很多,这使得通过YAML配置文件进行声明式对象配置难于调试并且出现异常时结果难以理解,这里将会简单描述一些常用的配置。

更多配置项见:Kubernetes API

Pod 配置项
字段 描述
apiVersion 指定使用的 Kubernetes API 版本。
kind 资源类型为 Pod。
metadata 包含 Pod 的元数据,如名称和标签。
spec 定义 Pod 的详细配置。
spec.containers 定义 Pod 中的容器列表。
spec.containers[].name 容器的名称。
spec.containers[].image 容器使用的 Docker 镜像。
spec.containers[].ports 定义容器的端口列表。
spec.containers[].ports[].containerPort 容器内部监听的端口号。
spec.volumes 定义 Pod 中的存储卷列表。
spec.volumes[].name 存储卷的名称。
spec.volumes[].mounts 定义存储卷的挂载点。
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1  # 指定 Kubernetes API 版本
kind: Pod # 资源类型为 Pod
metadata:
name: mypod # Pod 的名称
labels: # Pod 的标签
app: myapp
spec: # Pod 的规格
containers: # 容器列表
- name: mycontainer # 容器名称
image: myimage:latest # 容器镜像
ports: # 容器端口列表
- containerPort: 8080 # 容器内部端口
Deployment 配置项
字段 描述
apiVersion 指定使用的 Kubernetes API 版本。
kind 资源类型为 Deployment。
metadata 包含 Deployment 的元数据,如名称和标签。
spec 定义 Deployment 的详细配置。
spec.replicas 设置 Deployment 中 Pod 的期望副本数。
spec.selector 定义用于选择 Pod 的选择器。
spec.template 定义 Pod 模板,用于创建 Pod 实例。
spec.template.metadata Pod 模板的元数据,如标签。
spec.template.spec Pod 模板的规格和配置。
spec.template.spec.containers 定义 Pod 模板中的容器列表。
spec.template.spec.containers[].image 容器镜像。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1  # 指定 Kubernetes API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: mydeployment # Deployment 的名称
spec:
replicas: 3 # 期望的 Pod 副本数
selector: # 用于选择 Pod 的选择器
matchLabels:
app: myapp
template: # Pod 模板
metadata:
labels:
app: myapp
spec:
containers:
- name: mycontainer
image: myimage:latest
ports:
- containerPort: 8080
StatefulSet 配置项
字段 描述
apiVersion 指定使用的 Kubernetes API 版本。
kind 资源类型为 StatefulSet。
metadata 包含 StatefulSet 的元数据,如名称和标签。
spec 定义 StatefulSet 的详细配置。
spec.replicas 设置 StatefulSet 中 Pod 的期望副本数。
spec.selector 定义用于选择 Pod 的选择器。
spec.serviceName 定义 StatefulSet 中 Pod 通信的服务名称。
spec.template 定义 Pod 模板,用于创建 Pod 实例。
spec.template.spec Pod 模板的规格和配置。
spec.template.spec.containers 定义 Pod 模板中的容器列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1  # 指定 Kubernetes API 版本
kind: StatefulSet # 资源类型为 StatefulSet
metadata:
name: mystatefulset # StatefulSet 的名称
spec:
serviceName: "mystatefulset" # 服务名称,用于 StatefulSet 内部的网络通信
replicas: 3 # 期望的 Pod 副本数
selector: # 用于选择 Pod 的选择器
matchLabels:
app: myapp
template: # Pod 模板
metadata:
labels:
app: myapp
spec:
containers:
- name: mycontainer
image: myimage:latest
ports:
- containerPort: 8080
DaemonSet 配置项
字段 描述
apiVersion 指定使用的 Kubernetes API 版本。
kind 资源类型为 DaemonSet。
metadata 包含 DaemonSet 的元数据,如名称和标签。
spec 定义 DaemonSet 的详细配置。
spec.selector 定义用于选择 Pod 的选择器。
spec.template 定义 Pod 模板,用于在每个节点上创建 Pod 实例。
spec.template.metadata Pod 模板的元数据,如标签。
spec.template.spec Pod 模板的规格和配置。
spec.template.spec.tolerations 定义 Pod 可以容忍的节点污点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1  # 指定 Kubernetes API 版本
kind: DaemonSet # 资源类型为 DaemonSet
metadata:
name: mydaemonset # DaemonSet 的名称
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: mycontainer
image: myimage:latest
ports:
- containerPort: 8080
# 可以添加 tolerations 来控制 DaemonSet Pod 在哪些节点上运行
tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"

Kubernetes浅浅入门
https://www.fishingrodd.cn/2024/08/26/Kubernetes浅浅入门/
作者
FishingRod
发布于
2024年8月26日
更新于
2024年8月27日
许可协议