Docker容器实战(八) - 漫谈 Kubernetes 的本质

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 在前面以Docker项目为例,一步步剖析了Linux容器的具体实现方式。通过这些应该明白:一个“容器”,实际上是一个由Linux Namespace、Linux Cgroups和rootfs三种技术构建出来的进程的隔离环境。

0 前言

一个“容器”,是由Linux Namespace、Linux Cgroups和rootfs三种技术构建出的进程的隔离环境。一个运行的Linux容器,可被看做

  • 一组联合挂载在 /var/lib/docker/aufs/mnt 上的rootfs,即“容器镜像”(Container Image),容器静态视图
  • 一个由Namespace+Cgroups构成的隔离环境,即“容器运行时”(Container Runtime),容器动态视图

开发者不关心容器运行时差异。因为整个“开发-测试-发布”流程,承载容器信息进行传递的,是容器镜像,而非容器运行时。

这假设是容器技术圈在Docker成功后不久,迅速走向“容器编排”主要原因:作为云基础设施提供商,只要能将用户提交的Docker镜像容器方式运行,就能成为容器生态图的一个承载点,将整个容器技术栈价值,沉淀在这节点。

更重要的,只要从这承载点向Docker镜像制作者和使用者方向回溯,整条路径上的各个服务节点。如CI/CD、监控、安全、网络、存储等,都有发挥和盈利余地。

这逻辑正是所有云计算提供商热衷容器技术的重要原因:通过容器镜像,它们和开发者关联。从一个开发者和单一的容器镜像,到无数开发者和庞大容器集群,容器技术实现从“容器”到“容器云”。容器从一个小工具,跃为云计算主角,而能定义容器组织和管理规范的“容器编排”技术,坐上容器技术领域的“头把交椅”。最具代表性的容器编排工具:

  • Docker公司Compose+Swarm
  • Google、RedHat公司共同主导的k8s项目

k8s理论基础比工程实践走得靠前得多,归功Google 2015年4月发布的Borg论文。Borg承载Google整个基础设施的核心依赖,位居整个基础设施技术栈的最底层:

这图描绘当时Google已公开发表的整个基础设施栈。可找到MapReduce、BigTable等知名项目,也能看到Borg和其继任者Omega位于整个技术栈的最底层。所以Borg没开源。得益于Docker和容器技术风靡,它以另一种方式与开源社区见面,k8s。

k8s每个核心特性都脱胎于Borg/Omega系统设计与经验。逐渐觉察到Docker技术栈“稚嫩”和Mesos社区“老迈”,社区很快明白:k8s项目在Borg体系指导下,体现独有的先进与完备性,这才是一个基础设施领域开源项目核心价值。

1 k8s解决啥?

编排?调度?容器云?集群管理?至今无标准答案。不同发展阶段,k8s着力问题不同。

但大多数用户期望体验确定:现在我有应用的容器镜像,请帮我在一个给定集群上运行!还能给我提供路由网关、水平扩展、监控、备份、灾难恢复等一系列运维能力。

这不就是经典PaaS(eg. Cloud Foundry)项目能力?有Docker后,根本无需啥k8s、PaaS,只要用Docker公司Compose+Swarm项目,就可很方便DIY这些功能!

若k8s只停留在拉取用户镜像、运行容器及提供常见运维功能,早没了。定义核心功能过程中,正是依托Borg项目理论优势,才几个月迅速站稳脚跟,进而确定如下全局架构:

类似Borg,都有Master、Node两种节点,即控制节点、计算节点。

1.1 控制节点

即Master节点,由三个独立组件协作:

  • 负责API服务的kube-apiserver
  • 负责调度的kube-scheduler
  • 负责容器编排的kube-controller-manager

整个集群的持久化数据,由kube-apiserver处理后保存在Etcd。

1.2 计算节点

最核心

kubelet组件

负责同容器运行时(如Docker)打交道。该交互依赖CRI(Container Runtime Interface)的远程调用接口,该接口定义了容器运行时的核心操作,如启动一个容器需要的所有参数。

这也是为何k8s不关心部署的啥容器运行时、使用啥技术实现,只要你的容器运行时能运行标准的容器镜像,即可通过实现CRI接入K8s。

而具体的容器运行时,如Docker项目,一般通过OCI容器运行时规范同底层的Linux交互,即把CRI请求翻译成对Linux操作系统的调用(操作Namespace和Cgroups等)。

kubelet还通过gRPC协议,同Device Plugin插件交互。

这插件是k8s用来管理GPU等宿主机物理设备的主要组件,也是基于k8s进行机器学习训练、高性能作业支持等工作必须关注的功能。

另一重要功能,是调用网络插件、存储插件为容器配置网络和持久化存储。这两个插件与kubelet进行交互的接口:

  • CNI(Container Networking Interface)
  • CSI(Container Storage Interface)

kubelet名字来自Borg里的同源组件Borglet。因为Borg不支持这里的容器技术,而只是简单使用Linux Cgroups对进程进行限制。即像Docker这样“容器镜像”在Borg不存在,Borglet组件自然也不需要像kubelet考虑咋和Docker交互、咋管理容器镜像,也无需支持CRI、CNI、CSI等诸多容器技术接口。

kubelet完全是为实现k8s项目对容器的管理能力而重新实现的一个组件,与Borg无直接传承关系。

虽不使用Docker,但Google内部确实在使用一个包管理工具Midas Package Manager (MPM),可部分取代Docker镜像的角色。

2 Borg对k8s的指导

Master节点实现细节,Borg与k8s不尽相同,但出发点一致,即咋编排、管理、调度用户提交的作业。Borg完全能将Docker镜像看做一种新的应用打包方式,Borg过去在大规模作业管理与编排上的经验可直接“套”在k8s。

所以,一开始k8s就不像同期各种“容器云”项目,把Docker作为架构核心,而是仅把它作为最底层的一个容器运行时实现。而k8s着重Borg研究人员在论文中提到的:运行在大规模集群中的各种任务之间,实际上存在各种关系。这些关系处理,才是作业编排和管理系统最困难的。

2.1 任务之间的关系

  • 一个Web应用与数据库之间的访问关系
  • 一个负载均衡器和其后端服务
  • 一个门户应用与授权组件之间的调用关系

同属于一个服务单位的不同功能之间,也完全可能存在这样关系,如:

  • 一个Web应用与日志搜集组件之间的文件交换关系

而容器技术普及前,传统VM对这种关系处理都“粗粒度”:

  • 很多功能不相关的应用被一锅部署在同台虚拟机,只是因为偶尔会互相发几个HTTP请求
  • 一个应用被部署在虚拟机后,需手动维护很多跟它协作的守护进程(Daemon),用来处理它的日志搜集、灾难恢复、数据备份等辅助工作

2.2 “功能单位”划分

容器有独到“细粒度”优势:毕竟容器本质只是个进程,只要你愿意,那些原挤在同一VM里的各应用、组件、守护进程,都可被分别做成镜像,然后运行在一个个专属容器。它们互不干涉,拥有各自资源配额,可被调度在整个集群里的任一台机器。这正是PaaS系统最理想工作状态,即微服务思想落地的先决条件。

若只做到封装微服务、调度单容器,Swarm已绰绰有余。若再加Compose项目,甚至还具备处理一些简单依赖关系的能力,如一个“Web容器”和它要访问的数据库“DB容器”。

Compose中可为这样的两个容器定义一个“link”,而Docker则维护该“link”关系:Docker会在Web容器中,将DB容器的IP地址、端口等信息以环境变量注入,给应用进程使用,如:

DB_NAME=/web/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
DB_PORT_5432_TCP_PROTO=tcp
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_ADDR=172.17.0.5

2.3 平台项目自动处理容器间关系

典型例子,当DB容器变化时(如镜像更新,被迁移至其他宿主机),这些环境变量值会由Docker自动更新。

但若要求该项目能处理前面提到的所有类型的关系,甚至能支持未来可能的更多关系,这时,“link”这针对一种案例设计的解决方案过于简单。一旦要追求普适性,就要从顶层做好设计。

3 顶层设计

k8s主要设计思想,宏观角度以统一方式定义任务间的各种关系,并为将来支持更多关系留有余地。

如k8s对容器间的“访问”进行分类,先总结一类常见“紧密交互”的关系:

  • 应用间需频繁交互
  • 直接通过本地文件进行信息交换

常规环境下的应用往往被部在同一台机器:

  • 通过Localhost通信
  • 通过本地磁盘目录交换文件

而在k8s,这些容器会被划分为一个“Pod”。

3.1 Pod

Pod里的容器共享同一Network Namespace、同一组数据卷,以高效率交换信息。Pod是k8s中最基础的对象,源于Borg论文中的Alloc设计:

Borg alloc(allocation缩写)是一台机器上可运行1或多个任务的资源的保留集。无论是否用资源,资源都保持分配状态。 Alloc可用于为将来任务留出资源,在停止任务和重启任务之间保留资源,以及将来自不同作业的任务收集到同一台计算机。

如一个Web服务器实例和一个关联的logaver任务,用于复制服务器的URL日志从本地磁盘记录到分布式文件系统。分配资源与机器资源的处理方式相似。在一个内部运行的多个任务共享其资源。若必须将分配重定位到另一台计算机,则其任务将随之重新安排。

分配集就像一项工作:它是一组在多台机器保留资源的分配。创建分配集后,可提交1或多个作业以在其中运行。

为简便,使用“任务”指代分配或顶级任务(在分配外的一个),使用“作业”来指代作业或分配集。

而对另一种更常见需求,如

4 Web应用与DB间的访问关系

k8s提供“Service”服务。像这样的两个应用,故意不部署在同一机器,即使Web应用所在机器宕机,DB也不受影响。

可一个容器的IP地址等信息不固定,Web应用咋找到DB容器的Pod?k8s给Pod绑定一个

4.1 Service(服务)

Service声明的IP地址等信息“终生不变”。Service作为Pod的代理入口(Portal),代替Pod对外暴露一个固定的网络地址。

Web应用Pod,需关心DB Pod的Service信息。Service后端真正代理的Pod的IP地址、端口等信息的自动更新、维护,才是k8s的职责。

围绕容器、Pod不断向真实的技术场景扩展,得到k8s核心功能“全景图”:

  • 从容器出发,先遇到容器间“紧密协作”关系难题,于是扩展到Pod
  • 有了Pod,希望一次启动多个应用的实例,就需Deployment这个Pod的多实例管理器
  • 有了这组相同Pod后,又需通过一个固定的IP地址、端口以LB方式访问它,就有了Service

若现在两个不同Pod间不仅有“访问关系”,还要求在发起时加上授权信息。如Web应用访问DB需Credential(数据库用户名密码),k8s咋处理?

k8s提供Secret对象,一个保存在Etcd里的KV对:

把Credential信息以Secret方式存在Etcd,k8s就会在你的指定Pod(如Web应用Pod)启动时,自动把Secret里的数据以Volume方式挂载到容器。这样,Web应用就能访问DB。

除了应用之间的关系,应用运行形态是影响“咋容器化该应用”的第二因素。为此,k8s定义了基于Pod改进后的对象。如:

  • Job:一次性运行的Pod(如大数据任务)
  • DaemonSet:每个宿主机上,须且只能运行一个副本的守护进程服务
  • CronJob:定时任务

正是k8s定义容器之间关系和形态的主要方法。k8s不像其他项目那样,为每个管理功能创建一个指令,然后在项目中实现其中逻辑。这种做法,的确可解决当前问题,但更多问题来临后,力不从心。k8s推崇:

  • 先通过一个“编排对象”,如Pod/Job/CronJob等描述你试图管理的应用
  • 再为它定义一些“服务对象”,如Service/Secret/Horizontal Pod Autoscaler(自动水平扩展器)等。这些对象,会负责具体的平台级功能。

这种使用方法即“声明式API”。这种API对应的“编排对象”和“服务对象”,都是k8s中的API对象(API Object)。

这就是k8s最核心的设计理念。

5 k8s咋启动一个容器化任务

制作好一个Nginx容器镜像,希望让平台帮我启动。且要求平台帮我运行两个完全相同的Nginx副本,以LB方式共同对外提供服务。

若DIY,可能需启动两台VM,分别安装两个Nginx,然后用keepalived为这两个VM做一个虚拟IP。

而用k8s,要做的就是写YAML(nginx-deployment.yaml):

apiVersion: apps/v1  # 指定API版本
kind: Deployment  # 指定资源类型为Deployment,用于管理Pod的部署和扩缩容
metadata: # 定义资源的元数据,包括名称和标签
  name: nginx-deployment  # 指定Deployment名称
  labels: # 定义标签,用于标识和选择资源
    app: nginx
spec: # 定义Deployment的详细规格
  replicas: 2  # 指定Pod副本数,即需要创建的Pod实例数量
  selector: # 定义选择器,用于匹配具有指定标签的Pod
    matchLabels: # 匹配具有指定标签的Pod
      app: nginx
  template: # 定义Pod模板的元数据和规格。
    metadata: # 定义Pod模板的元数据
      labels: #  定义Pod的标签
        app: nginx
    spec: # 定义Pod中容器的详细信息
      containers: # 定义容器列表
      - name: nginx  # 指定容器名称
        image: nginx:1.7.9  # 指定容器使用的镜像
        ports: # 定义容器暴露的端口
        - containerPort: 80

该YAML文件定义一个Deployment对象,其主体部分(spec.template部分)是用Nginx镜像的Pod。

然后执行:

$ kubectl create -f nginx-deployment.yaml

两个完全相同的Nginx容器副本就被启动。

6 总结

容器可分为:

  • 容器运行时
  • 容器镜像

调度

过去很多的集群管理项目(Yarn、Mesos及Swarm)擅长把一个容器,按某种规则,放在某最佳节点运行。

编排

而k8s擅长按用户意愿和整个系统规则,全自动化处理容器之间各种关系。所以k8s本质是为用户提供具有普遍意义的容器编排工具。而不仅限于一个工具,真正价值在于提供一套基于容器构建分布式系统的基础依赖。

参考:

关注我,紧跟本系列专栏文章,咱们下篇再续!

作者简介:魔都架构师,多家大厂后端一线研发经验,在分布式系统设计、数据平台架构和AI应用开发等领域都有丰富实践经验。

各大技术社区头部专家博主。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。

负责:

  • 中央/分销预订系统性能优化
  • 活动&券等营销中台建设
  • 交易平台及数据中台等架构和开发设计
  • 车联网核心平台-物联网连接平台、大数据平台架构设计及优化
  • LLM Agent应用开发
  • 区块链应用开发
  • 大数据开发挖掘经验
  • 推荐系统项目

    目前主攻市级软件项目设计、构建服务全社会的应用系统。

参考:

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
14天前
|
人工智能 弹性计算 运维
ACK Edge与IDC:高效容器网络通信新突破
本文介绍如何基于ACK Edge以及高效的容器网络插件管理IDC进行容器化。
|
16天前
|
监控 NoSQL 时序数据库
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
156 77
|
3天前
|
存储 Kubernetes 开发者
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
Docker 是一种开源的应用容器引擎,允许开发者将应用程序及其依赖打包成可移植的镜像,并在任何支持 Docker 的平台上运行。其核心概念包括镜像、容器和仓库。镜像是只读的文件系统,容器是镜像的运行实例,仓库用于存储和分发镜像。Kubernetes(k8s)则是容器集群管理系统,提供自动化部署、扩展和维护等功能,支持服务发现、负载均衡、自动伸缩等特性。两者结合使用,可以实现高效的容器化应用管理和运维。Docker 主要用于单主机上的容器管理,而 Kubernetes 则专注于跨多主机的容器编排与调度。尽管 k8s 逐渐减少了对 Docker 作为容器运行时的支持,但 Doc
27 5
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
|
9天前
|
关系型数据库 应用服务中间件 PHP
实战~如何组织一个多容器项目docker-compose
本文介绍了如何使用Docker搭建Nginx、PHP和MySQL的环境。首先启动Nginx容器并查看IP地址,接着启动Alpine容器并安装curl测试连通性。通过`--link`方式或`docker-compose`配置文件实现服务间的通信。最后展示了Nginx配置文件和PHP代码示例,验证了各服务的正常运行。
29 3
实战~如何组织一个多容器项目docker-compose
|
1天前
|
Prometheus Kubernetes 监控
OpenAI故障复盘 - 阿里云容器服务与可观测产品如何保障大规模K8s集群稳定性
聚焦近日OpenAI的大规模K8s集群故障,介绍阿里云容器服务与可观测团队在大规模K8s场景下我们的建设与沉淀。以及分享对类似故障问题的应对方案:包括在K8s和Prometheus的高可用架构设计方面、事前事后的稳定性保障体系方面。
|
15天前
|
人工智能 运维 监控
阿里云ACK容器服务生产级可观测体系建设实践
本文整理自2024云栖大会冯诗淳(花名:行疾)的演讲,介绍了阿里云容器服务团队在生产级可观测体系建设方面的实践。冯诗淳详细阐述了容器化架构带来的挑战及解决方案,强调了可观测性对于构建稳健运维体系的重要性。文中提到,阿里云作为亚洲唯一蝉联全球领导者的容器管理平台,其可观测能力在多项关键评测中表现优异,支持AI、容器网络、存储等多个场景的高级容器可观测能力。此外,还介绍了阿里云容器服务在多云管理、成本优化等方面的最新进展,以及即将推出的ACK AI助手2.0,旨在通过智能引擎和专家诊断经验,简化异常数据查找,缩短故障响应时间。
阿里云ACK容器服务生产级可观测体系建设实践
|
15天前
|
运维 Kubernetes 调度
阿里云容器服务 ACK One 分布式云容器企业落地实践
阿里云容器服务ACK提供强大的产品能力,支持弹性、调度、可观测、成本治理和安全合规。针对拥有IDC或三方资源的企业,ACK One分布式云容器平台能够有效解决资源管理、多云多集群管理及边缘计算等挑战,实现云上云下统一管理,提升业务效率与稳定性。
|
25天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
64 7
|
25天前
|
监控 Docker 容器
在Docker容器中运行打包好的应用程序
在Docker容器中运行打包好的应用程序
|
18天前
|
数据建模 应用服务中间件 nginx
docker替换宿主与容器的映射端口和文件路径
通过正确配置 Docker 的端口和文件路径映射,可以有效地管理容器化应用程序,确保其高效运行和数据持久性。在生产环境中,动态替换映射配置有助于灵活应对各种需求变化。以上方法和步骤提供了一种可靠且易于操作的方案,帮助您轻松管理 Docker 容器的端口和路径映射。
60 3

相关产品

  • 容器服务Kubernetes版