[toc]
虚拟化容器#
经典的兼容性问题有
- ISA兼容:目标机器指令集的兼容性
- ABI兼容:目标系统或者依赖库的二进制兼容性
- 环境兼容: 目标环境的兼容性。例如环境变量、配置、注册中心等。
虚拟化技术则分为
- 指令集虚拟化。用软件模拟不同ISA架构的处理器过程。 例如QEMU和Bochs,甚至可以做到在web上运行操作系统。但是性能损失大
- 硬件抽象层虚拟化。 用软件来模拟计算机里的各种硬件设施。例如VMware等虚拟机。
- 操作系统层虚拟化。 不会提供真实的操作系统,而是采用隔离手段使不同进程拥有独立的系统资源和资源配额。我们熟知的容器化就是指在这个层面的虚拟化
- 运行库层虚拟化。 使用软件翻译的方法来模拟系统。例如WINE和WSL。
- 语言层虚拟化。例如JVM。
1 容器崛起的全部阶段#
这个章节的详细部分非常很精彩,很值得大家去原文完整看看:
1.1 隔离文件:chroot#
1979年unix提供了这个命令,让进程的根目录被锁定在指定参数位置中,不能放外该目录之外的其他目录。经常用来作为监控黑客行动的黑盒。
因此这个命令实现了容器最基础的文件隔离能力
1.2 隔离访问:名称空间#
2022年 linux引入了 linux名称空间namespace。
进程在一个独立的名称空间中,享有独立的文件系统、PID、UID、网络等带有名称的资源。
1.3 隔离资源: cgroups#
linux的cgroups可用来隔离或者分配进程可以使用的资源, 例如处理器、内存大小、磁盘IO速度等, 能够有效避免一个进程出现问题把同机器上的其他进程直接占用崩溃。
1.4 封装系统:LXC#
lxc是linux发布的系统级虚拟化功能。
lxc的理念在于封装系统,而docker的理念在于封装应用。
当系统内的部件需要修改,必须重写很多配置,构建无法很便捷快速。
1.5 封装应用:Docker#
docker的容器化能力直接来源自lxc。
后面又自己用go语言开发了libcontainer避免了对lxc的强依赖。
问题:为什么选择docker而不是LXC?
答:docker相比于lxc,有以下七点优势
- 跨机器的绿色部署: 将所有环境依赖打包到一起,避免对机器的依赖。
- 以应用为中心的封装。
- 自动构建: 无需关注目标机器具体配置,使用任务构建工具在容器中自动构建。
- 多版本支持: 支持git一样管理容器版本。
- 组件重用, 可以在基础镜像上构建专业化镜像。
- 共享,有公共的镜像仓库。
- 工具生态可以很方便扩展。
1.6 封装集群:kubernetes#
k8s是容器编排框架, 把大型软件系统运行所依赖的集群环境也进行了虚拟化,令集群得以实现跨数据中心的绿色部署,实现自动扩缩。
k8s最开始完全绑定依赖docker, 后面慢慢更新依赖路线,最终在调用链中可以解耦对docker engine的依赖了, k8s最终关注的是container而不是背后的docker
2 以容器构建大型系统(容器编排)#
分布式系统里应用需要多个进程共同协作,通过集群形式对外提供服务,实现这个目标的过程称为“容器编排”
2.1 隔离与协作(Pod的概念)#
这里作者先提出了一个问题:如果web服务进程和日志收集进程放在同一个容器中,有什么影响?
回答:这其实会违反了单进程应用理念, dockerfile只允许一个entrypoint,只能监视pid为1的进程来决定是否重启。
如果自己额外弄一个健康检查进程,可能因为健康检查进程失效却无法被容器侦测到。
因此这2个进程为了维持健康检查的有效性,必须被放到2个不同的容器中, 并且还要支持通过同节点目录挂载进行日志关联。
另外,如果同节点、不同容器之间需要进行基于操作系统的信号通信(不经过网络),则需要这2个容器依赖相同的IPC名称空间。
同节点上不同容器如果要支持共享部分命名空间,则可以用Pod来实现。
因为pod能共享以下内容:
- UTS名称空间:所有容器都有相同的主机名和域名
- 网络名称空间:所有容器都共享一样的网卡、网络栈、IP地址等。同一个Pod中容器占用的端口不能冲突
- IPC名称空间:可以用信号量或者POSIX共享内存
- 时间名称空间: 共享相同的系统时间
但POD中PID名称空间和文件名称空间仍然是隔离的。
注:POD中共享空间的能力是通过pause容器实现的,里面大部分都是在执行pause操作,其他时候用来传递各种状态。
POD的另一个关键点: 可以作为资源调度的最小单位(而不是容器)
如果日志收集和web服务因为资源分配问题被调度到了2个不同的节点上,那么功能就会出现问题。
因此当这2个服务整合成pod后,无论如何重启或升级,都会统一调度分到同一个节点上。
K8S里其他资源概念的解释:从小到大
- 容器container:镜像管理的最小单位
- 生产任务Pod:容器组,资源调度最小单位
- 节点Node:对应集群中的单台机器,是硬件单元的最小单位
- 集群Cluster:对应整个集群,是处理元数据的最小单位
- 集群联邦Federation:对应多个集群,是满足跨可用区域多活、跨地域容灾的要求
2.2 韧性和弹性(k8s自动维护原理)#
控制器模式是k8s的核心设计理念。
对于上文中定义的各种资源,用户只需要管自己设定好期望的资源状态即可,中间由k8s通过检视资源的控制器来逐步实现往期望状态的靠拢。
换言之,使用者只需要设置集群的期望状态即可, 而不需要你手动调用什么API去操作。
k8s设计了统一的控制器框架kube-controller-manager来维护控制器的正常运作,以及统一的指标监视器kube-apiserver来为控制器提供其工作时追踪资源的度量数据。
-
pod出现故障时,希望自动恢复且能不中断服务,则可以利用ReplicaSet副本集实现, 副本集中包含期望数量个pod。
-
pod升级时不希望中断,可以由deployment部署资源实现,由它来创建replicaset和pod,外部用户不感知,只管设置deployement参数。
-
pod压力过大希望扩容,则可以由AutoScaling(资源和自动扩缩通知其)来实现,自动根据度量指标、cpu、内存等进行后续从AutoScaling->deployement->relicaset->pod的自动化变更,无需用户参与任何手动调用。
3 以应用为中心的封装(介绍其他对k8s增强的能力)#
k8s本身还是有缺陷,写配置非常繁琐,需要懂很多方面才能写好一个配置文件。因此衍生出了其他的增强工具或者能力
3.1 kustomize#
kustomize支持根据环境来生成不同的部署配置, 可以建立多kust文件,开发人员就能以基于基准派生的方式,对不同模式(生产、调试模式)、不同的项目(同一个产品对不同客户的客制化)定制出不同的资源整合包。
即使用Base、overlay、patch来生成最终的k8s配置文件。
3.2 Helm和Chart#
如果k8s是云原生操作系统,则Helm是这个操作系统上的应用商店和包管理工具。
类似linux里的yum命令。
Chart则就是linux里的rpm包,封装k8s应用涉及的资源。
缺点在于无法很好处理有状态的服务,因为会产生依赖关系,不能直接部署安装。
3.3 Operator#
k8s里对于有状态应用,是通过有状态工作负载statefulSet来管理的,满足对pod的持久化存储、按顺序创建、唯一网络名称等,但很多应用特殊的运维操作无法满足。
Operator则支持自定义资源, 即脱离了k8s内置资源的限制。
例如它可以让k8s学会怎样操作es,只需要几行配置即可,而无需手写将近一百行的es依赖配置。
3.4 其他应用封装#
这里介绍了一些软件公司所推出的OAM开放应用模型
核心思想是开发人员关注业务逻辑,运维人员关注程序平稳运行,平台人员关注基础设置, 避免不同人员关注同一个all-in-one资源文件。