源码先锋

源码先锋

利用 Docker 在不同宿主机做 CentOS 系统容器 | 原力计划

admin 186 10

作者|于先森2017

责编|伍杏玲

出品|CSDN博客

最近公司新接到一个项目,惯例是通过技术架构、业务需求、用户量还有以往的经验大概评估出一份资源配置表格提供给客户,让客户参考采购的服务器资源。但这次客户根本没有根据我们提供的参考表格来,而是直接就提供给我们一些高配置的服务器实例,实例数与我们预期的少了很多,但配置相对的提高了很多,本着客户是上帝的原则,我们只能自己针对服务器做虚拟化。


我为什么选择用Docker虚拟化服务器?

之前一直是在Windows系统上做虚拟机,在Linux系统上虚拟化服务器还是第一次,更何况这个Linux系统是没有图形界面的。在虚拟化服务器之前我也查询资料做过很多技术比较,最终选择使用Docker来虚拟化服务器,具体总结优势无非以下几点:

1、Docker创建的容器启动速度快,秒级启动。

Docker管理容器操作(start、stop、rm、restart等等)都是以秒或毫秒为单位的。

2、Docker可以基于创建的镜像进行弹性扩展。

创建容器并且根据自己的需求配置好容器后提交镜像到仓库,等到需要扩展容器的时候可拉取镜像启动相同的容器。

3、Docker创建的容器较轻量级

我可以在一台服务器上启动很多容器,如果只是用到某个服务的话,你无需虚拟整套系统版本。当然本文目的是虚拟出一整套系统的运行环境,所以就另当别论了。

4、Docker开源免费

开源的,免费的,低成本的,这就不用我多说了。


Docker的安装

Docker的安装这个其实我不必多说什么,网上一搜一大堆。但是有几点我需要说明下:

1、Docker存储数据位置及镜像存储位置

默认情况下Docker是将数据存储在/var/lib/docker路径下的,如果你系统盘的磁盘空间比较小,那你就需要修改Docker的数据存储路径了,可通过如下命令查看:

sudodockerinfo|grep"DockerRootDir"

修改方法就是先停掉Docker服务,然后在/etc/docker/路径下创建一个文件,在文件里加入如下文本:

{

"graph":"/home/docker"

}

重启Docker,再次查看Docker存储路径是否已经修改,如果不成功请自行百度查找,修改方法不止这一种。

2、拉取私有仓库镜像

这个私有仓库不是Docker收费版的那个,而是针对自己公司搭建的私有仓库。当你想拉取私有仓库镜像的时候,你需要配置私有仓库的IP和端口号,目的是让Docker信任你的私有仓库。具体步骤还是先关闭Docker服务,然后修改文件,如下:

{

"graph":"/home/docker",

"insecure-registries":["192.168.10.123:5000"]

}

重启Docker,此时你就可以拉取你私有仓库的镜像了。


Docker容器在不同宿主机间通信

在说这个之前我先大概说下Docker网络配置,Docker安装后会自动创建3种网络:bridge、host、none,这三种网络模式的详细讲解我就不说了,因为太占篇幅,我就大概讲下我的理解吧。如下:

1、bridge模式

我理解就是Docker守护进程启动时会在宿主机上创建一个docker0虚拟网桥,这个网桥的作用就相当于一个交互机,该宿主机上的所有容器都是通过这个虚拟网桥连接外部网络的,docker0虚拟网桥的IP就相当于该宿主机上所有容器的默认网关。

当创建一个新容器时Docker会在宿主机上创建一对虚拟网卡vethpair设备,并且将vethpair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在宿主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。

该模式是Docker创建容器的默认模式,如果想让外部网络访问到容器中的服务,就是需针对端口做映射,归根究底它实际是在iptables做了DNAT规则,实现端口转发功能。本文也是使用的这个模式。

根据我使用这么长时间的经验来看,这种模式的缺点就是需要事先规划好容器哪些端口该做映射。网上也有教在容器创建好后给容器增添映射端口,但是有的不靠谱儿,有的则是需要修改Docker生成的配置文件,但是如果像我这种构建的是整套系统运行环境,修改配置后重启可能有些服务就需要重新配置了,比如集群相关的服务。

2、host模式

这种模式其实就是和宿主机共用一套网路环境,它使用的IP就是宿主机的IP,它使用的端口也是宿主机的端口,网络的隔离性不好,我没有使用它的根本原因也正是它的隔离性,因为我所使用的宿主机上是存在两台系统运行环境的,或多或少的会出现端口冲突问题。

3、none模式

这种模式下的容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。也就是说它没有办法联网,我至今还没有用过,可能这样更安全吧。

以上就是我对Docker安装后创建的三种网络模式的理解,还有两种模式(container模式和user-defined模式)可以自行查找了解。

3.1、不同宿主机间容器通信原理图


上图为不同宿主机间容器通信的的原理图,说实话这张图在网上都被用烂了,但是没得办法,谁让咱确实是按照这么做的呢,对于上图的讲解我也是直接照搬网上查到的,如下:

1)数据从源容器中发出后,经由所在主机的docker0虚拟网卡转发到flannel0虚拟网卡,这是个P2P的虚拟网卡,flanneld服务监听在网卡的另外一端。

2)Flannel通过Etcd服务维护了一张节点间的路由表,在稍后的配置部分我们会介绍其中的内容。

3)源主机的flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的flanneld服务,数据到达以后被解包,然后直接进入目的节点的flannel0虚拟网卡,

然后被转发到目的主机的docker0虚拟网卡,最后就像本机容器通信一下的有docker0路由到达目标容器。

这样整个数据包的传递就完成了,这里需要解释三个问题:

1)UDP封装是怎么回事?

在UDP的数据内容部分其实是另一个ICMP(也就是ping命令)的数据包。原始数据是在起始节点的Flannel服务上进行UDP封装的,投递到目的节点后就被另一端的Flannel服务

还原成了原始的数据包,两边的Docker服务都感觉不到这个过程的存在。

2)为什么每个节点上的Docker会使用不同的IP地址段?

这个事情看起来很诡异,但真相十分简单。其实只是单纯的因为Flannel通过Etcd分配了每个节点可用的IP地址段后,偷偷的修改了Docker的启动参数。

在运行了Flannel服务的节点上可以查看到Docker服务进程运行参数(psaux|grepdocker|grep“bip”),例如“–bip=182.48.56.1/24”这个参数,它限制了所在节点容器获得的IP范围。这个IP范围是由Flannel自动分配的,由Flannel通过保存在Etcd服务中的记录确保它们不会重复。

3)为什么在发送节点上的数据会从docker0路由到flannel0虚拟网卡,在目的节点会从flannel0路由到docker0虚拟网卡?

例如现在有一个数据包要从IP为172.17.18.2的容器发到IP为172.17.46.2的容器。根据数据发送节点的路由表,它只与172.17.0.0/16匹配这条记录匹配,因此数据从docker0出来以后就被投递到了flannel0。同理在目标节点,由于投递的地址是一个容器,因此目的地址一定会落在docker0对于的172.17.46.0/24这个记录上,自然的被投递到了docker0网卡。

3.2、不同宿主机间容器通信安装部署

虽然安装部署方法也是在网上找的,但是网上给出的方法大方向是没问题的就是一些细节讲的还不是很清楚,导致我部署的时候还是出现很多问题。下面我会将我安装部署的过程和遇到的问题整理到本文中。

3.2.1、宿主机环境准备

我准备了四台宿主机,如下:


四台宿主机都需要设置hosts:

[root@master~]vim/etc/etcd/
数据存放路径
ETCD_LISTEN_PEER_URLS="http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS=""ETCD_MAX_SNAPSHOTS="5"
部署节点的名称
ETCD_HEARTBEAT_INTERVAL="100"
ETCD_QUOTA_BACKEND_BYTES="0"
ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
[Clustering]
通知客户端地址

[root@master~]netstat-tnlp|grep-E"4001|2380"

:23800.0.0.0:*LISTEN22733/etcd

tcp600:::4001:::*LISTEN22733/etcd

[root@master~]etcdctl-Chttp://etcd:4001cluster-health

member8e9e05c52164694dishealthy:gothealthyresultfromhttp://etcd:2379

clusterishealthy

[root@master~]

5、在etcd中配置flannel需要用到的键值

[root@master~]vim/etc/sysconfig/flanneld

FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"
这个参数的值需要是etcd保存的key值,不然flannel启动不了
FLANNEL_OPTIONS=""

flanneld配置文件中的FLANNEL_ETCD_PREFIX参数与上文中保存在etcd中的一个键值是相对应的,但要注意FLANNEL_ETCD_PREFIX参数的值没有后边的/config。

3、启动flanneld服务

[root@master~]

4、查看flanneld服务是否启动成功

[root@master~]ifconfigflannel0
flannel0:flags=4305UP,POINTOPOINT,RUNNING,NOARP,MULTICASTmtu1472

inet6fe80::244d:d95c:a79f:af2dprefixlen64scopeid0x20link
unspec00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00txqueuelen500(UNSPEC)
RXpackets2691026bytes142959067(136.3MiB)
RXerrors0dropped0overruns0frame0
TXpackets2690704bytes152477868(145.4MiB)
TXerrors0dropped0overruns0carrier0collisions0

此时可看到flannel生成的flannel0网卡的IP是在etcd保存的网段内的,说明flannel网络配置完成。

3.2.4、配置docker0虚拟网桥

安装启动flanneld后重启Docker服务,查看Docker服务生成的docker0网桥IP是否已经位于flanneld生成flannel0网卡的网段之中,比如flannel0网卡的IP是:172.18.92.0,docker0的IP是:172.18.92.1,则配置成功。如果IP地址的前三段有一段不同,则说明需要重新对docker0虚拟网桥进行配置,配置方法如下:

1、停掉Docker服务,修改配置文件

[root@master~]vim/usr/lib/systemd/system/
ExecStart=/usr/bin/dockerd-Hfd://--containerd=/run/containerd/=172.18.92.1/24

如上就是需要在文件中的ExecStart参数后添加–bip=172.18.92.1/24,bip的值请查看/run/flannel/文件的FLANNEL_SUBNET值,这两个需要保持一致。

2、重启Docker

[root@master~]systemctlrestartdocker

3、docker0是否配置成功

[root@master~]ifconfigdocker0
docker0:flags=4163UP,BROADCAST,RUNNING,MULTICASTmtu1500

inet6fe80::42:cff:fe75:d72prefixlen64scopeid0x20link
ether02:42:0c:75:0d:72txqueuelen0(Ethernet)
RXpackets4010425bytes230843638(220.1MiB)
RXerrors0dropped0overruns0frame0
TXpackets3057671bytes995135672(949.0MiB)
TXerrors0dropped0overruns0carrier0collisions0

如上docker0处于flannel0的网段内,说明配置已经成功。

3.2.5、验证宿主机间容器是否通信

如果以上步骤都已配置成功,此时就需要验证不通宿主机间容器是否通信了,验证方法就是在每个宿主机创建个容器,然后在容器中ping其他宿主机中容器的Ip,如果能够ping通,则说明已经完成。如果Ping不通也不要惊慌,因为可能是底层的iptables造成的,所以解决办法是在各宿主机上执行下面操作:

[root@master~]iptables-PFORWARDACCEPT
[root@master~]iptables-L-n

以上只完成后再次测试容器间是否能够相互ping通,还是不可以的话就需要排查是否那个环节疏忽出现问题了。docker通过Flannel可以实现各容器间的相互通信,即宿主机和容器,容器和容器之间都能相互通信。


制作CentOS系统版本容器

1、拉取centos:7.6.1810系统版本的镜像

[root@master~]dockerrun-itd--namepre-centos--privileged=true-p10022:22centos:7.6.1810init

我对该命令中的参数具体讲解下:

-i:以交互模式运行容器,通常与-t同时使用。

-t:为容器重新分配一个伪输入终端,通常与-i同时使用。

-d:后台运行容器,并返回容器ID,如果不加这个参数,当退出容器时,这个容器也就停止了。

–privileged:默认是false,我们这里改成了true,使用该参数容器中的root拥有真正的root权限,否则容器的root用户只是宿主机的一个普通用户权限,有些命令如:systemctl、service是使用不了的。

-p:就是映射端口的作用

还有一个问题需要注意,就是该命令后的init,加上它赋值给容器真正的root权限才会生效,如果使用/bin/bash是不会生效的。

3、进入创建好的容器

[root@master~]yum-yinstallopenssh-server
[root@1fc31e49daxc~]vi/etc/ssh/sshd_config
/usr/sbin/sshd-D

7、设置linux容器的密码

[root@1fc31e49daxc~]exit
[root@master~]:5000/yuliang/pre-centos:1.0
[root@master~]:5000/yuliang/pre-centos:1.0

11、创建新的容器

[root@slave1~]dockerps
[root@slave1~]dockerinspecta38321832cfd

这条命令执行后显示的信息就是该a38321832cfd容器构建时候的全部信息,包括IP、端口映射等等。

14、访问容器

1、如果是在做过容器间通信的宿主机上连接访问可通过以下命令:

[root@master~]ssh-p10022root@192.168.10.2

3、如果是使用外部工具访问容器,需要用到也是宿主机的10022端口和宿主机的IP。

上文参考:

总结

以上关于如何做不同宿主机间容器通信和使用Docker创建虚拟机服务器我已经讲解的很清楚了,文中有些我是在网上找来的也添加了出处,在网上找来的内容我也有实际认认真真的研究过并且加以改进我才敢在我们的预生产环境使用。因为现在还没到真正的测试实验阶段,所以我不敢打包票说这些内容一定没有问题。

后续我会将遇到的问题整理进这篇文章的,如果我没有添加则说明确实没有问题了。看到这篇文章的人发现文中有问题可随时给我留言。最后说一句话,有些事情看着很容易,实际做起来你会发现也很容易,但得需要你去做啊。

版权声明:本文为CSDN博主「于先森2017」的原创文章,遵循版权协议,转载请附上原文出处链接及本声明。

☞比TensorFlowLite快15.6倍!业界首个移动GPUBNN加速引擎PhoneBit开源

☞华为副总裁回应应用删除用户图片;美国拟允许华为参与5G标准建设;发布|极客头条

☞艰难的这年,程序员的未来在哪里?

☞蚂蚁金服高要求的领域建模能力,对研发来说到底指什么?

☞一文看懂主流区块链攻击底层逻辑|博文精选

☞饿了么交易系统5年演化史