零、文章目录
架构11-虚拟化容器
1、从微服务到云原生
(1)从微服务到云原生的演进
- **微服务:**上一个模块介绍了微服务中的关键技术问题与解决方案,这是架构师和程序员的本职工作。
- **云原生:**从微服务过渡到云原生,重点讨论不可变基础设施的概念及其重要性。
(2)不可变基础设施
- 概念起源:
- 2012年,马丁·福勒提出"凤凰服务器"。
- 2013年,查德·福勒正式提出"不可变基础设施"。
- 重要性:
- 在云原生基金会的定义中,不可变基础设施与微服务平级重要。
- 不再仅仅是方便运维、程序升级和部署的手段,而是向应用代码隐藏分布式架构复杂度的必要前提。
(3)云原生技术
- 定义:
- 云原生技术使组织能够在公有云、私有云和混合云等动态环境中构建和运行可弹性扩展的应用。
- 代表技术:
- 容器
- 服务网格
- 微服务
- 不可变基础设施
- 声明式API
- 优势:
- 构建容错性好、易于管理和便于观察的松耦合系统。
- 结合可靠的自动化手段,使工程师能够轻松地对系统作出频繁和可预测的重大变更。
(4)容器化技术
- 目标:
- 让软件分发部署的过程从发布安装包、人工部署转变为发布包含整套运行环境的虚拟化镜像。
- 传统部署:
- 系统管理员编译或下载二进制安装包,准备操作系统、第三方库、配置文件等前置依赖。
- 兼容性问题:
- **ISA兼容性:**目标机器指令集兼容性。
- **ABI兼容性:**目标系统或依赖库的二进制兼容性。
- **环境兼容性:**目标环境的兼容性。
(5)虚拟化技术分类
- 指令集虚拟化(ISA Level Virtualization):
- 通过软件模拟不同ISA架构的处理器工作过程。
- 代表:QEMU、Bochs。
- 硬件抽象层虚拟化(Hardware Abstraction Level Virtualization):
- 以软件或硬件模拟处理器、芯片组等设备的工作过程。
- 代表:VMware ESXi、Hyper-V。
- 操作系统层虚拟化(OS Level Virtualization):
- 采用隔离手段,使不同进程拥有独立的系统资源和资源配额。
- 代表:容器化(Docker)。
- 运行库虚拟化(Library Level Virtualization):
- 使用软件翻译的方法模拟系统,提供目标软件运行所需的全部能力。
- 代表:WINE、WSL1。
- 语言层虚拟化(Programming Language Level Virtualization):
- 由虚拟机将高级语言生成的中间代码转换为目标机器可以直接执行的指令。
- 代表:Java的JVM、.NET的CLR。
2、 容器的崛起
(1)隔离文件:chroot
- 基本概念
- chroot 是一个 Unix 系统调用,用于更改当前进程及其子进程的根目录。
- 根目录 是文件系统的顶级目录,通常表示为
/
。 - 使用
chroot
可以创建一个独立的文件系统环境,使进程只能访问指定目录及其子目录中的文件,而无法访问其他部分的文件系统。
- 工作原理
- 更改根目录:
chroot
系统调用将当前进程的根目录更改为指定的目录。 - **隔离效果:**一旦根目录被更改,进程将无法访问原根目录下的文件,只能访问新根目录下的文件。
- 临时性:
chroot
的效果是临时的,只影响当前进程及其子进程,不会影响其他进程。
- 更改根目录:
- 使用场景
- **安全隔离:**防止恶意软件或不信任的应用程序访问系统敏感文件。
- **测试环境:**创建一个独立的文件系统环境,用于测试新的应用程序或配置。
- **软件包构建:**在构建软件包时,使用
chroot
创建一个干净的环境,避免依赖冲突。
- 实现步骤
- 准备环境:
- 创建一个新的目录,作为新的根目录。
- 复制或链接必要的文件和目录到新根目录中。
- 执行 chroot:
- 使用
chroot
命令更改根目录。 - 例如:
chroot /newroot /bin/bash
- 使用
- 运行命令:
- 在新的根目录下运行所需的命令或启动应用程序。
- 准备环境:
- 注意事项
- **依赖关系:**确保新根目录中包含所有必要的文件和库,否则命令可能无法正常运行。
- 权限问题:
chroot
通常需要 root 权限才能执行。 - **安全性:**虽然
chroot
提供了一定的隔离效果,但并不是绝对安全的。高级用户可以通过某些技术手段突破chroot
环境。
- 示例
bash
创建一个新的根目录
mkdir /newroot
复制必要的文件和目录
cp -r /bin /newroot/
cp -r /lib /newroot/
cp -r /lib64 /newroot/
cp -r /etc /newroot/
进入新的根目录
chroot /newroot /bin/bash
在新的根目录下运行命令
ls
(2)隔离访问:namespaces
- 基本概念
- 定义:
namespace
是 Kubernetes 中的一种逻辑分区,用于将集群中的资源划分为多个虚拟子集。 - **作用:**通过
namespace
,可以实现资源的隔离、命名冲突的避免以及权限管理的简化。
- 定义:
- 主要用途
- **资源隔离:**不同的
namespace
之间的资源是隔离的,一个namespace
中的资源不会影响到另一个namespace
中的资源。 - **命名冲突:**在同一个
namespace
内,资源名称必须唯一,但不同namespace
之间可以使用相同的名称。 - **权限管理:**可以通过 RBAC(Role-Based Access Control)为不同的
namespace
分配不同的权限,实现细粒度的访问控制。
- **资源隔离:**不同的
- **默认 **
**namespace**
- **default:**默认的
namespace
,如果没有指定namespace
,资源将被创建在这个namespace
中。 - **kube-system:**系统组件所在的
namespace
,如 kube-dns、kube-proxy 等。 - **kube-public:**这个
namespace
是公开的,所有用户都可以读取其中的资源。
- **default:**默认的
- **创建和管理 **
**namespace**
- 创建
namespace
:
- 创建
yaml
apiVersion: v1
kind: Namespace
metadata:
name: my-namespace
- 使用 `kubectl` 命令创建:
shell
kubectl create -f namespace.yaml
- 查看 `namespace`:
shell
kubectl get namespaces
- 删除 `namespace`:
shell
kubectl delete namespace my-namespace
- 资源命名空间
- Pods、Services、Deployments 等资源都属于某个
namespace
。 - 在创建资源时,可以通过
metadata.namespace
字段指定资源所属的namespace
:
- Pods、Services、Deployments 等资源都属于某个
yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
namespace: my-namespace
spec:
containers:
- name: my-container
image: nginx
- 跨
**namespace**
访问- Service 可以跨
namespace
访问,通过..svc.cluster.local
的格式进行访问。 - 例如,从
default
namespace
访问my-namespace
中的my-service
:
- Service 可以跨
shell
curl http://my-service.my-namespace.svc.cluster.local
- 配置和策略
- **Resource Quotas:**可以在
namespace
级别设置资源配额,限制该namespace
中资源的使用量。
- **Resource Quotas:**可以在
yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: my-resource-quota
namespace: my-namespace
spec:
hard:
pods: "10"
requests.cpu: "1"
requests.memory: 1Gi
- **Limit Ranges:**可以在 `namespace` 级别设置资源限制范围,确保资源请求和限制在合理范围内。
yaml
apiVersion: v1
kind: LimitRange
metadata:
name: my-limit-range
namespace: my-namespace
spec:
limits:
- default:
memory: 512Mi
cpu: 500m
defaultRequest:
memory: 256Mi
cpu: 250m
type: Container
- 最佳实践
- **命名规范:**使用有意义的
namespace
名称,便于管理和识别。 - **资源隔离:**根据项目或团队划分
namespace
,实现资源的有效隔离。 - **权限管理:**为不同的
namespace
分配适当的权限,确保安全性和可控性。
- **命名规范:**使用有意义的
(3)隔离资源:cgroups
- cgroups概述
- cgroups(Control Groups)是Linux内核提供的一种机制,用于限制、记录和隔离进程组使用的物理资源(如CPU、内存、磁盘I/O等)。cgroups最初由Google开发,并于2008年被合并到Linux内核中。
- cgroups的主要功能包括
- 资源限制:可以限制进程组使用资源的最大值,例如CPU时间、内存使用量、磁盘I/O等。
- 优先级分配:可以为不同的进程组分配不同的资源优先级。
- 资源统计:可以统计进程组使用的资源情况,便于监控和管理。
- 任务控制:可以将进程组挂起、恢复或终止。
- cgroups的主要组成部分
-
- **层级(Hierarchy):**一个cgroups层级是一个目录树,每个节点都是一个cgroup。每个cgroup可以包含多个子cgroup,形成一个树状结构。
- **控制器(Controller):**控制器是cgroups对不同资源类型进行管理的模块。常见的控制器包括:
- cpu:用于限制CPU使用时间。
- memory:用于限制内存使用量。
- blkio:用于限制块设备I/O操作。
- net_cls:用于分类网络流量。
- pids:用于限制进程数量。
- **任务(Task):**任务是指被cgroups管理的进程。每个任务可以属于一个或多个cgroup。
- **策略(Policy):**策略是指对cgroup中任务的资源使用进行限制和控制的具体规则。
- cgroups的工作原理
- **创建cgroup:**通过在cgroups层级中创建目录来创建一个新的cgroup。
- **配置控制器:**在创建的cgroup目录中,通过写入特定的文件来配置控制器的参数。
- **添加任务:**将进程的PID写入cgroup目录中的
tasks
文件,将进程加入到该cgroup中。 - **监控和管理:**通过读取cgroup目录中的统计文件,监控资源使用情况;通过修改配置文件,动态调整资源限制。
- 示例
- 假设我们有一个名为
mygroup
的cgroup,我们希望限制其CPU使用率不超过50%。 - 创建cgroup:
- 假设我们有一个名为
shell
sudo mkdir /sys/fs/cgroup/cpu/mygroup
- 配置CPU控制器:
shell
echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us
echo 100000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_period_us
- 添加任务:
shell
echo 1234 > /sys/fs/cgroup/cpu/mygroup/tasks
- 监控资源使用:
shell
cat /sys/fs/cgroup/cpu/mygroup/cpu.stat
- cgroups在容器中的应用
- **资源隔离:**确保每个容器只能使用分配给它的资源,防止资源争抢。
- **资源限制:**限制容器的资源使用,避免某个容器占用过多资源影响其他容器。
- **资源监控:**监控容器的资源使用情况,便于性能优化和故障排查。
(4)封装系统:LXC
- 背景与起源
- **背景:**在理解了从隔离角度出发的容器化技术的发展之后,LXC(LinuX Containers)作为系统级虚拟化功能的代表,进一步推动了容器技术的发展。
- **起源:**2008年,Linux Kernel 2.6.24 内核在提供 cgroups 的同时,发布了 LXC。LXC 的目标是降低普通用户综合使用 namespaces 和 cgroups 等低级特性的门槛。
- LXC 的特点
- **系统级虚拟化:**LXC 提供了一种轻量级的虚拟化解决方案,允许用户在单个主机上运行多个独立的 Linux 系统实例。
- **性能损耗低:**相比传统的虚拟化技术,LXC 的性能损耗非常低,通常只有 1-3%。
- **内核支持:**LXC 依赖于 Linux 内核的 namespaces 和 cgroups 功能,这些功能提供了资源隔离和控制的基础。
- LXC 与其他系统级虚拟化解决方案的比较
- **OpenVZ 和 Linux-VServer:**在 LXC 之前,OpenVZ 和 Linux-VServer 已经实现了类似的容器隔离功能,但它们是非官方的技术,需要通过非官方内核补丁来修改标准内核。
- **LXC 的优势:**LXC 作为官方内核的一部分,不需要额外的补丁,这使得它更容易被广泛接受和使用。
- LXC 的使用场景
- **快速部署:**LXC 提供了快速部署虚拟系统的功能,用户可以通过预定义的模板(template)快速创建包含特定软件和配置的虚拟系统。
- **系统管理员的便利:**对于传统系统管理员来说,LXC 提供了一种高效的方式来管理和部署多个虚拟系统,减少了手动配置的时间和复杂性。
- LXC 的局限性
- **封装系统的思维:**LXC 主要关注于封装整个系统,而不是单独的应用。这种思维方式限制了其在现代 DevOps 和微服务架构中的应用。
- **灵活性不足:**如果需要对已有的虚拟系统进行修改(如更换软件版本或添加新的组件),通常需要重新创建整个虚拟系统,这在动态变化的环境中显得不够灵活。
- **缺乏生态系统支持:**相比 Docker,LXC 缺乏一个成熟的生态系统,如公共镜像仓库、自动构建工具等。
- LXC 与 Docker 的对比
- **封装理念:**LXC 将容器视为对系统的封装,而 Docker 将容器视为对应用的封装。
- **应用效果:**Docker 的封装方式更加灵活,可以快速构建和部署不同的应用环境,而 LXC 更适合传统的系统管理任务。
- **生态系统:**Docker 拥有丰富的生态系统,包括公共镜像仓库、自动构建工具、版本管理等,这些都使得 Docker 在现代软件开发和部署中更加受欢迎。
(5)封装应用:Docker
- Docker 的起源与背景
- **起源:**Docker 于 2013 年宣布开源,迅速成为容器发展历史上的里程碑。
- **背景:**Docker 的成功并非主要依赖于技术创新,而是其符合历史潮流的创意与设计理念,以及充分开放的生态运营。
- Docker 的核心理念
- **跨机器的绿色部署:**Docker 定义了一种将应用及其所有环境依赖打包在一起的格式,使得应用可以在不同机器上无缝部署。
- **以应用为中心的封装:**Docker 封装应用而非封装机器,这一理念贯穿其设计、API、界面、文档等多个方面。
- **自动构建:**Docker 提供了从容器中构建产品的全部支持,开发人员无需关注目标机器的具体配置。
- **多版本支持:**Docker 支持类似 Git 的容器版本管理,可以进行版本间差异检查、提交或回滚等操作。
- **组件重用:**Docker 允许将现有容器作为基础镜像来使用,构建更加专业的镜像。
- **共享:**Docker 拥有公共的镜像仓库,用户可以上传和使用他人的镜像。
- **工具生态:**Docker 开放了一套可自动化和自行扩展的接口,支持各种工具的扩展,如容器编排、管理界面、持续集成等。
- Docker 的技术实现
- **容器化能力:**Docker 的容器化能力直接来源于 LXC。
- **镜像分层组合的文件系统:**Docker 使用 AUFS(Another Union File System)来实现镜像的分层组合。
- **libcontainer:**2014 年,Docker 开源了用 Golang 开发的 libcontainer,这是一个越过 LXC 直接操作 namespaces 和 cgroups 的核心模块。
- Docker 的架构演进
- **早期架构:**Docker 最初依赖于 LXC 来提供容器化隔离能力。
- **libcontainer 的引入:**通过 libcontainer,Docker 能够直接与系统内核打交道,不再依赖 LXC。
- runC 与 containerd:
- **runC:**libcontainer 被独立出来,封装重构成 runC 项目,并捐献给 Linux 基金会管理。runC 是 OCI Runtime 的首个参考实现。
- **containerd:**Docker 进一步重构了 Docker Daemon 子系统,将其中与运行时交互的部分抽象为 containerd 项目。containerd 负责管理容器执行、分发、监控、网络、构建、日志等功能。
- Docker 的开源与标准化工作
- **OCI(Open Container Initiative):**Docker 推动了 OCI 标准的制定,定义了容器运行时标准、容器镜像标准和镜像分发标准。
- **捐赠 runC 和 containerd:**Docker 将 runC 和 containerd 捐献给 CNCF 管理,既体现了对开源信念的追求,也带有在云计算大厂夹击下自救的无奈。
- Docker 的现状与未来
- **统治地位:**Docker 目前在容器领域具有统治地位,但其统治的稳固程度面临挑战。
- **容器编排战争:**Docker Swarm 输掉了容器编排战争,Kubernetes 成为容器编排的主导者。
- **未来趋势:**随着 Kubernetes 的持续发展壮大,Docker Engine 可能会逐步被淘汰,但 Docker 的一些核心组件如 runC 和 containerd 仍将继续存在和发展。
(6)封装集群:Kubernetes
- 背景与起源
- **出身名门:**Kubernetes 的前身是 Google 内部已经运行多年的集群管理系统 Borg。
- **开源时间:**2014 年 6 月,Google 使用 Golang 完全重写了 Borg 并将其开源为 Kubernetes。
- **早期支持者:**IBM、RedHat、Microsoft、VMware 和华为等业界巨头都是 Kubernetes 最早期的代码贡献者。
- 云计算时代的挑战
- **传统 IDC 模式:**尽管云计算已经从实验室走向工业化应用,但大量应用仍然停留在用云端虚拟机替代传统物理机的阶段。
- **云原生概念:**2013 年,Pivotal 提出了"云原生"概念,但实现服务化、具备韧性、弹性和可观测性的软件系统依然困难重重。
- Kubernetes 的诞生与演变
- **破局希望:**Kubernetes 的出现被视为云原生时代的操作系统,是让复杂软件在云计算下获得韧性、弹性和可观测性的最佳路径。
- **关键事件:**2015 年 7 月,Kubernetes 发布了第一个正式版本 1.0 版。同年,Google 宣布与 Linux 基金会共同筹建云原生计算基金会(CNCF),并将 Kubernetes 托管到 CNCF。
- 成功因素
- **技术功底:**Google 深厚的技术功底为 Kubernetes 提供了坚实的基础。
- **设计理念:**领先时代的设计理念使得 Kubernetes 能够更好地适应云原生环境。
- **业界支持:**云计算大厂的广泛支持是 Kubernetes 成功的关键因素。
- 与 Docker 的关系
- **早期依赖:**Kubernetes 最初完全依赖 Docker,通过 DockerManager 与 Docker Engine 交互。
- **引入 CRI:**2016 年,Kubernetes 1.5 版本引入了容器运行时接口(CRI),使得 Kubernetes 可以支持多种容器引擎。
- **CRI-O 项目:**2017 年,CRI-O 项目发布,完全遵循 CRI 规范,支持所有符合 OCI 运行时标准的容器引擎。
- **containerd 支持:**2018 年,containerd 1.1 版本发布,完美支持 CRI 标准,Kubernetes 从 1.10 版本开始支持 containerd。
- 调用关系变化
- 早期调用链:
plain
Kubernetes Master → kubelet → DockerManager → Docker Engine → containerd → runC
- 引入 CRI 后:
plain
Kubernetes Master → kubelet → KubeGenericRuntimeManager → DockerShim → Docker Engine → containerd → runC
- 支持 CRI-O:
plain
Kubernetes Master → kubelet → KubeGenericRuntimeManager → CRI-O → runC
- 支持 containerd:
plain
Kubernetes Master → kubelet → KubeGenericRuntimeManager → containerd → runC
- 未来展望
- **Docker 的地位:**随着 Kubernetes 的持续发展壮大,Docker Engine 从不可或缺、默认依赖、可选择到被淘汰,是大概率的事件。
- **技术潮流:**Docker 本身很难彻底消亡,CLI 界面和成熟的镜像仓库等会长期存在,但在容器编排领域,Docker 很可能只会以 runC 和 containerd 的形式存续。
- **Dockershim 移除:**Kubernetes 宣布将在 v1.23 版本中移除 Dockershim,这将进一步推动容器运行时的多样化和标准化。
3、以容器构建系统
(1)隔离与协作
- 容器编排的背景与发展
- **容器的发展:**Docker 提出"以封装应用为中心"的容器发展理念,成功取代了"以封装系统为中心"的 LXC,使得一个容器封装一个单进程应用成为最佳实践。
- **分布式系统的需求:**单体时代结束后,分布式系统中应用的概念不再等同于进程,需要多个进程共同协作,通过集群形式对外提供服务,这就是容器编排(Container Orchestration)的目标。
- **Kubernetes 的地位:**Kubernetes 已成为容器编排的代名词,但本课程的重点在于理解其设计意图,而非具体功能和配置。
- 容器编排系统面临的问题
- 场景一:单容器封装多个应用
- **问题:**违背了单个容器封装单进程应用的最佳实践,Docker 只能通过监视 PID 为 1 的进程判断容器状态。
- **解决方案:**将应用拆分为多个容器。
- 场景二:多容器协作
- **问题:**容器间需要共享日志、配置等信息,涉及文件系统、IPC 通信等。
- **解决方案:**使用 Docker 的 Volume、--ipc、--uts、--net 参数实现共享。
- 场景三:跨节点调度
- **问题:**在集群环境中,容器可能被调度到不同节点,导致名称空间共享和资源配额共享失效。
- **解决方案:**引入 Pod 概念,实现原子性调度。
- 场景一:单容器封装多个应用
- Pod 的概念与职责
- **Pod 的定义:**Kubernetes 中的 Pod 是容器组的概念,多个容器可以放在同一个 Pod 中,共享某些名称空间。
- 共享的名称空间:
- **UTS 名称空间:**所有容器共享相同的主机名和域名。
- **网络名称空间:**所有容器共享相同的网卡、网络栈、IP 地址等。
- **IPC 名称空间:**所有容器可以通过信号量或 POSIX 共享内存等方式通信。
- **时间名称空间:**所有容器共享相同的系统时间。
- 隔离的名称空间:
- **PID 名称空间:**默认隔离,每个容器有自己的进程 ID 编号。
- **文件名称空间:**默认隔离,容器需要独立的文件系统以避免冲突,但可以通过 Volume 共享存储。
- **实现细节:**通过 Infra Container 实现名称空间共享,Infra Container 是 Pod 中第一个启动的容器,其他容器以它为父容器。
- Pod 的基本职责
- **原子性调度:**以 Pod 为最小单位进行调度,确保多个容器在同一个节点上运行,避免跨节点调度带来的问题。
- **资源管理:**Pod 是资源调度的最小单位,可以声明运行所需的资源。
- Kubernetes 的计算资源
-
- **容器(Container):**延续了 Docker 的理念,一个容器封装一个应用进程,是镜像管理的最小单位。
- **生产任务(Pod):**补充了容器化后缺失的"容器组"概念,是资源调度的最小单位。
- **节点(Node):**对应集群中的单台机器,是处理器和内存等资源的资源池。
- **集群(Cluster):**对应整个集群,通过声明式 API 管理应用,无需关心具体节点分配。
- **集群联邦(Federation):**统一管理多个 Kubernetes 集群,支持跨可用区域多活、跨地域容灾等需求。
- 容器编排系统的设计思想
- **隔离与协作:**容器要让管理的进程相互隔离,使用独立的资源与配额;容器编排系统要让管理的容器相互协作,共同维持分布式系统的运作。
- **非功能特性:**容器编排系统还需要考虑如何调度容器、分配资源、扩缩规模、接管系统中的非功能特性等问题,以提高应用的生产力。
(2)韧性与弹性
- 引言
- **背景:**容器编排系统的目标不仅仅是让容器能够相互连通和协作,还需要确保系统能够健壮运行,抵御意外与风险。
- **比喻:**真实世界的软件系统类似于电影《Bubble Boy》中的小男孩,极度脆弱,需要额外的保护措施。
- Kubernetes 的控制器设计模式
- **核心理念:**控制器设计模式是 Kubernetes 的核心设计理念之一,旨在实现系统的韧性与弹性。
- **控制回路:**借鉴工业控制系统中的控制回路思想,通过比较资源的期望状态与实际状态,自动调整资源状态,使其向期望状态靠拢。
- 声明式 API
- **定义:**用户通过描述资源的期望状态,而不是调用具体的方法来实现需求。
- **示例:**在 Kubernetes 中,
spec
字段描述资源的期望状态。
- 常见的资源对象与控制器
- 资源对象分类:
- **工作负荷:**如
Deployment
、ReplicaSet
、Job
等。 - **配置信息:**如
ConfigMap
、Secret
等。 - **存储:**如
PersistentVolume
、PersistentVolumeClaim
等。 - **网络与安全:**如
Service
、NetworkPolicy
等。 - **虚拟集群:**如
Namespace
、Node
等。
- **工作负荷:**如
- 控制器分类:
- **必须启用:**如
EndpointController
、ReplicationController
等。 - **默认启用:**如
TokenController
、NodeController
等。 - **默认禁止:**如
BootstrapSignerController
、TokenCleanerController
等。
- **必须启用:**如
- 资源对象分类:
- 控制器模式的工作原理
- 场景五:通过服务编排实现以下三种通用能力:
- **故障恢复:**Pod 出现故障时,自动恢复,不中断服务。
- **滚动更新:**Pod 更新程序时,滚动更新,不中断服务。
- **自动扩缩:**Pod 遇到压力时,自动水平扩展,不中断服务。
- 场景五:通过服务编排实现以下三种通用能力:
- 具体示例
- ReplicaSet:
- **功能:**确保 Pod 副本的数量始终符合期望状态。
- **实现:**当 Pod 发生故障时,自动创建新的 Pod 替代。
- Deployment:
- **功能:**实现滚动更新,避免服务中断。
- **实现:**通过创建新版本的
ReplicaSet
,逐步替换旧版本的ReplicaSet
。
- Autoscaling:
- **功能:**根据度量指标自动调整 Pod 数量。
- **实现:**通过
HorizontalPodAutoscaler
(HPA)控制器,根据 CPU、内存等指标自动扩缩 Pod。
- ReplicaSet:
4、以应用为中心的封装
(1)Kustomize
- 背景:
- Kubernetes 官方提供的"用配置文件来配置文件"的解决方案。
- 从 Kubernetes 1.14 起,被纳入
kubectl
命令中,成为内置功能。
- 主要功能:
- Base、Overlay 和 Patch:
- **Base:**基础配置文件,包含应用的核心资源。
- **Overlay:**基于基础配置的定制化配置文件,用于不同环境(如生产、调试)的定制。
- **Patch:**用于在部署期间修改特定属性的补丁文件。
- **Kustomization 文件:**YAML 格式的配置文件,定义了构成应用的全部资源及需覆盖的变量值。
- Base、Overlay 和 Patch:
yaml
k8s
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
└── prod
│ ├── load-loadbalancer-service.yaml
│ └── kustomization.yaml
└── debug
└── kustomization.yaml
- 优势:
- **轻量便捷:**避免了"字符替换"对资源元数据文件的入侵,不需要用户学习额外的 DSL 语法。
- **生成 All-in-One 整合包:**简化了应用的部署过程,只需一行命令即可安装所有服务。
- 局限:
- **未解决应用管理复杂的问题:**虽然简化了配置,但最终需要编写的配置文件数量并未减少。
- **缺乏全生命周期管理:**主要关注部署,未涵盖应用的更新、回滚、卸载等环节。
(2)Helm 与**Chart **
- 背景:
- 由 Deis 公司开发,旨在成为 Kubernetes 应用商店与包管理工具。
- 参考了 Linux 包管理工具的思路。
- 主要功能:
- Chart 格式:
- **Chart.yaml:**应用的详细信息(名称、版本、许可证等)。
- **requirements.yaml:**应用的依赖关系。
- **values.yaml:**可配置项目的预定义值。
- **templates 目录:**包含应用的资源文件模板,通过字符串替换生成最终的资源文件。
- Chart 格式:
yaml
WordPress
├── templates
│ ├── NOTES.txt
│ ├── deployment.yaml
│ ├── externaldb-secrets.yaml
│ └── 版面原因省略其他资源文件
│ └── ingress.yaml
└── Chart.yaml
└── requirements.yaml
└── values.yaml
- **Repository 应用仓库:**
* **中央仓库:**Helm 社区维护的 Stable 和 Incubator 仓库。
* **私有仓库:**支持个人或组织搭建私有仓库。
* **Hub 服务:**聚合不同个人或组织的公共仓库,便于查找与共享。
* ![](https://cdn.nlark.com/yuque/0/2024/png/12741366/1733647426079-a4e927bd-7819-41a7-98a1-25bb23229ea3.png)
- **Release:**每次安装应用都会生成一个 Release,相当于 Chart 的安装实例。
- 优势:
- **全生命周期管理:**支持应用的安装、升级、部署、卸载、回滚等操作。
- **依赖管理:**自动处理应用的依赖项。
- **图形化界面:**根据 Chart 信息自动生成图形化的应用安装、参数设置界面。
- **扩展插件:**支持 CI/CD 及其他辅助功能。
- 局限:
- **有状态应用的支持:**无法很好地管理有状态服务的依赖关系,如数据库的持久化数据。
(3)Operator 与CRD
- 定义与特点
- **定义:**Operator 是一种封装、部署和管理 Kubernetes 应用的方法,尤其适用于复杂的有状态应用。
- 特点:
- 通过自定义资源(CRD)将应用封装为更高层次的资源。
- 扩展 Kubernetes 的控制器模式,使其能够管理自定义资源。
- 自动化管理和运维,支持复杂的操作如备份恢复数据、创建删除索引等。
- 设计理念
- 高级指令与低级操作:
- **高级指令:**用户在自定义资源(CR)中提供的高级配置和设置。
- **低级操作:**Kubernetes Operator 基于嵌入的逻辑将高级指令转换为具体的操作。
- **监视与管理:**Operator 监视 CR 类型并采取特定于应用的操作,确保当前状态与理想状态相符。
- 高级指令与低级操作:
- 示例
- Elasticsearch 集群:
- **传统方法:**使用 StatefulSet 需要定义大量细节配置。
- Elasticsearch 集群:
yaml
apiVersion: v1
kind: Service
metadata:
name: elasticsearch-cluster
spec:
clusterIP: None
selector:
app: es-cluster
ports:
- name: transport
port: 9300
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch-loadbalancer
spec:
selector:
app: es-cluster
ports:
- name: http
port: 80
targetPort: 9200
type: LoadBalancer
---
apiVersion: v1
kind: ConfigMap
metadata:
name: es-config
data:
elasticsearch.yml: |
cluster.name: my-elastic-cluster
network.host: "0.0.0.0"
bootstrap.memory_lock: false
discovery.zen.ping.unicast.hosts: elasticsearch-cluster
discovery.zen.minimum_master_nodes: 1
xpack.security.enabled: false
xpack.monitoring.enabled: false
ES_JAVA_OPTS: -Xms512m -Xmx512m
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: esnode
spec:
serviceName: elasticsearch
replicas: 3
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: es-cluster
spec:
securityContext:
fsGroup: 1000
initContainers:
- name: init-sysctl
image: busybox
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
command: ["sysctl", "-w", "vm.max_map_count=262144"]
containers:
- name: elasticsearch
resources:
requests:
memory: 1Gi
securityContext:
privileged: true
runAsUser: 1000
capabilities:
add:
- IPC_LOCK
- SYS_RESOURCE
image: docker.elastic.co/elasticsearch/elasticsearch:7.9.1
env:
- name: ES_JAVA_OPTS
valueFrom:
configMapKeyRef:
name: es-config
key: ES_JAVA_OPTS
readinessProbe:
httpGet:
scheme: HTTP
path: /_cluster/health?local=true
port: 9200
initialDelaySeconds: 5
ports:
- containerPort: 9200
name: es-http
- containerPort: 9300
name: es-transport
volumeMounts:
- name: es-data
mountPath: /usr/share/elasticsearch/data
- name: elasticsearch-config
mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
subPath: elasticsearch.yml
volumes:
- name: elasticsearch-config
configMap:
name: es-config
items:
- key: elasticsearch.yml
path: elasticsearch.yml
volumeClaimTemplates:
- metadata:
name: es-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 5Gi
* **使用 Operator:**通过简单的 CR 定义即可实现复杂操作,大大简化了配置。
yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: elasticsearch-cluster
spec:
version: 7.9.1
nodeSets:
- name: default
count: 3
config:
node.master: true
node.data: true
node.ingest: true
node.store.allow_mmap: false
- 优势
- **灵活性:**通过编程扩展 Kubernetes,比只使用内置资源更灵活。
- **降低运维成本:**将运维操作封装在程序代码中,减少手动配置。
- **DevOps 一体化:**符合 DevOps 理念,促进开发与运维的协作。
- 挑战
- **开发门槛:**开发 Operator 需要较高的技术水平,通常由专业的平台开发者完成。
- **复杂性:**即使是相对简单的应用,Operator 的实现也可能非常复杂。
(4)开放应用模型(OAM)
- 定义与特点
- **定义:**OAM 是阿里云和微软联合发布的云原生应用标准定义与架构模型。
- 特点:
- 将开发人员、运维人员与平台人员的关注点分离。
- 提供统一的方式来定义应用组件、参数和关联关系。
- 核心概念
- **Components(服务组件):**抽象出开发人员关注的元素,如应用名字、容器镜像等。
- **Workload(工作负荷):**决定应用的运行模式,预定义了六种 Workload 类型。
- **Traits(运维特征):**封装模块化后的运维能力,如日志收集、负载均衡等。
- **Application Scopes(应用边界):**将多个 Component 划分到一个或多个应用边界中。
- **Application Configuration(应用配置):**将 Component、Trait 和 Scope 组合起来形成具体的配置。
- 优势
- **角色分工:**不同角色分工协作,简化单个角色关注的内容。
- **灵活性:**支持多种 Workload 类型和 Traits,可以根据需要扩展。
- **标准化:**提供统一的标准定义,促进不同厂商和项目的互操作性。
- 挑战
- **依赖云计算基础设施:**OAM 的自定义资源一般由云计算基础设施负责解释和驱动。
- **生态建设:**成功与否取决于云计算厂商的支持力度。