王朝网络
分享
 
 
 

容器私有云和持续发布都要解决哪些基础问题第一集

王朝学院·作者佚名  2016-08-27  
宽屏版  字体: |||超大  

郑昀编著,文字资料来自于张帆、白俊华、刘飞宇以及网络资料 创建于2015/10/21 最后更新于2015/10/29关键词:Docker,容器,持续集成,持续发布,CI,私有云

本文档适用人员:广义上的技术人员

提纲:

集装箱还是卷挂载?Host Networking 还是 Bridge Networking?容器要固定ip吗?容器内部如何获取宿主机的IP?待续

首先,你要明白容器并不是虚拟机,虽然它可以解决虚拟机能够解决的问题,同时也能够解决虚拟机由于资源要求过高而无法解决的问题,但它真的不是虚拟机。以往我们的开发、配置管理、部署发布、监控报警思路都要跟着变。

其次,一开始注定只有一少部分工程迁移到容器私有云上,既然还有大多数应用服务还在虚拟机或物理机上,那么它们之间如何通讯就成了一个必须解决的问题。

那么,我们在构建基于容器的私有云以及相应的持续发布时,遇到并解决了哪些问题呢?

0x00 集装箱还是卷挂载?

先抛出问题,下面这个选择题你怎么选:

代码不放入 Image(镜像) 里,而是放在 Volume(卷) 上,这样镜像只需要维护程序运行的环境(如 Resin+JDK1.7)即可,准备几种java、php、Python 运行时环境的镜像即可,不同的应用运行不同的容器挂载不同的代码;代码打包放入 Image 里,典型场景如下图(图源自出处3)所示:

我们再来看一下 Docker 的 Logo,它隐含天机:

一艘鲸鱼大船,载着无数集装箱。操作系统就是这艘货轮,每一个容器就是一个集装箱,交付运行环境如同海运。大家知道吗,集装箱的英文单词就是 container!

集装箱有什么好处?

规格标准,在港口和船上可以层叠摆放,节省大量空间,可以进行快速装卸,并可从一种运输工具方便地换装到另一种运输工具,途中转运不用移动箱内货物,就可以直接换装,货物的装满和卸空很方便。

那么,上面的选择题如何回答呢?

触控科技运维负责人萧田国认为,把代码放在宿主机上,让容器通过卷组映射来读取,不建议采用这种方案,原因是,将代码拆分出容器,这违背了 Docker 的集装箱原则:

从货运工人角度考虑,整体才是最经济的。这也导致装卸复杂度增加。 或者说,容器时代,一切版本化,抛弃过去文件分发的思想,才是正途,这样也才能实现真正意义上的容器级迁移。

我们是怎么考虑的呢?

假定是代码和 Image 分开的场景,主要有两种实现方式:

代码放到 slave 节点的本地磁盘:那么必须要有一种机制,来确保每台 slave 上代码包版本的一致性,而且对于磁盘空间和网络分发来讲也是一种浪费(考虑一下 100 台 slave,其中可能只有 10 台需要运行这个版本的代码) 代码放到分布式共享文件系统(如 ceph):它倒是解决了数据过度冗余以及一致性的问题,但分布式共享文件系统本身成为了『单点』,虽然可以设置多个副本。它的性能和可靠性都必须得到充分保障才行。

在容器云之前,我们采用的是基于 OpenStack 的虚拟机管理方案。在线下环境用 OpenStack 时,我们将所有的虚拟机放置到 ceph(注:linuxPB 级分布式文件系统) 上,但是由于线下 ceph 节点太少,单节点出问题时影响较大。每次 ceph 出现问题,所有的虚拟机都特别慢。

来到了容器时代,如果还把代码放置到 ceph 上,对 ceph 的依赖太高了,ceph 一旦有问题,有可能使用了 ceph 的所有容器都会出问题 。线上业务主要考虑的是性能(容器本地运行代码 vs 通过网络获取代码)和可靠性(每个 slave 都本地运行容器 vs 所有容器依赖共享文件系统),结论不言而喻。所以一开始决策时,没敢把代码放在 ceph 上,而是放在镜像里。所以我们选的是方案2,代码在镜像里。

在我们的场景里,镜像会被下载到 mesos slave 物理机的本地磁盘上,所以启动容器时读的是本地磁盘。

多说一句,Qunar 等公司在2014年选择的是卷挂载方案,业界也有人认为,这事儿得分环境具体问题具体分析,开发集成环境和生产环境可能就不一样。

0x01 Host Networking 还是 Bridge Networking?

网络基础 Docker 现有的网络模型主要是通过使用 Network namespace、Linux Bridge、iptables、veth pair 等技术实现的。(出处8)

Network namespace:它主要提供了网络资源的隔离,包括网络设备、IPv4/IPv6 协议栈、IP 路由表、防火墙、/PRoc/net 目录、/sys/class/net 目录、端口(socket)等。Linux Bridge:功能相当于物理交换机,为连在其上的设备(容器)转发数据帧,如 docker0 网桥。Iptables:主要为容器提供 NAT 以及容器网络安全。veth pair:两个虚拟网卡组成的数据通道。在 Docker 中,用于连接 Docker 容器和 Linux Bridge。一端在容器中作为 eth0 网卡,另一端在 Linux Bridge 中作为网桥的一个端口。

容器的网络模式

用来设置网络接口的 docker run --net 命令,它的可用参数有四个:

none:关闭了 container 内的网络连接。容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,配置 IP 等。

bridge:通过 veth 接口来连接其他 container。这是 docker 的默认选项。host:允许 container 使用 host 的网络堆栈信息。容器和宿主机共享 Network namespace。container:使用另外一个 container 的网络堆栈信息。kubernetes 中的 pod 就是多个容器共享一个 Network namespace。

我们需要从中选一个作为我们的网络方案,实际上只有 bridge 和 host 两种模式可选。(想了解这四个参数,请翻到附录B之 Network settings。)

在 docker 默认的网络环境下,单台主机上的容器可以通过 docker0 网桥直接通信,如下图(图作者冯明振)所示:

而不同主机上的容器之间只能通过在主机上做端口映射进行通信。这种端口映射方式对集群应用来说极不方便。(出处8)我们重点要解决这个问题。

先看一下其他学生怎么做这道选择题的:

公司

网络方案

备注

网易(2014)

tinc+quagga+pipework

Pipework 是对 Docker Bridge 的扩展,它由 200 多行 shell 脚本实现。通过使用 ip、brctl、ovs-vsctl 等命令来为 Docker 容器配置自定义的网桥、网卡、路由等。

CoreOS(2014)

flannel

flannel 属于隧道方案,UDP 广播,VxLan。

大众点评网(2015)

Bridge Networking 工作在 level 2 的模式,使公共 IP 得以暴露出来,这部分是做了定制的

汽车之家(2015)

Bridge Networking

去哪儿(2015)

Host Networking

『大吞吐量平台下,bridge 模式性能测试都偏低,于是选择了 host 模式』——20150915,徐磊

芒果TV(2015)

Macvlan

属于路由方案。『从逻辑和 Kernel 层来看隔离性和性能最优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现』——20150505,彭哲夫

新浪微博(2015)

Host Networking

先说一下 host 模式。

容器的网络直接和外部网络打通,解决了不同 slave 物理机之间容器互联互通的问题,减少了 NAT 转换的损耗,但需要自行来维护容器的 IP 地址和端口,否则会冲突,这增加了管理上的复杂度。请考虑这个场景:在同一个 slave 物理机上运行两个 80 端口 Nginx 容器的情况,除非分配两个不同的 IP 地址,这种方案我们之前在 shipyard 方案中使用过。

新浪微博在《大规模Docker集群助力微博迎接春晚峰值挑战》一文中曾经介绍过:

Docker 部署被诟病最多就是网络,平台目前采用的是 host 模式,为什么没有采用 NAT 或者 Bridge 呢?由于涉及的技术细节比较繁冗,这里仅分享一些踩过的坑。例如 NAT 使用 iptables 底层流量转发依靠内核 netfilter 模块,其默认仅保持 65536 个链接,在服务有大量链接的场景下,会出现大量拒绝链接的现象。再如 Bridge 的 MAC 地址默认是选择其子接口中最先的一个,这样就会导致一个宿主机下多个容器启停时出现网络瞬断。还有很多问题不一一列举,平台未来计划采用 vlanif 的方案来解决容器网络部署难题。

再看 bridge 模式,它是 docker 默认的网络模式,为了解决容器间互通问题,通常有两种解决方案:

采用 SDN(软件定义网络) 技术,如 flannel,weave 等,直接将容器内网打通; 采用 NAT(网络地址转换) 技术,直接使用 slave 主机的 IP 地址互通。

我们认为,bridge 模式加 NAT 方式,是当前 mesos+marathon 支持的最好的模式(采用的是 container port,host port,service port 的对应关系)。我们的容器云主要构建于 mesos+marathon 之上,封装了我们的业务逻辑,采用一些方式解决了容器与现存非容器架构之间的互通问题, 如 consul 的服务注册和发现机制,dubbo 的应用注册和发现机制等。

最终我们选择了 Bridge Networking。

Docker网络模型以后如何发展

Libnetwork 是 Docker 官方 2015年初推出的项目,旨在将 Docker 的网络功能从 Docker 核心代码中分离出去,形成一个单独的库。 Libnetwork 以插件的形式为 Docker 提供网络功能,使得用户可以根据自己的需求实现自己的 Driver 来提供不同的网络功能。 Libnetwork 所要实现的网络模型基本是这样的: 用户可以创建一个或多个网络(一个网络就是一个网桥或者一个 VLAN ),一个容器可以加入一个或多个网络。 同一个网络中容器可以通信,不同网络中的容器隔离。 Docker 网络的发展以后就都在这个项目上了。

0x02 容器要固定IP吗?

默认情况下,当 docker 启动时,它会在宿主机器上创建一个名为 docker0 的虚拟网络接口。它会从 RFC 1918 定义的私有地址中随机选择一个主机不用的地址和子网掩码,并将它分配给 docker0。(出处9)所以,容器的 IP 是动态变化的。

于是乎大家一开始接触 Docker 就纷纷提出给容器分配静态 IP 的需求。看一下各大公司容器云技术栈对比,几家历史包袱较重的公司都选择不让上层应用感知到底层是 VM 还是容器,如360/点评/汽车之家,都改了docker 代码,固定了容器 IP。

docker 官方对此需求的态度是,Docker maintainers prefers a more abstract way to separate user intent fromOperational intent. Based on this feedback and various other discussions on a flexible ip address management, we feel that having a pluggable IPAM will help a great deal.

上一章节里提到的 Pipework 可以做到让容器有一个可以直接访问的静态 IP 地址,just like this:

If you’re using named Docker instances, then adding the IP address 10.40.33.21 to a Docker instance bind is as simple as:

pipework br0 bind 10.40.33.21/24

If you want to route out of 10.40.33.1, change it to:

pipework br0 bind 10.40.33.21/24@10.40.33.1

(出处:https://opsbot.com/advanced-docker-networking-pipework/)

这样的话,需要在容器启动后在宿主机上运行 pipework 来设置容器的 ip,这样就增加了自动化的难度。

我们的考虑是,第一,容器应该是无状态的,分配固定 IP 违背了这个理念,第二,Docker 刚出来一两年,还在飞速发展中,现在你改了内核代码,将来它大版本升级,你怎么跟随?第三,使用固定 IP 很大程度上是为了让技术人员能像以前一样直接登录虚拟机操作,但我们的持续集成管理平台里使用 webconsole 也能登到容器里面操作。

我们的实践是:首先,我们内部调用都走内部域名,有专门的 DNS Server,其次,我们很早以前就引入了服务治理框架 Dubbo,基本做到了服务的注册和发现。再次,我们在容器云里引入了 consul 的注册和发现服务,配合 slave 节点上的 registrator 容器,以及 haproxy 和 consul-template组件,实现了完整的容器服务的注册和发现架构。

第一,dubbo 能帮我们解决什么容器问题:

进驻容器云后 java 工程之间的调用:直接将物理机的 ip 和容器 java 工程对外提供的随机端口,注册到 dubbo 里。例如, 容器 javaA 要调用容器 javaB,容器 javaB 已经将它对外提供的 ip 和随机端口注册到了 dubbo 里,容器 javaA 可以从 dubbo 里找到容器 javaB 相关的信息直接调用。

第二,dubbo 不能解决的问题有:

我们的线上还有 php 或者其他开发语言的应用,它怎么调用容器化的 java 工程呢? 容器化的工程如何对外网提供服务 ,如何把它放入 nginx 和 F5中呢?

基于以上两个需求、以及同一个工程的容器也要做负载均衡 ,我们引入了 consul + consul-template + registrator + haproxy,来做服务注册和发现。

实施详细流程如下:

第一步,每一台 slave 节点上都会启动一个 registrator 的容器,该容器检测 docker 引擎的 unix socket 地址:/var/run/docker.sock,从中获得该 slave 上所有容器的启动、停止以及其他运行时相关的信息;

第二步,registrator 容器同时会把它获取的其他容器的信息(IP、端口等)注册到 consul 集群中,服务信息如下面的输出:

curl 172.28.128.3:8500/v1/catalog/service/python-micro-service

[

{

"Node":"host-1",

"Address":"172.28.128.3",

"ServiceID":"registrator:service1:5000",

"ServiceName":"python-micro-service",

"ServiceTags":null,

"ServicePort":49154

}]

第三步,consul-template 组件从 consul 中获得所有容器注册的服务信息,应用相应的规则(如,区分为镜像环境和生产环境)后,将容器提供的服务信息写入 haproxy 中,并 reload haproxy 以生效配置。

第四步,client 端通过 DNS 中注册的域名指向 haproxy 的地址,访问到具体提供服务的容器。

0x03 容器内部如何获取宿主机的IP?

容器启动后,宿主机 IP 会被写入容器的环境变量里。

容器内的程序可以从环境变量里读取。

——未完待续——

附录A:参考资源

1,知乎Docker话题,http://www.zhihu.com/topic/19950993;

2,2015,Docker终极指南(原作者German Jaber);

3,2015,Docker持续部署图文详解;

4,2015,使用Docker搭建Java Web运行环境;

5,2015,dockone上对代码放里面还是外面的讨论;

6,2013,dockerfile最佳实践;

7,2015,集群规模下日志处理和网络方案;

8,2015,Docker网络详解及Libnetwork前瞻;

9,docker官网讲网络配置,中文译稿;

附录B:术语简单介绍

Registry/Repository/Image/Tag:

Registry 存储镜像数据,并且提供拉取和上传镜像的功能。Registry 中镜像是通过 Repository 来组织的,而每个 Repository 又包含了若干个 Image。

Registry 包含一个或多个 Repository Repository 包含一个或多个 Image Image 用 GUID 表示,有一个或多个 Tag 与之关联

比如,你在本地机器上运行 docker image 命令,可能会得到这样的输出结果:

我们常说的“Ubuntu”镜像其实不是一个镜像名称,而是代表了一个名为 ubuntu 的 Repository,同时在这个 Repository 下面有一系列打了 tag 的 Image,Image 的标记是一个 GUID,为了方便也可以通过 Repository:tag 来引用。

——《玩转Docker镜像,2014,孙宏亮》

Network settings:

docker run --net 的四个参数进一步解释如下:

None:

将网络模式设置为 none 时,这个 container 将不允许访问任何外部 router。这个 container 内部只会有一个 loopback 接口,而且不存在任何可以访问外部网络的 router。

Bridge:

默认为 bridge 模式。此时在 host 上面将存在一个 docker0 的网络接口,同时会针对 container 创建一对 veth 接口。其中一个 veth 接口是在 host 充当网卡桥接作用,另一个 veth 接口存在于 container 的命名空间中,并且指向 container 的 loopback。docker 会自动给这个 container 分配一个 IP,并且将 container 内的数据通过桥接转发到外部。

如下图(图作者冯明振)所示:

容器 eth0 网卡从 docker0 网桥所在的 IP 网段中选取一个未使用的 IP,容器的 IP 在容器重启的时候会改变。docker0 的 IP 为所有容器的默认网关。容器与外界通信为 NAT。

Host:

此时,这个 container 将完全共享 host 的网络堆栈。host 所有的网络接口将完全对 container 开放。container 的主机名也会存在于 host 的 hostname 中。这时,container 所有对外暴露的 port 和对其它 container 的 link,将完全失效。

Container:

此时,这个 container 将完全复用另一个 container 的网络堆栈。

附录C:

目前,我们容器管理集群的技术栈包括以下内容:

mesos(资源调度)marathon(服务编排)chronos(分布式计划任务)docker(容器引擎)consul+registrator(服务注册和发现)haproxy(负载均衡)prometheus(服务监控)nagios/zabbix(节点监控)salt(节点配置管理)cobbler(节点自动化装机)ELK(日志收集分析)窝窝持续集成管理平台在这些技术的基础上,实现了我们的集群管理、容器管理、应用管理等业务流程。

欢迎订阅我的微信订阅号『老兵笔记』,请扫描二维码关注:

-EOF-

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有