容器云平台基础架构方案设计思考

aoxiang 发表了文章 • 0 个评论 • 246 次浏览 • 2019-05-29 22:02 • 来自相关话题

【编者的话】本文是作者作为一名云计算运维工程师在参与容器云平台建设中的一些有感记录,此次主要针对基础架构技术方案设计方面谈谈自己的一些认知,如有描述不妥之处,还请多包涵并给予指正。 如今,在移动互联的大时代下,互联网公司金融业务的爆炸 ...查看全部
【编者的话】本文是作者作为一名云计算运维工程师在参与容器云平台建设中的一些有感记录,此次主要针对基础架构技术方案设计方面谈谈自己的一些认知,如有描述不妥之处,还请多包涵并给予指正。

如今,在移动互联的大时代下,互联网公司金融业务的爆炸式发展给传统金融行业带来了巨大的冲击和挑战,金融行业也纷纷顺应发展趋势,大力发展移动端业务和互金类型业务,因此对业务需求的响应速度有了更高的要求,越来越多传统应用架构,为了适应不断变化的业务需求,难以预估的访问量,而开始进行分布式改造、微服务改造,实现持续集成、持续部署、支持弹性伸缩、灰度发布、蓝绿部署等能力,容器云平台恰恰可以很好的支撑上述需求。容器技术是近些年来最火热的技术弄潮儿,我们关注他,肯定不止是因为它足够火热,需要任何一项技术,一定都是以更好服务于应用,让用户使用感受越来越美好为目的。

笔者在容器平台的建设过程中,参与了大量的技术讨论和思维碰撞,一个非常大的感触就是,容器云的知识栈非常长,想对平台有一个全局的透彻理解,要学习的东西非常之多,而且很多是跨领域的。作为一名云计算运维工程师,在这里也简单聊聊在平台基础架构设计中自己的一些认知。
#平台选型
在做IaaS时,即使经过了深度的定制化自动化改造,IaaS上的流程走完时也普遍是在交付时把带有应用软件及软件配置的一台虚拟机交到申请者手中,申请者要自己通过IP登录去部署应用,更不用说各应用组件之间的配合设置。而在容器平台里,从代码开发集成,到一个容器镜像里打包了应用和应用的运行时环境,加上容器的配置文件,一套完整流程走下来时,应用已经可以上线了,负载均衡、安全策略都可以具备了,可以说容器云平台是DevOps理论的最佳实现。所以,对于容器平台的建设,从初期就需要各技术团队紧密结合,了解互相的需求,平台相关技术的原理机制,才能共同设计好一个容器平台。如果你想和更多容器技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

而对于传统应用容器化改造,应用接入容器云平台一定是一个循序渐进的过程,更是一个不断演讲的过程。为了让应用尽可能平滑的接入,平台设计也应适当考虑业务原场景和使用习惯,尽可能的避免大幅度修改逻辑,不希望为了容器化而容器化,还是要因地制宜,互相找到一个平衡。虽做了很多技术实践经验的调研,但真正在自己的环境中落地时,大家都是摸着石头过河,要通过试点应用,积累应用改造的经验,运维的经验。

对于容器平台,Docker已经成了容器引擎公认的事实标准,而Kubernetes也是公认的容器编排最佳调度平台,早在一两年前声音还没有如此的一致,记得最初做容器平台技术调研时,还要关注Mesos,Swarm等,但现在无论是商业产品还是纯自研,基本都转向了Kubernetes的阵营,说到这里我来简单谈谈Docker和Kubernetes最吸引人,或者说最值得应用的地方。
##Docker
Docker我认为最有价值的地方是优秀的可移植性,我们日常中最常见的问题就是应用部署的环境差异,操作系统版本差异,生产测试环境不一致等,往往这种差异会导致应用部署调试消耗大量的人力,还容易出现安全隐患,即使很多部署工作已经自动化,但也对基础环境有一定要求,这点比虚拟机有了更友好的移植能力,Docker能够将应用程序和它依赖的操作系统、类库以及运行时环境整体打包,统一交付,真正抹去了应用程序多个运行实例间的环境和依赖版本差异,同时也把对运维人员的重度依赖解耦开来。Docker有一句响亮的口号不是白叫的“Build once,Run anywhere”。

还有一点就是快,秒级启动,虚拟机虽说是分钟级的启动,其实也已经非常快了,但从单体来看,当出现故障重启(Docker是重新生成),这种差别就是非常明显的,容器甚至可以做到外界无感知,尤其对于当需要应用扩容弹新的节点时,这种秒与分钟效率的差别,对应用的使用对象就是天壤之别的使用体验了,这里还不说虚拟机应急扩节点时应用配置的复杂度和配置时长,单是创建和启动时间,可能就是一个外部用户无感知,一个外部用户感觉到慢甚至短时间内服务不可用了。
1.jpg

##Kubernetes
Kubernetes,这个单词来自于希腊语,含义是舵手或领航员,简称K8S。2014年以Google内部用了很久的Brog为原型孵化出来贡献给开源社区的一个自动化部署、伸缩和编排容器的开源平台,其功能强大,Kubernetes实现了IP地址管理、负载均衡、服务发现和DNS名称注册,还原生提供运维人员更为关注的高可用特性及资源智能调度,在我看来Kubernetes对管理基础设施的抽象解耦比虚拟化技术更为彻底、极致,其对CPU兼容性、系统兼容性更为优秀。Kubernetes的自动扩缩容、负载均衡和重新启动应用程序的功能,这些也是使用IaaS或裸机时要二次定制开发的。

这里也要说下,Kubernetes不只支持Docker,它支持符合CRI(containerruntime interface)接口的容器引擎,CoreOS的rkt就是一大代表。

当然构成一套容器云平台,不只是Docker和Kubernetes就够了,他们只是应用运行和调度的最核心的载体,还要有一系列CI\CD、镜像管理、安全、监控、网络、存储等组件,才能构成一个完整的解决方案。
2.jpg

#计算方案
##应该部署在物理机还是虚拟机上?
这是架构设计时一定会讨论的一个问题,从容器云的架构设计来看,我觉得没有绝对的谁更好的答案,物理机或虚拟化平台均可以,前面也说到了,其核心组件K8S将基础设施抽象的更为极致,所以我认为要综合企业自身基础设施建设现状和内部制度流程等综合因素权衡。

如果之前已经有了IaaS平台建设,并且已经有成熟的运维规范和配套工具,那么就部署于IaaS之上,享受IaaS建设的红利。融入了自助服务、内部流程审批、应用软件安装等自动化流程及规范,且IaaS平台有一些对于运维人员爱不释手的功能——热迁移、快照、HA、快速创建虚拟机等,IaaS平台在易管理性和资源弹性上相比物理机还是优势巨大的。

如果没有现成的IaaS建设,那么我认为首选物理机,没有必要再去投入人力去设计IAAS基础设施,K8S原生解耦了基础设施的依赖,提供了智能调度和高可用能力,针对物理机去定制一些满足自身的管理功能和运维的自动化手段也是理想之选,毕竟建设一套适合自身企业需求的IAAS本身也是个巨大的工程,而且少了一层虚拟化,从架构来看更为清晰简洁,troubleshooting时理论故障点也会少些,虚拟化层的性能损耗也不用考虑了。
#网络方案
在容器平台的基础架构层面,网络方案的设计一般都是涉及讨论最多,意见碰撞最多的地方,毕竟网络是底层的基础设施,牵一发动全身,所以定会格外谨慎。underlay、overlay、routing的网络模型都比较了遍,当然这些方案都是要Kubernetes CNI(Container Network Interface)插件标准的,主要关注的有:ipvlan(underlay)、Macvlan(underlay)、Flannel(overlay)、Calico(routing)、NSX-T(routing)。

对于underlay的方案,对于传统的网络架构可以无缝适配,网络的管理模式(IP资源管理,流量管理等)也可以保持一致,但从Kubernetes的管理功能和生态圈来看,underlay的网络方案都不是方向,更多是一种适配传统网络架构的过渡方案,对于ip的管理还是要在外部完成,而且Kubernetes也失去了对于容器的隔离控制能力,此外,例如Macvlan要求启用混杂模式,ipvlan要求linux内核版本要在4.1之上等刚性要求,也不适合绝大多数企业的网络管理规范及操作系统使用现状。对于Overlay的方案,对于传统网络和容器通讯及跨Kubernetes集群的容器通讯需求,该类型方案均存在很大弊端,而且基于vxlan的数据封装传输,对于容器ip的流量监控也不易实现(除非支持解析 vxlan 数据包),对于vxlan的解封包,在性能上也会一定损失,性能表现亦不占优。所以,综合应用的通信需求、运维的管理需求、功能的完善度、技术趋势、性能、安全等多方面的因素,我认为routing的网络模型方案更优,routing模式对传统应用适配,接受传统组织结构都更友好。

接下来我也将routing方案的主要代表介绍下:
##Calico
Calico是综合对比后,各方面功能需求最为满足的开源网络方案,而且其在社区的活跃度非常高,通过调研了解到一些容器平台厂商也开始或已经在产品中集成此方案。

Calico是一个纯三层的数据中心网络方案(不需要Overlay),基于BGP协议通过路由转发的方式实现容器的跨主机通信。Calico 将每个节点(Node)虚拟为一个“路由器”,并为之分配独立的虚拟网段,该路由器为当前节点上的容器提供路由服务,完全利用路由规则实现动态组网,通过BGP协议通告路由,小规模部署可以直接互联,大规模下可通过指定的BGProutereflector来完成。

Calico在每一个计算节点实现了Linux内核级的vRouter来负责数据转发,所以性能优异。

其相较其他开源方案,还有一大优势是安全能力,基于iptables提供了丰富而灵活的network policy,支持很细致的ACL控制。

Calico主要由Felix、etcd、BGP client以及BGPRoute Reflector组成:

  1. Felix,Calico Agent,跑在每台需要运行Workload的节点上,主要负责为容器配置IP,路由及ACLs(iptable规则)等信息来确保Endpoint的连通状态;
  2. etcd,分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性;
  3. BGP Client(BIRD),主要负责把Felix写入Kernel的路由信息分发(广播)到当前Calico网络( 通过BGP协议),确保Workload间的通信的有效性;
  4. BGP Route Reflector(BIRD),大规模集群的分级路由分发,摒弃所有节点互联的Mesh模式,通过一个或者多个BGP Route Reflector来完成集中式的路由分发。

3.jpg

#NSX-T
NSX-T是VMware的企业级网络虚拟化商业解决方案,是2016年5月在NSX-V/NSX-MH之后推出的新产品,到现在是2.3版本,T版本主要是加入容器网络支持和兼容裸金属物理机这两个重要功能,未来也会逐步将NSX-V/NSX-MH的代码整合完成替代。同Calico一样,也是内核级的数据转发,性能优异,而且产品自身提供了良好的负载均衡及安全能力。对于商业软件,企业级的服务支持和可视化的管理界面是商业方案优势较为明显的地方。

NSX-T我认为最显著的特点是,与传统网络有个南北向清晰地边界——Edge节点,而东西向全部在自己的自制范围内。

这里还有两个我认为比较重要的点应该了解一下,NSX-T与K8S的适配方式,是通过NSX-T Container Plug-in(NCP)插件与其集成,包括其他的容器平台解决方案也是通过此插件进行集成,例如Pivotal Cloud Foundry等。

还有一点是从NSX-T开始,VMware已经从NSX-V使用的基于vxlan的封装转移,并采用了更新的“Geneve”封装。Geneve是由VMware,Microsoft,Red Hat和Intel共同撰写的新版封装。Geneve将当前最佳的封装协议(如VXLAN,STT和NVGRE)整合到一个协议中。封装头的MTU为1600,所以对NSX-T自治域内的MTU值要求大于1600。
4.jpg

#存储方案
存储也是基础架构的重要一环,尤其是对于有状态的应用,数据持久化需求的支持。

我觉得在Kubernetes里,对于基础资源(CPU、内存、网络、存储)的管理,存储使用的设计较为别致,使用方式有别于常见的思路,还需要认真去理解。

这里简单介绍下在K8S中存储设计的四个重要概念:Volume、PV(PersistentVolume)、PVC(PersistentVolumeClaim)、Storage Class。
##Volume
Volume是最基础的存储抽象,其支持多种类型,包括本地存储、NFS、FC以及众多的云存储,也可以通过flex volume driver或CSI(contaioner storage Interface)编写自己的存储插件来支持特定的存储系统。

Volume可以被Pod直接使用,也可以被PV使用。普通的Volume和Pod之间是一种静态的绑定关系,在定义Pod的同时,通过volume属性来定义存储的类型,通过volumeMount来定义容器内的挂载点。

Volume有一个重要属性是,它与所属的Pod具有相同的生命周期。

Pod是Kubernetes的最小工作单元,每个 Pod 包含一个或多个容器
##PV
PV与普通的Volume不同,它是Kubernetes中的一个资源对象,创建一个PV相当于创建了一个存储资源对象,向用户屏蔽了具体的存储实现形式,而且这个资源的使用要通过PVC来请求。PV定义的内容包含存储的类型,存储的大小和访问模式等。

PV的生命周期独立于Pod,即当使用它的Pod销毁时对PV没有影响。
##PVC
PVC是用户对存储资源PV的请求,请求信息包含存储大小,访问模式等。根据PVC中指定的条件Kubernetes寻找系统中的PV资源并进行绑定。PVC消耗PV资源,PV和PVC是一一对应的。
##StorageClass
StorageClass的引入是为了解决个性化的存储需求动态供给的问题,集群管理员可以先将存储资源定义为不同类型的资源,比如高性能存储、常规存储等,之后通过StorageClass的定义动态的去创建PV,然后通过PVC来请求PV绑定。

对于多数银行业的企业,都有丰富的SAN和NAS的存储管理及运维经验,结合应用的存储需求、平台镜像方案的设计,以及银行业的应用系统普遍有多中心部署的监管需求,我认为采用NFS类型的存储支持容器数据持久化以及镜像服务的相关存储需求对容器平台在银行业的落地不失为一个不错的选择,此外还应同时开展对象存储的研究与测试,以给应用对数据存储的使用方式更多选择。

容器云平台建设会是一个不断完善、迭代积累的过程,同时容器相关技术的发展变化非常之快,在平台的建设中要持续保持新技术的敏锐嗅觉,来提升应用服务、运维管理、安全监管等各方面的水平。

原文链接:https://mp.weixin.qq.com/s/O6Za5JGywmnZ-Rswlu5WzA

基于 ZooKeeper 实现爬虫集群的监控

阿娇 发表了文章 • 0 个评论 • 155 次浏览 • 2019-05-29 13:03 • 来自相关话题

微服务中集成分布式配置中心 Apollo

大卫 发表了文章 • 0 个评论 • 189 次浏览 • 2019-05-29 12:56 • 来自相关话题

#背景 随着业务的发展、微服务架构的升级,服务的数量、程序的配置日益增多(各种微服务、各种服务器地址、各种参数),传统的配置文件方式和数据库的方式已无法满足开发人员对配置管理的要求:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、 ...查看全部
#背景
随着业务的发展、微服务架构的升级,服务的数量、程序的配置日益增多(各种微服务、各种服务器地址、各种参数),传统的配置文件方式和数据库的方式已无法满足开发人员对配置管理的要求:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制。分布式环境下,这些配置更加复杂。

因此,我们需要配置中心来统一管理配置!把业务开发者从复杂以及繁琐的配置中解脱出来,只需专注于业务代码本身,从而能够显著提升开发以及运维效率。同时将配置和发布包解藕也进一步提升发布的成功率,并为运维的细力度管控、应急处理等提供强有力的支持。

在之前的文章中,我们介绍过 Spring Cloud 中的分布式配置中心组件:Spring Cloud Config。本文将会介绍功能更为强大的 Apollo。如果你想和更多微服务技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
#分布式配置中心
在一个分布式环境中,同类型的服务往往会部署很多实例。这些实例使用了一些配置,为了更好地维护这些配置就产生了配置管理服务。通过这个服务可以轻松地管理成千上百个服务实例的配置问题。配置中心的特点:

* 配置的增删改查;
* 不同环境配置隔离(开发、测试、预发布、灰度/线上);
* 高性能、高可用性;
* 请求量多、高并发;
* 读多写少;

现有的配置中心组件有:Spring Cloud Config、Apollo、Disconf、Diamond 等等,这些组件在功能上有或多或少的差异,但是都具有基本的配置中心的功能。
#Apollo 简介
Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。目前的有超过 14k 的 star,使用广泛。Apollo基于开源模式开发,开源地址:https://github.com/ctripcorp/apollo。
1.jpg

首先用户在配置中心对配置进行修改并发布;配置中心通知Apollo客户端有配置更新;Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用。

Apollo 支持4个维度管理 Key-Value 格式的配置:

* application(应用):实际使用配置的应用,Apollo客户端在运行时需要知道当前应用是谁,从而可以去获取对应的配置;每个应用都需要有唯一的身份标识 – appId,应用身份是跟着代码走的,所以需要在代码中配置。
* environment(环境):配置对应的环境,Apollo客户端在运行时需要知道当前应用处于哪个环境,从而可以去获取应用的配置。
* cluster(集群):一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。对不同的cluster,同一个配置可以有不一样的值,如ZooKeeper地址。
* namespace(命名空间):一个应用下不同配置的分组,可以简单地把namespace类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,RPC配置文件,应用自身的配置文件等;应用可以直接读取到公共组件的配置namespace,如DAL,RPC等;应用也可以通过继承公共组件的配置namespace来对公共组件的配置做调整,如DAL的初始数据库连接数。

我们在集成 Apollo 时,可以根据需要创建相应的维度。
#快速入门
下面我们搭建一个基于 Spring Boot 的微服务,集成 Apollo。
##启动服务端
Apollo配置中心包括:Config Service、Admin Service 和 Portal。

* Config Service:提供配置获取接口、配置推送接口,服务于Apollo客户端;
* Admin Service:提供配置管理接口、配置修改发布接口,服务于管理界面Portal;
* Portal:配置管理界面,通过MetaServer获取AdminService的服务列表,并使用客户端软负载SLB方式调用AdminService。

官网准备好了一个Quick Start安装包,大家只需要下载到本地,就可以直接使用,免去了编译、打包过程。也可以自行编译,较为繁琐。

Apollo服务端共需要两个数据库:ApolloPortalDB和ApolloConfigDB。创建的语句见安装包,创建好之后需要配置启动的脚本,即 demo.sh 脚本:
#apollo config db info
apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
apollo_config_db_username=用户名
apollo_config_db_password=密码(如果没有密码,留空即可)

# apollo portal db info
apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8
apollo_portal_db_username=用户名
apollo_portal_db_password=密码(如果没有密码,留空即可)

脚本会在本地启动3个服务,分别使用8070, 8080, 8090端口,请确保这3个端口当前没有被使用。执行:
./demo.sh start

看到输出如下的日志信息:
==== starting service ====
Service logging file is ./service/apollo-service.log
Started [10768]
Waiting for config service startup.......
Config service started. You may visit http://localhost:8080 for service status now!
Waiting for admin service startup....
Admin service started
==== starting portal ====
Portal logging file is ./portal/apollo-portal.log
Started [10846]
Waiting for portal startup......
Portal started. You can visit http://localhost:8070 now!

Apollo 服务端启动成功。
##客户端应用
搭建好 Apollo 服务器之后,接下来将我们的应用接入 Apollo。

引入依赖

com.ctrip.framework.apollo
apollo-client
1.1.0

在依赖中只需要增加 apollo-client 的引用。

入口程序
@SpringBootApplication
@EnableApolloConfig("TEST1.product")
public class ApolloApplication {

public static void main(String[] args) {
SpringApplication.run(ApolloApplication.class, args);
}
}

我们通过 @EnableApolloConfig("TEST1.product") 注解开启注册到 Apollo 服务端,并指定了 namespace 为 TEST1.product。

配置文件
app.id: spring-boot-logger
# set apollo meta server address, adjust to actual address if necessary
apollo.meta: http://localhost:8080
server:
port: 0

配置文件中指定了appid 和 Apollo 服务器的地址。

测试应用

我们通过动态设置输出的日志等级来测试接入的配置中心。
@Service
public class LoggerConfiguration {
private static final Logger logger = LoggerFactory.getLogger(LoggerConfiguration.class);
private static final String LOGGER_TAG = "logging.level.";

@Autowired
private LoggingSystem loggingSystem;

@ApolloConfig
private Config config;

@ApolloConfigChangeListener
// 监听 Apollo 配置中心的刷新事件
private void onChange(ConfigChangeEvent changeEvent) {
refreshLoggingLevels();
}

@PostConstruct
// 设置刷新之后的日志级别
private void refreshLoggingLevels() {
Set keyNames = config.getPropertyNames();
for (String key : keyNames) {
if (containsIgnoreCase(key, LOGGER_TAG)) {
String strLevel = config.getProperty(key, "info");
LogLevel level = LogLevel.valueOf(strLevel.toUpperCase());
loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level);
logger.info("{}:{}", key, strLevel);
}
}
}

private static boolean containsIgnoreCase(String str, String searchStr) {
if (str == null || searchStr == null) {
return false;
}
int len = searchStr.length();
int max = str.length() - len;
for (int i = 0; i <= max; i++) {
if (str.regionMatches(true, i, searchStr, 0, len)) {
return true;
}
}
return false;
}
}

如上的配置类用于根据 Apollo 配置中心的日志等级配置,设置本地服务的日志等级,并监听刷新事件,将刷新后的配置及时应用到本地服务,其中 @PostConstruct 注解用于在完成依赖项注入以执行任何初始化之后需要执行的方法。
@Service
public class PrintLogger {
private static Logger logger = LoggerFactory.getLogger(PrintLogger.class);

@ApolloJsonValue("${kk.v}")
private String v;

@PostConstruct
public void printLogger() throws Exception {
Executors.newSingleThreadExecutor().submit(() -> {
while (true) {
logger.error("=========" + v);
logger.info("我是info级别日志");
logger.error("我是error级别日志");
logger.warn("我是warn级别日志");
logger.debug("我是debug级别日志");
TimeUnit.SECONDS.sleep(1);
}
});
}
}

起一个线程,输出不同级别的日志。根据配置的日志等级,过滤后再打印。我们在如上的程序中,还自定义了一个字段,同样用以测试随机打印最新的值。
##测试
我们在 Apollo 的配置界面中,增加如下的配置:
2.jpg

并将配置发布,启动我们本地的 SpringBoot 服务:
2019-05-28 20:31:36.688 ERROR 44132 --- [pool-1-thread-1] com.blueskykong.apollo.PrintLogger       : =========log-is-error-level.
2019-05-28 20:31:36.688 ERROR 44132 --- [pool-1-thread-1] com.blueskykong.apollo.PrintLogger : 我是error级别日志

我们将调整日志的级别为warn,只需要在界面上编辑。
3.jpg

将编辑好的配置发布,应用服务将会收到刷新事件。
4.jpg

可以看到,服务刷新了日志的级别,打印 warn 的日志信息。
2019-05-28 20:35:56.819  WARN 44132 --- [pool-1-thread-1] com.blueskykong.apollo.PrintLogger       : 我是warn级别日志
2019-05-28 20:36:06.823 ERROR 44132 --- [pool-1-thread-1] com.blueskykong.apollo.PrintLogger : =========log-is-warn-level.

#原理细究
在体验了 Apollo 作为配置中心之后,我们将了解下 Apollo 的总体设计和实现的原理。
##Apollo 整体架构
5.png

上图简要描述了 Apollo 的总体设计,从下往上看:

* Config Service 提供配置的读取、推送等功能,服务对象是Apollo客户端
* Admin Service 提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
* Config Service 和 Admin Service 都是多实例、无状态部署,所以需要将自己注册到 Eureka 中并保持心跳
* 在 Eureka 之上我们架了一层 Meta Server 用于封装 Eureka 的服务发现接口
* Client 通过域名访问Meta Server获取Config Service服务列表(IP+Port),而后直接通过IP+Port 访问服务,同时在 Client 侧会做 load balance、错误重试
* Portal 通过域名访问 Meta Server 获取Admin Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Portal侧会做load balance、错误重试
* 为了简化部署,我们实际上会把Config Service、Eureka和Meta Server三个逻辑角色部署在同一个JVM进程中

ConfigService、AdminService、Portal 属于 Apollo 服务端的模块,其中提到的 Eureka 是为了保证高可用,Config和Admin都是无状态以集群方式部署的,Client 怎么找到 Config?Portal 怎么找到 Admin?为了解决这个问题,Apollo在其架构中引入了Eureka服务注册中心组件,实现微服务间的服务注册和发现用于服务发现和注册,Config和Admin Service注册实例并定期报心跳, Eureka与ConfigService一起部署。

MetaServer 其实是一个Eureka的Proxy,将Eureka的服务发现接口以更简单明确的HTTP接口的形式暴露出来,方便 Client/Protal 通过简单的 HTTPClient 就可以查询到 Config/Admin 的地址列表。获取到服务实例地址列表之后,再以简单的客户端软负载(Client SLB)策略路由定位到目标实例,并发起调用。
##客户端实现
在配置中心中,一个重要的功能就是配置发布后实时推送到客户端。下面我们简要看一下这块是怎么设计实现的。
6.png

上图简要描述了配置发布的大致过程:用户在Portal操作配置发布;Portal调用Admin Service的接口操作发布;Admin Service发布配置后,发送ReleaseMessage给各个Config Service;Config Service收到ReleaseMessage后,通知对应的客户端。

如何通知客户端呢?我们看到 Apollo 的实现步骤如下:

  1. 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)
  2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。

* 这是一个fallback机制,为了防止推送机制失效导致配置不更新
* 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified
* 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。

  1. 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中
  2. 客户端会把从服务端获取到的配置在本地文件系统缓存一份,在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置。
  3. 应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知

#小结
本文首先介绍分布式配置中心的概念和 Apollo 接入的实践,然后深入介绍了 Apollo 的总体架构和实现的一些细节。总得来说, Apollo 是现有配置中心组件中,功能最全的一个。能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

本文对应的代码地址: https://github.com/keets2012/Spring-Boot-Samples/tree/master/apollo-demo

原文链接:http://blueskykong.com/2019/05/27/apollo-spring-boot/

DockOne微信分享(二一零):平安证券Kubernetes容器集群的DevOps实践

齐达内 发表了文章 • 0 个评论 • 389 次浏览 • 2019-05-29 11:54 • 来自相关话题

【编者的话】最近两三年,Docker容器技术及Kubernetes编排调度系统,在DevOps领域,大有星火燎原,一统天下之势。平安证券IT团队一直紧跟最新技术,践行科技赋能。本次分享,聚焦于公司在DevOps转型过程中的几个典型的技术细节的解决方案,希望对同 ...查看全部
【编者的话】最近两三年,Docker容器技术及Kubernetes编排调度系统,在DevOps领域,大有星火燎原,一统天下之势。平安证券IT团队一直紧跟最新技术,践行科技赋能。本次分享,聚焦于公司在DevOps转型过程中的几个典型的技术细节的解决方案,希望对同行有所借鉴和帮助。
#生产环境的高可用Master部署方案
Kubernetes的高可用Master部署,现在网络上成熟的方案不少。大多数是基于Haproxy和Keepalived实现VIP的自动漂移部署。至于Haproxy和Keepalived,可独立出来,也可寄生于Kubernetes Master节点。

我司在IT设备的管理上有固定的流程,VIP这种IP地址不在标准交付范围之内。于是,我们设计了基于DNS解析的高可用方案。这种方案,是基于Load Balancer变形而来。图示如下:
1.png

这种构架方案,平衡了公司的组织结构和技术实现。如果真发生Master挂掉,系统应用不受影响,DNS的解析切换可在十分钟内指向新的Master IP,评估在可接受范围之内。

公司内部安装Master节点时,使用的基本工具是Kubeadm,但是作了脚本化改造及替换成了自己的证书生成机制。经过这样的改进之后,使用kubeadm进行集群安装时,就更有条理性,步骤更清晰,更易于在公司进行推广。

底层的etcd集群使用独立的Docker方式部署,但共享kubeadm相关目录下的证书文件,方便了api-server和etcd的认证通信。脚本的相关配置如下:
2.png

当以DNS域名的形式进行部署后,各个证书配置认证文件,就不会再以IP形式连接,而是以DNS域名形式连接api-server了。如下图所示:
3.png

#分层的Docker镜像管理
接下来,我们分享一下对Docker镜像的管理。Docker的企业仓库,选用的是业界流行的Harbor仓库。根据公司研发语言及框架的广泛性,采用了三层镜像管理,分为公共镜像,业务基础镜像,业务镜像(tag为部署发布单),层层叠加而成,即形成标准,又照顾了一定的灵活性。

* 公共镜像:一般以alpine基础镜像,加上时区调整,简单工具。
* 业务基础镜像:在公共镜像之上,加入JDK、Tomcat、Node.js、Python等中间件环境。
* 业务镜像:在业务基础镜像之上,再加入业务软件包。

4.png

#Dashboard、Prometheus、Grafana的安全实践
尽管在Kubernetes本身技术栈之外,我司存在体系化的日志收集,指标监控及报警平台,为了运维工具的丰富,我们还是在Kubernetes内集成了常用的Dashboard、Prometheus、Grafana组件,实现一些即时性运维操作。

那么,这些组件部署,我们都纳入一个统一的Nginx一级url下,二级url才是各个组件的管理地址。这样的设计,主要是为了给Dashborad及Prometheus增加一层安全性(Grafana自带登陆验证)。

这时,可能有人有疑问,Dashboard、kubectl都是可以通过cert证书及RBAC机制来实现安全性的,那为什么要自己来引入Nginx作安全控制呢?

在我们的实践过程中,cert证书及RBAC方式,结合SSH登陆帐号,会形成一系列复杂操作,且推广难度高,我们早期实现了这种模式,但目前公司并不具备条件,所以废弃了。公司的Kubernetes集群,有专门团队负责运维,我们就针对团队设计了这个安全方案。

Prometheus的二级目录挂载参数如下:
5.png

Grafana的二级目录挂载参数如下:
6.png

Dashboard在Nginx里的配置如下:
7.png

#一个能生成所有软件包的Jenkins Job
在CI流水线实践,我们选用的GitLab作为源代码管理组件,Jenkins作为编译组件。但为了能实现更高效标准的部署交付,公司内部实现一个项目名为prism(棱镜)的自动编译分发部署平台。在容器化时代,衍生出一个Prism4k项目,专门针对Kubernetes环境作CI/CD流程。Prism4k版的构架图如下所示:
8.png

在这种体系下,Jenkins就作为我们的一个纯编译工具和中转平台,高效的完成从源代码到镜像的生成。

由于每个IT应用相关的变量,脚本都已组织好,放到Prism4k上。故而,Jenkins只需要一个Job,就可以完成各样各样的镜像生成功能。其主要Pipeline脚本如下(由于信息敏感,只列举主要流程,有删节):
9.png

在Jenkins中,我们使用了一个Yet Another Docker Plugin,来进行Jenkins编译集群进行Docker生成时的可扩展性。作到了编译节点的容器即生即死,有编译任务时,指定节点才生成相关容器进行打包等操作。
#计算资源在线配置及应用持续部署
在Prism4k平台中,针对Jenkins的Job变量是通过网页配置的。在发布单的编译镜像过程中,会将各个变量通过API发送到Jenkins,启动Jenkins任务,完成指定task任务。
10.png

Pod的实例数,CPU和内存的配置,同样通过Web方式配置。
11.png

在配置好组件所有要素之后,日常的流程就可以基于不同部门用户的权限把握,实现流水线化的软件持续交付。

* 研发:新建发布单,编译软件包,形成镜像,上传Harbor库。
* 测试:环境流转,避免部署操作污染正在进行中的测试。
* 运维:运维人员进行发布操作。

在FAT这样的测试环境中,为加快测试进度,可灵活的为研发人员赋予运维权限。但在更正式的测试环境和线上生产环境,作为金融行业的IT建设标准,则必须由运维团队成员操作。

下面配合截图,了解一下更具体的三大步骤。

  1. 发布单
12.png

在Prism4k与Jenkins的API交互,我们使用了Jenkins的Python库。

  1. 环境流转
13.png


  1. 部署
14.png


在部署操作过程中,会将这次发布的信息全面展示给运维同事,让运维同事可以进行再次审查,减少发布过程中的异常情况。
#总结
由于Kubernetes版本的快速更新和发布,我们对于其稳定性的功能更为青睐,而对于实验性的功能,或是需要复杂运维技能的功能,则保持理智的观望态度。所以,我们对Kubernetes功能只达到了中度使用。当然,就算是中度使用,Kubernetes的运维和使用技巧,还是有很多方面在此没有涉及到,希望以后有机会,能和各位有更多的沟通和交流。愿容器技术越来越普及,运维的工作越来越有效率和质量。
#Q&A
Q:镜像有进行安全扫描吗:
A:外部基本镜像进入公司内部,我们基于Harbor内置的安全功能进行扫描。

Q:Harbor有没有做相关监控,比如发布了多少镜像,以及镜像同步时长之类的?
A:我们没有在Harbor上作扩展,只是在我们自己的Prism4k上,会统计各个项目的一些镜像发布数据。

Q:有没有用Helm来管理镜像包?后端存储是用的什么,原因是?
A:没有使用Helm。目前集群有存储需求时,使用的是NFS。正在考虑建基于Ceph的存储,因为现在接入项目越来越多,不同的需求会导致不同的存储。

Q:想了解下目前贵公司监控的纬度和监控的指标和告警这块。
A:监控方面,我公司也是大致大致划分为基础资源,中间件,业务指标三大块监控。方法论上也是努力在向业界提倡的RED原则靠拢。

Q:想了解下,Yaml文件怎么管理的,可以自定义生成吗?
A:我们的Yaml文件,都统一纳到Prism4k平台管理,有一些资源是可以自定义的,且针对不同的项目,有不同的Yaml模板,然后,透过django的模块功能统一作解析。熟悉Yaml书写的研发同事可以自己定义自己项目的Yaml模板。

Q:Pipeline会使用Jenkinfile来灵活code化Pipeline,把Pipeline的灵活性和创新性还给开发团队,这比一个模板化的统一Pipeline有哪些优势?
A:Pipeline的运行模式,采用单一Job和每个项目自定义Job,各有不同的应用场景。因为我们的Jenkins是隐于幕后的组件,研发主要基于Prism4k操作,可以相对减少研发的学习成本。相对来说,Jenkins的维护人力也会减少。对于研发各种权限比较高的公司,那统一的Job可能并不合适。

Q:想了解下贵公司使用什么网络方案?Pod的网络访问权限控制怎么实现的?
A:公司现在用的是Flannel网络CNI方案。同时,在不同的集群,也有作Calico网络方案的对比测试。Pod的网络权限,这块暂时没有,只是尝试Istio的可行性研究。

Q: 一个Job生成所有的Docker镜像,如果构建遇到问题,怎么去追踪这些记录?
A:在项目前期接入时,生成镜像的流程都作了宣传和推广。标准化的流程,会减少产生问题的机率。如果在构建中遇到问题,Prism4k的界面中,会直接有链接到本次建的次序号。点击链接,可直接定位到Console输出。

Q:遇到节点Node上出现100+ Pod,Node会卡住,贵公司Pod资源怎么做限制的?
A:我们的业务Pod资源,都作了limit和request限制。如果出现有卡住的情况,现行的方案是基于项目作拆分。Prism4k本身对多环境和多集群都是支持的。

Q:多环境下,集中化的配置管理方案,你们选用的是哪个,或是自研的?
A:我们现在正在研发的Prism4k,前提就是要支持多环境多集群的部署,本身的功能里,yaml文件的配置管理,都是其内置功能。

Q:etcd的--initial-cluster-state选项设置为new,重启etcd后会不会创建新的etcd集群?还是加入原有的etcd集群?
A:我们测试过轮流将服务器(3 Master)完全重启,ectd集群的功能均未受影响。但全部关机重启,还未测试过。所以不好意思,这个问题,我暂时没有考虑过。

Q:网络方案用的什么?在选型的时候有没有对比?
A:目前主要应用的还是Flannel方案,今年春节以来,还测试过Flannel、Caclico、kube-router方案。因为我们的集群有可能越机房,而涉及到BGP协议时,节点无法加入,所以一直选用了Flannel。

Q:部署的动态过程是在Jenkins的Web界面上看还是在自研的Prism4k上能看到,如果是Prism4k的话,整个可视化过程的展示这些等等也是自己开发的吗?Prism4k是用什么语言开发的,Python吗?
A:部署的动态过程,是在Prism4k上显示。可视化方案,也只是简单的使用ajax及websocket。Prism4k后端是基于Django 2.0以上开发,其中使用了RESTful framework、channels等库,前端使用了一些js插件。

以上内容根据2019年5月28日晚微信群分享内容整理。分享人陈刚,平安证券运维研发工程师,负责经纪业务IT应用的持续交付平台的设计和开发。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiese,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

浅析 Kubernetes原生NetworkPolicy 网络策略,让更安全的容器运行环境唾手可得

灵雀云 发表了文章 • 0 个评论 • 146 次浏览 • 2019-05-29 10:33 • 来自相关话题

k8s中的网络策略主要分为原生 NetworkPolicy 和第三方网络插件提供的网络策略。本文将主要分析原生Networkpolicy的网络策略。 什么是网络策略 ...查看全部

k8s中的网络策略主要分为原生 NetworkPolicy 和第三方网络插件提供的网络策略。本文将主要分析原生Networkpolicy的网络策略。



什么是网络策略



网络策略(NetworkPolicy)是一种关于 Pod 间及 Pod 与其他网络端点间所允许的通信规则的规范。NetworkPolicy 资源使用标签选择 Pod,并定义选定 Pod 所允许的通信规则。

k8s中的网络策略由实现了CNI接口的网络插件提供,网络插件监听集群中 NetworkPolicy 资源的创建/删除/更新事件生成对应的规则来控制 Pod 的流量是否放行。

常见的支持 NetworkPolicy 的网络插件有:

  • Calico
  • Cilium
  • Kube-router
  • Romana
  • Weave Net
默认情况下 Pod 间及 Pod 与其他网络端点间的访问是没有限制的。
pic1.png
如下是一个 NetworkPolicy 定义的例子,该策略的含义是阻止所有流量访问有`app=web`这个 label 的 Pod。经常有人会问网络策略要怎么写,或者是这个网络策略代表了什么含义。笔者认为这个问题主要是因为使用者不了解网络策略的省缺行为。NetworkPolicy 字段含义NetworkPolicy 这个资源属于命名空间级别的,因此metadata 中的 namespace 不可省略,否则只会对default 命名空间下的满足条件的 Pod 生效。下面介绍下 NetworkPolicy 中各字段的含义,并说明各字段省缺值及其含义,主要看 (http://www.alauda.cn]Spec.io/docs/reference/generated/kubernetes-api/v1.14/#networkpolicyspec-v1-networking-k8s-io) 中的字段,podSelector: 必填字段,Pod 的标签选择器,表示该网络策略作用于哪些 Pod。如果为空`{}`则表示选中本命名空间下所有 Pod。policyTypes: 可选字段,字符串,策略规则类型, 表示该网络策略中包含哪些类型的策略,可选为"Ingress", "Egress", 或 "Ingress,Egress"。未填时,这个值依据下面的 ingress 和 egress 来定。如果该字段未设置且下面只出现了 ingress,则对 egress 不做限制。如果填了这个值,同时后续没有设定对应的规则,则认为设定的规则对应的流量全部禁止。例如:
pic2.png
该规则就限制了所有 Pod 的出流量。ingress: 可选字段,数组,入站规则。互相间为或的关系,满足其中一条则放行。ports: 可选字段,数组,放行端口信息。互相间为或的关系,如果为空表示端口不受约束,如果非空,则表示除了出现的端口放行,其他未指定的端口都禁止。 -port: 可选字段,数字,协议端口号。如果不写,表示协议所有端口。 -protocol: 可选字段,字符串,协议。允许取值为 TCP,UDP,SCTP。省缺为 TCP。from: 可选字段,数组,放行源地址信息。互相间为或的关系,如果为空表示不约束源地址,如果非空,则表示除了出现的源地址放行外,其他源地址都禁止。 -ipBlock: 可选字段,放行 ip 段。 cidr: 标准 cidr,除了指定的cidr放行外其他都禁止。 except: 标准 cidr 字符串数组,表示前面cidr 中的放行的 cidr 段需要再排除掉 except 中指定的。 -namespaceSelector: 可选字段,namespace 的标签选择器,表示放行集群中的哪些命名空间中过来的流量。如果为空`{}`或未出现则表示选中所有命名空间。 -podSelector: 可选字段,Pod 的标签选择器,表示放行哪些 Pod 过来的流量,默认情况下从NetworkPolicy 同命名空间下的 Pod 中做筛选,如果前面设定了`namespaceSelector`则从符合条件的命名空间中的 Pod 中做筛选。如果为空`{}`则表示选中满足`namespaceSelector` 条件的所有 Pod。egress: 可选字段,数组,出站规则。互相间为或的关系,满足其中一条就放行。ports: 可选字段,数组,放行端口信息。互相间为或的关系,如果为空表示端口不受约束,如果非空,则表示除了出现的端口放行,其他未指定的端口都禁止。(详细字段同 ingress 中的 ports)to: 可选字段,数组,放行目的地址信息。互相间为或的关系,如果为空表示不约束目的,如果非空,则表示除了出现的目的地址放行外,其他目的地址都禁止。(详细字段同ingress 中的 from)介绍完 Spec 中各字段的含义及其默认行为后,做个简单的小结,NetworkPolicy 定义了放行规则,规则间是或的关系,只要命中其中一条规则就认为流量可以放行。下面以一个kubernetes官网中的例子来回顾下前面的知识。
pic3.png
首先该规则指定了命名空间为 default, 选择了其中所有包含 `role=db` 这个 label 的 Pod,定义了入站流量规则与出站流量规则。对于入站流量,放行源地址来自 cidr 172.17.0.0/16 除了 172.17.1.0/24 之外的流量,放行来自有`project=myproject` 这个label的namespace中的流量,放行 default 命名空间下有 label `role=frontend` 的 Pod 的流量,并限定这些流量只能访问到 `role=db` 这个 label 的 Pod 的 TCP 6379端口。对于出站流量,只放行其访问目的地址属于 cidr 10.0.0.0/24 中,且端口为 TCP 5978的流量。需要注意的是 NetworkPolicy 选中的 Pod 只能是与 NetworkPolicy 同处一个 namespace 中的 Pod,因此对于有些规则可能需要在多个命名空间中分别设置。或者使用非原生的网络策略定义,例如 Calico 中的 GlobalNetworkPolicyNetworkPolicy 变更历史v1.6 以及以前的版本需要在 kube-apiserver 中开启 extensions/v1beta1/networkpolicies;v1.7 版本 Network Policy 已经 GA,API 版本为 networking.k8s.io/v1;v1.8 版本新增 Egress 和 IPBlock 的支持;附录

从Tuxedo运维走向Kubernetes运维

JetLee 发表了文章 • 0 个评论 • 124 次浏览 • 2019-05-29 09:38 • 来自相关话题

【编者的话】Tuxedo作为一款成熟的交易中间件,具有强大的交易处理性能、高度的可靠性和无限的伸缩性。Kubernetes作为新兴容器编排调度引擎,基于容器技术,实现资源管理的自动化以及跨多个数据中心的资源利用率最大化。前者以交易事务管理闻名,后者以容器编排著 ...查看全部
【编者的话】Tuxedo作为一款成熟的交易中间件,具有强大的交易处理性能、高度的可靠性和无限的伸缩性。Kubernetes作为新兴容器编排调度引擎,基于容器技术,实现资源管理的自动化以及跨多个数据中心的资源利用率最大化。前者以交易事务管理闻名,后者以容器编排著称。无论是Tuxedo还是Kubernetes,其运行离不开网络、设备及存储等基础设施的支撑。

本文重点对运行于基础设施之上两者运行特点进行分析对比,使具有Tuxedo运维经验的运维人员对Kubernetes有进一步的了解,给后续Kubernetes运维提供参考借鉴。
#Tuxedo

1.jpg

Tuxedo ATMI体系架构图

大多数Tuxedo应用都是采用ATMI来实现运行环境和编程接口的,其体系架构如上图所示,整个架构划分为外部接口和内部服务层两个部分。外部接口层的基础是ATMI层,之上是Client。Tuxedo服务层包括通讯模型、管理信息库(MIBs)、应用服务器及管理服务器等。通讯模型指的是Tuxedo客户端和服务端、Tuxedo服务端与服务端之间传递消息的模型。管理信息库为其他应用程序管理和配置Tuxedo系统提供接口,通过该接口,使用人员可以对Tuxedo配置信息进行动态调整及对其运行状态进行实时监控(如某些系统通过MIBs获取Tuxedo队列地址、队列深度等实现流量控制)。应用服务为ATMI应用程序提供了数路由、编码、负载均衡和命名服务等。管理服务为ATMI应用程序提供事件、安全等服务。
##Kubernetes

Kubernetes作为一个开源的大规模容器集群管理软件,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部属容器化的应用简单并且高效,Kubernetes提供了应用部署、规划、更新和维护的一种机制。典型Kubernetes架构图如下所示:
2.jpg

典型Kubernetes架构图

如上图所示,Kubernetes将集群中的机器划分为一个Master节点和一群工作节点(Node)。其中,在Master节点上运行着集群管理相关的一组进程:kube-apiserver、kube-controller-manager、kube-scheduler、etcd和kube-ctl。这些进程实现了整个集群的资源管理、Pod调度、弹性伸缩、安全控制、系统监控和纠错等管理功能,并且都是全自动完成的。Node作为集群中的工作节点,运行真正的应用程序,在Node上Kubernetes管理的最小运行单元是Pod。Node上运行着Kubernetes的kubelet、kube-proxy、docker和kube-ctl,这些服务进程负责Pod的创建、启动、监控、重启、销毁,以及实现软件模式的负载均衡器。如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

上面对Tuxedo和Kubernetes的基本架构和组成要素进行了简要介绍,下面通过如下几个方面对两者进行对比分析:
##运行态

应用程序要正常运行并提供服务,除了依赖的底层基础设施(如网络、服务器、存储等)外,还依赖应用本身的可执行文件及对应配置文件。基于Tuxedo应用在生产部署及运行时主要依赖应用程序包(可执行文件)、配置文件(ubb和bdm),基于Kubernetes应用在生产部署及运行时同样主要依赖应用程序包、配置文件(YAML或ConfigMap)。二者均通过配置文件和执行文件的组合,实现了服务的正常运行、服务(或服务数)控制或弹性伸缩、负载均衡、容错、监控检测等功能。Tuxedo中进程或可执行文件做为服务的载体,其在

Tuxedo配置文件主要参数如下所示(节选):
*RESOURCES  

……

LDBAL Y 负载均衡

SCANUNIT 10 健康检查控制

SANITYSCAN 12

*MACHINES

gumby LMID=SITE1

……

APPDIR=”/usr/apps/bin” 可执行程序目录

……

*SERVERS

DEFAULT: RESTART=Y MAXGEN=5 GRACE=3600 容错控制

TLR SRVGRP=BANKB1 SRVID=10 MIN=1 MAX=2 副本控制

RQADDR=QNAME REPLYQ=Y -p [L][low_water][,[terminate_time]][:[high_water][,create_time]] 弹性伸缩控制

……

*SERVICES

SRVGRP=BANKB1

LOAD=25 PRIO=70 负载因子及优先级控制

Kubernetes配置文件主要参数如下所示(节选):
……

metadata:

name: nginx

spec:

replicas: 2 副本数

……

spec:

restartPolicy:Always 重启策略

container:

- name: nginx

image: nginx 镜像

livenessProbe: 健康检查

httpGet:

……

initialDelaySeconds: 15 表明第一次检测在容器启动后多长时间后开始

timeoutSeconds: 1 检测的超时时间

……

##弹性伸缩

对于一些和电商促销或外部行情紧密相关系统,其业务量随着促销或行情变化出现交易高峰,待促销结束或行情稳定后,业务量又快速回落。无论是基于Tuxedo的应用还是基于Kubernetes应用,均提供弹性伸缩功能。

基于Tuxedo应用通过在ubb中配置min、max值,以及队列深度基线值,可实现服务数随业务量变化而动态扩缩容(当然也可通过手工方式快速增加或减少服务),也即Tuxedo是基于业务量进行扩缩容。具体配置如下:
*SERVERS

BillServer SRVGRP=GROUP1 SRVID=1 MIN=2 MAX=4

RQADDR=QNAME REPLYQ=Y -p [L][low_water][,[terminate_time]][:[high_water][,create_time]]

如果MAX>1,并且使用了MSSQ(RQADDR, RQPERM)的Server可以配置-p来控制进程的动态增加和减少。控制算法如下:如果请求队列中的请求个数大于high_water 后超过create_time 秒,就增加该服务的一个新进程;如果请求队列中的请求个数小于low_water后超过terminate_time秒,就停止该服务的一个进程。low_water缺省是平均每个服务进程有一个请求消息或者workload 50;high_water 缺省是平均每个服务进程有两个请求消息或者workload 100。create_time 缺省最小是50秒, and terminate_time 缺省最小是60秒。

基于Kubernetes应用,通过Kubernetes的HPA(Horizontal Pod Autoscaler)实现Pod横向自动扩容(Kubernetes管理最小单位为Pod)。属于一种Kubernetes资源对象。通过追踪分析RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性的调整目标Pod的副本数。HPA可以根据CPU使用率或应用自定义metrics自动扩展Pod数量(也即Kubernetes基于系统资源进行扩缩容)。
3.png

HPA自动扩缩容示意图

工作流程:

  1. 创建HPA资源(通过编写YAML文件进行创建),设定目标CPU使用率限额,以及最大、最小实例数;
  2. 控制管理器每隔30s(可以通过–horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况;
  3. 然后与创建时设定的值和指标做对比(平均值之和/限额),求出目标调整的实例个数;
  4. 目标调整的实例数不能超过1中设定的最大、最小实例数,如果没有超过,则扩容;超过,则扩容至最大的实例个数;

重复2-4步。

基于Tuxedo的应用和Kubernetes应用,在弹性伸缩方面有相同处,也有不同处。相同点为两者通过弹性伸缩可以控制运行服务数量,有效应对业务的突变,不同之处为Tuxedo弹性伸缩(以及负载、服务发现、容错等)均在原服务器(原Node、原IP)上进行,而Kubernetes的扩缩容与服务器(原Node、原IP)没有绑定关系,可以跨Node伸缩、容错,IP也会发生改变。

在Kubernetes中,Node节点可以在运行期间动态增加到Kubernetes集群中,在默认情况下kubelet会向Master节点注册自己。一旦Node被纳入集群管理范围,Master可以根据负载情况将部分流量负载到新加入Node节点。而在Tuxedo中,SHM模式中不具备类似Kubernetes中Node节点的扩容,在MP模式下动态增加节点也相对比较复杂。
##容错和故障隔离

对线上业务来说,保证服务的正常稳定是重中之重,对故障服务的及时处理避免影响业务以及快速恢复一直是开发运维的难点。无论Tuxedo还是Kubernetes都提供了健康检查服务,对于检测到故障服务会被及时自动下线,以及通过重启服务的方式使服务自动恢复。Tuxedo和Kubernetes依据配置文件(ubb或yaml)配置策略,按照约定间隔对应用服务进行探测,在约定时间段内探测失败则进行重启或隔离。Tuxedo的容错和故障隔离既可基于服务级别,也可基于节点级别(仅针对集群部署模式,目前集群部署模式较少)。Tuxedo具体配置如下:
……

*RESOURCES

MASTER SITE1,SITE2//site2为备用Master,site1宕机了site2顶替

MODEL MP //模式是multiple machine

OPTIONS LAN //置为lan,这和MP配对使用

SCANUNIT 10 // 健康检查控制

SANITYSCAN 12

*MACHINES

"node1"//master主机名

LMID=SITE1

"node2"//从主机主机名

LMID=SITE2

*GROUPS

APPGRP1

LMID=SITE1 GRPNO=1

APPGRP2

LMID=SITE2 GRPNO=2

*NETWORK//配置集群不可少的网络配置

SITE1

NADDR="//IP1:port1-1"//bridge进程使用的网络地址及端口

NLSADDR="//IP1:port1-2"//tlisten进程使用的网络地址及端口

SITE2

NADDR="//IP2:port2-1"

NLSADDR="//IP2:port2-2"

*SERVERS

DEFAULT: RESTART=Y MAXGEN=5 GRACE=3600 //容错控制

server SRVID=10 SRVGRP=APPGRP1

server SRVID=20 SRVGRP=APPGRP2

Tuxedo按照探测间隔,定期对相关服务或节点进行健康检查,发现某个服务异常(coredump)后会自动拉起该服务,如果发现某个节点异常后会自动将该节点从集群中剔除,通过这种方法实现容错和故障隔离功能。

Kubernetes采用Liveness和Readiness探针进行健康检查,其中Liveness探针主要用于判断Container是否处于运行状态,比如当服务crash或者死锁等情况发生时,kubelet会kill掉Container, 然后根据其设置的restart policy进行相应操作,而Readiness探针主要用于判断服务是否已经正常工作,如果服务没有加载完成或工作异常,服务所在的Pod的IP地址会从服务的endpoints中被移除,也就是说,当服务没有ready时,会将其从服务的load balancer中移除,不会再接受或响应任何请求。具体配置如下:
……

spec:

restartPolicy:Always 重启策略

……

livenessProbe: 健康检查

httpGet:

path: /health

port: 8080

initialDelaySeconds: 15 表明第一次检测在容器启动后多长时间后开始

timeoutSeconds: 1 检测的超时时间

……

Kubernetes具体容错和故障隔离流程如下:
  1. 如果服务的健康检查(Readiness)失败,故障的服务实例从service endpoint中下线,外部请求将不会再转发到该服务上,一定程度上保证正在提供的服务的正确性,如果服务自我恢复了(比如网络问题),会自动重新加入service endpoint对外提供服务。
  2. 如果设置了Container(Liveness)的探针,对故障服务的Container(Liveness)的探针同样会失败,container会被kill掉,并根据原设置的container重启策略,系统倾向于在其原所在的机器上重启该container、或其他机器重新创建一个Pod。
  3. 由于上面的机制,整个服务实现了自身可用与自动恢复。

##服务发现

Tuxedo使用公告板来提供命名服务。Bulletin Board(公告板)是一块共享内存,Tuxedo把系统的配置保存在一个该共享内存中,主要包括服务进程、服务、消息队列、事件、运行环境的配置和统计信息等,TUXEDO通过BBL对公告板等进行管理。Tuxedo在服务启动时根据配置文件首先会创建一片共享内存作为公告板并将相关参数加载到共享内存中,在服务启动时会将服务相关信息(如服务名、队列名、服务数量、服务状态、请求数等)注册到BB中,在服务调用过程中,调用方通过BB的命名服务获取后台服务信息,实现服务的发现和调用。
4.png

Tuxedo服务发现及调用(一)
5.png

Tuxedo服务发现及调用(二)

Tuxedo服务发现及调用如上图一所示,客户端连接到Tuxedo公告板,根据服务名查找(Looks up)公告板、获取(Gets)所调用服务相关信息、调用(Invokes)服务。由于tuxedo是基于队列通过ATMI接口进行信息交互,具体ATMI、Message Queue、Bulletin Board交互如图二所示,客户端通过ATMI接口将消息发送到服务端队列(队列信息通过BB获取),服务端处理完后通过ATMI接口将处理结果返回到客户端队列。

Kubernetes提供了Service的概念,可以通过VIP访问Pod提供的服务,但是在使用的时候还有一个问题:怎么知道某个应用的 VIP?比如我们有两个应用,一个App,一个是db,每个应用使用rc进行管理,并通过service暴露出端口提供服务。App需要连接到db应用,我们只知道db应用的名称,但并不知道其VIP地址。起初,kubernetes采用了Docker使用过的方法——环境变量。每个Pod启动时候,会通过环境变量设置所有服务的IP和port信息,这样Pod中的应用可以通过读取环境变量来获取依赖服务的地址信息。这种方式服务和环境变量的匹配关系有一定的规范,使用起来也相对简单,存在的问题是:依赖的服务必须在Pod启动之前就存在,否则不会出现在环境变量中。理想方案是:应用能够直接使用服务的名字,不需要关心它实际IP地址,中间的转换能够自动完成,名字和IP之间的转换就是DNS系统的功能,因此Kubernetes也提供了DNS 方法来解决这个问题。
6.jpg

Kubernetes服务发现

如有两个服务frontend和backend,服务frontend调用服务backend。其调用过程如下:

* 先通过本Node上运行的DNS Server查找到backend服务的Cluster IP。
* 再通过本Node上运行的代理Kube-proxy,将请求分发给其中任意一个backend实例。

##一次完整的请求

我们从Tuxedo ATMI体系架构图中可以看出,Tuxedo系统服务层包括管理信息库(MIBs),管理信息库为其他应用程序管理和配置Tuxedo系统提供了一套编程接口,通过这套接口可以对Tuxedo系统进行动态调整和监控。如动态增加Tuxedo服务时,用户通过ATMI Client调用管理信息库(MIBs),通过管理信息库完成服务的增加,最后将服务信息注册到公告板(BB)。

类似地,Kubernetes也提供了一套接口供使用者进行服务的管理维护,具体流程如下:
7.jpg

Kubernetes一次完整的服务请求示意图

使用人员通过Kubectl提交一个创建RC的请求,该请求通过API Server被写入etcd中,此时Controller Manager通过API Server的监听资源变化的接口监听到这个RC事件,分析之后,发现当前集群中还没有它所对应的Pod实例,于是根据RC里的Pod模板定义生成一个Pod对象,通过API Server写入etcd中,接下来,此事件被Scheduler发现,它立即执行一个复杂的调度流程,为这个新Pod选定一个落户的Node,然后又通过API Server将这一结果写入到etcd中。随后,目标Node上运行的Kubelet进程通过API Server检测到这个“新生的”Pod并且按照它的定义,启动该Pod并负责他的一生。

综上所述,Tuxedo软件在金融等行业已应用多年,经过多年积累,运维人员对Tuxedo维护积累了丰富的运维经验。Kubernetes作为后起之秀,逐步在互联网、金融等行业开始应用,相关运维积累存在提升空间。本文通过对两者运行态、容错、扩缩容、服务发现以及一次完整的请求等方面进行对比,希望通过对两者的对比,找出两者运行及运维的相通之处,能够给运维人员维护Kubernetes提供一个思路和借鉴,使得具备Tuxedo等传统软件运维经验的运维人员快速具备Kubernetes运维能力。

原文链接:https://mp.weixin.qq.com/s/P77jueYtBiM_bQy4dtvEag

Docker容器互联方法

翔宇 发表了文章 • 0 个评论 • 276 次浏览 • 2019-05-28 22:34 • 来自相关话题

【编者的话】本文为Eddy Mavungu博士于DEIS官方博客中发布的系列文章的第二部分,Eddy博士在本篇系列文章中分享了Docker容器间互联的方法,并且做了演示。Eddy博士是DEIS公司的创始人,同时也是一位高级研究顾问。本文根据他于DEIS官方博客 ...查看全部
【编者的话】本文为Eddy Mavungu博士于DEIS官方博客中发布的系列文章的第二部分,Eddy博士在本篇系列文章中分享了Docker容器间互联的方法,并且做了演示。Eddy博士是DEIS公司的创始人,同时也是一位高级研究顾问。本文根据他于DEIS官方博客上发布的文章翻译而成。

这篇系列文章的第二部分会看一下如何连接Docker各容器。

我们在第一节谈及了Docker的bridge接口,它可以让我们连接所有在相同Docker宿主机上的容器。特别需要指出的是,我们看了三个基本并且比较早先的网络驱动技术:端口公开(port exposure),端口绑定(port binding)以及链接(linking)。如果你想和更多Docker技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

在本文,我们将来看这些更高级并且最新的基于bridge接口的使用案例。

同时,我们也会看看使用overlay技术来将不同宿主机上的Docker容器连接起来。
#用户定义的网络(User-Defined Networks)
Docker公司在2015年11月初发布了Docker 1.9.0,随之而来整合了一些令人兴奋的关于网络方面的新内容。通过这些更新,如果我们现在为了让两个容器间可以相互通信,那么只需要将他们放在同一网络或者子网中。

让我们来证明一次。

首先,来看看我们准备了哪些:
$ sudo docker network ls
NETWORK ID NAME DRIVER
362c9d3713cc bridge bridge
fbd276b0df0a singlehost bridge
591d6ac8b537 none null
ac7971601441 host host

现在,让我们来创建网络:
$ sudo docker network create backend

如果起作用了,我们的网络列表上会显示刚才新建立的网络:
$ sudo docker network ls
NETWORK ID NAME DRIVER
362c9d3713cc bridge bridge
fbd276b0df0a singlehost bridge
591d6ac8b537 none null
ac7971601441 host host
d97889cef288 backend bridge

我们可以看到在这里backend已经被bridge驱动创建出来了。这是一个桥接(bridge)网络,就像在前文的第一部分中提到的一样,它也同样适用于所有在该宿主机上的容器。

我们将会用到上一节中创建的client_img和server_img镜像。如果你还没有在你的主机上配置好他们,可以现在查阅第一节并且设置好,这并不会花费太长时间。

什么?你说你已经设置好了?太棒了。

让我们从server_img镜像中运行一个服务器容器并且通过--net选项把它放置于之前配置的backend网络中。

就像下面命令一样:
$ sudo docker run -itd --net=backend --name=server server_img /bin/bash

像之前一样,登录到该容器:
$ sudo docker attach server

如果你看不见shell提示符,按键盘方向键的上箭头。

现在让我们启动在该容器里基于Apache的HTTP服务:
$ /etc/init.d/apache2 start

到这里为止,任何位于backend网络中的容器将可以连接到我们刚才创建的Apache HTTP服务器上。

我们可以通过在另一个终端上开启一个客户端容器并且把它至于backend网络进行测试。

就像这样:
$ sudo docker run -itd --net=backend --name=client client_img /bin/bash

进入容器:
$ sudo docker attach client

同样地,如果你看不见shell提示符,按键盘方向键的上箭头。
接着运行:
$ curl server

你应该可以看见默认的HTML页面。这意味着我们配置的网络是可以正常运行的。

就像在本系列文章的第一节中提及到的一样,Docker负责设置容器名称便于解析,这就是为什么我们可以直接用curl server 这个命令而不用知晓它的IP地址。

我们可以创建多个用户定义的网络,并且可以根据应用程序的拓扑结构把这些容器放在单个或多个网络中。这是非常灵活的,特别是对于那些需要交付微服务(microservices),多租户(multitenancy)及微分段(micro-segmentation)的人员来说是非常有用的。
#多主机网络(Multi-Host Networking)
如果我们想要建立一个跨越多台主机的网络该怎么做呢?当然,自从Docker1.9.0之后,你就可以这么做了!

目前为止,我们已经使用了基于本地范围的bridge网络驱动,这意味着桥接网络是在Docker宿主机本地的。Docker现在提供了一个新的全局范围的overlay网络驱动,这意味着overlay的网络可以跨越多台Docker宿主机。并且这些Docker宿主机可以存在于不同的数据中心,甚至不同的云服务提供商中!

为了设置一个overlay网络,以下几点是必须的:

* 一台内核版本高于3.16的主机
* 关键的key-value存储(例如 etcd, ConsulApache ZooKeeper
* 集群内的主机可以保证连接到以上的key-value存储
* 每一个集群内的主机都正确配置了基于 Docker Engine的后台实例

让我们来看一个案例吧。

我将会使用multihost-local.sh脚本和Docker Machine这个命令去开启三台虚拟主机。

这个脚本是用于虚拟机的而不是用于容器的。在这之后,我们在这些虚拟机上面运行Docker命令去模拟一个Docker宿主机集群。

在运行过脚本之后,可以看到我现在有的主机清单:
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM ERRORS
mhl-consul - virtualbox Running tcp://192.168.99.100:2376
mhl-demo0 - virtualbox Running tcp://192.168.99.101:2376
mhl-demo1 - virtualbox Running tcp://192.168.99.102:2376

好了,那么让我们倒退回去看下刚才发生了些什么。

这个脚本利用了Docker Machine,这意味着你必须安装它。在本篇文章中,我们安装了0.5.2版本的Docker Machine。你可以参考该版本的发行注释说明来下载并安装它。

该脚本(multihost-local.sh)使用了Docker Machine去部署三台基于VirtualBox的虚拟机并且安装并适当的配置了Docker Engine。

Docker Machine可以与很多主流虚拟化管理程序以及云服务提供商一起协助。它现在支持AWS、Digital Ocean、Google Cloud Platform、IBM Softlayer、Microsoft Azure和Hyper-V、OpenStack、Rachspace、VitrualBox、VMware Fusion®、vCloud® Air™ and vSphere®。

我们现在有了三个虚拟机:

* mhl-consul: 运行 Consul
* mhl-demo0: Docker 集群节点
* mhl-demo1: Docker 集群节点

这些Docker集群节点是被配置为协调通过VM来运行Consul,我们的key-value仓库。这也就是这些集群所涉及到的。

很酷吧,让我们再快速地往前看一看。

现在,让我们设置一个overlay网络。

首先,我们需要用一个在mhl-demo0这个VM上的终端,像这样:
$ eval $(docker-machine env mhl-demo0)

然后运行:
$ docker network create -d overlay myapp

该命令建立了一个名为myapp的跨越所有集群中主机的overlay网络。由于Docker通过key-value与该集群上的其他主机协调使得该操作变成了可能。

为了确保它正常的工作,我们可以通过终端登录到每一个集群中的VM去列出这些Docker网络。

复制下面所有的eval命令,然后用相对应的主机名去替换mhl-demo0。

然后运行:
$ docker network ls
NETWORK ID NAME DRIVER
7b9e349b2f01 host host
1f6a49cf5d40 bridge bridge
38e2eba8fbc8 none null
385a8bd92085 myapp overlay

到这里你就看到名为myapp的overlay网络了。

咱们成功啦!

但请记住:我们目前仅仅是创建了一个基于Docker 虚拟机的集群并配置了用于共享的overlay网络。我们实际上并没有创建任何Docker容器。所以让我们接着创建它们并来试一下这个overlay网络。

我们将做以下步骤:

1. 在mhl-demo0宿主机上运行默认地nginx镜像(这提供给了我们一个预先配置好的Nginx HTTP服务器)
2. 在mhl-demo1宿主机上运行默认的busybox镜像(它提供给我们一个基本的操作系统并且还包含一个类似于基于GNU的Wget工具)
3. 将两个容器添加进myapp网络
4. 测试他们之间的网络连通性

首先,让我们调出在mhl-demo0宿主机上的终端:
$ eval $(docker-machine env mhl-demo0)

然后启动nginx镜像:
$ docker run --name ng1 --net=myapp -d nginx

简而言之,我们现在有以下环境:

* 一台基于Nginx的HTTP服务器
* 该服务跑在名为ng1的容器里
* 它处在myapp网络中
* 该容器位于mhl-demo0宿主机上

让我们从其他宿主机上的另外一个容器试着去访问该环境,去验证它是可用的。

这一次调出mhl-demo1宿主机上的终端:
$ eval $(docker-machine env mhl-demo1)

然后运行:
$ docker run -it --net=myapp busybox wget -qO- ng1

以上命令其实做了以下几点:

* 从busybox镜像中创建了一个未命名的容器
* 将它添加进了myapp网络
* 运行了wget -qO- ng1命令
* 并且停止了该容器(我们在这之前是让容器运行的)

在以上的Wget命令中,ng1是我们Nginx的容器名称。Docker可以让我们使用解析到的主机名作为容器名称,甚至该容器是运行在不同的Docker宿主机上。

如果所有操作都是成功的,那么我们应该会看见以下类似的内容:






Welcome to nginx!

你看吧!我们现在拥有了一个基于多主机的容器网络。
#总结
Docker给予了诸如轻量级且独立地并能隔离的环境这样的优点。然而,要使容器对我们而言有用途,容器之间以及容器与主机网络之间要能互相通信才是至关重要的。

在这一系列文章中,我们探索了一些容器间本地互联和跨多个宿主机互联的方法。同样地,我们也聊了聊该如何在主机网络中去连接多个容器。

原文链接:Connecting Docker Containers, Part Two (翻译:薛开成)

===========================================
译者介绍
薛开成,趋势科技南京研发中心工程工具服务事业部基础架构高级工程师,负责容器仓库实施及落地。

Docker网络原则入门:EXPOSE,-p,-P,-link

aoxiang 发表了文章 • 0 个评论 • 125 次浏览 • 2019-05-28 22:31 • 来自相关话题

【编者的话】构建多容器应用程序,需要定义网络参数来设置容器间的通信,可以通过EXPOSE或者-expose暴露端口、使用-p发布特定端口,还可以用-link等等来实现,这些方法可能会得到一样的效果,但是这些方法之间是否有不同,应该选择什么样的方法,将是本文讨论 ...查看全部
【编者的话】构建多容器应用程序,需要定义网络参数来设置容器间的通信,可以通过EXPOSE或者-expose暴露端口、使用-p发布特定端口,还可以用-link等等来实现,这些方法可能会得到一样的效果,但是这些方法之间是否有不同,应该选择什么样的方法,将是本文讨论的重点内容。

如果你已经构建了一些多容器的应用程序,那么肯定需要定义一些网络规则来设置容器间的通信。有多种方式可以实现:可以通过`--expose`参数在运行时暴露端口,或者在Dockerfile里使用`EXPOSE`指令。还可以在Docker run的时候通过`-p`或者`-P`参数来发布端口。或者通过`--link`链接容器。虽然这些方式几乎都能达到一样的结果,但是它们还是有细微区别。那么到底应该使用哪一种呢?如果你想和更多Docker技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

# TL;DR
使用-p或者-P来创建特定端口绑定规则最为可靠,EXPOSE可以看做是容器文档化的方式,谨慎使用--link的方式。



在比较这些不同方式之前,我们先分别了解细节。

#通过EXPOSE或者-expose暴露端口

有两种方式可以用来暴露端口:要么用`EXPOSE`指令在Dockerfile里定义,要么在docker run时指定`--expose=1234`。这两种方式作用相同,但是,`--expose`可以接受端口范围作为参数,比如 `--expose=2000-3000`。但是,`EXPOSE`和`--expose`都不依赖于宿主机器。默认状态下,这些规则并不会使这些端口可以通过宿主机来访问。

基于`EXPOSE`指令的上述限制,Dockerfile的作者一般在包含`EXPOSE`规则时都只将其作为哪个端口提供哪个服务的提示。使用时,还要依赖于容器的操作人员进一步指定网络规则。和`-P`参数联合使用的情况,下文会进一步阐述。不过通过`EXPOSE`命令文档化端口的方式十分有用。

本质上说,`EXPOSE`或者`--expose`只是为其他命令提供所需信息的元数据,或者只是告诉容器操作人员有哪些已知选择。

实际上,在运行时暴露端口和通过Dockerfile的指令暴露端口,这两者没什么区别。在这两种方式启动的容器里,通过`docker inspect $container_id | $container_name`查看到的网络配置是一样的:

"NetworkSettings": {
"PortMapping": null,
"Ports": {
"1234/tcp": null
}
},
"Config": {
"ExposedPorts": {
"1234/tcp": {}
}
}

可以看到端口被标示成已暴露,但是没有定义任何映射。注意这一点,因为我们查看的是发布端口。

ProTip:使用运行时标志`--expose`是附加的,因此会在Dockerfile的`EXPOSE`指令定义的端口之外暴露添加的端口。

#使用-p发布特定端口
可以使用`-p`参数显式将一个或者一组端口从容器里绑定到宿主机上,而不仅仅是提供一个端口。注意这里是小写的p,不是大写。因为该配置依赖于宿主机器,所以Dockerfile里没有对应的指令,这是运行时才可用的配置。`-p`参数有几种不同的格式:

ip:hostPort:containerPort| ip::containerPort \
| hostPort:containerPort | containerPort

实际中,可以忽略ip或者hostPort,但是必须要指定需要暴露的containerPort。另外,所有这些发布的规则都默认为tcp。如果需要udp,需要在最后加以指定,比如`-p 1234:1234/udp`。如果只是用命令`docker run -p 8080:3000 my-image`运行一个简单的应用程序,那么容器里运行在3000端口的服务在宿主机的8080端口也就可用了。端口不需要一样,但是在多个容器都暴露端口时,必须注意避免端口冲突。

避免冲突的最佳方法是让Docker自己分配hostPort。在上述例子里,可以选择`docker run -p 3000 my_image`来运行容器,而不是显式指定宿主机端口。这时,Docker会帮助选择一个宿主机端口。运行命令`docker port $container_id | $container_name`可以查看Docker选出的端口号。除了端口号,该命令只能显示容器运行时端口绑定信息。还可以通过在容器上运行`docker inspect`查看详细的网络信息,在定义了端口映射时,这样的信息就很有用。该信息在Config、HostConfig和NetworkSettings部分。我们查看这些信息来对比不同方式搭建的容器间的网络区别。

ProTip:可以用`-p`参数定义任意数量的端口映射。

#-expose/EXPOSE和-p对比
为了更好得理解两者之间的区别,我们使用不同的端口设置来运行容器。

运行一个很简单的应用程序,会在curl它的时候打印'hello world'。称这个镜像为no-exposed-ports:

FROM ubuntu:trusty
MAINTAINER Laura Frank
CMD while true; do echo 'hello world' | nc -l -p 8888; done

实验时注意使用的是Docker主机,而不是`boot2docker`。如果使用的是`boot2docker`,运行本文示例命令前先运行`boot2docker ssh`。

注意,我们使用`-d`参数运行该容器,因此容器一直在后台运行。(端口映射规则只适用于运行着的容器):

$ docker run -d --name no-exposed-ports no-exposed-ports
e18a76da06b3af7708792765745466ed485a69afaedfd7e561cf3645d1aa7149

这儿没有太多的信息,只是回显了容器的ID,提示服务已经成功启动。和预期结果一样,运行`docker port no-exposed-ports`和`docker inspect no-exposed-ports`时没显示什么信息,因为我们既没有定义端口映射规则也没有发布任何端口。

因此,如果我们发布一个端口会发生什么呢,`-p`参数和`EXPOSE`到底有什么区别呢?

还是使用上文的`no-exposed-ports`镜像,在运行时添加`-p`参数,但是不添加任何expose规则。在`config.ExposedPorts`里重新查看--expose参数或者EXPOSE指令的结果。

$ docker run -d --name no-exposed-ports-with-p-flag -p 8888:8888 no-exposed-ports
c876e590cfafa734f42a42872881e68479387dc2039b55bceba3a11afd8f17ca
$ docker port no-exposed-ports-with-p-flag
8888/tcp -> 0.0.0.0:8888

太棒了!我们可以看到可用端口。注意默认这是tcp。我们到网络设置里看看还有什么信息:

"Config": {
[...]
"ExposedPorts": {
"8888/tcp": {}
}
},
"HostConfig": {
[...]
"PortBindings": {
"8888/tcp": [
{
"HostIp": "",
"HostPort": "8888"
}
]
}
},
"NetworkSettings": {
[...]
"Ports": {
"8888/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "8888"
}
]
}
}

注意”Config“部分的暴露端口字段。这和我们使用`EXPOSE`或者`--expose`暴露的端口是一致的。Docker会隐式暴露已经发布的端口。已暴露端口和已发布端口的区别在于已发布端口在宿主机上可用,而且我们可以在“HostConfig”和“NetworkSettings”两个部分都能看到已发布端口的信息。

所有发布(`-p`或者`-P`)的端口都暴露了,但是并不是所有暴露(`EXPOSE`或`--expose`)的端口都会发布。

#使用-P和EXPOSE发布端口
因为`EXPOSE`通常只是作为记录机制,也就是告诉用户哪些端口会提供服务,Docker可以很容易地把Dockerfile里的`EXPOSE`指令转换成特定的端口绑定规则。只需要在运行时加上`-P`参数,Docker会自动为用户创建端口映射规则,并且帮助避免端口映射的冲突。

添加如下行到上文使用的Web应用Dockerfile里:

EXPOSE 1000
EXPOSE 2000
EXPOSE 3000

构建镜像,命名为exposed-ports。

docker build -t exposed-ports .

再次用`-P`参数运行,但是不传入任何特定的`-p`规则。可以看到Docker会将`EXPOSE`指令相关的每个端口映射到宿主机的端口上:

$ docker run -d -P --name exposed-ports-in-dockerfile exposed-ports
63264dae9db85c5d667a37dac77e0da7c8d2d699f49b69ba992485242160ad3a
$ docker port exposed-ports-in-dockerfile
1000/tcp -> 0.0.0.0:49156
2000/tcp -> 0.0.0.0:49157
3000/tcp -> 0.0.0.0:49158

很方便,不是么?
#--link怎么样呢?

你可能在多容器应用程序里使用过运行时参数 `--link name:alias`来设定容器间关系。虽然`--link`非常易于使用,几乎能提供和端口映射规则和环境变量相同的功能。但是最好将`--link`当做服务发现的机制,而不是网络流量的门户。

`--link`参数唯一多做的事情是会使用源容器的主机名和容器ID来更新新建目标容器(使用`--link`参数创建的容器)的/etc/hosts文件。

当使用`--link`参数时,Docker提供了一系列标准的环境变量,如果想知道细节的话可以查看相应文档

虽然`--link`对于需要隔离域的小型项目非常有用,它的功能更像服务发现的工具。如果项目中使用了编排服务,比如Kubernetes或者Fleet,很可能就会使用别的服务发现工具来管理关系。这些编排服务可能会不管理Docker的链接,而是管理服务发现工具里包含的所有服务,在Panamax项目里使用的很多远程部署适配器正是做这个的。

#找到平衡
哪一种网络选择更为适合,这取决于谁(或者哪个容器)使用Docker运行的服务。需要注意的是一旦镜像发布到Docker Hub之后,你无法知道其他人如何使用该镜像,因此要尽可能让镜像更加灵活。如果你只是从Docker Hub里取得镜像,使用`-P`参数运行容器是最方便迅速的方式,来基于作者的建议创建端口映射规则。记住每一个发布的端口都是暴露端口,但是反过来是不对的。
#快速参考
1.jpg


原文链接:A Brief Primer on Docker Networking Rules: EXPOSE, -p, -P, –link(翻译:崔婧雯 校对:魏小红)
===========================
译者介绍
崔婧雯,现就职于IBM,高级软件工程师,负责IBM WebSphere业务流程管理软件的系统测试工作。曾就职于VMware从事桌面虚拟化产品的质量保证工作。对虚拟化,中间件技术,业务流程管理有浓厚的兴趣。

使用Spring Cloud和Docker构建微服务架构

老马 发表了文章 • 0 个评论 • 212 次浏览 • 2019-05-28 22:27 • 来自相关话题

【编者的话】如何使用Spring Boot、Spring Cloud、Docker和Netflix的一些开源工具来构建一个微服务架构。本文通过使用Spring Boot、Spring Cloud和Docker构建的概念型应用示例,提供了了解常见的微服务架构模式 ...查看全部
【编者的话】如何使用Spring Boot、Spring Cloud、Docker和Netflix的一些开源工具来构建一个微服务架构。本文通过使用Spring Boot、Spring Cloud和Docker构建的概念型应用示例,提供了了解常见的微服务架构模式的起点。

该代码可以在GitHub上获得,并且在Docker Hub上提供了镜像。您只需要一个命令即可启动整个系统。

我选择了一个老项目作为这个系统的基础,它的后端以前是单一应用。此应用提供了处理个人财务、整理收入开销、管理储蓄、分析统计和创建简单预测等功能。如果你想和更多Spring Cloud技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
#功能服务
整个应用分解为三个核心微服务。它们都是可以独立部署的应用,围绕着某些业务功能进行组织。
1.png


账户服务

包含一般用户输入逻辑和验证:收入/开销记录、储蓄和账户设置。
2.png


统计服务

计算主要的统计参数,并捕获每一个账户的时间序列。数据点包含基于货币和时间段正常化后的值。该数据可用于跟踪账户生命周期中的现金流量动态。
3.png


通知服务

存储用户的联系信息和通知设置(如提醒和备份频率)。安排工作人员从其它服务收集所需的信息并向订阅的客户发送电子邮件。
4.png


注意

* 每一个微服务拥有自己的数据库,因此没有办法绕过API直接访问持久数据。
* 在这个项目中,我使用MongoDB作为每一个服务的主数据库。拥有一个多种类持久化架构(polyglot persistence architecture)也是很有意义的。
* 服务间(Service-to-service)通信是非常简单的:微服务仅使用同步的REST API进行通信。现实中的系统的常见做法是使用互动风格的组合。例如,执行同步的GET请求检索数据,并通过消息代理(broker)使用异步方法执行创建/更新操作,以便解除服务和缓冲消息之间的耦合。然而,这带给我们是最终的一致性

#基础设施服务
分布式系统中常见的模式,可以帮助我们描述核心服务是怎样工作的。Spring Cloud提供了强大的工具,可以增强Spring Boot应用的行为来实现这些模式。我会简要介绍一下:
5.png

##配置服务
Spring Cloud Config是分布式系统的水平扩展集中式配置服务。它使用了当前支持的本地存储、Git和Subversion等可拔插存储库层(repository layer)。

在此项目中,我使用了native profile,它简单地从本地classpath下加载配置文件。您可以在配置服务资源中查看shared目录。现在,当通知服务请求它的配置时,配置服务将响应回shared/notification-service.yml和shared/application.yml(所有客户端应用之间共享)。

客户端使用

只需要使用sprng-cloud-starter-config依赖构建Spring Boot应用,自动配置将会完成其它工作。

现在您的应用中不需要任何嵌入的properties,只需要提供有应用名称和配置服务url的bootstrap.yml即可:
spring:
application:
name: notification-service
cloud:
config:
uri: http://config:8888
fail-fast: true

使用Spring Cloud Config,您可以动态更改应用配置

比如,EmailService bean使用了@RefreshScope注解。这意味着您可以更改电子邮件的内容和主题,而无需重新构建和重启通知服务应用。

首先,在配置服务器中更改必要的属性。然后,对通知服务执行刷新请求:curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh。

您也可以使用webhook来自动执行此过程

注意

* 动态刷新存在一些限制。@RefreshScope不能和@Configuraion类一同工作,并且不会作用于@Scheduled方法。
* fail-fast属性意味着如果Spring Boot应用无法连接到配置服务,将会立即启动失败。当您一起启动所有应用时,这非常有用。
* 下面有重要的安全提示

##授权服务
负责授权的部分被完全提取到单独的服务器,它为后端资源服务提供OAuth2令牌。授权服务器用于用户授权以及在周边内进行安全的机器间通信。

在此项目中,我使用密码凭据作为用户授权的授权类型(因为它仅由本地应用UI使用)和客户端凭据作为微服务授权的授权类型。

Spring Cloud Security提供了方便的注解和自动配置,使其在服务器端或者客户端都可以很容易地实现。您可以在文档中了解到更多信息,并在授权服务器代码中检查配置明细。

从客户端来看,一切都与传统的基于会话的授权完全相同。您可以从请求中检索Principal对象、检查用户角色和其它基于表达式访问控制和@PreAuthorize注解的内容。

PiggyMetrics(帐户服务、统计服务、通知服务和浏览器)中的每一个客户端都有一个范围:用于后台服务的服务器、用于浏览器展示的UI。所以我们也可以保护控制器避免受到外部访问,例如:
@PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)
public List getStatisticsByAccountName(@PathVariable String name) {
return statisticsService.findByAccountName(name);
}

##API网关
您可以看到,有三个核心服务。它们向客户端暴露外部API。在现实系统中,这个数量可以非常快速地增长,同时整个系统将变得非常复杂。实际上,一个复杂页面的渲染可能涉及到数百个服务。

理论上,客户端可以直接向每个微服务直接发送请求。但是这种方式是存在挑战和限制的,如果需要知道所有端点的地址,分别对每一段信息执行http请求,将结果合并到客户端。另一个问题是,这不是web友好协议,可能只在后端使用。

通常一个更好的方法是使用API网关。它是系统的单个入口点,用于通过将请求路由到适当的后端服务或者通过调用多个后端服务并聚合结果来处理请求。此外,它还可以用于认证、insights、压力测试、金丝雀测试(canary testing)、服务迁移、静态响应处理和主动变换管理。

Netflix开源这样的边缘服务,现在用Spring Cloud,我们可以用一个@EnabledZuulProxy注解来启用它。在这个项目中,我使用Zuul存储静态内容(UI应用),并将请求路由到适当的微服务。以下是一个简单的基于前缀(prefix-based)路由的通知服务配置:
zuul:
routes:
notification-service:
path: /notifications/**
serviceId: notification-service
stripPrefix: false

这意味着所有以/notification开头的请求将被路由到通知服务。您可以看到,里面没有硬编码的地址。Zuul使用服务发现机制来定位通知服务实例以及断路器和负载均衡器,如下所述。
##服务发现
另一种常见的架构模式是服务发现。它允许自动检测服务实例的网络位置,由于自动扩展、故障和升级,它可能会动态分配地址。

服务发现的关键部分是注册。我使用Netflix Eureka进行这个项目,当客户端需要负责确定可以用的服务实例(使用注册服务器)的位置和跨平台的负载均衡请求时,Eureka就是客户端发现模式的一个很好的例子。

使用Spring Boot,您可以使用spring-cloud-starter-eureka-server依赖、@EnabledEurekaServer注解和简单的配置属性轻松构建Eureka注册中心(Eureka Registry)。

使用@EnabledDiscoveryClient注解和带有应用名称的bootstrap.yml来启用客户端支持:
spring:
application:
name: notification-service

现在,在应用启动时,它将向Eureka服务器注册并提供元数据,如主机和端口、健康指示器URL、主页等。Eureka接收来自从属于某服务的每个实例的心跳消息。如果心跳失败超过配置的时间表,该实例将从注册表中删除。

此外,Eureka还提供了一个简单的界面,您可以通过它来跟踪运行中的服务和可用实例的数量:http://localhost:8761
6.png

##负载均衡器、断路器和Http客户端
Netflix OSS提供了另一套很棒的工具。

Ribbon

Ribbon是一个客户端负载均衡器,可以很好地控制HTTP和TCP客户端的行为。与传统的负载均衡器相比,每次线上调用都不需要额外的跳跃——您可以直接联系所需的服务。

它与Spring Cloud和服务发现是集成在一起的,可开箱即用。Eureka客户端提供了可用服务器的动态列表,因此Ribbon可以在它们之间进行平衡。

Hystrix

Hystrix是断路器模式的一种实现,它可以通过网络访问依赖来控制延迟和故障。中心思想是在具有大量微服务的分布式环境中停止级联故障。这有助于快速失败并尽快恢复——自我修复在容错系统中是非常重要的。

除了断路器控制,在使用Hystrix,您可以添加一个备用方法,在主命令失败的情况下,该方法将被调用以获取默认值。

此外,Hystrix生成每个命令的执行结果和延迟的度量,我们可以用它来监视系统的行为

Feign

Feign是一个声明式HTTP客户端,能与Ribbon和Hystrix无缝集成。实际上,通过一个spring-cloud-starter-feign依赖和@EnabledFeignClients注解,您可以使用一整套负载均衡器、断路器和HTTP客户端,并附带一个合理的的默认配置。

以下是账户服务的示例:
@FeignClient(name = "statistics-service")
public interface StatisticsServiceClient {
@RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
void updateStatistics(@PathVariable("accountName") String accountName, Account account);
}


* 您需要的只是一个接口
* 您可以在Spring MVC控制器和Feign方法之间共享@RequestMapping部分
* 以上示例仅指定所需要的服务ID——statistics-service,这得益于Eureka的自动发现(但显然您可以使用特定的URL访问任何资源)。

##监控仪表盘
在这个项目配置中,Hystrix的每一个微服务都通过Spring Cloud Bus(通过AMQP broker)将指标推送到Turbine。监控项目只是一个使用了TurbineHystrix仪表盘的小型Spring Boot应用。

让我们看看系统行为在负载下:账户服务调用统计服务和它在一个变化的模拟延迟下的响应。响应超时阈值设置为1秒。
7.png

##日志分析
集中式日志记录在尝试查找分布式环境中的问题时非常有用。Elasticsearch、Logstash和Kibana技术栈可让您轻松搜索和分析您的日志、利用率和网络活动数据。在我的另一个项目中已经有现成的Docker配置。
##安全

高级安全配置已经超过了此概念性项目的范围。为了更真实地模拟真实系统,请考虑使用https和JCE密钥库来加密微服务密码和配置服务器的properties内容(有关详细信息,请参阅文档)。
#基础设施自动化

部署微服务比部署单一的应用的流程要复杂得多,因为它们相互依赖。拥有完全基础设置自动化是非常重要的。我们可以通过持续交付的方式获得以下好处:

* 随时发布软件的能力。
* 任何构建都可能最终成为一个发行版本。
* 构建工件(artifact)一次,根据需要进行部署。

这是一个简单的持续交付工作流程,在这个项目的实现:

在此配置中,Travis CI为每一个成功的Git推送创建了标记镜像。因此,每一个微服务在Docker Hub上的都会有一个latest镜像,而较旧的镜像则使用Git提交的哈希进行标记。如果有需要,可以轻松部署任何一个,并快速回滚。
8.png

#如何运行全部?
这真的很简单,我建议您尝试一下。请记住,您将要启动8个Spring Boot应用、4个MongoDB实例和RabbitMq。确保您的机器上有4GB的内存。您可以随时通过网关、注册中心、配置、认证服务和账户中心运行重要的服务。

运行之前

* 安装Docker和Docker Compose。
* 配置环境变量:CONFIG_SERVICE_PASSWORD, NOTIFICATION_SERVICE_PASSWORD, STATISTICS_SERVICE_PASSWORD, ACCOUNT_SERVICE_PASSWORD, MONGODB_PASSWORD

生产模式

在这种模式下,所有最新的镜像都将从Docker Hub上拉取。只需要复制docker-compose.yml并执行docker-compose up -d即可。

开发模式

如果您想自己构建镜像(例如,在代码中进行一些修改),您需要克隆所有仓库(repository)并使用Mavne构建工件(artifact)。然后,运行docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

docker-compose.dev.yml继承了docker-compose.yml,附带额外配置,可在本地构建镜像,并暴露所有容器端口以方便开发。

重要的端点(Endpoint)

* localhost:80 —— 网关
* localhost:8761 —— Eureka仪表盘
* localhost:9000 —— Hystrix仪表盘
* localhost:8989 —— Turbine stream(Hystrix仪表盘来源)
* localhost:15672 —— RabbitMq管理

注意

所有Spring Boot应用都需要运行配置服务器才能启动。得益于Spring Boot的fail-fast属性和docker-compsoe的restart:always选项,我们可以同时启动所有容器。这意味着所有依赖的容器将尝试重新启动,直到配置服务器启动运行为止。

此外,服务发现机制在所有应用启动后需要一段时间。在实例、Eureka服务器和客户端在其本地缓存中都具有相同的元数据之前,任何服务都不可用于客户端发现,因此可能需要3次心跳。默认的心跳周期为30秒。

原文链接:Microservice Architectures With Spring Cloud and Docker(翻译:Oopsguy

Docker五大优势:持续集成、版本控制、可移植性、隔离性和安全性

Andy_Lee 发表了文章 • 0 个评论 • 175 次浏览 • 2019-05-28 22:18 • 来自相关话题

【编者的话】 随着Docker技术的不断成熟,越来越多的企业开始考虑使用Docker。Docker有很多的优势,本文主要讲述了Docker的五个最重要优势,即持续集成、版本控制、可移植性、隔离性和安全性。 对于Docker,应该不需要 ...查看全部
【编者的话】 随着Docker技术的不断成熟,越来越多的企业开始考虑使用Docker。Docker有很多的优势,本文主要讲述了Docker的五个最重要优势,即持续集成、版本控制、可移植性、隔离性和安全性。

对于Docker,应该不需要进行详细的介绍了。它是最火热的开源项目之一,通过在容器中增加一个抽象层(a layer of abstraction),就可以将应用程序部署到容器中。在看似稳定而成熟的场景下,使用Docker的好处越来越多。在这篇文章中,我不谈论Docker是什么或者Docker是怎么工作的,取而代之,我会提出使用这个不断成长的平台的五大好处。
#持续部署与测试
Docker在开发与运维的世界中具有极大的吸引力,因为它能保持跨环境的一致性。在开发与发布的生命周期中,不同的环境具有细微的不同,这些差异可能是由于不同安装包的版本和依赖关系引起的。然而,Docker可以通过确保从开发到产品发布整个过程环境的一致性来解决这个问题*Docker容器通过相关配置,保持容器内部所有的配置和依赖关系始终不变。最终,你可以在开发到产品发布的整个过程中使用相同的容器来确保没有任何差异或者人工干预。

使用Docker,你还可以确保开发者不需要配置完全相同的产品环境,他们可以在他们自己的系统上通过VirtualBox建立虚拟机来运行Docker容器。Docker的魅力在于它同样可以让你在亚马逊EC2实例上运行相同的容器。如果你需要在一个产品发布周期中完成一次升级,你可以很容易地将需要变更的东西放到Docker容器中,测试它们,并且使你已经存在的容器执行相同的变更。这种灵活性就是使用Docker的一个主要好处。和标准部署与集成过程一样,Docker可以让你构建、测试和发布镜像,这个镜像可以跨多个服务器进行部署。哪怕安装一个新的安全补丁,整个过程也是一样的。你可以安装补丁,然后测试它,并且将这个补丁发布到产品中。如果你想和更多Docker技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
#多云平台
Docker最大的好处之一就是可移植性。在过去的几年里,所有主流的云计算提供商,包括亚马逊AWS和谷歌的GCP,都将Docker融入到他们的平台并增加了各自的支持。Docker容器能运行在亚马逊的EC2实例、谷歌的GCP实例、Rackspace服务器或者VirtualBox这些提供主机操作系统的平台上。举例来说,如果运行在亚马逊EC2实例上的Docker容器能够很容易地移植到其他几个平台上,比如说VirtualBox,并且达到类似的一致性和功能性,那这将允许你从基础设施层中抽象出来。除了AWS和GCP,Docker在其他不同的IaaS提供商也运行的非常好,例如微软的Azure、OpenStack和可以被具有不同配置的管理者所使用的Chef、Puppet、Ansible等。
#环境标准化和版本控制
通过上面的讨论,Docker容器可以在不同的开发与产品发布生命周期中确保一致性,进而标准化你的环境。除此之外,Docker容器还可以像git仓库一样,可以让你提交变更到Docker镜像中并通过不同的版本来管理它们。设想如果你因为完成了一个组件的升级而导致你整个环境都损坏了,Docker可以让你轻松地回滚到这个镜像的前一个版本。这整个过程可以在几分钟内完成,如果和虚拟机的备份或者镜像创建流程对比,那Docker算相当快的,它可以让你快速地进行复制和实现冗余。此外,启动Docker就和运行一个进程一样快。
#隔离性
Docker可以确保你的应用程序与资源是分隔开的。几个月前,Gartner发表了一篇报告,这份报告说明了运行Docker 容器进行资源隔离的效果和虚拟机(VM)管理程序一样的好,但是管理与控制方面还需要进行完善。

我们考虑这样一个场景,你在你的虚拟机中运行了很多应用程序,这些应用程序包括团队协作软件(例如Confluence)、问题追踪软件(例如JIRA)、集中身份管理系统(例如Crowd)等等。由于这些软件运行在不同的端口上,所以你必须使用Apache或者Nginx来做反向代理。到目前为止,一切都很正常,但是随着你的环境向前推进,你需要在你现有的环境中配置一个内容管理系统(例如Alfresco)。这时候有个问题发生了,这个软件需要一个不同版本的Apache Tomcat,为了满足这个需求,你只能将你现有的软件迁移到另一个版本的Tomcat上,或者找到适合你现有Tomcat的内容管理系统(Alfresco)版本。

对于上述场景,使用Docker就不用做这些事情了。Docker能够确保每个容器都拥有自己的资源,并且和其他容器是隔离的。你可以用不同的容器来运行使用不同堆栈的应用程序。除此之外,如果你想在服务器上直接删除一些应用程序是比较困难的,因为这样可能引发依赖关系冲突。而Docker可以帮你确保应用程序被完全清除,因为不同的应用程序运行在不同的容器上,如果你不在需要一款应用程序,那你可以简单地通过删除容器来删除这个应用程序,并且在你的宿主机操作系统上不会留下任何的临时文件或者配置文件。

除了上述好处,Docker还能确保每个应用程序只使用分配给它的资源(包括CPU、内存和磁盘空间)。一个特殊的软件将不会使用你全部的可用资源,要不然这将导致性能降低,甚至让其他应用程序完全停止工作。
#安全性
如上所述,Gartner也承认Docker正在快速地发展。从安全角度来看,Docker确保运行在容器中的应用程序和其他容器中的应用程序是完全分隔与隔离的,在通信流量和管理上赋予你完全的控制权。Docker容器不能窥视运行在其他容器中的进程。从体系结构角度来看,每个容器只使用着自己的资源(从进程到网络堆栈)。

作为紧固安全的一种手段,Docker将宿主机操作系统上的敏感挂载点(例如/proc和/sys)作为只读挂载点,并且使用一种写时复制系统来确保容器不能读取其他容器的数据。Docker也限制了宿主机操作系统上的一些系统调用,并且和SELinux与AppArmor一起运行的很好。此外,在Docker Hub上可以使用的Docker镜像都通过数字签名来确保其可靠性。由于Docker容器是隔离的,并且资源是受限制的,所以即使你其中一个应用程序被黑,也不会影响运行在其它Docker容器上的应用程序。
#结语
将云计算一起考虑,上面提到的这些好处能够清楚地证明Docker是一个有效的开源平台。使用Docker的好处越来越多,今天我只想强调这前五大好处。如果你使用了Docker,欢迎分享你的使用案例或者任何你觉得使用Docker带来的好处。

原文链接:5 Key Benefits of Docker: CI, Version Control, Portability, Isolation and Security(翻译:肖远昊 校对:魏小红)