基于Docker的持续发布都要解决哪些问题 第一集,docker第一集
基于Docker的持续发布都要解决哪些问题 第一集,docker第一集
郑昀编著,文字资料来自于张帆、白俊华、刘飞宇以及网络资料 创建于2015/10/21 最后更新于2015/10/29 关键词:Docker,容器,持续集成,持续发布,CI,私有云本文档适用人员:广义上的技术人员 提纲:
首先,你要明白容器并不是虚拟机,虽然它可以解决虚拟机能够解决的问题,同时也能够解决虚拟机由于资源要求过高而无法解决的问题,但它真的不是虚拟机。以往我们的开发、配置管理、部署发布、监控报警思路都要跟着变。 其次,一开始注定只有一少部分工程迁移到容器私有云上,既然还有大多数应用服务还在虚拟机或物理机上,那么它们之间如何通讯就成了一个必须解决的问题。 那么,我们在构建基于容器的私有云以及相应的持续发布时,遇到并解决了哪些问题呢?
0x00 集装箱还是卷挂载?
先抛出问题,下面这个选择题你怎么选:- 从货运工人角度考虑,整体才是最经济的。
- 这也导致装卸复杂度增加。
- 代码放到 slave 节点的本地磁盘:那么必须要有一种机制,来确保每台 slave 上代码包版本的一致性,而且对于磁盘空间和网络分发来讲也是一种浪费(考虑一下 100 台 slave,其中可能只有 10 台需要运行这个版本的代码)
- 代码放到分布式共享文件系统(如 ceph):它倒是解决了数据过度冗余以及一致性的问题,但分布式共享文件系统本身成为了『单点』,虽然可以设置多个副本。它的性能和可靠性都必须得到充分保障才行。
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 命令,它的可用参数有四个: 我们需要从中选一个作为我们的网络方案,实际上只有 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 |
Docker 部署被诟病最多就是网络,平台目前采用的是 host 模式,为什么没有采用 NAT 或者 Bridge 呢?由于涉及的技术细节比较繁冗,这里仅分享一些踩过的坑。例如 NAT 使用 iptables 底层流量转发依靠内核 netfilter 模块,其默认仅保持 65536 个链接,在服务有大量链接的场景下,会出现大量拒绝链接的现象。再如 Bridge 的 MAC 地址默认是选择其子接口中最先的一个,这样就会导致一个宿主机下多个容器启停时出现网络瞬断。还有很多问题不一一列举,平台未来计划采用 vlanif 的方案来解决容器网络部署难题。再看 bridge 模式,它是 docker 默认的网络模式,为了解决容器间互通问题,通常有两种解决方案: 我们认为,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 from operational 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:
If you want to route out of 10.40.33.1, change it to:
(出处:https://opsbot.com/advanced-docker-networking-pipework/) |
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。
|
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 的网络堆栈。 |
目前,我们容器管理集群的技术栈包括以下内容:
窝窝持续集成管理平台在这些技术的基础上,实现了我们的集群管理、容器管理、应用管理等业务流程。
欢迎订阅我的微信订阅号『老兵笔记』,请扫描二维码关注: -EOF-
评论暂时关闭