一、K8S的用武之地

今天,大型单体应用正被逐渐拆分成小的、可独立运行的组件,我们称之为微服务。微服务彼此之间解耦,所以它们可以被独立开发、部署、升级、伸缩。这使得我们可以对每一个微服务实现快速迭代,并且迭代的速度可以和市场需求变化的速度保持一致。

但是,随着部署组件的增多和数据中心的增长,配置、管理并保持系统的正常运行变得越来越困难。如果我们想要获得足够高的资源利用率并降低硬件成本,把组件部署在什么地方变得越来越难以决策。手动做所有的事情,显然不太可行。我们需要一些自动化的措施,包括自动调度、配置、监管和故障处理。这正是K8S的用武之地。

K8S抽象了数据中心的硬件基础设施,使得对外暴露的只是一个巨大的资源池。它让我们在部署和运行组件时,不用关注底层的服务器。使用K8S部署多组件应用时,它会为每个组件都选择一台合适的服务器,部署之后它能够保证每个组件可以轻易地发现其他组件,并彼此之间实现通信。

通过K8S部署应用程序时,你的集群包含多少节点都是一样的。集群规模不会造成什么差异性,额外的集群节点只是代表一些额外的可用来部署应用的资源。

二、K8S集群架构

一个K8S集群由多个节点组成,节点可分为两种类型:

主节点:负责管理和调度工作节点

工作节点:负责运行部署的应用程序,每台服务器都是一个工作节点(主节点除外)

API服务器:主节点和工作节点的通信媒介

Scheduler:负责调度应用(为应用的每个可部署组件分配一个工作节点)

Controller Manager:它执行集群级别的功能,如复制组件、持续跟踪工作节点、处理失败节点等。

etcd:持久化存储集群配置

容器运行时:Docker、Containerd、RTK或其他容器类型。

Kubelet:管理所在的节点的容器

Kube-Proxy:负责组件之间的负载均衡网络流量

三、容器的隔离机制

一个容器里运行的进程实际上运行在宿主机的操作系统上,就像所有其他进程一样(不像虚拟机,进程是运行在不同的操作系统上的)。但在容器里的进程仍然是和其他进程隔离的。对于容器内进程本身而言,就好像是在机器和操作系统上运行的唯一一个进程。

容器的隔离机制主要依靠 Linux 命名空间 namespace 和 Linux 控制组 cgroups。namespace 提供隔离视图(文件、进程、网络接口、主机名等),cgroups 限制进程可使用的资源(CPU、内存、网络带宽等)。

默认情况下,每个 Linux 系统最初仅有一个命名空间,所有系统资源都属于这一个命名空间,但是你能创建额外的命名空间,以及在它们之间组织资源。这就是容器的隔离机制。

四、K8S的最小单位 pod

一个 pod 由一个或一组紧密相关的容器组成,它们总是一起运行在同一个工作节点上。

每个 pod 就像是一个独立的逻辑机器,拥有自己的 IP,即使不同的 pod 运行在同一个工作节点,它们也是独立的。

前面我们讲到容器的隔离机制是通过 namespace 和 cgroup 来实现的,一个 pod 内的容器,或者说是容器组通常需要共享某些资源,K8S 通过配置 Docker 来让一个 pod 内的所有容器共享相同的 network 和 UTS 命名空间,这样它们都有相同的主机名和网络接口。但这也意味着在同一 pod 中的容器运行的多个进程不能绑定到相同的端口号,否则会导致端口冲突,这也表示着一个道理有共享就有冲突。

K8S 集群中的所有 pod 都在同一个共享网络地址空间中,每个 pod 都可以通过其他 pod 的 IP 地址来实现相互访问。

pod 的定义

已部署 pod 的 yaml 通常包含三个部分:

metadata:包括名称、命名空间、标签和关于该容器的其他信息

spec:包含 pod 内容的实际说明,例如 pod 的容器、卷和其他数据

status:包含运行中的 pod 的当前信息(创建新的 pod 不需要这一部分)

一个简单的 pod 定义 yaml:

五、pod 的创建和管理者

pod 并不是直接创建出来的,它是通过 ReplicatiionController、ReplicaSet 或 Deployment......等方式创建出来的。

ReplicaSet 是 ReplicationController 的升级版,ReplicaSet 在标签选择器上拥有更强大的选择功能。

但是 ReplicaSet 也很少使用,我们通常用更高级的资源对象 Deployment,它会创建 ReplicaSet 来创建和管理 pod。

当然还有一些其他资源对象如:DaemonSet、Job、CronJob.....等等。

六、服务

由于 pod 是动态的,为了高可用并且通常不是单节点,没有一个固定访问的 IP。前面提到过K8S拥有负载均衡和弹性伸缩的能力,它提供了服务这个资源对象。如果想要从集群外部访问 pod 的话,就需要借助 LoadBalancer 服务来访问,LoadBalancer 服务拥有一个不变的 IP,这样 pod 就可以自由的伸缩了。

服务有多种,LoadBalancer 服务相当于是对集群外部的,Service 是对集群内部的,主要目的就是使集群内部的其他 pod 可以访问当前这组 pod,集群外部是没法访问这个 IP的。

另外,服务并不是和 pod 直接相连的,相反,有一种资源介于两者之间,它就是 Endpoint 资源,Endpoint 资源就是暴露一个服务的 IP 地址和端口的列表。

如果创建不包含 pod 选择器的服务,K8S 将不会创建 Endpoint 资源(毕竟缺少选择器,不知道服务中包含哪些 pod),你可能会想为什么要用 Endpoint 资源,直接用选择器不行嘛。尽管在 spec 服务中定义了 pod 选择器,但在重定向传入连接时不会直接使用它。相反,选择器用于构建 IP 和端口列表,然后存储在 Endpoint 资源中。当客户端连接到服务时,服务代理选择这些 IP 和端口中的一个,并将连接重定向到该位置监听的服务器。另外,Endpoint 对象需要与服务具有相同的名称,并包含该服务的目标 IP 地址和端口列表。如果不是手动创建 Endpoint,Endpoint 对于开发者来说几乎是无感的。

前面说到的都是将服务暴露给集群内部(LoadBalancer除外),如果想将服务暴露给集群外部,可以将服务的类型设置为 NodePort,这样每个集群节点都会在节点上打开一个端口,然后将端口上收到的流量重定向到基础服务。

如图所示:

当然也可以将服务的类型设置为 LoadBalancer,它是 NodePort 类型的一种扩展,这使得服务可以通过一个专用的负载均衡器来访问,这是有 K8S 中正在运行的云基础设施提供的。负载均衡器将流量重定向到跨所有节点的节点端口,客户端通过负载均衡器的 IP 连接到服务。

如图所示:

还可以通过 Ingress 资源,这是一种完全不同的机制,通过一个 IP 地址公开多个服务。

七、标签、注解和命名空间

标签可用于组织 pod,也可组织所有其他的 K8S 资源。一个资源可以拥有多个标签,通常我们在创建资源的时候就会将标签附件到资源上,但也可以之后添加标签或修改标签。

标签是一个键值对,上面就是 creation_method 和 env 两个标签。另外,上面说了标签不仅用于组织 pod,还可以组织其他 K8S 资源,比如你的 pod 对硬件有特定要求,比如需要 GPU 等特殊资源,你还可以对节点打标签。让 pod 调度到拥有该标签的节点上。

除标签外,pod 和其它对象还可以包含注解。注解也是键值对,所以它们非常相似。但是注解不是用于保存标识信息而存在的,因为已经有标签了,注解主要用于工具使用。

标签是用于组织资源的,由于每个对象都可以拥有多个标签,因此这些对象组是可以重叠的,另外当在集群中工作时,如果没有明确指定标签选择器,我们总能看到所有对象。

但是,当你想将对象分割成完全独立且不重叠的组时,就需要用到命名空间了。这个命名空间和 Linux 命名空间不一样,这个仅为对象名称提供一个作用域。

八、健康检查

K8S 可以通过存活探针检查容器是否还在运行。可以为 pod 中的每个容器指定存活探针。如果探测失败,K8S 将定期执行探针并重新启动容器。

HTTP GET 探针:对给定的URL执行 GET 请求,如果探测器收到相应,并且状态码不代表错误,则探测成功。

TCP 套接字探针:尝试与容器指定端口建立 TCP 连接,如果连接建立成功,则探测成功。

Exec 探针:在容器内执行任意命令,并检查命令的退出状态码。如果状态码是 0,则探测成功。

九、ReplicationController、ReplicaSet、DaemonSet、Job、CronJob

ReplicationController 是一种 K8S 资源,可确保它的 pod 始终保持运行状态,如果 pod 因任何原因消失,则 ReplicationController 会注意到缺少了的 pod 并创建替代 pod。

ReplicationController 会持续监控正在运行的 pod 列表,并保 pod 的数目与期望相符,如果运行的 pod 太少则会创建新副本,否则会删除多余副本。

一个 ReplicationController 有三个主要部分:

Label Selector(标签选择器):确定 ReplicationController 作用域中有哪些 pod

Replica Count(副本个数):指定应运行的 pod 数量

Pod Template(pod 模板):用于创建新的 pod 副本

ReplicaSet 的行为和 ReplicationController 完全相同,但 pod 选择器的表达能力更强,可完全替代 ReplicationController。

DaemonSet 和 ReplicaSet 的区别是,它会在每个节点上都运行一个 pod,比如日志收集器和资源监控器就有这样的需求。

前面介绍的都是需要持续运行的 pod,如果你想要运行完成工作后就终止任务的情况就需要用到 Job。

Job 资源在创建时会立即运行 pod,但是更多的需求是定时执行,这就要用到 CronJob。

十、Ingress

为什么需要 Ingress,一个重要的原因是每个 LoadBalancer 服务都需要自己的负载均衡器,以及独有的公有 IP 地址,而 Ingress 只需要一个公网 IP 就能为许多服务提供访问。当客户端向 Ingress 发生 HTTP 请求时,Ingress 会根据请求的主机名和路径决定请求转发到的服务,如图所示:

十一、就绪探针

不知道你有没有考虑到这么一种情况,如果 pod 的标签与服务的 pod 选择器相匹配,那么 pod 就将作为服务的后端,请求就会被重定向到 pod 上,但是如果 pod 没有准备好,如何处理服务请求呢?

该 pod 可能需要时间来加载配置或数据,或者可能需要执行预热过程以防止第一个用请求时间太长影响用户体验。在这种情况下,不希望该 pod 立即开始接受请求,尤其是在运行的实例可以正确快速地处理请求的情况下。不要将请求转发到正在启动的 pod 中,直到完全准备就绪。

与前面介绍的存活探针类似,K8S 还允许为容器定义准备就绪探针,就绪探针也有三种类型:Exec 探针、HTTP GET 探针、TCP Socket 探针。

十二、Headless

上面我们已经知道服务可提供负载均衡的能力,将请求转发到随机的一个 pod 上,但是如果你想要让请求连接到所有的 pod,那该怎么办呢?

幸运的是,K8S 允许客户端通过 DNS 查找发现 pod IP。通常,当执行服务的 DNS 查找时,DNS 服务器会返回单个 IP---服务的集群 IP。但是如果告诉K8S 不需要为服务提供集群 IP(通过在服务 spec 中将 clusterIP 字段设置为 None 来完成此操作),则 DNS 服务器将返回 pod IP 而不是单个服务 IP。DNS 服务器不会返回单个 DNS 记录,而是会为该服务返回多个记录,每个记录指向当时支持该服务的单个 pod 的 IP。

将服务的 spec 中的 clusterIP 字段设置为 None 会使服务成为 headless 服务:

十三、卷

我们之前说过,pod 类似逻辑主机,在逻辑主机中运行的进程共享诸如 CPU、RAM、网络接口等资源,或许你会认为进程也能共享磁盘,那你就错了。pod 中的每个容器都有自己的独立文件系统,因为文件系统来自容器镜像。

K8S 中的卷是 pod 的一个组成部分,因此像容器一样在 pod 的规范中就定义了。它们不是独立的 K8S 对象,也不能单独创建或删除。 pod 中的所有容器都可以使用卷,但必须先将它挂载在每个需要访问它的容器中。在每个容器中,都可以在其文件系统的任意位置挂载卷。

假设有一个带有三个容器的 pod,一个容器运行了一个 web 服务器,该 web 服务器的 HTML 页面目录位于 /var/htdocs,并将站点访问日志存储到 /var/logs 目录中。第二个容器运行了一个代理来创建 HTML 文件,并将它们存放在 /var/html 中,第三个容器处理在 /var/logs 目录中找到的日志。每个容器都有一个明确的用途,但是每个容器单独使用就没多大用处了。但是如果将两个卷添加到 pod 中,并在三个容器的适当路径上挂载它们,就会创建一个完善的系统。

常见的卷有如下几种:

  • emptypDir:用于存储临时数据的简单空目录,卷的生命周期和 pod 相关联,所以当删除 pod 时,卷的内容就会丢失。
  • gitRepo:通过检出 git 仓库的内容来初始化卷,通过克隆 Git 仓库并在 pod 启动时拉取最新版本(创建容器之前)填充数据,缺点是不能和 repo 保持同步,每次将更改推送到 gitRepo时,需要删除 pod 才能更新。
  • hostPath:用于将目录从工作节点的文件系统挂载到 pod 中,hostPath 卷指向节点文件系统上的特定文件或目录,这表示着他和节点相关,另外他是持久性存储,因为 gitRepo 和 emptyDir 卷的内容会在 pod 被删除时被删除,而 hostPath 的内容则不会被删除。

1、emptyDir

2、gitRepo

3、hostPath

hostPath 虽然可用于持久化存储卷,但是使用的很少,通常使用其他云存储卷,例如 gce、aws 存储卷。

十四、ConfigMap 和 Secret

几乎所有的应用程序都需要配置信息,并且这些配置数据不应该被嵌入应用本身。通常传递配置选项给容器化应用程序的方法是环境变量、命令行参数、亦或者是通过 gitRepo 存储卷,但其实还有一种更好的方式,那就是 ConfigMap。

尽管绝大多数配置选项并未包含敏感信息,少量配置可能含有证书、私钥,以及其他需要保持安全的相似数据,这类型数据需要被特殊对待,这就需要用到 Secret。

应用配置的关键在于能够在多个环境中区分配置选项,将配置从应用程序源码中分离,可频繁变更配置值,而不用重新部署 pod。如果将 pod 定义描述看作是应用程序源码,显然需要将配置移除 pod 定义。

1、ConfigMap 定义

2、使用 ConfigMap

十五、Downward API

前面通过环境变量、或者 ConfigMap、Secret 卷向应用传递配置数据都是预先知道的。但是对于那些不能预先知道的数据,比如 pod 的 IP、主机名或者是 pod 自身的名称该怎么获取呢?此外对于那些已经在 pod 中定义的数据,比如 pod 的标签和注解又该如何获取呢?这些问题都可以使用 Downward API 解决。Downward API 允许我们通过环境变量或文件传递 pod 的元数据。Downward API 主要是将在 pod 的定义和状态中取得的数据作为环境变量和文件的值。

十六、Deployment

Deployment 是一种更高价资源,用于部署应用程序并以声明的方式升级应用,而不是通过 ReplicationController 或 ReplicaSet 进行部署,它们都被认为是更底层的概念。当创建一个 Deployment 时,ReplicatSet 资源也会随之创建。使用 Deployment 可以更容易的更新应用程序,因为可以直接定义单个 Deployment 资源所需达到的状态,并让 K8S 处理中间的状态。总之,部署应用程序使用 Deployment 就行了。

十七、Statefulset

我们之前使用 ReplicaSet 创建的 pod 都是共享一个持久卷:

那能不能通过一个 ReplicaSet 让多个 pod 副本都指定独立的持久卷声明呢,很明显这是做不到的,除非你先手动创建 pod,之后在创建 ReplicaSet 来管理它们,但是如果发生节点故障后,你还需要手动管理它们,所以这是不合适的。

由于每个副本都是独立有状态的,所以你先得创建多个持久卷声明,当创建 Statefulset 的时候,你就需要指定 pod 对应的持久卷。

十八、总结

K8S 的一些资源对象书中介绍的大概就这些了,上面只是一些简单的概念,具体还是需要看书和实操深入理解。

K8S in Action 读后感(概念简介)的更多相关文章

  1. 云原生 • Kubernetes 认识 k8s、k8s 架构、核心概念点介绍

    云原生 • Kubernetes 认识 k8s.k8s 架构.核心概念点介绍 一.Kubernetes 简介Kubernetes 简称 k8s,是支持云原生部署的一个平台,起源于谷歌.谷歌早在十几年之 ...

  2. 【Machine Learning】机器学习及其基础概念简介

    机器学习及其基础概念简介 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  3. java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)

    目前对于同步,仅仅介绍了一个关键字synchronized,可以用于保证线程同步的原子性.可见性.有序性 对于synchronized关键字,对于静态方法默认是以该类的class对象作为锁,对于实例方 ...

  4. Java多线程概念简介 多线程中篇(一)

    Java的线程与操作系统的线程   在线程的相关介绍中,有讲到“线程的实现”分为三种:内核支持,用户级以及两者混合.(这只是一种简要的分类) Java线程在JDK1.2之前,是用户线程实现的 而在JD ...

  5. 转:WebGL、Asm.js和WebAssembly概念简介

    WebGL.Asm.js和WebAssembly概念简介 转:http://www.techbrood.com/zh/news/webgl/webgl%E3%80%81asm_js%E5%92%8Cw ...

  6. 在k8s中的基本概念

    在k8s中的基本概念 一.Pod1. podk8s下最重要也最基本的概念,由一个根容器Pause和许多用户业务容器组成,是容器的载体. 2. pod的yaml定义格式及字段 apiVersion: v ...

  7. 进击的K8S:Kubernetes基础概念

    Kubernetes简介 Kubernetes简称K8S(因为k和s中间有8个字母),是一个开源的容器集群管理平台,基于Go语言编写. 使用K8S,将简化分布式系统上的容器应用部署,使得开发人员可以专 ...

  8. NSIS打包(一)常用概念简介

    1.NSIS简介 官网:http://sourceforge.net/projects/nsis/ 维基百科: http://zh.wikipedia.org/wiki/Nullsoft%E8%85% ...

  9. k8s 集群基本概念

    一.概述: kubernetes是google开源的容器集群管理系统,提供应用部署.维护.扩展机制等功能,利用kubernetes能方便管理跨集群运行容器化的应用,简称:k8s(k与s之间有8个字母) ...

  10. Kubernetes核心概念简介

    本文将会简单介绍Kubernetes的核心概念.因为这些定义可以在Kubernetes的文档中找到,所以文章也会避免用大段的枯燥的文字介绍.相反,我们会使用一些图表(其中一些是动画)和示例来解释这些概 ...

随机推荐

  1. 最简单的for循环语句

    前言 在前面的文章中,壹哥给大家讲解了顺序结构.分支结构,接下来我们就来学习Java里的循环结构.Java里的循环结构,可以通过while.do-while.for.foreach等方式进行实现,今天 ...

  2. 【LeetCode动态规划#02】图解不同路径I + II(首次涉及二维dp数组,)

    不同路径 力扣题目链接(opens new window) 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 "Start" ). 机器人每次只能向下或者向右移 ...

  3. 对一些常用RDD算子的总结

    虽然目前逐渐sql化,但是掌握 RDD 常用算子是做好 Spark 应用开发的基础,而数据转换类算子则是基础中的基础,因此学习这些算子还是很有必要的. 这篇博客主要参考Spark官方文档中RDD编程一 ...

  4. 一个bug重温对JRE和JDK的关系思考

    前几天做一个springboot项目时,导入的JAVA版本是17,然后后面想更贴近下企业中使用的JDK版本就改成了JDK 1,8,然后就编译错误,bug如下 java: java.lang.Unsup ...

  5. 为什么说 ICMP 协议是网络最强辅助

    大家好,我是风筝 轻解网络系列又来了.已有高清 PDF 版本可以离线阅读了,全册 65 页,如果有需要离线版的高清 PDF 可以直接下载. 今天咱们说说 ICMP 协议.ICMP 可谓是网络世界中的最 ...

  6. ABAP READ内表新老语法对比

    1.读取内表行新语法 740新语法中,对标READ,提出了新的语法,如下: 1.1.根据字段值查找 "-----------------------------@斌将军----------- ...

  7. ChatGPT与码农的机会

    之前一篇博客已经写了有关AI在博客编写方面的优势与对未来博客的编写方面的思考.这篇文档我继续分享一个我在开发中的一个案例和相关的感想. 事件还原 我发现ChatGPT也可以帮助我编写OData,于是我 ...

  8. nginx中的proxy_pass配置

    Nginx 是最常用的反向代理工具之一,一个指令 proxy_pass搞定反向代理,对于接口代理.负载均衡很是实用,但 proxy_pass指令后面的参数很有讲究,通常一个/都可能引发一个血案. 通常 ...

  9. STM32 HAL库学习 (3) 中断!

        中断在单片机开发中有着重中之重的地位.    中断即打断,实至CPU再执行当前程序时,由于系统出现了某种需要处理的紧急情况,CPU暂停正在执行的程序,转而去执行另一段特殊程序来处理的出现的紧急 ...

  10. broadcom Ethernet BCM57412 驱动更新记录(dkms方式)

    一 背景 现场Dell R740xd2机器使用网卡Broadcom 57412 10Gb SFP+,固件版本22.21.06.80.bnxt_en.ko内核模块是该网卡的驱动,我们默认的驱动版本为1. ...