| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
fxmo7195
7年前发布

一种在Swarm集群中实现IP保持的方法

   <p>Docker在1.12版本中开始集成Swarmkit,本文研究在Swarmkit管理的集群中实现IP保持的方法。</p>    <h2><strong>Swarmkit简介</strong></h2>    <p>Swarmkit是Docker公司推出的Docker集群管理和容器编排工具,自Docker1.12版本,开始集成到Docker-engine里发布。Swarmkit是从Swarm项目发展而来。作为Docker自身的编排系统,可提供服务编排,集群管理和调度功能。</p>    <h3><strong>Swarmkit中节点分为两类</strong></h3>    <p>1. 工作节点负责通过执行器运行任务。Swarmkit的默认执行器为Docker容器执行器(Docker Container Executor);</p>    <p>2. 管理节点负责接收和响应用户的请求,将集群状态调节成最终状态。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/50c8bad2a4039ebfa9a99aa1d4b0de6a.jpg"></p>    <p>上图给出了Docker中Swarm集群的组织方式,集群中可包含多个manager节点,这些 manager选举一个节点作为leader节点。由leader节点负责整个集群的管理工作。如果该leader节点出现故障,剩余manager节点会重新选举,新的leader节点会接管集群的管理工作,原leader节点在恢复后可重新加入集群,此时身份是普通manager节点。</p>    <p>Swarmkit在服务编排方面可实现服务状态一致性,为服务按指定策略进行升级及重启等。简单来说,在创建服务后,Swarmkit根据服务类型确定task的数目,并生成相应task,定期检查以保证task数目稳定,并按照调度策略将这些任务分派到各个工作节点上。如果有节点不可用,Leader节点会将该节点上的任务迁移到其它可用节点上继续运行,还可以根据用户命令增加或缩减任务的数目。具体使用方法参见官方文档,下图给出了Swarmkit的内部结构示意图。Swarmkit中通过libnetwork实现对网络资源的管理。</p>    <p><img src="https://simg.open-open.com/show/a9755b5ace4c5793ffd55282c1d47253.jpg"></p>    <h2><strong>问题提出</strong></h2>    <p>从运维角度来看,为提高运维效率,希望容器在重启或者迁移之后,可以保持容器IP地址不变。这样运维人员可通过具体的静态IP地址来对容器进行维护,升级等操作。</p>    <p>现在的实际情况是,在Docker.10之后的版本中,创建容器时可以通过在命令行使用–ip选项来指定其IP地址。但是目前Swarmkit的实现中,在为某个服务的task分配IP时,并不支持指定IP地址,而是采用随机分配的方式。在任务需要重启或迁移时,并不能保证前后两次任务对应容器所得到的IP地址相同。要提高swarm集群的运维效率,需要一种能保持任务对应容器IP地址的方法。</p>    <h2><strong>实现思路</strong></h2>    <p>通过对Docker文档及代码进行阅读,发现在为每个任务创建容器时,容器名称由三部分组成,详见下方代码( daemon/cluster/executor/container/container.go name() )。</p>    <pre>  return strings.Join([]string{c.task.ServiceAnnotations.Name, fmt.Sprint(c.task.Slot), c.task.ID}, “.”)   </pre>    <p>其中服务名称与Slot的值是确定的,任务的ID由系统自动生成,每一次重启或迁移都会变化。可以通过容器名称的前两部分唯一标识容器所执行的任务,这里将其称为任务标识 (Swarmkit具体实现中对任务的标识与此类似,不过用到的是ServiceID)。</p>    <p>解决方案的主要思路就是将容器的IP地址与任务标识关联起来,在系统中保存任务标识与Swarmkit为该任务分配IP地址之间的映射关系。在任务重启或迁移时,为新生成的容器分配之前保存在映射关系中的IP地址,这样就可以保持一个任务对应的IP地址不变。</p>    <p>另一个需要考虑的问题是在leader节点不可用后,如何在新的leader节点上恢复之前所保存的映射关系。一种方案是将对应关系写入图1中的状态存储,另一种方案是在leader初始化时从task列表中重建对应关系。这里选择的是后一种方案,因为第一种方案还要学习protobuffer的使用及Swarmkit的分布式存储实现代码,实现起来更复杂。</p>    <h2><strong>IP保持的具体实现</strong></h2>    <p>这里主要讲一下为实现IP保持所要修改代码的位置及功能。</p>    <ol>     <li>注释libnetwork中检查指定IP地址合法性语句<br> 在libnetwork代码中注释掉为指定IP的容器进行IP地址合法性检查部分的语句,该语句检查为容器分配的指定IP地址是否可用。原因是容器在停止后,会对其IP地址进行回收,但这种回收并不是实时的。如果新创建的容器在创建时,该IP地址还没有被回收,容器创建会由于资源冲突而失败。实际上拥有该IP地址的老容器已经停止,所以这样做并不会影响服务的正确性。该修改位于getAddress 函数中。</li>     <li>增加保存映射关系的数据结构<br> 映射关系的保持,在networkAllocator 中,将部分网络信息保存在一个名字为network 的局部结构中。为保存映射关系,在该结构中增加一个map,其key为前面提到的可唯一标识一个任务的任务标识,其value值为该任务对应的IP地址。</li>     <li>增加分配IP功能函数<br> 在为一个任务分配IP地址时,首先根据网络名称,查找到保存对应网络信息的数据结构,并在该结构中新增的map里进行查找。如果命中,说明该任务之前已经被分配过IP地址,这次可能是该任务进行重启或迁移,此时直接将已经分配过的IP地址再分配给该任务。如果没有命中,说明该任务是首次执行,这时直接调用libnetwork的接口为其分配一个未用的IP地址。该功能通过修改AllocateTask 函数和增加allocateTaskIP 函数实现。</li>     <li>增加记录已分配IP功能函数<br> 在为一个任务分配了IP地址后,还需要对新增map中的数据进行更新。即将以任务标识为key,以分配的IP地址为value值的映射保存在map中。如果后续需要对任务进行重启或迁移,就可以通过分配函数实现IP保持。该功能通过修改AllocateTask 函数和增加recordTaskIP 函数实现。</li>     <li>修改回收IP功能函数<br> 为实现IP保持,还需要将对回收任务IP地址部分的代码进行修改,以防止对已经分配过的IP地址进行回收。因为IP地址一旦被回收,就有可能被分配给新的任务。这样就无法实现IP保持了。该功能对原有的releaseEndpoints 函数进行了修改。</li>     <li>增加映射关系初始化功能函数<br> 该函数负责Leader改变后映射数据的重建。节点在被选为leader后,将负责集群后续的各项管理工作。为实现IP保持,需要在leader的初始化工作中重建映射关系。该项工作由修改doNetworkInit 函数和增加IpmapsInit 函数实现,该函数遍历保存在一致性存储中的所有task,对每个任务,从其保存的网络信息中读取已分配的IP地址,将这些IP与任务标识的映射关系保存到网络中新增的map中,这样就实现了对映射关系的重建。</li>    </ol>    <h2><strong>编译安装方法(以 Docker1.12.1版本为例)</strong></h2>    <p>(1)从github上克隆Docker项目,并切换到1.12.1版本,或者直接下载Docker1.12.1的源代码。</p>    <p>(2) 完成代码修改。</p>    <p>(3)进入项目目录,输入make shell,会安装对应1.12.1版本的开发环境,并进入开发环境所在容器。</p>    <p>(4)输入hack/make.sh binary会编译生成二进制可执行文件。在bundle/latest目录下。</p>    <p>(5)安装方法,在编译生成二进制文件后,将文件复制到系统的/usr/bin或/usr/local/bin目录下。宿主机系统最好是刚安装完同版本的Docker或未安装Docker,否则可能会出现Docker启动不成功。</p>    <h2><strong>效果测试</strong></h2>    <ol>     <li>在三台VM上安装新编译的Docker程序,三个节点都是manager,这里省略了创建集群和服务的过程</li>    </ol>    <pre>  root@vm-1476374349871:/home/ubuntu# docker service ls    ID            NAME        REPLICAS  IMAGE   COMMAND    7huiwv4vgrs7  helloworld  10/10     alpine  ping www.docker.com    root@vm-1476374349871:/home/ubuntu# docker node ls    ID                           HOSTNAME                                        STATUS  AVAILABILITY  MANAGER STATUS    bn68rlizdmnchk14fd1ft9izx    vm-1473648642890.vm-14736486428901473648642890  Ready   Active        Reachable    bu5cc1nx0aj29q984kkngeftd *  vm-1476374349871                                Ready   Active        Leader    cm1k85xgzxivrazge4qqteotv    vm-1473648611529.vm-14736486115291473648611529  Ready   Active        Reachable    root@vm-1476374349871:/home/ubuntu#  </pre>    <p>2. 将副本数目增加到10,在其中的一台VM上的task如下</p>    <pre>  [root@vm-1473648611529 ~]# docker ps    CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS              PORTS               NAMES    971b6cca77c4        alpine:latest       "ping www.docker.com"   2 minutes ago       Up 2 minutes                            helloworld.2.8hnyq37xrkkvoc1ddzoxxacv5    8773911a47fc        alpine:latest       "ping www.docker.com"   2 minutes ago       Up 2 minutes                            helloworld.3.9egflo60nvh1i96l1y110ejg7    1315a7fb46d1        alpine:latest       "ping www.docker.com"   2 minutes ago       Up 2 minutes                            helloworld.5.e25s0snjn960zu6xlmt3a8cqq    [root@vm-1473648611529 ~]#  </pre>    <p>3. 其中helloworld.3的eth0的IP为10.0.0.3</p>    <pre>  [root@vm-1473648611529 ~]# docker exec -ti 8773911a47fc sh    / # ifconfig    eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:03            inet addr:10.0.0.3  Bcast:0.0.0.0  Mask:255.255.255.0          inet6 addr: fe80::42:aff:fe00:3%32520/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1          RX packets:29 errors:0 dropped:0 overruns:0 frame:0          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:0           RX bytes:2334 (2.2 KiB)  TX bytes:648 (648.0 B)        eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:03            inet addr:172.18.0.3  Bcast:0.0.0.0  Mask:255.255.0.0          inet6 addr: fe80::42:acff:fe12:3%32520/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1          RX packets:214 errors:0 dropped:0 overruns:0 frame:0          TX packets:235 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:0           RX bytes:19918 (19.4 KiB)  TX bytes:22174 (21.6 KiB)        lo        Link encap:Local Loopback            inet addr:127.0.0.1  Mask:255.0.0.0          inet6 addr: ::1%32520/128 Scope:Host          UP LOOPBACK RUNNING  MTU:65536  Metric:1          RX packets:4 errors:0 dropped:0 overruns:0 frame:0          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:1           RX bytes:334 (334.0 B)  TX bytes:334 (334.0 B)        / # exit    [root@vm-1473648611529 ~]#  </pre>    <p>4. 将该节点设为不可用,该VM上的任务会重新分配到另外两台机器上</p>    <pre>  [root@vm-1473648611529 ~]# docker node ls    ID                           HOSTNAME                                        STATUS  AVAILABILITY  MANAGER STATUS    bn68rlizdmnchk14fd1ft9izx    vm-1473648642890.vm-14736486428901473648642890  Ready   Active        Reachable    bu5cc1nx0aj29q984kkngeftd    vm-1476374349871                                Ready   Active        Leader    cm1k85xgzxivrazge4qqteotv *  vm-1473648611529.vm-14736486115291473648611529  Ready   Active        Reachable    [root@vm-1473648611529 ~]# docker node update --availability drain cm1k85xgzxivrazge4qqteotv    cm1k85xgzxivrazge4qqteotv    [root@vm-1473648611529 ~]# docker node ls    ID                           HOSTNAME                                        STATUS  AVAILABILITY  MANAGER STATUS    bn68rlizdmnchk14fd1ft9izx    vm-1473648642890.vm-14736486428901473648642890  Ready   Active        Leader     bu5cc1nx0aj29q984kkngeftd    vm-1476374349871                                Ready   Active        Reachable    cm1k85xgzxivrazge4qqteotv *  vm-1473648611529.vm-14736486115291473648611529  Ready   Drain         Reachable    [root@vm-1473648611529 ~]# docker service ls    ID            NAME        REPLICAS  IMAGE   COMMAND    7huiwv4vgrs7  helloworld  10/10     alpine  ping www.docker.com    [root@vm-1473648611529 ~]#  </pre>    <p>5. 其中helloworld.3分配到了leader节点上(helloworld.3.后面的任务ID是不一样的)</p>    <pre>  [root@vm-1473648642890 ~]# docker ps    CONTAINER ID        IMAGE               COMMAND                 CREATED              STATUS              PORTS               NAMES    7308b277a77d        alpine:latest       "ping www.docker.com"   About a minute ago   Up About a minute                       helloworld.3.95dodap792m1l2d9of2tg6lt0    8b78496370c3        alpine:latest       "ping www.docker.com"   6 minutes ago        Up 6 minutes                            helloworld.6.auphkstyrt0yrrqpile2wjatz    243d15b67aaa        alpine:latest       "ping www.docker.com"   6 minutes ago        Up 6 minutes                            helloworld.8.e9v6zdshztpvik79zt9tooei9    4d84734f60f9        alpine:latest       "ping www.docker.com"   6 minutes ago        Up 6 minutes                            helloworld.10.4rbworz9sa4mvmby6aj2ys8m6    c1a833410e3a        alpine:latest       "ping www.docker.com"   6 minutes ago        Up 6 minutes                            helloworld.7.5y4urb3mnn9395hzzkxp1ffgs    [root@vm-1473648642890 ~]#  </pre>    <p>6. 查看一下它的eth0的IP,还是10.0.0.3</p>    <pre>  [root@vm-1473648642890 ~]# docker exec -ti 7308b277a77d sh    / # ifconfig    eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:03            inet addr:10.0.0.3  Bcast:0.0.0.0  Mask:255.255.255.0          inet6 addr: fe80::42:aff:fe00:3%32684/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1          RX packets:8 errors:0 dropped:0 overruns:0 frame:0          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:0           RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)        eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:06            inet addr:172.18.0.6  Bcast:0.0.0.0  Mask:255.255.0.0          inet6 addr: fe80::42:acff:fe12:6%32684/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1          RX packets:101 errors:0 dropped:0 overruns:0 frame:0          TX packets:125 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:0           RX bytes:9416 (9.1 KiB)  TX bytes:11674 (11.4 KiB)        lo        Link encap:Local Loopback            inet addr:127.0.0.1  Mask:255.0.0.0          inet6 addr: ::1%32684/128 Scope:Host          UP LOOPBACK RUNNING  MTU:65536  Metric:1          RX packets:4 errors:0 dropped:0 overruns:0 frame:0          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:1           RX bytes:334 (334.0 B)  TX bytes:334 (334.0 B)        / # exit    [root@vm-1473648642890 ~]#  </pre>    <p>7. 重新将刚才的VM设为可用,并将leader重启</p>    <pre>  [root@vm-1473648611529 ~]# docker node update --availability active cm1k85xgzxivrazge4qqteotv    cm1k85xgzxivrazge4qqteotv    [root@vm-1473648611529 ~]#    [root@vm-1473648642890 ~]# reboot  </pre>    <p>8. 在其它VM上查看,大约半分钟后,已经选举出新的leader,且task的数目已经恢复到10个</p>    <pre>  [root@vm-1473648611529 ~]# docker node ls    ID                           HOSTNAME                                        STATUS  AVAILABILITY  MANAGER STATUS    bn68rlizdmnchk14fd1ft9izx    vm-1473648642890.vm-14736486428901473648642890  Down    Active        Unreachable    bu5cc1nx0aj29q984kkngeftd    vm-1476374349871                                Ready   Active        Leader    cm1k85xgzxivrazge4qqteotv *  vm-1473648611529.vm-14736486115291473648611529  Ready   Active        Reachable    [root@vm-1473648611529 ~]# docker service ls    ID            NAME        REPLICAS  IMAGE   COMMAND    7huiwv4vgrs7  helloworld  10/10     alpine  ping www.docker.com    [root@vm-1473648611529 ~]#  </pre>    <p>9. 此时原leader节点上的任务已经迁移到重新变为可用的节点上</p>    <pre>  [root@vm-1473648611529 ~]# docker ps    CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS              PORTS               NAMES    1d3a252664d8        alpine:latest       "ping www.docker.com"   23 seconds ago      Up 22 seconds                           helloworld.3.25sfbbqwqggvpdwbst8dgqmza    8ca053e810c1        alpine:latest       "ping www.docker.com"   23 seconds ago      Up 22 seconds                           helloworld.6.3z3dy1w216eu2833sdpxjz7mr    a1744b36a51d        alpine:latest       "ping www.docker.com"   24 seconds ago      Up 23 seconds                           helloworld.10.28ikt9ajopam1lf11c6vm0b91    981ba2a3ffec        alpine:latest       "ping www.docker.com"   24 seconds ago      Up 23 seconds                           helloworld.7.7ce9f4ia66op0pi08h897vsw8    7af8cbd1e07c        alpine:latest       "ping www.docker.com"   30 seconds ago      Up 27 seconds                           helloworld.8.339nbcym1ttyvnytm6ls65zuu    [root@vm-1473648611529 ~]#  </pre>    <p>10. 再查看一个helloworld.3的eth0的IP, 仍然是10.0.0.3</p>    <pre>  [root@vm-1473648611529 ~]# docker exec -ti 1d3a252664d8 sh    / # ifconfig    eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:03            inet addr:10.0.0.3  Bcast:0.0.0.0  Mask:255.255.255.0          inet6 addr: fe80::42:aff:fe00:3%32585/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1          RX packets:26 errors:0 dropped:0 overruns:0 frame:0          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:0           RX bytes:2036 (1.9 KiB)  TX bytes:648 (648.0 B)        eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:06            inet addr:172.18.0.6  Bcast:0.0.0.0  Mask:255.255.0.0          inet6 addr: fe80::42:acff:fe12:6%32585/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1          RX packets:218 errors:0 dropped:0 overruns:0 frame:0          TX packets:224 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:0           RX bytes:20106 (19.6 KiB)  TX bytes:20984 (20.4 KiB)        lo        Link encap:Local Loopback            inet addr:127.0.0.1  Mask:255.0.0.0          inet6 addr: ::1%32585/128 Scope:Host          UP LOOPBACK RUNNING  MTU:65536  Metric:1          RX packets:4 errors:0 dropped:0 overruns:0 frame:0          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:1           RX bytes:334 (334.0 B)  TX bytes:334 (334.0 B)        / # exit    [root@vm-1473648611529 ~]#  </pre>    <p> </p>    <p> </p>    <p>来自:http://dockone.io/article/1861</p>    <p> </p>    
 本文由用户 fxmo7195 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
 转载本站原创文章,请注明出处,并保留原始链接、图片水印。
 本站是一个以用户分享为主的开源技术平台,欢迎各类分享!
 本文地址:https://www.open-open.com/lib/view/open1480558414182.html
Docker