集成Docker和Calico网络

组件介绍

Calico:

Calico是一个纯三层的协议,为OpenStack和Docker容器提供多主机间通信。Calico不使用重叠网络,使用虚拟路由代替虚拟交换,每一台虚拟路由通过BGP协议传播可达信息(路由)到剩余数据中心。

 

etcd:

etcd是一个高可用的键值(key/value)存储系统,主要用于共享配置和服务发现,etcd 会在集群的各个节点中复制这些数据并保证这些数据始终正确。etcd是由CoreOS开发并维护的,灵感来自于 ZooKeeper 和 Doozer,它使用Go语言编写,并通过Raft一致性算法处理日志复制以保证强一致性,有基于HTTP+JSON的API接口。Raft是一个来自Stanford的新的一致性算法,适用于分布式系统的日志复制,Raft通过选举的方式来实现一致性,在Raft中,任何一个节点都可能成为Leader。Google的容器集群管理系统Kubernetes、开源PaaS平台Cloud Foundry和CoreOS的Fleet都广泛使用了etcd。

raft 共识算法的优点在于可以在高效的解决分布式系统中各个节点日志内容一致性问题的同时,也使得集群具备一定的容错能力。即使集群中出现部分节点故障、网络故障等问题,仍可保证其余大多数节点正确的步进。甚至当更多的节点(一般来说超过集群节点总数的一半)出现故障而导致集群不可用时,依然可以保证节点中的数据不会出现错误的结果。

 

关于raft算法,感兴趣的话,可以通过http://thesecretlivesofdata.com/raft/来查看动画演示过程。

环境

Docker版本:1.12.1

Etcd版本:2.2.1

Calico版本:0.22.0

Centos操作系统:7.2

配置主机

在/etc/hosts文件中添加如下主机信息:

192.168.1.23  dockera

192.168.1.24  dockerb

 

安装Docker

因为虚拟机环境无法连接Docker官网,这里采用RPM包离线安装方式。

相关包下载地址:

https://yum.dockerproject.org/repo/main/centos/7/Packages/docker-engine-1.12.1-1.el7.centos.x86_64.rpm

 

https://yum.dockerproject.org/repo/main/centos/7/Packages/docker-engine-selinux-1.12.1-1.el7.centos.noarch.rpm

 

将下载的包放到一个指定的路径中,然后执行如下命令安装Docker:

yum localinstall -y docker-engine*

 

设置自启动

systemctl enable docker.service

 

启动Docker

systemctl start docker

 

 

安装etcd集群

步骤一:下载etcd

https://github.com/coreos/etcd/releases/download/v2.2.1/etcd-v2.2.1-linux-amd64.tar.gz
 
步骤二:解压缩
tar xzvf etcd-v2.2.1-linux-amd64.tar.gz
 

步骤三:配置

mv etcd-v2.2.1-linux-amd64 /usr/local/

 

在/etc/profile文件中添加如下环境变量:

export PATH=/usr/local/etcd-v2.2.1-linux-amd64:$PATH

source /etc/profile

 

步骤四:启动etcd集群(具体参数的含义见“etcd集群扩容”章节)

192.168.1.23节点:

nohup etcd --name node1--initial-advertise-peer-urls http://192.168.1.23:2380   \

--listen-peer-urls http://0.0.0.0:2380 --listen-client-urlshttp://0.0.0.0:2379,http://0.0.0.0:4001 \

--advertise-client-urlshttp://0.0.0.0:2379  --initial-cluster-token etcd-cluster  \

--initial-cluster node1=http://192.168.1.23:2380,node2=http://192.168.1.24:2380   --initial-cluster-state new &> etcd.log&

 

192.168.1.24节点:

nohup etcd --name node2--initial-advertise-peer-urls http://192.168.1.24:2380   \

--listen-peer-urls http://0.0.0.0:2380--listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \

--advertise-client-urlshttp://0.0.0.0:2379   --initial-cluster-tokenetcd-cluster   \

--initial-cluster node1=http://192.168.1.23:2380,node2=http://192.168.1.24:2380   --initial-cluster-state new &>etcd.log &

 

注:为了方便etcd启动操作,可以将上面的内容封装为一个shell脚本。

 

步骤五:查看etcd集群状态

etcdctl -C http://192.168.1.23:2379,http://192.168.1.24:2379member list

输出结果为:

8b28023d2233a213:name=node1 peerURLs=http://192.168.1.23:2380 clientURLs=http://0.0.0.0:2379

d8251b9c0a2a054c:name=node2 peerURLs=http://192.168.1.24:2380 clientURLs=http://0.0.0.0:2379

 

当然也可以查看etcd集群的memebers:

curl -L http://192.168.1.23:2379/v2/members

 

因为etcd 是一个应用在分布式环境下的 key/value 存储服务,所以我们可以写一些数据,如下:

curl -L http://192.168.1.23:2379/v2/keys/newworld-XPUT -d value="Hello Docker"

输出结果为:

{"action":"set","node":{"key":"/newworld","value":"HelloDocker","modifiedIndex":2869,"createdIndex":2869}}

 

然后我们通过192.168.1.24节点查询键为newworld的:

curl -L http://192.168.1.24:2379/v2/keys/newworld

 

结果为:

{"action":"get","node":{"key":"/newworld","value":"HelloDocker","modifiedIndex":2869,"createdIndex":2869}}

 

我们也可以通过使用etcdctl工具进行操作:

etcdctl set /zy/message "Hello Docker"

 

etcdctl get /zy/message

结果为:

Hello Docker

以Docker方式启动Calico

Docker Daemon需要能够访问etcd集群,需要增加--cluster-store参数。比较好的方式是修改systemd,打开/usr/lib/systemd/system/docker.service文件进行修改。

 

192.168.1.23节点的内容如下:

[Unit]

Description=Docker Application ContainerEngine

Documentation=https://docs.docker.com

After=network.target docker.socket

 

[Service]

Type=notify

EnvironmentFile=/etc/sysconfig/docker

ExecStart=/usr/bin/dockerd $INSECURE_REGISTRY--cluster-store=etcd://192.168.1.23:2379

MountFlags=slave

LimitNOFILE=1048576

LimitNPROC=1048576

LimitCORE=infinity

 

[Install]

WantedBy=multi-user.target

 

192.168.1.24节点:

[Unit]

Description=Docker Application ContainerEngine

Documentation=https://docs.docker.com

After=network.target docker.socket

 

[Service]

Type=notify

EnvironmentFile=/etc/sysconfig/docker

#ExecStart=/usr/bin/dockerd$INSECURE_REGISTRY

ExecStart=/usr/bin/dockerd$INSECURE_REGISTRY --cluster-store=etcd://192.168.1.24:2379

MountFlags=slave

LimitNOFILE=1048576

LimitNPROC=1048576

LimitCORE=infinity

 

[Install]

WantedBy=multi-user.target

 

修改完之后,重启Docker:

systemctl daemon-reload
systemctl restart docker

 

 

安装Calico和配置Calico网络

步骤一:下载calicoctl并配置

下载calicoctl,下载地址为:

http://www.projectcalico.org/builds/calicoctl

 

将下载的calicoctl文件放到/usr/bin/calicoctl,并增加可执行权限:

chmod +x /usr/bin/calicoctl  

 

步骤二:拉取Calico相关镜像

这样演示一下对于无法联网的节点如何使用Docker Hub上的镜像:

1)      首先使用可以联网的节点pull镜像并导出镜像

从Docker Hub上拉取镜像:

docker pullcalico/node

docker pull calico/node-libnetwork

 

导出镜像到本地:

docker save -o calico-node-libnetwork.tar.gzcalico/node-libnetwork

docker save -o calico-node.tar.gz calico/node

 

 

2)      将保存的镜像文件拷贝到需要使用镜像的节点并导入

docker load -i calico-node-libnetwork.tar.gz

docker load -i calico-node.tar.gz

 

步骤三:启动Calico服务

在Docker环境中Calico服务是做为容器来运行的,使用host的网络配置。所有容器配置使用Calico服务,做为calico节点互相通信。

 

在每个节点上执行:

192.168.1.23节点:

calicoctl node--ip=192.168.1.23

 

192.168.1.24节点:

calicoctl node--ip=192.168.1.24

 

我们选其中一个节点查看时容器时,可以看到新建了一个calico-node容器。

 

在启动别的容器之前,我们需要在启动别的容器之前,我们需要配置一个IP地址池带有ipip和nat-outgoing选项,在每个节点执行:

calicoctl pooladd 10.20.10.0/24 --ipip --nat-outgoing

 

 

 

步骤四:容器网络配置

         首先,我们先启动几个容器:

192.168.1.23节点:

docker run -itd--net=none --name=centos-1 centos:7.2

docker run -itd--net=none --name=centos-2 centos:7.2

 

192.168.1.24节点:

docker run -itd--net=none --name=centos-3 centos:7.2

 

现在所有容器都运行了,但没有任何网络设备,用Calico来分配网络设备给这些容器,分配给容器的IP应该在IP地址池范围内。

192.168.1.23节点:

calicoctlcontainer add centos-1 10.20.10.1

calicoctl containeradd centos-2 10.20.10.2

 

192.168.1.24节点:

calicoctl containeradd centos-3 10.20.10.3

 

一旦容器有Calico网络了,他们能获取到对应IP的网络设备,至此他们还不能互相访问或访问互联网,因为没有创建并分配配置文件给容器。

 

         在任意一个节点上创建一些配置文件:

         calicoctlprofile add myprofile1

         calicoctlprofile add myprofile2

         分配配置文件给容器,在相同配置文件中的容器可以互相访问:

         192.168.1.23节点:

calicoctlcontainer centos-1 profile append myprofile1

         calicoctlcontainer centos-2 profile append myprofile2

        

         192.168.1.24节点:

         calicoctlcontainer centos-3 profile append myprofile1

        

         至此所有配置都完成了,稍后测试一下这些容器之间的网络连接。

 

步骤五:验证

         我们先验证跨节点的容器之间通信:

         192.168.1.23节点:

         docker execcentos-1 ping -c2 10.20.10.3

         结果为:

         PING10.20.10.3 (10.20.10.3) 56(84) bytes of data.

64 bytes from10.20.10.3: icmp_seq=1 ttl=62 time=0.728 ms

64 bytes from10.20.10.3: icmp_seq=2 ttl=62 time=0.437 ms

……

之所以能够ping通,是因为centos-1和centos-3位于同一个profile(myprofile1)。

 

然后我们再测试一下同一个节点的容器之间通信:

192.168.1.23节点:

docker execcentos-1 ping -c2 10.20.10.2

结果是无法ping通的,同一个节点的容器位于不同的profile,起到隔离的作用。

 

 

集成Calico到Docker网络

Calico能够被集成到Docker网络中。在Docker1.9版后,Calico运行另一个容器(calico/node-libnetwork)作为Docker网络插件,并集成到Docker docker network 命令中。

 

在Calico的每个节点使用带 --libnetwork参数运行Calico,如下:

192.168.1.23节点:

HOSTNAME=dockera calicoctl node --libnetwork--ip=192.168.1.23

 

192.168.1.24节点:

HOSTNAME=dockerb calicoctl node --libnetwork--ip=192.168.1.24

 

         然后我们查看一下启动的容器:

[root@dockera~]# docker ps

CONTAINER ID  IMAGE   COMMAND CREATED STATUS PORTS           NAMES

fe01bdf1d6a4  calico/node-libnetwork:latest   "./start.sh"             About a minute ago   Up About a minute                            calico-libnetwork

e5568ce5b870 calico/node:latest             "/sbin/start_runit"     About a minute ago   Up About aminute                           calico-node

 

可以看到比上面多启动了一个node-libnetwork的容器。

        

         使用 dockernetwork 命令创建Calico网络:

calicoctl pooladd 192.168.0.0/16 --ipip --nat-outgoing

         dockernetwork create --driver calico --subnet=192.168.0.0/24 mynet

        

        

         执行如下命令查看网络:

         dockernetwork  ls

         结果为:

         NETWORKID          NAME                DRIVER              SCOPE

dad28eee665d        bridge              bridge              local              

68a64e8083e6        mynet              calico              global             

25447694d835        host                host                local              

cc6658447ef0        none                null                local

下面我们使用mynet网络在不同节点创建容器:

192.168.1.23节点:

docker run -itd--net=mynet --ip 192.168.0.10 --name=centos-1 centos:7.2

docker run -itd--net=mynet --ip 192.168.0.11 --name=centos-2 centos:7.2

 

192.168.1.24节点:

docker run -itd--net=mynet --ip 192.168.0.12 --name=centos-3 centos:7.2

etcd集群扩容

         我们先将etcd相关的主要参数描述一下:

--data-dir 指定节点的数据存储目录,这些数据包括节点ID,集群ID,集群初始化配置,Snapshot文件,若未指定--wal-dir,还会存储WAL文件

 

--wal-dir  指定节点的was文件的存储目录,若指定了该参数,wal文件会和其他数据文件分开存储。

--name                   节点名称

--initial-advertise-peer-urls  告知集群其他节点url.

--listen-peer-urls       监听URL,用于与其他节点通讯

--advertise-client-urls   告知客户端url, 也就是服务的url

--initial-cluster-token     集群的ID

--initial-cluster         集群中所有节点

        

         注:具体详细内容,可以执行etcd--help查看。

        

         下面正式介绍etcd集群的扩容详细过程。

         步骤一:通过 etcdctl 或对应的 API 注册新节点

我们想将新192.168.1.25加入到etcd集群中,etcd的节点名为node3,peer-urls为192.168.1.25:2380,则在已有的etcd集群任意节点执行如下命令:

etcdctl memberadd node3 http://192.168.1.25:2380

输出结果为:

Added membernamed node3 with ID e0d570d7a4cdccef to cluster

 

ETCD_NAME="node3"

ETCD_INITIAL_CLUSTER="node1=http://192.168.1.23:2380,node2=http://192.168.1.24:2380,node3=http://192.168.1.25:2380"

ETCD_INITIAL_CLUSTER_STATE="existing"

 

etcdctl 在注册完新节点后,会返回上面的内容,包含3个环境变量,这三个变量我们会在新节点用到。

 

步骤二:

登录新节点192.168.1.25,执行如下命令:

exportETCD_NAME="node3"

exportETCD_INITIAL_CLUSTER_STATE="existing"

exportETCD_INITIAL_CLUSTER="node1=http://192.168.1.23:2380,node2=http://192.168.1.24:2380,node3=http://192.168.1.25:2380"

然后我们执行etcd,启动该服务并加入etcd集群环境:

cd/usr/local/etcd-v2.2.1-linux-amd64

#我们没有指定etcd数据目录,默认数据位于当前所在目录

nohup etcd--listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001--advertise-client-urls http://0.0.0.0:2379 \

--listen-peer-urlshttp://0.0.0.0:2380 --initial-advertise-peer-urls http://192.168.1.25:2380&> etcd.log &

 

到这里新节点就会运行起来并且加入到已有的集群中了。下面我们验证一下:

执行如下命令:

etcdctl memberlist

 

返回结果为:

8b28023d2233a213: name=node1 peerURLs=http://192.168.1.23:2380clientURLs=http://0.0.0.0:2379

d8251b9c0a2a054c: name=node2 peerURLs=http://192.168.1.24:2380clientURLs=http://0.0.0.0:2379

e0d570d7a4cdccef: name=node3 peerURLs=http://192.168.1.25:2380clientURLs=http://0.0.0.0:2379

 

检查etcd集群的健康状态:

etcdctlcluster-health

 

返回结果为:

member 8b28023d2233a213is healthy: got healthy result from http://0.0.0.0:2379

memberd8251b9c0a2a054c is healthy: got healthy result from http://0.0.0.0:2379

membere0d570d7a4cdccef is healthy: got healthy result from http://0.0.0.0:2379

 

 

etcd数据备份

定期备份etcd的数据是很重要的,便于后面etcd出问题时进行恢复。我们可以写一个脚本并使用cron进行定时调度执行备份etcd数据。

         #!/bin/bash

date_time=`date+%Y%m%d`

etcdctl backup--data-dir /usr/local/etcd-v2.2.1-linux-amd64/node1.etcd --backup-dir/backup_etcd/${date_time}

find /backup_etcd/-ctime +5 -exec rm -r {} \;

         

你可能感兴趣的:(Docker)