过往年少|微服务架构开发实战:基于容器的部署与发布微服务,30K有望了
在微服务架构系统中包含了大量的服务 , 并且服务之间存在复杂的依赖关系 , 以拓扑的形式运行并相互协作 , 如果部署的时候采取方式来解决整体的依赖、配置通信的协议和地址等 , 那么重新部署到新环境的成本会非常高 。 而容器技术提供了一种将所有的服务能够迅速快捷地重新部署的方案 , 并且可以根据需求进行横向的扩展 , 且保证高可用性 , 在出现问题的时候可以自动重启或者启动备份服务 。
本文插图
所谓虚拟化技术就是将事物从一种形式转变成另一种形式 , 最常用的虚拟化技术有操作系统中内存的虚拟化 , 实际运行时用户需要的内存空间可能远远大于物理机器的内存大小 , 利用内存的虚拟化技术 , 用户可以将一部分硬盘虚拟化为内存 , 而这对用户是透明的 。 又如 , 可以利用虚拟专用网技术(VPN)在公共网络中虚拟化一条安全、稳定的“隧道” , 用户感觉像是在使用私有网络一样 。
虚拟机技术是虚拟化技术的一种 , 虚拟机技术最早由IBM于20世纪六七十年代提出 , 被定义为硬件设备的软件模拟实现 , 通常的使用模式是分时共享昂贵的大型机 。 Hypervisor是一种运行在基础物理服务器和操作系统之间的中间软件层 , 可允许多个操作系统和应用共享硬件 , 也可称为VMM (Virtual Machine Monitor , 虚拟机监视器) 。 VMM是虚拟机技术的核心 , 用来将硬件平台分割成多个虚拟机 。 VMM运行在特权模式 , 主要作用是隔离并且管理上层运行的多个虚拟机 , 仲裁它们对底层硬件的访问 , 并为每个客户操作系统虚拟一套独立于实际硬件的硬件环境(包括处理器、内存、I/O 设备) 。 VMM采用某种调度算法在各个虚拟机之间共享CPU , 如采用时间片轮转调度算法 。
虚拟化技术已经改变了现代计算方式 , 它能够提升系统资源的使用效率 , 消除应用程序和底层硬件之间的依赖关系 , 同时加强负载的可移植性和安全性 , 但是Hypervisor和虚拟机只是部署虚拟负载的方式之一 。 作为一种能够替代传统虚拟化技术的解决方案 , 容器虚拟化技术凭借其高效性和可靠性得到了快速发展 , 它能够提供新的特性 , 以帮助数据中心专家解决新的顾虑 。
容器具有轻量级特性 , 所需的内存空间较少 , 提供非常快的启动速度 , 而虚拟机提供了专用操作系统的安全性和更牢固的逻辑边界 。 如果是虚拟机 , 虚拟机管理程序与硬件对话 , 就如同虚拟机的操作系统和应用程序构成了一个单独的物理机 。 虚拟机中的操作系统可以完全不同于主机的操作系统 。
容器提供了更高级的隔离机制 , 许多应用程序在主机操作系统下运行 , 所有应用程序共享某些操作系统库和操作系统的内核 。 已经过证明的屏障可以阻止运行中的容器彼此冲突 , 但是这种隔离存在一些安全方面的问题 , 我们稍后会探讨 。
容器和虚拟机都具有高度可移植性 , 但方式不一样 。 就虚拟机而言 , 可以在运行同一虚拟机管理程序(通常是VMware的ESX、微软的Hyper-V或者开源Zen、KVM)的多个系统之间进行移植 。
而容器不需要虚拟机管理程序 , 因为它与某个版本的操作系统绑定在一起 。 但是容器中的应用程序可以移到任何地方 , 只要那里有一份该操作系统的副本 。
容器的一大好处就是应用程序以标准方式进行了格式化之后才放到容器中 。 开发人员可以使用同样的工具和工作流程 , 不管目标操作系统是什么 。 一旦在容器中 , 每种类型的应用程序都以同样的方式在网络上移动 。 这样一来 , 容器酷似虚拟机 , 它们又是程序包文件 , 可以通过互联网或内部网络来移动 。
我们已经有了Linux容器、Solaris容器和FreeBSD容器 。 微软正与Docker公司合作 , 开发Windows容器 。 Docker容器里面的应用程序无法迁移到另一个操作系统 。 确切地说 , 它能够以标准方式在网络上移动 , 因而更容易在数据中心内部或数据中心之间移动软件 。 单一容器总是与单一版本的操作系统内核关联起来 。
1.成熟度方面的比较
虚拟机是一项高度发展、非常成熟的技术 , 事实证明其可以运行最关键的业务工作负载 。 虚拟化软件厂商已开发出了能处理成千上万个虚拟机的管理系统 , 那些系统旨在适合企业数据中心的现有运营 。
容器代表了未来的新技术 , 而这种大有希望的新兴技术未必能解决每一个困难 。 开发人员正在开发相应的管理系统 , 以便一启动就将属性分配给一组容器 , 或者将要求相似的容器分成一组 , 以便组成网络或加强安全 , 但是这类系统仍在开发之中 。
Docker最初的格式化引擎正成为一种平台 , 并附有许多工具和工作流程 。 而容器获得了一些大牌技术厂商的支持 。 IBM、红帽、微软和Docker都加入了Google的Kubernetes项目 , 这个开源容器管理系统可用于将诸多Linux容器作为单一系统来管理 。
2启动速度的比较
创建容器的速度比虚拟机要快得多 , 那是由于虚拟机必须从存储系统检索10~20GB的空间给操作系统 。 容器中的工作负载使用主机服务器的操作系统内核 , 避免了这一步 。 容器可以实现秒级启动 。
拥有这么快的速度让开发团队可以激活项目代码 , 以不同的方式测试代码 , 或者在其网站上推出额外的电子商务容量 , 这一切都非常快 。
3.安全方面的比较
就目前来说 , 虚拟机比容器有更高的安全性 。 容器技术并不像看上去那么可靠 。 以应用Libcontainers作为技术支持的Docker为例 , 在Linux系统的工作模式下 , Libcontainers可以访问五个命名空间:流程、网络、安装、主机名和共享内存 。 这固然很好、很强大 , 然而仍然有很多重要的Linux核心子系统不能被容器所兼容 , 包括所有的设备、SELinux、Cgroup 及lsys下的所有文件系统 。 这意味着 , 如果某位用户或应用程序获取了容器内部的超级用户权限 , 底层操作系统理论上可以被破解 。 这是一件非常糟糕的事情 。
现在出现了很多保护Docker 和其他容器技术的措施 。 举例来说 , 我们可以将一个lsys文件系统设置为“只读” , 或者强制某个容器进程对特定的文件系统执行“只写”操作 , 或者设置网络命名空间 , 以使其只能与特定的企业内联网交流信息 。 但是 , 这些办法都不能从根本上解决问题 , 如此维护容器安全需要耗费大量的时间和精力 。
另一项安全问题是 , 很多人都在发布基于容器的应用 , 如果未对网络上的这些应用加以识别 , 很可能会下载到带有木马的应用 , 这样就可能给我们的服务器带来严重的安全隐患 。
4.性能方面的比较
在2014年 , IBM研究部门发表了一篇关于容器和虚拟机环境性能比较的论文:An UpdatedPerformance Comparison of Virtual Machines and Linux ContainersR 。 这篇论文使用了Docker和KVM作为研究对象 , 阐述了Docker使用NAT或AUFS时的开销 , 并且质疑了在虚拟机上运行容器的实践方法 。
论文作者在原生、容器和虚拟化环境中运行了CPU、内存、网络和IO的Benchmark 。 其中 , 分别使用KVM和Docker作为虚拟化和容器技术的代表 。 Benchmark也包含了对不同环境下Redis和MySQL负载的采样 。 通过小数据包和多客户端的对比发现 , Redis侧重于网络栈的性能 , 而MySQL侧重于内存、网络和文件系统的性能 。
结果显示 , 在每一项测试中 , Docker 的性能等同于或超出KVM的性能 。 在CPU和内存性能方面 , KVM和Docker都引入了明显的但可粗略不计的开销 。 但是 , 对于IO密集型的应用 , 两者
都需要进行调整 , 以减少开销带来的影响 。
当使用AUFS存储文件时 , Docker 的性能会降低 。 而相比之下 , 使用卷(Volume)能够获得更好的性能 。 卷是一种专门设计的目录 , 存在于一个或多个容器内 。 通过这种目录能够绕过联合文件系统(Union File System) 。 这样它就没有了存储后端可能带来的开销 。 默认的AUFS后端会引起显著的IO开销 , 特别是当有多层目录深度嵌套的时候 。
Docker 的默认网络选项是--net=bridge , 由于NAT会重写数据包 , 也引入了性能开销 。 当数据包收发率变高时 , 这种开销会变得很明显 。 可以通过使用--net=host来改善网络的性能 。 这个选项告诉Docker不要为容器创建一个独立的网络栈 , 并允许容器拥有宿主机网络接口的完全访问权限 。
但是 , 使用这个选项时要小心 。 因为它允许容器内的进程像其他根进程一样使用数值较小的端口 , 并允许容器内的进程访问本地网络服务 , 如D-bus 。 这使容器内的进程可以做一些预料之外的事情 , 如重启宿主机 。
尽管自诞生以来 , KVM的性能有了相当大的提升 , 但它仍然不适用于对延时敏感或高IO访问率的工作负载 。 因为每次IO操作 , 它都会增加一些开销 。 这个开销对于耗时较少的IO操作是有意义的 , 但对于耗时较长的I/O操作是可以忽略的 。
尽管在虚拟环境中运行容器是一种常见的实践方法 , 但是论文中建议直接在物理的Linux服务器上运行它们 。 否则 , 相比于直接运行在非虚拟化的Linux上的方法 , 由于虚拟机的性能开销 , 这种实践方法不会得到任何额外的好处 。
本文插图
随着Docker等容器技术的纷纷涌现及开源发布 , 软件开发行业对于现代化应用的打包及部署方式发生了巨大的变化 。 想象下在没有容器等虚拟化技术的年代 , 程序经常需要手工部署和测试 , 这种工作极其烦琐且容易出错 , 特别是服务器数量多的时候 , 重复性的工作总是令人厌烦 。 由于开发环境、测试环境以及最终的生产环境的不一致 , 同样的程序 , 有可能在不同的环境出现不同问题 ,
所以经常会出现开发人员和测试人员“扯皮”的事 。 开发机上没有出现问题 , 部署到测试服务器上就出问题了 。
现在就来介绍一下如何基于容器来实现持续部署上提到的种种问题 。
1.建立持续部署流水线
持续部署流水线(Continuous Deployment Pipeline )是指在每次代码提交时会执行的一系列步骤 。
流水线的目的是执行一系列任务 , 将一个经过完整测试的功能性服务或应用部署至生产环境 。
唯一一个手工操作就是向代码仓库执行一次嵌入操作 , 之后的所有步骤都是自动完成的 。 这种流程可以在一定程度上消除人为产生错误的因素 , 从而增加可靠性 。 并且可让机器完成它们最擅长的工作——运行重复性的过程 , 而不是创新性思考 , 从而增加了系统的吞吐量 。 之所以每次提交都需要通过这个流水线 , 原因就在于“持续”这个词 。 如果选择延迟这一过程的执行 , 例如 , 在某个Sprint结束前再运行 , 那么整个测试与部署过程都不再是持续的了 。
2.测试
容器技术的出现可以轻松地处理各种测试问题 , 因为测试和最后需要部署到生产环境的将是同一个容器 , 里面包含的系统运行所需要的运行时与依赖都是相同的 。 这样开发者在测试过程中选择应用所需的组件 , 通过团队所用的持续部署工具构建并运行容器 , 让这一容器执行所需的各种测试 。
当代码通过全部测试之后 , 就可以进入下一阶段的工作了 。 测试所用的容器应当在注册中心(可选择私有或公有)中进行注册 , 以便之后重用 。 除了已经提到的各种益处 , 在测试执行结束之后 , 就可以销毁该容器 , 使服务器回到原来的状态 。 如此一来 , 就可以使用同一台服务器(或服务集群)对全部服务进行测试了 。
3.构建
当执行完所有测试后 , 就可以开始创建容器 , 并最终将其部署至生产环境中了 。 由于我们很可能会将其部署至一个与构建所用不同的服务器中 , 因此同样应当将其注册在注册中心 。
当完成测试并构建好新的发布后 , 就可以准备将其部署至生产服务器中了 。 我们所要做的就是获取对应的镜像并运行容器 。
4.部署
当容器上传至注册中心后 , 就可以在每次签入之后部署我们的微服务 , 并以前所未有的速度将新的特性交付给用户 。
5.蓝-绿部署
整个流水线中最危险的步骤可能就是部署了 。 如果我们获取了某个新的发布并开始运行 , 容器就会以新的发布取代旧的发布 。 也就是说 , 在过程中会出现一定程度的停机时间 。 容器需要停止旧的发布并启动新的发布 , 同时我们的服务也需要进行初始化 。 虽然这一过程可能只需几分钟、几秒钟甚至是几微秒 , 但还是造成了停机时间 。 如果实施了微服务与持续部署实践 , 那么发布的次数会比之前更频繁 。 最终 , 我们可能会在一天之内进行多次部署 。 无论决定采用怎样的发布频率 , 对用户的干扰都是我们应当避免的 。
应对这一问题的解决方案是蓝绿部署(Blue-Green Deployment) 。 简单地说 , 这个过程将部署一个新发布 , 使其与旧发布并行运行 。 可将某个版本称为“蓝” , 另一个版本称为“绿” 。 当新版本部署之后验证没有问题 , 再完全撤掉旧版本 , 而在这之前 , 老版本还能继续提供服务 。
6.运行预集成及集成后测试
虽然测试的运行至关重要,但它无法验证要部署至生产环境中的服务是否真的能够按预期运行 。
服务在生产环境上无法正常工作的原因是多种多样的 , 许多环节都有可能产生错误 , 可能是没有正确地安装数据库或是防火墙阻碍了对服务的访问 。 即使代码按预期工作 , 也不代表已验证了部署的服务得到了正确的配置 。 即便搭建了一个预发布服务器以部署我们的服务 , 并且进行了又一轮测试 , 也无法完全确信在生产环境中总是能够得到相同的结果 。 为了区分不同类型的测试 , Viktor Farcic
将其称为“预部署(Pre Deployment)”测试 , 这些测试的相同点是在构建与部署服务之前运行 。
7.回滚与清理
如果在整个流程中有任何一部分出错 , 整个环境就应当保持与该流程初始化之前相同的状态 , 即状态回滚(Rolling Back ) 。
即使整个过程如计划般一样顺利执行 , 也仍然有一些清理工作需要处理 。 我们需要停止旧的发布 , 并删除其注册信息 。
8.决定每个步骤的执行环境
决定每个步骤的执行环境是至关重要的 。 按照一般的规则来说 , 尽量不要在生产服务器中执行 。
这表示除了部署相关的任务 , 都应当在一个专属于持续部署的独立的集群中执行 。
举例来说 , 如果使用Docker Swarm进行容器的部署 , 那么无须直接访问主节点所在的服务 ,
而是创建DOCKER_HOST变量 , 将最终的目标地址通知本地Docker客户端 。
9.完成整个持续部署流
现在我们已经能够可靠地将每次签入部署至生产环境中了 , 但我们的工作只完成了一半 。 另一半工作是对部署进行监控 , 并根据实时数据与历史数据进行相应的操作 。 由于我们的最终目标是将代码签入后的一切操作实现自动化 , 因此人为的交互将会降至最低 。 创建一个具备自恢复能力的系统是一个很大的挑战 , 它需要我们进行持续的调整 。 我们不仅希望系统能够从故障中恢复(响应式恢复) , 同时也希望尽可能第一时间防止这些故障出现(预防性恢复) 。
如果某个服务进程出于某种原因中止了运行 , 系统应当再次将其初始化 。 如果产生故障的原因是某个节点变得不可靠 , 那么初始化过程应当在另一个健康的服务器中运行 。 响应式恢复的要点在于通过工具进行数据收集、持续地监控服务 , 并在发生故障时采取行动 。 预防性恢复则要复杂许多,它需要将历史数据记录在数据库中 , 对各种模式进行评估 , 以预测未来是否会发生某些异常情况 。
预防性恢复可能会发现访问量处于不断上升的情况 , 需要在几个小时之内对系统进行扩展 。 也可能是每个周一早上是访问量的峰值 , 系统在这段时间需要扩展 , 随后在访问量恢复正常之后收缩成原来的规模 。
目前 , 大家对基于容器的部署流程有了初步的了解 , 在后面章节还将会继续对基于Docker容器的部署做深入的探讨 。
本文插图
- 下篇文章给大家讲解使用Docker来构建、运行、发布微服务;
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!
推荐阅读
- 显微镜|假如人类可以把显微镜提升到40亿倍,是不是全新的宇宙观?
- 各地地方风味特色菜!
- 猜成语|看图猜成语:稍微转一转,生命更精彩!
- 布法罗大学|新工具可以通过眼睛里的微小反射来识别出深度伪造照片
- 微创手术|女大学生双手“挥汗如雨” 微创手术20分钟搞定顽疾
- 大叔用xo酱炖的辣豆腐,嫩滑可口,咸鲜微辣,家人爱吃!
- 鲫鱼我只服这样做,稍微腌制风干,做好一次可以吃上半年
- 使用微波炉蒸蔬菜,要想好吃营养不流失,不同的蔬菜方法不同
- 微笑豆沙巧克力面包
- 螺旋测微器|敲黑板!千分尺就怕这样用……
