云原生
【整理总结自 CNCF × Alibaba 云原生技术公开课】
【非全部内容】
【图片看不到,可以去gitee上看】
文章目录
相关定义和概念
云原生为用户指定了一条低心智负担的、敏捷的、能够以可扩展、可复制的方式最大化地利用云的能力、发挥云的价值的最佳路径。云原生其实是一套指导进行软件架构设计的思想。按照这样的思想而设计出来的软件:首先,天然就“生在云上,长在云上”;其次,能够最大化地发挥云的能力,使得我们开发的软件和“云”能够天然地集成在一起,发挥出“云”的最大价值。
技术范畴
- 第一部分是云应用定义与开发流程。这包括应用定义与镜像制作、配置 CI/CD、消息和 Streaming 以及数据库等。
- 第二部分是云应用的编排与管理流程。这也是 Kubernetes 比较关注的一部分,包括了应用编排与调度、服务发现治理、远程调用、API 网关以及 Service Mesh。
- 第三部分是监控与可观测性。这部分所强调的是云上应用如何进行监控、日志收集、Tracing 以及在云上如何实现破坏性测试,也就是混沌工程的概念。
- 第四部分就是云原生的底层技术,比如容器运行时、云原生存储技术、云原生网络技术等。
- 第五部分是云原生工具集,在前面的这些核心技术点之上,还有很多配套的生态或者周边的工具需要使用,比如流程自动化与配置管理、容器镜像仓库、云原生安全技术以及云端密码管理等。
- 最后则是 Serverless。Serverless 是一种 PaaS 的特殊形态,它定义了一种更为“极端抽象”的应用编写方式,包含了 FaaS 和 BaaS 这样的概念。而无论是 FaaS 还是 BaaS,其最为典型的特点就是按实际使用计费(Pay as you go),因此 Serverless 计费也是重要的知识和概念。
两个理论
- 第一个理论基础是:不可变基础设施。这一点目前是通过容器镜像来实现的,其含义就是应用的基础设施应该是不可变的,是一个自包含、自描述可以完全在不同环境中迁移的东西;
- 第二个理论基础就是:云应用编排理论。当前的实现方式就是 Google 所提出来的“容器设计模式”,这也是本系列课程中的 Kubernetes 部分所需主要讲解的内容。
云原生关键技术点
- 如何构建自包含、可定制的应用镜像;
- 能不能实现应用快速部署与隔离能力;
- 应用基础设施创建和销毁的自动化管理;
- 可复制的管控系统和支撑组件
容器
进程间隔离
操作系统中进程有自己的特点:
- 进程可以相互看到并通信–》高级权限的进程可以攻击其他进程
- 进程使用同一个文件系统–》高级权限进程对其他进程数据进行增删改查,破环其正常运行;此外进程与进程之间依赖容易产生冲突
- 进程会使用相同的资源–》进程与进程之间会存在资源抢占的问题
解决办法:提供一个独立的运行环境
- chroot:将子目录变成根目录,达到视图级别的隔离;进程在 chroot 的帮助下可以具有独立的文件系统,对于这样的文件系统进行增删改查不会影响到其他进程
- namespace:实现进程在资源的视图上进行隔离,不让进程相互看见
- Cgroup :来限制其资源使用率,设置其能够使用的 CPU 以及内存量
namespace
-
mout namespace。mout namespace 就是保证容器看到的文件系统的视图,是容器镜像提供的一个文件系统,也就是说它看不见宿主机上的其他文件,除了通过 -v 参数 bound 的那种模式,是可以把宿主机上面的一些目录和文件,让它在容器里面可见的。
-
uts namespace,这个 namespace 主要是隔离了 hostname 和 domain。
-
pid namespace,这个 namespace 是保证了容器的 init 进程是以 1 号进程来启动的。
-
network namespace,除了容器用 host 网络这种模式之外,其他所有的网络模式都有一个自己的 network namespace 的文件。
-
user namespace,这个 namespace 是控制用户 UID 和 GID 在容器内部和宿主机上的一个映射,不过这个 namespace 用的比较少。
-
IPC namespace,这个 namespace 是控制了进程间通信的一些东西,比方说信号量。
-
cgroup namespace,用 cgroup namespace 带来的一个好处是容器中看到的 cgroup 视图是以根的形式来呈现的,这样的话就和宿主机上面进程看到的 cgroup namespace 的一个视图方式是相同的。另外一个好处是让容器内部使用 cgroup 会变得更安全。
Cgroup(以docker为例)
- cgroup 主要是做资源限制的,docker 容器有两种 cgroup 驱动:一种是 systemd 的,另外一种是 cgroupfs 的。
- cgroupfs 比较好理解。比如说要限制内存是多少,要用 CPU share 为多少,其实直接把 pid 写入对应的一个 cgroup 文件,然后把对应需要限制的资源也写入相应的 memory cgroup 文件和 CPU 的 cgroup 文件就可以了。
- 因为 systemd 本身可以提供一个 cgroup 管理方式,写 cgroup 操作都必须通过 systemd 的接口来完成,不能手动更改 cgroup 的文件
- docker 常用cgroup
- CPU,CPU 一般会去设置 cpu share 和 cupset,控制 CPU 的使用率
- memory,是控制进程内存的使用量。
- device ,device 控制了你可以在容器中看到的 device 设备。
- freezer。它和第三个 cgroup(device)都是为了安全的。当你停止容器的时候,freezer 会把当前的进程全部都写入 cgroup,然后把所有的进程都冻结掉,这样做的目的是,防止你在停止的时候,有进程会去做 fork,防止进程逃逸到宿主机上面去,是为安全考虑。
- blkio,blkio 主要是限制容器用到的磁盘的一些 IOPS(每秒读操作次数) 还有 bps(每秒读取块设备的数据量) 的速率限制。因为 cgroup 不唯一的话,blkio 只能限制同步 io,docker io 是没办法限制的
- pid, 限制的是容器里面可以用到的最大进程数量
镜像
容器具有一个独立的文件系统,因为使用的是系统的资源,所以在独立的文件系统内不需要具备内核相关的代码或者工具,我们只需要提供容器所需的二进制文件、配置文件以及依赖即可,这些容器运行时所需要的所有的文件集合称之为容器镜像。
构建容器镜像
通常情况下,我们会采用 Dockerfile 来构建镜像,这是因为 Dockerfile 提供了非常便利的语法糖,能够帮助我们很好地描述构建的每个步骤,每个构建步骤都会对已有的文件系统进行操作,这样就会带来文件系统内容的变化,我们将这些变化称之为 changeset。
changeset 的分层以及复用特点能够带来几点优势:
-
第一,能够提高分发效率,对于大的镜像而言,如果将其拆分成各个小块就能够提高镜像的分发效率,这是因为镜像拆分之后就可以并行下载这些数据;
-
第二,因为这些数据是相互共享的,也就意味着当本地存储上包含了一些数据的时候,只需要下载本地没有的数据即可,举个简单的例子就是 golang 镜像是基于 alpine 镜像进行构建的,当本地已经具有了 alpine 镜像之后,在下载 golang 镜像的时候只需要下载本地 alpine 镜像中没有的部分即可;
-
第三,因为镜像数据是共享的,因此可以节约大量的磁盘空间,简单设想一下,当本地存储具有了 alpine 镜像和 golang 镜像,在没有复用的能力之前,alpine 镜像具有 5M 大小,golang 镜像有 300M 大小,因此就会占用 305M 空间;而当具有了复用能力之后,只需要 300M 空间即可。
如下图所示的 Dockerfile 适用于描述如何构建 golang 应用的。
如图所示:
- FROM 行表示以下的构建步骤基于什么镜像进行构建,正如前面所提到的,镜像是可以复用的;
- WORKDIR 行表示会把接下来的构建步骤都在哪一个相应的具体目录下进行,其起到的作用类似于 Shell 里面的 cd;
- COPY 行表示的是可以将宿主机上的文件拷贝到容器镜像内;
- RUN 行表示在具体的文件系统内执行相应的动作。当我们运行完毕之后就可以得到一个应用了;
- CMD 行表示使用镜像时的默认程序名字
docker Images
- docker 镜像是基于联合文件系统的。联合文件系统:它允许文件是存放在不同的层级上面的,但是最终是可以通过一个统一的视图,看到这些层级上面的所有文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lH6CZJlG-1623207610981)(云原生.assets/image-20210607112239877.png)]
- docker 镜像的存储,它的底层是基于不同的文件系统的,所以它的存储驱动也是针对不同的文件系统作为定制的,比如 AUFS、btrfs、devicemapper 还有 overlay。docker 对这些文件系统做了一些相对应的一个 graph driver 的驱动,也就是通过这些驱动把镜像存在磁盘上面。
- 存储流程 overlay为例
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C88oZo3R-1623207610982)(云原生.assets/image-20210607112403069.png)]
- lower 层,也就是镜像层,它是一个只读层
- upper 层,容器的读写层,采用了写时复制的机制,也就是说只有对某些文件需要进行修改的时候才会从 lower 层把这个文件拷贝上来,之后所有的修改操作都会对 upper 层的副本进行修改
- workdir,它的作用是充当一个中间层的作用。当对 upper 层里面的副本进行修改时,会先放到 workdir,然后再从 workdir 移到 upper 里面去。
- mergedir,是一个统一视图层。从 mergedir 里面可以看到 upper 和 lower 中所有数据的整合,然后我们 docker exec 到容器里面,看到一个文件系统其实就是 mergedir 统一视图层
- 文件操作 overlay为例
- 读,如果 upper 层没有副本,数据都是从 lower 层上读取
- 写,容器刚创建时,upper 层为控,只有对文件进行写操作时,才会从 lower 层拷贝文件上来,对副本进行操作
- 删,overlay 里面其实是没有真正的删除操作的。它所谓的删除其实是通过对文件进行标记,然后从最上层的统一视图层去看,看到这个文件如果做标记,认为这个文件是被删掉的,就不会让这个文件显示出来。
容器生命周期
容器的生命周期和 initial 进程的生命周期是一致的, initial 进程退出的时候,所有的子进程也会随之退出
这样会导致有状态数据不能持久化,因此需要有数据卷的存在
数据卷的生命周期是独立于容器的生命周期的,其管理主要有两种方式:
- 第一种是通过 bind 的方式,直接将宿主机的目录直接挂载到容器内;这种方式比较简单,但是会带来运维成本,因为其依赖于宿主机的目录,需要对于所有的宿主机进行统一管理。
- 第二种是将目录管理交给运行引擎。
容器项目架构
moby 容器引擎架构
moby 是目前最流行的容器管理引擎,moby daemon 会对上提供有关于容器、镜像、网络以及 Volume的管理。moby daemon 所依赖的最重要的组件就是 containerd,containerd 是一个容器运行时管理引擎,其独立于 moby daemon ,可以对上提供容器、镜像的相关管理。
containerd 底层有 containerd shim 模块,其类似于一个守护进程,这样设计的原因有几点:
- 首先,containerd 需要管理容器生命周期,而容器可能是由不同的容器运行时所创建出来的,因此需要提供一个灵活的插件化管理。而 shim 就是针对于不同的容器运行时所开发的,这样就能够从 containerd 中脱离出来,通过插件的形式进行管理。
- 其次,因为 shim 插件化的实现,使其能够被 containerd 动态接管。如果不具备这样的能力,当 moby daemon 或者 containerd daemon 意外退出的时候,容器就没人管理了,那么它也会随之消失、退出,这样就会影响到应用的运行。
- 最后,因为随时可能会对 moby 或者 containerd 进行升级,如果不提供 shim 机制,那么就无法做到原地升级,也无法做到不影响业务的升级,因此 containerd shim 非常重要,它实现了动态接管的能力。
containerd 容器架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrEpiS5l-1623207610984)(云原生.assets/image-20210607112937753.png)]
两大功能
- 对于容器生命周期的管理(左边)
- 镜像存储的管理(右边)
一个镜像存储的管理
- 第一层
- GRPC,containerd 对于上层来说是通过 GRPC server 的形式来对上层提供服务的。
- Metrics ,这个部分主要是提供 cgroup Metrics 的一些内容
- 第二层
- 左边是容器镜像的一个存储,
- 中线 images、containers 下面是 Metadata,这部分 Matadata 是通过 bootfs 存储在磁盘上面的。
- 右边的 Tasks 是管理容器的容器结构,Events 是对容器的一些操作都会有一个 Event 向上层发出,然后上层可以去订阅这个 Event,由此知道容器状态发生什么变化。
- 第三层
- Runtimes 层,这个 Runtimes 可以从类型区分,比如说 runC 或者是安全容器之类的
容器流程
start流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9E11ZndY-1623207610985)(云原生.assets/image-20210607113809704.png)]
组成部分:
- 第一个部分是容器引擎部分,容器引擎可以是 docker,也可以是其它的。
- 两个虚线框框起来的 containerd 和 containerd-shim,它们两个是属于 containerd 架构的部分。
- 最下面就是 container 的部分,这个部分是通过一个 runtime 去拉起的,可以认为是 shim 去操作 runC 命令创建的一个容器
流程:
首先它会去创建一个 matadata,然后会去发请求给 task service 说要去创建容器。通过中间一系列的组件,最终把请求下发到一个 shim。containerd 和 shim 的交互其实也是通过 GRPC 来做交互的,containerd 把创建请求发给 shim 之后,shim 会去调用 runtime 创建一个容器出来。
exec 流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oo0fZKhy-1623207610986)(云原生.assets/image-20210607113756658.png)]
exec 的操作还是发给 containerd-shim 的。对容器来说,去 start 一个容器和去 exec 一个容器,其实并没有本质的区别。
start 和 exec 区别:
- exec 的时候,需要把这个进程加入到一个已有的 namespace 里面;
- start 的时候,容器进程的 namespace 是需要去专门创建。
容器和虚拟机
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1iSaZ0J-1623207610986)(云原生.assets/image-20210601143638048.png)]
VM 利用 Hypervisor 虚拟化技术来模拟 CPU、内存等硬件资源,这样就可以在宿主机上建立一个 Guest OS,这是常说的安装一个虚拟机。
- 容器是一个进程集合,具有自己独特的视图视角;
- 镜像是容器所需要的所有文件集合,其具备一次构建、到处运行的特点;
- 容器的生命周期和 initial 进程的生命周期是一样的;
- 容器和 VM 相比,各有优劣,容器技术在向着强隔离方向发展。
Kubernetes 概念
核心功能
-
服务的发现与负载的均衡;
-
容器的自动装箱,我们也会把它叫做 scheduling,就是“调度”,把一个容器放到一个集群的某一个机器上,Kubernetes 会帮助我们去做存储的编排,让存储的声明周期与容器的生命周期能有一个连接;
-
Kubernetes 会帮助我们去做自动化的容器的恢复。在一个集群中,经常会出现宿主机的问题或者说是 OS 的问题,导致容器本身的不可用,Kubernetes 会自动地对这些不可用的容器进行恢复;
-
Kubernetes 会帮助我们去做应用的自动发布与应用的回滚,以及与应用相关的配置密文的管理;
-
对于 job 类型任务,Kubernetes 可以去做批量的执行;
-
为了让这个集群、这个应用更富有弹性,Kubernetes 也支持水平的伸缩。
架构
Kubernetes 架构是一个比较典型的二层架构和 server-client 架构。Master 作为中央的管控节点,会去与 Node 进行一个连接。
所有 UI 的、clients、这些 user 侧的组件,只会和 Master 进行连接,把希望的状态或者想执行的命令下发给 Master,Master 会把这些命令或者状态下发给相应的节点,进行最终的执行。
-
**API Server:**顾名思义是用来处理 API 操作的,Kubernetes 中所有的组件都会和 API Server 进行连接,组件与组件之间一般不进行独立的连接,都依赖于 API Server 进行消息的传送;
-
**Controller:**是控制器,它用来完成对集群状态的一些管理。比如刚刚我们提到的两个例子之中,第一个自动对容器进行修复、第二个自动进行水平扩张,都是由 Kubernetes 中的 Controller 来进行完成的;
-
**Scheduler:**是调度器,“调度器”顾名思义就是完成调度的操作,就是我们刚才介绍的第一个例子中,把一个用户提交的 Container,依据它对 CPU、对 memory 请求大小,找一台合适的节点,进行放置;
-
**etcd:**是一个分布式的一个存储系统,API Server 中所需要的这些原信息都被放置在 etcd 中,etcd 本身是一个高可用系统,通过 etcd 保证整个 Kubernetes 的 Master 组件的高可用性。
Kubernetes 的 **Node 是真正运行业务负载的,每个业务负载会以 Pod 的形式运行。等一下我会介绍一下 Pod 的概念。**一个 Pod 中运行的一个或者多个容器,真正去运行这些 Pod 的组件的是叫做 kubelet,也就是 Node 上最为关键的组件,它通过 API Server 接收到所需要 Pod 运行的状态,然后提交到我们下面画的这个 Container Runtime 组件中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y4Z1ygJG-1623207610987)(云原生.assets/image-20210601205016872.png)]
在 OS 上去创建容器所需要运行的环境,最终把容器或者 Pod 运行起来,也需要对存储跟网络进行管理。Kubernetes 并不会直接进行网络存储的操作,他们会靠 Storage Plugin 或者是网络的 Plugin 来进行操作。用户自己或者云厂商都会去写相应的 Storage Plugin 或者 Network Plugin,去完成存储操作或网络操作。
在 Kubernetes 自己的环境中,也会有 Kubernetes 的 Network,它是为了提供 Service network 来进行搭网组网的。(等一下我们也会去介绍“service”这个概念。)真正完成 service 组网的组件的是 Kube-proxy,它是利用了 iptable 的能力来进行组建 Kubernetes 的 Network,就是 cluster network,以上就是 Node 上面的四个组件。
Kubernetes 的 Node 并不会直接和 user 进行 interaction,它的 interaction 只会通过 Master。而 User 是通过 Master 向节点下发这些信息的。Kubernetes 每个 Node 上,都会运行我们刚才提到的这几个组件
核心概念
Pod
Pod 是 Kubernetes 的一个。用户可以通过 Kubernetes 的 Pod API 生产一个 Pod,让 Kubernetes 对这个 Pod 进行调度,也就是把它放在某一个 Kubernetes 管理的节点上运行起来。一个 Pod 简单来说是对一组容器的抽象,它里面会包含。
- 最小调度以及资源单元
- 一个或多个容器组成
- 定义容器运行的方式(Command、环境变量)
- 提供给容器共享的运行环境(网络、进程空间)
Volume
- 声明Pod中容器可访问的文件目录
- 可以被挂载在Pod中一个(或者多个)容器的指定路径下
- 支持多种后端存储抽象:分布式、本地、云存储
Deployment
- 定义一组Pod的副本数目、版本等
- 通过控制器(Controller)维持Pod的数目
- 自动恢复失败的Pod
- 通过控制器以指定的策略控制版本
- 滚动升级、重新生成、回滚等
Service
-
Service 提供了一个或者多个 Pod 实例的稳定访问地址
-
实现 Service 有多种方式,
- Kubernetes 支持 Cluster IP,上面我们讲过的 kuber-proxy 的组网,
- 它也支持 nodePort、 LoadBalancer 等其他的一些访问的能力
Namespace
- 一个集群内部的逻辑隔离的,它包括鉴权、资源管理等
- Kubernetes 的每个资源,比如刚才讲的 Pod、Deployment、Service 都属于一个 Namespace,
- 同一个 Namespace 中的资源需要命名的唯一性
- 不同的 Namespace 中的资源可以重名。
API相关
结构
- 从 high-level 上看,Kubernetes API 是由 HTTP+JSON 组成的:用户访问的方式是 HTTP,访问的 API 中 content 的内容是 JSON 格式的
- 可以通过 kubectl、 UI、curl访问
对于这个 Pod 类型的资源,它的 HTTP 访问的路径,就是 API,然后是 apiVesion: V1, 之后是相应的 Namespaces,以及 Pods 资源,最终是 Podname,也就是 Pod 的名字
Label
这个 label 可以是一组 KeyValuePair
- 可以被selector查询
- 资源集合的默认表达形式
Pod
具体概念
在 kubernetes 里面,Pod 实际上正是 kubernetes 项目为你抽象出来的一个可以类比为进程组的概念
进程组
-
一个应用一般由多个进程组成,进程之间会共享一些资源和文件。
-
由于容器实际上是一个“单进程”模型,所以如果你在容器里启动多个进程,只有一个可以作为 PID=1 的进程,而这时候,如果这个 PID=1 的进程挂了,或者说失败退出了,那么其他三个进程就会自然而然的成为孤儿,没有人能够管理它们,没有人能够回收它们的资源,这是一个非常不好的情况
-
容器的设计本身是一种“单进程”模型,不是说容器里只能起一个进程,由于容器的应用等于进程,所以只能去管理 PID=1 的这个进程,其他再起来的进程其实是一个托管状态。
- 除非,服务应用进程本身就具有“进程管理”的能力
- 或者使用systemd,用它来管理其他所有的进程,但会导致我们实际上没办法直接管理我的应用了,因为我的应用被 systemd 给接管了,那么这个时候应用状态的生命周期就不等于容器生命周期
pod在k8s
- Pod 在 Kubernetes 里面只有一个逻辑单位,没有一个真实的东西对应说这个就是 Pod
- 真正起来在物理上存在的东西,就是四个容器。这四个容器,或者说是多个容器的组合就叫做 Pod
- Pod 是 Kubernetes 分配资源的一个单位,因为里面的容器要共享某些资源,所以 Pod 也是 Kubernetes 的原子调度单位。
- 组合资源需求避免应用调度失败。Task co-scheduling 问题
超亲密关系
亲密关系是一定可以通过调度来解决的,超亲密关系来说,有一个问题,即它必须通过 Pod 来解决。
超亲密关系大概分为以下几类:
- 比如说两个进程之间会发生文件交换,前面提到的例子就是这样,一个写日志,一个读日志;
- 两个进程之间需要通过 localhost 或者说是本地的 Socket 去进行通信,这种本地通信也是超亲密关系;
- 这两个容器或者是微服务之间,需要发生非常频繁的 RPC 调用,出于性能的考虑,也希望它们是超亲密关系;
- 两个容器或者是应用,它们需要共享某些 Linux Namespace。最简单常见的一个例子,就是我有一个容器需要加入另一个容器的 Network Namespace。这样我就能看到另一个容器的网络设备,和它的网络信息。
实现机制
Pod 要解决这个问题,核心就在于如何让一个 Pod 里的多个容器之间最高效的共享某些资源和数据。
具体的解法分为两个部分:网络和存储
共享网络
- 会在每个 Pod 里,额外起一个 Infra container 小容器来共享整个 Pod 的 Network Namespace。
- Infra container 是一个非常小的镜像,大概 100~200KB 左右,是一个汇编语言写的、永远处于“暂停”状态的容器。由于有了这样一个 Infra container 之后,其他所有容器都会通过 Join Namespace 的方式加入到 Infra container 的 Network Namespace 中
- 一个 Pod 里面的所有容器,它们看到的网络视图是完全一样的。即:它们看到的网络设备、IP地址、Mac地址等等,跟网络相关的信息,其实全是一份,这一份都来自于 Pod 第一次创建的这个 Infra container。也就是所有容器共享这个 infra 的 IP 地址。
- 整个 Pod 里面,必然是 Infra container 第一个启动。并且整个 Pod 的生命周期是等同于 Infra container 的生命周期的,与容器 A 和 B 是无关的。所以 k8s 可以单独更新一个 Pod 里的一个镜像。
共享存储
通过yaml文件声明共享存储名字以及对应mountPath就行。
sidecar容器设计模式
在 Pod 里面,可以定义一些专门的容器,来执行主业务容器所需要的一些辅助工作
其它有哪些操作呢?比如说:
-
原本需要在容器里面执行 SSH 需要干的一些事情,可以写脚本、一些前置的条件,其实都可以通过像 Init Container 或者另外像 Sidecar 的方式去解决;
-
当然还有一个典型例子就是我的日志收集,日志收集本身是一个进程,是一个小容器,那么就可以把它打包进 Pod 里面去做这个收集工作;
-
还有一个非常重要的东西就是 Debug 应用,实际上现在 Debug 整个应用都可以在应用 Pod 里面再次定义一个额外的小的 Container,它可以去 exec 应用 pod 的 namespace;
-
查看其他容器的工作状态,这也是它可以做的事情。不再需要去 SSH 登陆到容器里去看,只要把监控组件装到额外的小容器里面就可以了,然后把它作为一个 Sidecar 启动起来,跟主业务容器进行协作,所以同样业务监控也都可以通过 Sidecar 方式来去做。
将辅助功能从我的业务容器解耦了,所以我就能够独立发布 Sidecar 容器,并且更重要的是这个能力是可以重用的,即同样的一个监控 Sidecar 或者日志 Sidecar,可以被全公司的人共用的
应用场景:
-
tomcat + war 部署
-
应用与日志收集
业务容器将日志写在一个 Volume 里面,而由于 Volume 在 Pod 里面是被共享的,所以日志容器 —— 即 Sidecar 容器一定可以通过共享该 Volume,直接把日志文件读出来,然后存到远程存储里面,或者转发到另外一个例子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6301Im5k-1623207610988)(云原生.assets/image-20210602110338980.png)]
-
代理容器
-
单独写一个这么小的 Proxy,用来处理对接外部的服务集群,它对外暴露出来只有一个 IP 地址就可以了。所以接下来,业务容器主要访问 Proxy,然后由 Proxy 去连接这些服务集群,这里的关键在于 Pod 里面多个容器是通过 localhost 直接通信的,因为它们同属于一个 network Namespace,网络视图都一样,所以它们俩通信 localhost,并没有性能损耗
-
代理容器除了做了解耦之外,并不会降低性能,更重要的是,像这样一个代理容器的代码就又可以被全公司重用了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bKmyZGyJ-1623207610988)(云原生.assets/image-20210602110513271.png)]
-
-
适配器容器
- 业务容器暴露出来的监控接口是 /metrics,访问这个这个容器的 metrics 的这个 URL 就可以拿到了。可是现在,这个监控系统升级了,它访问的 URL 是 /health,我只认得暴露出 health 健康检查的 URL,才能去做监控,metrics 不认识
- 额外写一个 Adapter,用来把所有对 health 的这个请求转发给 metrics 就可以了,所以这个 Adapter 对外暴露的是 health 这样一个监控的 URL
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oE27RfzX-1623207610988)(云原生.assets/image-20210602110657160.png)]
编排和管理
资源元信息
Labels
- 资源标签是一种