【职场技术栈学习实录】Kubernetes 详解 (二)—— 核心概念篇

系列文章介绍

本系列是我作为一名后端开发,在日常工作中积累的技术学习与实践笔记。在这里,我将分享工作中后端开发领域的技术栈、架构设计、代码实现以及问题解决的经验与心得。出于保护公司隐私的原因,实际业务场景无法详细展开,但我会通过抽象化的需求和通用的技术问题,来介绍与探讨如何在实际工作中应用这些技术。



前言

K8S中有非常多的概念和专业术语,许多小伙伴上手会感觉知识点又多又杂,难以理解。我推荐的方式是,先学习理论知识,再去实操,再回来复习一遍理论知识,达到融汇贯通的境界。在这篇博客中,我会详细介绍K8S的核心概念和专业术语。

近些年我们正越来越多地听到一个概念——“云原生”,而Kubernetes(下文简称为K8S)作为云原生技术的核心组件之一,是现如今企业云原生系统的主流解决方案,也正在成为后端开发所必须要了解和使用的一项技术。现在实习公司的基础架构平台正是基于K8S所搭建的,为了更好上手公司业务,并拓展自己的技术深度与广度,特此开辟K8S专题技术博客,记录自己的所学、所想、所悟。


一、前置知识

在正式进入K8S核心概念前,需要先介绍两个前置知识。

1. 服务的分类

在讨论 Kubernetes(K8S)的核心概念前,我们需要明确服务可以划分为两类:

  1. 有状态服务(Stateful Services)
  2. 无状态服务(Stateless Services)

下面将详细说明这两类服务的特点,并通过列表和表格进行对比。

1.有状态服务(Stateful Services)

有状态服务需要维护上下文信息或状态,例如用户会话或数据更新记录,代表是MySQL与Tomcat。需要确保状态在服务实例间或持久存储中保持一致。它具有如下特点:

a.状态管理:每个请求可能依赖于先前的请求结果或上下文数据。
b.扩展难度较大:由于需要同步或共享状态,扩展时常常需要额外的协调机制。
c.数据一致性:对于数据一致性有较高要求,通常依赖于持久存储解决方案(如数据库)。

在这里插入图片描述
在K8S中,通常使用 StatefulSet 部署,借助持久卷(Persistent Volume)来管理和共享状态数据,以保证服务的正确运行。

2.无状态服务(Stateless Services)

无状态服务的核心特点是不依赖于内部或外部保存的状态,代表是Nginx与Tomcat。每次请求都是独立的,即使请求之间没有共享任何信息,服务依然能够正确响应。它具有如下特点:

a.独立性:每个请求都是独立处理,不依赖先前的交互历史。
b.扩展性:容易进行水平扩展,因为不需要在多个实例间同步状态。
c.容错性:单个实例出问题不会影响其他实例,重试生效率较高。

在这里插入图片描述
在K8S中,通常使用 Deployment 或 ReplicaSet 部署,实例之间是相互独立的。

2. 资源与对象

在 K8S 中,我们常说“一切皆资源”,而每个资源创建后就会生成一个“对象”。这种设计使得对集群中各个组件的管理更加统一和抽象。下面分别介绍两个概念。

1.资源(Resource)

资源指的是 Kubernetes API 中的一类实体,是对系统中各类对象类型的抽象描述。资源定义了一种操作接口的行为与规范,它不是具体的数据实例,而是定义了集群中能够管理的各种实体。每一种资源都在API中有统一的表示,例如Pod、Service、Deployment等。

个人理解中 ,可以将资源类比于面向对象编程的“类”,它定义了对象的蓝本。

2.对象(Object)

对象是根据资源类型创建出的实际实例,代表着集群中被持久存储和管理的具体数据单元。对象是用户提交资源相应资源配置后才生成的。每个对象都有唯一标识,作为集群实际运行和管理的单元。在K8S中,我们通过各类控制器对操作对象的创建、修改和删除。

个人理解中 ,可以将对象类比于面向对象编程的“实例”,它实现了资源这一蓝本。

3. 规约与状态

在 Kubernetes 中,每个资源对象除了包含其类型信息外,还由两个核心部分组成:规约(Spec)和状态(Status)。这两者在对象的描述中各有分工,共同帮助系统实现期望与现实之间的对齐。

1.规约(Spec)

规约是自愿的声明,描述了用户希望资源具备的配置和期望状态。比如在 Pod 的配置中,规约可能包括镜像名称、容器端口、环境变量等。它具有以下特点:

  1. 用户主观定义:由用户在配置文件中明确指定。
  2. 声明目标状态:它是不变的期望目标,由控制器作为依据来驱动实际状态的调整。
  3. 可更新性:用户可以在运行期间通过更新规约来调整应用行为,系统随之进行变更操作。

2.状态(Status)

状态(Status)是资源的反馈部分,反映了当前资源在集群中实际运行的情况。例如,Pod 的状态信息可能包含当前运行的副本数、错误信息、健康检查状况等。它具有以下特点:

  1. 自动更新:状态由 Kubernetes 控制器自动进行更新,展示实际运行情况。
  2. 实时反馈:它帮助用户和系统及时了解当前资源是否达到规约所定义的期望状态。
  3. 不由用户直接修改:通常状态信息只读,用户调整资源只需修改规约,后续状态会自动更新。

简而言之,规约是用户对资源的期望,而状态是资源的实际情况。


二、核心概念

核心概念主要是各类资源,资源可以分类为三种:元数据、集群、命名空间。

  1. 元数据资源可以跨集群使用,比如跨测试、预发、生产集群;
  2. 集群级资源可以跨命名空间使用;
  3. 命名空间级资源只能在自己的命名空间内使用。
    在这里插入图片描述

1. 元数据型

1. Horizontal Pod Autoscaler(HPA)

Pod 自动扩容:可以根据 CPU 使用率或自定义指标(metrics)自动对 Pod 进行扩/缩容。

  1. 控制管理器每隔30s(可以通过–horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况
  2. 支持三种metrics类型
    a. 预定义metrics(比如Pod的CPU)以利用率的方式计算
    b. 自定义的Pod metrics,以原始值(raw value)的方式计算
    c. 自定义的object metrics
  3. 支持两种metrics查询方式:Heapster和自定义的REST API
  4. 支持多metrics

例如,每日早上十点抢iphone,可以定义HPA,在每日十点扩容为五倍容量,时间过后自动缩容恢复。

2. PodTemplate

Pod Template 是关于 Pod 的定义,但是被包含在其他的 Kubernetes 对象中(例如 Deployment、StatefulSet、DaemonSet 等控制器)。控制器通过 Pod Template 信息来创建 Pod。
例如,如果两个 Pod 使用相同的Pod Template,那么他俩对象是相同。

3. LimitRange

可以对集群内 Request 和 Limits 的配置做一个全局的统一的限制,相当于批量设置了某一个范围内(某个命名空间)的 Pod 的资源使用限制。
例如,限定 Pod 初始资源为 1核 GPU, 2GB 内存。

2. 集群级

1. NameSpace

K8S 支持多个虚拟集群,它们底层依赖于同一个物理集群,这些虚拟集群被称为命名空间。作用是用于实现多团队/环境的资源隔离。命名空间 namespace 是 k8s 集群级别的资源,可以给不同的用户、租户、环境或项目创建对应的命名空间。

默认 namespace:

  1. kube-system 主要用于运行系统级资源,存放 k8s 自身的组件
  2. kube-public 此命名空间是自动创建的,并且可供所有用户(包括未经过身份验证的用户)读取。此命名空间主要用于集群使用,关联的一些资源在集群中是可见的并且可以公开读取。此命名空间的公共方面知识一个约定,但不是非要这么要求。
  3. default 未指定名称空间的资源就是 default,即你在创建pod 时如果没有指定 namespace,则会默认使用 default

2. Node

Node 不像其他的资源(如 Pod 和 Namespace),Node 本质上不是Kubernetes 来创建的,K8S 只是管理 Node 上的资源。虽然可以通过 Manifest 创建一个Node对象(如下 json 所示),但 Kubernetes 也只是去检查是否真的是有这么一个 Node,如果检查失败,也不会往上调度 Pod。

3. ClusterRole

ClusterRole 是一组权限的集合,但与命名空间的 Role 不同的是,ClusterRole 可以在包括所有 Namespace 和集群级别的资源或非资源类型进行鉴权。

4. ClusterRoleBinding

ClusterRoleBinding:ClusterRole 声明了权限组,但是应用到某一个集群之上,需要使用将ClusterRoleBinding,它可以将 Subject 绑定到 ClusterRole,ClusterRoleBinding 将使规则在所有命名空间中生效。

3. 命名空间级(极其重要!)

1. 工作负载型——Pod

K8S 官方对 Pod 定义:Pod(容器组)是 K8S 中最小的可部署单元。一个 Pod(容器组)包含了一个应用程序容器(某些情况下是多个容器)、存储资源、一个唯一的网络 IP 地址、以及一些确定容器该如何运行的选项。Pod 容器组代表了 K8S 中一个独立的应用程序运行实例,该实例可能由单个容器或者几个紧耦合在一起的容器组成。

Docker 是 K8S Pod 中使用最广泛的容器引擎;K8S Pod 同时也支持其他类型的容器引擎。

K8S 集群中的 Pod 存在如下两种使用途径:

  1. 一个 Pod 中只运行一个容器。“one-container-per-pod” 是 K8S 中最常见的使用方式。此时,您可以认为 Pod 容器组是该容器的 wrapper,Kubernetes 通过 Pod 管理容器,而不是直接管理容器。
  2. 一个 Pod 中运行多个需要互相协作的容器,可以将多个紧密耦合、共享资源且始终在一起运行的容器编排在同一个 Pod 中。

那么,为什么要使用Pod,而不是直接使用容器?
一图以解之,举两个案例说明。

  1. 我们希望部署的多个应用程序或服务,可以共享网络,传统的做法是通过–links,在etc.hosts加入本地域名的映射,这样操作麻烦且并不是真正的网络共享,还是通过服务间通信完成的。
  2. 我们希望部署的多个应用程序或服务,可以共享存储,比如说容器5写,容器4读,传统的做法是挂载在同一个文件夹下,这样需要我们对两个容器都去做操作,如果需要共享的容器比较多,需要每一个都进行操作,还是很麻烦。

Pod的出现完美解决了这两个问题,它使用了一个内置容器 pause,用它去提供了公共资源——共享网络、共享文件系统、内存等,本质上来说,它就是一个 wrapper+轻量化虚拟机

这与 Pod 的英文名含义非常接近,Pod 就是豌豆荚嘛,包裹着大大小小的“容器”豌豆~
在这里插入图片描述

1. 副本(replicas)

先引入“副本”的概念——一个 Pod 可以被复制成多份,每一份可被称之为一个“副本”,这些“副本”除了一些描述性的信息(Pod 的名字、uid 等)不一样以外,其它信息都是一样的,譬如 Pod 内部的容器、容器数量、容器里面运行的应用等的这些信息都是一样的,这些副本提供同样的功能。

Pod 的“控制器”通常包含一个名为 “replicas” 的属性。“replicas”属性则指定了特定 Pod 的副本的数量,当当前集群中该 Pod 的数量与该属性指定的值不一致时,k8s 会采取一些策略去使得当前状态满足配置的要求。

2. 控制器

当 Pod 被创建出来,Pod 会被调度到集群中的节点上运行,Pod 会在该节点上一直保持运行状态,直到进程终止、Pod 对象被删除、Pod 因节点资源不足而被驱逐或者节点失效为止。Pod 并不会自愈,当节点失效,或者调度 Pod 的这一操作失败了,Pod 就该被删除。如此,单单用 Pod 来部署应用,是不稳定不安全的。

Kubernetes 使用更高级的资源对象 “控制器” 来实现对Pod的管理。控制器可以为您创建和管理多个 Pod,管理副本和上线,并在集群范围内提供自修复能力。 例如,如果一个节点失败,控制器可以在不同的节点上调度一样的替身来自动替换 Pod。

1. 适用无状态服务(RC/RS/Deployment)
1.ReplicationController(RC)

Replication Controller 简称 RC,RC 是 Kubernetes 系统中的核心概念之一,简单来说,RC 可以保证在任意时间运行 Pod 的副本数量,能够保证 Pod 总是可用的。如果实际 Pod 数量比指定的多那就结束掉多余的,如果实际数量比指定的少就新启动一些Pod,当 Pod 失败、被删除或者挂掉后,RC 都会去自动创建新的 Pod 来保证副本数量,所以即使只有一个 Pod,我们也应该使用 RC 来管理我们的 Pod。可以说,通过 ReplicationController,Kubernetes 实现了 Pod 的高可用性。

不过在新版本的 K8S 中,因为 RS 的出现,我们主要使用的不是 RC 了。
在这里插入图片描述

2. ReplicaSet(RS)

RC (ReplicationController )主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数 。即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收(已经成为过去时),在 v1.11 版本废弃。

​Kubernetes 官方建议使用 RS(ReplicaSet ) 替代 RC (ReplicationController ) 进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector。
在这里插入图片描述

3. Deployment

实际工作中,我们既不会使用 RC ,也不会使用 RS,这主要是因为这两者只能帮助我们完成动态扩缩容。Deployment 对 RS 做了更高层次的封装,以及更丰富的部署相关功能。其功能如下:

  1. 创建 Replica Set / Pod
  2. 滚动升级/回滚
  3. 平滑扩容和缩容
  4. 暂停与恢复 Deployment
    在这里插入图片描述
    小 tips :
    滚动升级:RS1升级到RS2的过程中,每一步都只更新一个 Pod ,使得用户无感知条件下完成系统升级,时刻保证有一个服务可用。
    回滚:保留原有服务,假定RS2某个服务挂了,可以使用RS1中的服务进行替代。
    暂停:这里的暂停并不是指服务。经过亲测,暂停的是编排,而不是服务。
2. 适用有状态服务(StatefulSet)

有状态服务不同于无状态服务,有状态服务有两个问题。

  1. 换一个pod后,网络ip会变化
  2. 换一个pod后,数据会丢失

相比于无状态服务,接下来介绍的有状态服务—— StatefulSet 主要围绕解决这两个问题展开。

1. 主要特点
  1. 稳定的持久化存储: Pod 重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现
  2. 稳定的网络标志:稳定的网络标志,即 Pod 重新调度后其 PodName 和 HostName 不变,基于 Headless Service(即没有 Cluster IP 的 Service)来实现
  3. 有序部署,有序扩展:有序部署,有序扩展,即 Pod 是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从 0到 N-1,在下一个Pod 运行之前所有之前的 Pod 必须都是 Running 和 Ready 状态),基于 init containers 来实现
  4. 有序收缩,有序删除:有序收缩,有序删除(即从 N-1 到 0)
2. 组成
  1. Headless Service(解决网络问题):用于定义网络标志(DNS domain),将域名与 ip 绑定映射关系,即服务名 => 访问路径(域名) => ip
  2. volumeClaimTemplate(解决存储问题):用于创建 PersistentVolumes
3. 注意事项
  1. kubernetes v1.5 版本以上才支持
  2. 所有Pod的Volume必须使用PersistentVolume或者是管理员事先创建好
  3. 为了保证数据安全,删除StatefulSet时不会删除Volume
  4. StatefulSet 需要一个 Headless Service 来定义 DNS domain,需要在 StatefulSet 之前创建好

在这里插入图片描述

3. 守护进程(DaemonSet)

DaemonSet 保证在每个 Node 上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。典型的应用包括:

  1. 日志收集,比如 fluentd,logstash 等
  2. 系统监控,比如 Prometheus Node Exporter,collectd,New Relic agent,Ganglia gmond 等
  3. 系统程序,比如 kube-proxy, kube-dns, glusterd, ceph 等

如图,我们可以根据type进行匹配,当type=logs,便会自动部署日志收集程序,否则便不部署。
在这里插入图片描述

4. 任务/定时任务(Job / Cron Job)

任务(Job):一次性任务,运行完成后Pod销毁,不再重新启动新容器。

定时任务(Cron Job):在 Job 基础上加上了定时功能。

2. 服务发现(重要!)

1.Service

“Service” 简写 “svc”。Pod 不能直接提供给外网访问,而是应该使用 service。Service 就是把 Pod 暴露出来提供服务,Service 才是真正的“服务”,它的中文名就叫“服务”。

可以说 Service 是一个应用服务的抽象,定义了 Pod 逻辑集合和访问这个 Pod 集合的策略。Service 代理 Pod 集合,对外表现为一个访问入口,访问该入口的请求将经过负载均衡,转发到后端 Pod 中的容器。

简单来说,K8S 集群内部的网络通信就是通过 Service 暴露网络端口来实现,用互联网黑话说就是"东西流量"。

当两个容器进行"东西流量"通信时,可以为每一个容器都创立一个service,当容器A想向容器B进行通信,可以向serviceA发送一个信息,其中包含serviceB的端口号,这样serviceA便可以找到serviceB,进而转发到容器B。

在这里插入图片描述

2.Ingress

Ingress 可以提供外网访问 Service 的能力。可以把某个请求地址映射、路由到特定的 service。

ingress 需要配合 ingress controller 一起使用才能发挥作用,ingress 只是相当于路由规则的集合而已,真正实现路由功能的,是 Ingress Controller,ingress controller 和其它 k8s 组件一样,也是在 Pod 中运行。

简单来说,K8S 集群与外网的网络通信就是通过 Ingress 暴露网络端口来实现,用互联网黑话说就是"南北流量"。

3. 存储

3.1 Volume

数据卷,类似 Docker 的 Volume,共享 Pod 中容器使用的数据。用来放持久化的数据,比如数据库数据。

3.2 CSI

Container Storage Interface 是由来自 Kubernetes、Mesos、Docker 等社区成员联合制定的一个行业标准接口规范,旨在将任意存储系统暴露给容器化应用程序。

CSI 规范定义了存储提供商实现 CSI 兼容的 Volume Plugin 的最小操作集和部署建议。CSI 规范的主要焦点是声明 Volume Plugin 必须实现的接口。

4. 特殊类型配置

4.1 ConfigMap

用来放配置,与 Secret 是类似的,只是 ConfigMap 放的是明文的数据,Secret 是密文存放。

4.2 Secret

Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用。

Secret 有三种类型:

  1. Service Account:用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中;
  2. Opaque:base64 编码格式的 Secret,用来存储密码、密钥等;
  3. kubernetes.io/dockerconfigjson:用来存储私有 docker registry 的认证信息。
4.3 DownwardAPI

downwardAPI 这个模式和其他模式不一样的地方在于它不是为了存放容器的数据也不是用来进行容器和宿主机的数据交换的,而是让 pod 里的容器能够直接获取到这个 pod 对象本身的一些信息。

downwardAPI 提供了两种方式用于将 pod 的信息注入到容器内部:

  1. 环境变量:用于单个变量,可以将 pod 信息和容器信息直接注入容器内部
  2. volume 挂载:将 pod 信息生成为文件,直接挂载到容器内部中去

5. 其他

4.1 Role

Role 是一组权限的集合,例如 Role 可以包含列出 Pod 权限及列出 Deployment 权限,Role 用于给某个 Namespace 中的资源进行鉴权。

4.2 RoleBinding

RoleBinding :将 Subject 绑定到 Role,RoleBinding 使规则在命名空间内生效。


下一期预告:Kubernetes 实战进阶

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值