虚拟化技术作为云计算的前提之一,不断伴随引发着深远的技术变更。早期的虚拟机虚拟化,将传统物理计算资源虚拟化为若干虚拟服务器,可各自运行各自的操作系统,从而提高整体计算资源利用率。但随着业务敏捷需求逐步显现,业务服务颗粒度不断变小,微服务架构便随之产生。微服务架构的细颗粒度隔离需求和管理需求使得容器技术逐渐成为对云计算领域具有深远影响的变革技术。容器技术的发展和应用,将为各行业应用云计算提供了新思路,同时容器技术也将对云计算的交付方式、效率、PaaS平台的构建等方面产生深远的影响,具体体现在以下几个方面:
• 部署:容器可以将应用打包成单一可运行、可储存的组件,并且在任何时间任何地点进行部署。
• 启动:容器共享宿主机操作系统kernel,使得容器中的进程启动和在操作系统中类似,不必像虚拟机一样额外启动操作系统,故启动速度将变快。
• 组装:容器的细颗粒度和轻量化实现导致运行在容器中的应用可以轻易进行服务组合和再封装。
• 迁移透明:容器技术最重要的价值就是为在不同宿主机上运行服务提供一个轻便的、一致的格式。容器的标准化和CNCF等组织的成立,使得相关技术逐步标准化和透明化,避免局限于单一的平台提供商。
术语 | 定义/解释 |
---|---|
镜像 | 容器运行的必备软件集合,可用于运行容器实例。 |
微服务架构 | 微服务架构是一种特定的软件应用程序设计方式——将大型软件拆分为多个独立可部署服务组合而成的套件方案。 |
DEVOPS | 可定义为是一种过程、方法、文化、运动或实践,主要是为了通过一条高度自动化的流水线来加强开发和其他IT职能部门之间的沟通和协作,加速软件和服务的交付。 |
CI/CD | Continuous Integration/Continuous Delivery,即持续集成和持续交付。通过自动化手段持续开发集成测试并交付应用服务,到达快速交付的目的。 |
CaaS | Container as a Service ,即容器即服务。 |
CLI | command-line interface,即命令行界面。 |
DNS | Domain Name System,即域名系统 |
IaaS | Infrastructure as a Service,即基础设施即服务 |
PaaS | Platform as a Service,即平台即服务 |
SaaS | Software as a Service,即软件即服务 |
SDN | Software Defined Network,即软件定义网络 |
LXC | Linux Container,即Linux容器 |
VM | Virtual Machine,虚拟机 |
Docker是一个开源项目,诞生于2013年初。最初由dotCloud公司开发,其基于Go语言实现。后续该项目加入了Linux基金会,遵从了Apache2.0协议,代码在GitHub上进行维护。
Docker项目的目标是实现轻量级的操作系统虚拟化解决方案。其隔离的基础是基于Linux Kernel实现。无论是早期使用的LXC还是后续自开发的libcontainer,Docker都基于底层的隔离进行了进一步的封装,使得对应用用户透明,不必去关注底层实现,操作就像一个快速轻量级的虚拟机一样简单。
传统虚拟机虚拟化和容器虚拟化的差异,参考下图。
对比项 | 虚拟机 | 容器 |
---|---|---|
虚拟化级别 | 运行在虚拟硬件上,应用运行在虚机上 | 宿主机的一个进程,直接运行在宿主机上。 |
运行环境 | 必须是物理机 | 物理机、虚机、甚至是容器内 |
启动速度 | 分钟级 | 秒级 |
大小 | 独立 Kernel,附加各类服务 | 共享 Kernel, 一项服务 |
弹性计算 | 纵向扩容,但需重启 | 横向扩容 |
libcontainer功能实现上涵盖了包括对Linux Kernel中namespaces的使用、cgroups管理、Rootfs的配置启动、默认的Linux capability权限集、以及进程运行的环境变量配置。
容器虽然通过操作系统Kernel实现了虚拟化,但其毕竟没有物理上的Hypervisor层,无法实现如果虚拟机这样完全的隔离。同时,类似于原先虚拟机中vcenter、nova等调度方案,容器也需调度编排方案用于降低平台管理成本。综上,其劣势主要涉及以下三方面:
隔离性:Namespaces 和 cgroups 虽然允许一个进程以及它的子进程从共享的内核资源(入网络栈和进程列表)里获得一个仅自己可见的视图。虽然这样占用更低的内存,启动速度更快,但是会降低操作系统Kernel的安全性、稳定性和兼容性。一个极端的情况就是 Linux 内核接口,在内核和命名空间中运行不相容的或者未经测试的 glibc 可能产生一些无法预测的操作。
安全性:从设计上来说,Docker过于依赖Linux Kernel中Namespaces的能力,但Namespaces相比普通的Hypervisor有太多的漏洞。对于企业内部而言,可以通过一系列外部约束手段降低该风险,但对于在公有云多租户环境中却很难实现如上要求。一旦Namespaces漏洞导致宿主机被攻击,那么运行在其之上的所有容器实例将变得非常危险。
编排方案:通常一个应用程序在其架构中通常是多层的,可能包含若干应用服务组件即若干中间件组件,同时各层之间可能存在非常复杂的互相依赖场景。于此同时,容器的轻量及稳定性特点意味着其生命周期并非像传统虚拟机这么持久。因此需要通过一种编排手段来管理容器和容器,容器和外部依赖,容器和下层基础资源的依赖关系。原生的Docker只包含容器本身,但对于容器编排调度等管理工作则需要依赖其他方案完成。
通常一个集群编排调度平台需要实现如下功能:提高集群资源利用率、支持用户配置约束、及时管理以此保证彼此状态可知、“公平”调度,服务具有高可用性等。根据Google发布的关于其内部使用的Omega容器管理平台的白皮书中所描述的,实现上述功能主要可通过如下三种调度架构:
巨石架构(Monolithic)通过单一的调度代理来处理所有请求,通常用于高性能计算。巨石架构通常实现了一个单一的算法来处理所有的job,因此根据job的类型来运行不同的调度逻辑是困难的。
两级调度(Two-level)通过中央协调器来动态地决定各个调度模块可以调用多少资源。在这类架构里,分配器会将给定的资源一次性分配个一个调度模块,因此避免了资源使用的冲突,并且通过控制资源分配的顺序和大小来实现一种相对的资源公平分配。但是由于一个资源单元同一时间只能被一个调度模块使用,其使用的是悲观并发策略,速度相对较慢,且整体资源利用率不高。
共享状态调度(Shared-state)赋予了每一个调度模块对整个集群的全部访问权限,其之间可以自由地竞争。没有了中央策略引擎,每一个调度器能够自己做决定。通过支持独立的调度器实现和公布整个资源分配的状况。在Google Omega中不仅支持扩展多个调度器,还能够支持它们自己的调度策略。
对企业而言,容器编排调度工具的主要任务就是负责在最合适的宿主机上启动容器,并且将它们关联起来。同时其需要支持自动的故障转移来处理局部的底层宿主机资源错误。当某个容器实例服务能力不足响应业务需求之时,其能够扩展容器来解决问题。我司在2016年开始进行Docker容器的平台构建准备工作,期间主要调研了Docker Swarm 和Kubernetes 两种调度工具。
Docker Swarm是一个Docker内部包含的调度框架,其API集成在Docker API中。Swarm的架构由两部分组成:Swarm管理节点和Swarm 工作节点。
Docker Swarm管理节点负责调度容器,其本身也可以通过集群部署实现高可用。由于Docker Swarm API与Docker标准API类似,开发者在使用Swarm的同时并不需要过多改变其原先使用的Docker工作方式。
Docker Swarm可包含若干个宿主机工作节点。这些宿主机在启动Docker daemon的时候就会打开相应的端口,以通过Docker远程API供Swarm管理节点调度。
关于调度策略,Docker Swarm采用了三个策略:
spread:最少的容器,并且忽视它们的状态
binpack:最拥挤(比如说,拥有最少数量的CPU/RAM)
random:随机选择
关于节点和容器选择过滤策略,Docker Swarm提供了两个节点过滤器和三个容器配置过滤器:
约束过滤器:每个节点可标记特定的key=value值,在运行容器时根据这个特定值进行查找。如果没有节点满足要求,这个容器将不会运行。
健康状态过滤器:用来防止调度不健康的节点。
Affinity过滤器:对于容器Affinity,在运行一个新的容器时指定Affinity容器,这些容器就会互相链接。如果其中一个容器停止运行了,剩下的容器都会停止运行。镜像Affinity会把想要运行的容器调度到已经拥有该镜像的节点上。标签Affinity会和容器的label一起查找容器宿主机进行运行。
依赖过滤器:其能够用来运行一个依赖于其他容器的容器。依赖意味着和其他容器共享磁盘卷,或者是链接到其他容器,亦或者和其他容器在同一个网络栈上。
端口过滤器可支持容器集群在特定端口上暴露服务端点。如果集群中没有任何一个节点该端口可用的话,系统就会给出一个错误的提示信息。
Kubernetes是由Google开源的容器的编排系统,Docker可作为其容器的实现。其使用pod的概念来将多个容器划分为软件最小可执行逻辑单元。这些pod被共同部署和调度,形成了一个服务。相比于其他容器调度方式,这个方法简化了应用颗粒度对容器集群管理的复杂度需求。
Kubernetes调度器查找NodeName为空的pod,通过nodeSelector和Affinity来选择在哪台宿主机上运行。
灵活的语法:支持In,NotIn,Exists,DoesNotExist,Gt,Lt等语法定义。
支持定义软性要求和硬性要求。所谓硬性要求表示pod 调度到某个宿主机节点必须满足Affinity要求。软性要求表示scheduler的时候,无法满足调度要求的时候,会选择非nodeSelector匹配的节点。
如果在nodeAffinity的基础上添加多个nodeSelectorTerms字段,则调度的时候宿主机只需要在nodeSelectorTerms满足一条即满足nodeAffinity的规则。如果在nodeSelectorTerms中添加matchExpressions,则需要满足matchExpressions中的所有规则。
我司着重调研了Docker Swarm和Kubernetes平台。
从架构的完整性上看由于Docker Swarm较为轻量,且与Docker原生API集成,使用较为简单。但其在容器模型抽象和集群调度的复杂需求满足度上就远比Kubernetes轻量。相比于Swarm,Kubernetes添加了pod和replica的逻辑。这个更加复杂的结构为调度器和编排工具提供了更加丰富的功能,比如说负载均衡,扩展或者收缩应用的能力。
从开源社区的支持力度看,CNCF协会的成立促使Kubernetes及其生态圈衍生项目逐步完整化,并逐步构建成云原生基础架构蓝图。相较之下Docker Swarm则逐步向封闭靠拢,Docker后续改名为Moby更是导致开源社区嘘声一片。
从容器云调度平台市场占有率来看,Kubernetes始终时排名第一。
传统行业的第一个痛点就是“剪不断、理不清的业务流程”。由于传统企业更注重线下业务和流程,其业务模式与互联网企业有较大差异。以我司为例,下图描述了从客户购车前至二手车卖家出售车整个客户生命周期中整车厂对客户的触点。而每个客户触点均对应了一个完整的业务流程。因此如何将这些业务流程解耦变为系统?这就是第一个痛点。
针对上文企业痛点分析,我们希望通过容器平台实施需要实现如下目标:
因原文较长,故将文章拆分成三篇发布,此篇为第一部分,后两部分将于下两周发布。
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞6
添加新评论2 条评论
2019-03-20 18:31
2018-10-11 22:30