簡單來說,實現docker跨主機容器間通信,常用的第三方網絡方案是Flannel,Weave,Calico:
Flannel會為每個host分配一個subnet,容器從這個subnet中分配ip,這些ip可以在host間路由,容器間無需NAT和port mapping轉發就可以實現跨主機通信。Flannel網絡沒有提供Docker DNS服務, 容器間不能通過hostname訪問。
Weave對於容器來說,它就像是一個巨大的以太網交換機, 所有容器都被接入到這個交換機,同樣容器間無需NAT和port mapping轉發就可以實現跨主機通信。Weave網絡提供了Docker DNS服務, 容器之間可以通過hostname訪問。
Calico是一個純三層的虛擬網絡,它會為每個容器分配一個ip,每個host都是router,把不同host的容器連接起來,從而實現跨主機間容器通信。與vxlan不同的是,calico網絡不對數據包進行額外封裝,不需要NAT和端口映射,擴展性和 性能都很好。Calico網絡提供了Docker DNS服務, 容器之間可以通過hostname訪問。
以上三種網絡方案區別:
1)從網絡模型上來說
-> Flannel網絡有兩種模式:vxlan模式是一種overlay覆蓋網絡,而host-gw模式將主機作為網關,依賴於純三層的ip轉發;
-> Weave網絡是一種overlay覆蓋網絡;
-> Calico網絡也是一種純三層的網絡;
(overlay是基於vxlan的虛擬網絡,可以將二層網絡數據封裝到UDP進行傳輸,在主機間建立vxlan虛擬隧道,實現跨主機容器之間通信)。
2)分布式存儲(Distributed Store)
-> Flannel和Calico都需要分布式健值存儲數據庫(key-values),比如etcd或consul;
-> Weave自己負責在主機間交換網絡配置信息,不需要etcd或consul這些數據庫;
3)IP地址管理(IPAM)
-> Flannel為每個主機自動分配獨立的subnet,用戶只需要指定一個大的IP池。不同subnet之間的路由信息也由Flannel自動生成和配置。
-> Weave默認配置下所有容器使用10.32.0.0/12的subnet,如果此地址空間與現有IP沖突,則可以通過--ipalloc-range分配特定的subnet。
-> Calico通過IP Pool可以為每個主機定制自己的subnet。
4)網絡連通和隔離
-> 不同Flannel網絡中的容器可以直接通信,Flannel沒有提供網絡隔離。與外網通信可以通過bridge網絡。
-> Weave網絡默認配置下所有容器在一個大的subnet中,可以自由通信,如果要實現網絡隔離,需要為容器指定不同的subnet或IP。若要與外網通信,則需要將主機加入到weave網絡,並把主機當作網關。
-> Calico默認配置下只允許同一網絡中的容器之間通信,但通過其強大的Policy能夠實現幾乎任意場景的訪問控制。
之前詳細介紹了Flannel網絡、Weave網絡,下面就說下Calico網絡的相關知識:
一、Calico 基本介紹
Calico是一個純三層的協議,為OpenStack虛機和Docker容器提供多主機間通信。Calico不使用重疊網絡比如flannel和libnetwork重疊網絡驅動,它是一個純三層的方法,使用虛擬路由代替虛擬交換,每一台虛擬路由通過BGP協議傳播可達信息(路由)到剩余數據中心。
二、Calico 結構組成
Calico不使用重疊網絡比如flannel和libnetwork重疊網絡驅動,它是一個純三層的方法,使用虛擬路由代替虛擬交換,每一台虛擬路由通過BGP協議傳播可達信息(路由)到剩余數據中心;Calico在每一個計算節點利用Linux Kernel實現了一個高效的vRouter來負責數據轉發,而每個vRouter通過BGP協議負責把自己上運行的workload的路由信息像整個Calico網絡內傳播——小規模部署可以直接互聯,大規模下可通過指定的BGP route reflector來完成。
結合上面這張圖,我們來過一遍 Calico 的核心組件:
Felix: Calico agent,跑在每台需要運行 workload 的節點上,主要負責配置路由及 ACLs 等信息來確保 endpoint 的連通狀態;
etcd:分布式鍵值存儲,主要負責網絡元數據一致性,確保 Calico 網絡狀態的准確性;
BGPClient(BIRD):主要負責把 Felix 寫入 kernel 的路由信息分發到當前 Calico 網絡,確保 workload 間的通信的有效性;
BGP Route Reflector(BIRD): 大規模部署時使用,摒棄所有節點互聯的 mesh 模式,通過一個或者多個BGP Route Reflector來完成集中式的路由分發;
通過將整個互聯網的可擴展 IP 網絡原則壓縮到數據中心級別,Calico 在每一個計算節點利用Linux kernel實現了一個高效的vRouter來負責數據轉發而每個vRouter通過BGP
協議負責把自己上運行的 workload 的路由信息像整個 Calico 網絡內傳播 - 小規模部署可以直接互聯,大規模下可通過指定的BGP route reflector 來完成。這樣保證最終所有的 workload 之間的數據流量都是通過 IP 包的方式完成互聯的。
三、Calico 工作原理
Calico把每個操作系統的協議棧認為是一個路由器,然后把所有的容器認為是連在這個路由器上的網絡終端,在路由器之間跑標准的路由協議——BGP的協議,然后讓它們自己去學習這個網絡拓撲該如何轉發。所以Calico方案其實是一個純三層的方案,也就是說讓每台機器的協議棧的三層去確保兩個容器,跨主機容器之間的三層連通性。
對於控制平面,它每個節點上會運行兩個主要的程序,一個是Felix,它會監聽ECTD中心的存儲,從它獲取事件,比如說用戶在這台機器上加了一個IP,或者是分配了一個容器等。接着會在這台機器上創建出一個容器,並將其網卡、IP、MAC都設置好,然后在內核的路由表里面寫一條,注明這個IP應該到這張網卡。綠色部分是一個標准的路由程序,它會從內核里面獲取哪一些IP的路由發生了變化,然后通過標准BGP的路由協議擴散到整個其他的宿主機上,讓外界都知道這個IP在這里,你們路由的時候得到這里來。
由於Calico是一種純三層的實現,因此可以避免與二層方案相關的數據包封裝的操作,中間沒有任何的NAT,沒有任何的overlay,所以它的轉發效率可能是所有方案中最高的,因為它的包直接走原生TCP/IP的協議棧,它的隔離也因為這個棧而變得好做。因為TCP/IP的協議棧提供了一整套的防火牆的規則,所以它可以通過IPTABLES的規則達到比較復雜的隔離邏輯。
Calico節點組網可以直接利用數據中心的網絡結構(支持 L2 或者 L3),不需要額外的 NAT,隧道或者 VXLAN overlay network。
如上圖所示,這樣保證這個方案的簡單可控,而且沒有封包解包,節約 CPU 計算資源的同時,提高了整個網絡的性能。此外,Calico 基於 iptables 還提供了豐富而靈活的網絡 policy, 保證通過各個節點上的 ACLs 來提供 workload 的多租戶隔離、安全組以及其他可達性限制等功能。
四、Calico網絡方式(兩種)
1)IPIP
從字面來理解,就是把一個IP數據包又套在一個IP包里,即把 IP 層封裝到 IP 層的一個 tunnel,看起來似乎是浪費,實則不然。它的作用其實基本上就相當於一個基於IP層的網橋!一般來說,普通的網橋是基於mac層的,根本不需 IP,而這個 ipip 則是通過兩端的路由做一個 tunnel,把兩個本來不通的網絡通過點對點連接起來。ipip 的源代碼在內核 net/ipv4/ipip.c 中可以找到。
2)BGP
邊界網關協議(Border Gateway Protocol, BGP)是互聯網上一個核心的去中心化自治路由協議。它通過維護IP路由表或‘前綴’表來實現自治系統(AS)之間的可達性,屬於矢量路由協議。BGP不使用傳統的內部網關協議(IGP)的指標,而使用基於路徑、網絡策略或規則集來決定路由。因此,它更適合被稱為矢量性協議,而不是路由協議。BGP,通俗的講就是講接入到機房的多條線路(如電信、聯通、移動等)融合為一體,實現多線單IP,BGP 機房的優點:服務器只需要設置一個IP地址,最佳訪問路由是由網絡上的骨干路由器根據路由跳數與其它技術指標來確定的,不會占用服務器的任何系統。
五、Calico網絡通信模型
calico是純三層的SDN 實現,它基於BPG 協議和Linux自身的路由轉發機制,不依賴特殊硬件,容器通信也不依賴iptables NAT或Tunnel 等技術。
能夠方便的部署在物理服務器、虛擬機(如 OpenStack)或者容器環境下。同時calico自帶的基於iptables的ACL管理組件非常靈活,能夠滿足比較復雜的安全隔離需求。
在主機網絡拓撲的組織上,calico的理念與weave類似,都是在主機上啟動虛擬機路由器,將每個主機作為路由器使用,組成互聯互通的網絡拓撲。當安裝了calico的主機組成集群后,其拓撲如下圖所示:
每個主機上都部署了calico/node作為虛擬路由器,並且可以通過calico將宿主機組織成任意的拓撲集群。當集群中的容器需要與外界通信時,就可以通過BGP協議將網關物理路由器加入到集群中,使外界可以直接訪問容器IP,而不需要做任何NAT之類的復雜操作。
當容器通過calico進行跨主機通信時,其網絡通信模型如下圖所示:
從上圖可以看出,當容器創建時,calico為容器生成veth pair,一端作為容器網卡加入到容器的網絡命名空間,並設置IP和掩碼,一端直接暴露在宿主機上,
並通過設置路由規則,將容器IP暴露到宿主機的通信路由上。於此同時,calico為每個主機分配了一段子網作為容器可分配的IP范圍,這樣就可以根據子網的
CIDR為每個主機生成比較固定的路由規則。
當容器需要跨主機通信時,主要經過下面的簡單步驟:
- 容器流量通過veth pair到達宿主機的網絡命名空間上。
- 根據容器要訪問的IP所在的子網CIDR和主機上的路由規則,找到下一跳要到達的宿主機IP。
- 流量到達下一跳的宿主機后,根據當前宿主機上的路由規則,直接到達對端容器的veth pair插在宿主機的一端,最終進入容器。
從上面的通信過程來看,跨主機通信時,整個通信路徑完全沒有使用NAT或者UDP封裝,性能上的損耗確實比較低。但正式由於calico的通信機制是完全基於三層的,這種機制也帶來了一些缺陷,例如:
- calico目前只支持TCP、UDP、ICMP、ICMPv6協議,如果使用其他四層協議(例如NetBIOS協議),建議使用weave、原生overlay等其他overlay網絡實現。
- 基於三層實現通信,在二層上沒有任何加密包裝,因此只能在私有的可靠網絡上使用。
- 流量隔離基於iptables實現,並且從etcd中獲取需要生成的隔離規則,有一些性能上的隱患。
六、Docker+Calico 部署記錄
1)環境准備
172.16.60.215 node1 安裝docker+etcd+calicoctl 172.16.60.216 node2 安裝docker+etcd+calicoctl 172.16.60.217 node3 安裝docker+etcd+calicoctl [root@node1 ~]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) 修改三個節點的主機名 (主機名最好和后面ETCD_NAME和calico的NODENAME名稱起一樣的名,否則最后可能會出現容器之間ping不通的現象) [root@node1 ~]# hostnamectl --static set-hostname node1 [root@node1 ~]# echo "node1" > /etc/hostname [root@node2 ~]# hostnamectl --static set-hostname node2 [root@node2 ~]# echo "node2" > /etc/hostname [root@node3 ~]# hostnamectl --static set-hostname node3 [root@node3 ~]# echo "node3" > /etc/hostname 關閉三台主機的防火牆。若開啟iptables防火牆,則需要打開2380端口通信。 [root@node1 ~]# systemctl disable firewalld.service [root@node1 ~]# systemctl stop firewalld.service [root@node1 ~]# iptables -F [root@node1 ~]# firewall-cmd --state not running 在三台機器上都要設置hosts,均執行如下命令: [root@node1 ~]# vim /etc/hosts 172.16.60.215 node1 172.16.60.216 node2 172.16.60.217 node3 三台集機器上的ip轉發功能打開 [root@node1 ~]# echo 1 > /proc/sys/net/ipv4/ip_forward [root@node1 ~]# cat /etc/sysctl.conf ...... net.ipv4.conf.all.rp_filter=1 net.ipv4.ip_forward=1 [root@node1 ~]# sysctl -p
2)安裝docker(三個節點都要安裝)
[root@node1 ~]# yum install -y docker [root@node1 ~]# systemctl start docker [root@node1 ~]# systemctl enable docker 下載nginx容器鏡像(172.16.60.214為私有倉庫Registry服務器地址),也可以直接"docker pull nginx"從docker倉庫中下載。 [root@node1 ~]# vim /etc/sysconfig/docker ....... OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false --insecure-registry=172.16.60.214:5000' [root@node1 ~]# systemctl restart docker [root@node1 ~]# docker pull 172.16.60.214:5000/kevin_nginx [root@node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE 172.16.60.214:5000/kevin_nginx latest 2a67965979c5 6 days ago 436 MB
3)構建etcd集群環境
三個節點都要安裝etcd [root@node1 ~]# yum install etcd -y 配置etcd集群 node1節點配置 [root@node1 ~]# cp /etc/etcd/etcd.conf /etc/etcd/etcd.conf.bak [root@node1 ~]# > /etc/etcd/etcd.conf [root@node1 ~]# cat /etc/etcd/etcd.conf #[Member] ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_NAME="node1" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.60.215:2380" ETCD_ADVERTISE_CLIENT_URLS="http://172.16.60.215:2379" ETCD_INITIAL_CLUSTER="node1=http://172.16.60.215:2380,node2=http://172.16.60.216:2380,node3=http://172.16.60.217:2380" node2節點配置 [root@node2 ~]# > /etc/etcd/etcd.conf [root@node2 ~]# vim /etc/etcd/etcd.conf #[Member] ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_NAME="node2" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.60.216:2380" ETCD_ADVERTISE_CLIENT_URLS="http://172.16.60.216:2379" ETCD_INITIAL_CLUSTER="node1=http://172.16.60.215:2380,node2=http://172.16.60.216:2380,node3=http://172.16.60.217:2380" node3節點配置 [root@node3 ~]# > /etc/etcd/etcd.conf [root@node3 ~]# vim /etc/etcd/etcd.conf #[Member] ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_NAME="node3" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.60.217:2380" ETCD_ADVERTISE_CLIENT_URLS="http://172.16.60.217:2379" ETCD_INITIAL_CLUSTER="node1=http://172.16.60.215:2380,node2=http://172.16.60.216:2380,node3=http://172.16.60.217:2380" 接着修改三個節點的docker啟動文件,使docker支持etcd 在ExecStart區域內添加 (在--seccomp-profile 這一行的下面一行添加) node1節點 [root@node1 ~]# cp /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service.bak [root@node1 ~]# vim /usr/lib/systemd/system/docker.service ........ --cluster-store=etcd://172.16.60.215:2379 \ [root@node1 ~]# systemctl daemon-reload [root@node1 ~]# systemctl restart docker node2節點 [root@node2 ~]# cp /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service.bak [root@node2 ~]# vim /usr/lib/systemd/system/docker.service ........ --cluster-store=etcd://172.16.60.216:2379 \ [root@node2 ~]# systemctl daemon-reload [root@node2 ~]# systemctl restart docker node3節點 [root@node3 ~]# cp /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service.bak [root@node3 ~]# vim /usr/lib/systemd/system/docker.service ........ --cluster-store=etcd://172.16.60.217:2379 \ [root@node3 ~]# systemctl daemon-reload [root@node3 ~]# systemctl restart docker 如上修改並重啟docker服務后, 查看各個節點,發現當前docker支持了etcd (這里以node1節點為例) [root@node1 ~]# ps -ef|grep etcd root 17785 1 0 15:18 ? 00:00:00 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --cluster-store=etcd://172.16.60.215:2379 --selinux-enabled --log-driver=journald --signature-verification=false --insecure-registry=172.16.60.214:5000 --storage-driver overlay2 root 17885 16476 0 15:19 pts/1 00:00:00 grep --color=auto etcd 此時還沒有啟動etcd服務,所以要啟動三個節點的etcd服務 (這里以node1節點為例) [root@node1 ~]# systemctl enable etcd [root@node1 ~]# systemctl start etcd 再次查看,發現多了一個etcd進程 [root@node1 ~]# ps -ef|grep etcd root 17785 1 0 15:18 ? 00:00:00 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --cluster-store=etcd://172.16.60.215:2379 --selinux-enabled --log-driver=journald --signature-verification=false --insecure-registry=172.16.60.214:5000 --storage-driver overlay2 etcd 17905 1 2 15:20 ? 00:00:00 /usr/bin/etcd --name=node1 --data-dir=/var/lib/etcd/default.etcd --listen-client-urls=http://0.0.0.0:2379 root 17918 16476 0 15:20 pts/1 00:00:00 grep --color=auto etcd 查看集群成員(在三個節點機任意一個上面查看都可以,因為做的是集群環境): [root@node1 ~]# etcdctl member list f3393747d893564: name=node3 peerURLs=http://172.16.60.217:2380 clientURLs=http://172.16.60.217:2379 isLeader=true a92e0e07c3a85849: name=node2 peerURLs=http://172.16.60.216:2380 clientURLs=http://172.16.60.216:2379 isLeader=false c918e6150938757a: name=node1 peerURLs=http://172.16.60.215:2380 clientURLs=http://172.16.60.215:2379 isLeader=false [root@node1 ~]# etcdctl cluster-health member f3393747d893564 is healthy: got healthy result from http://172.16.60.217:2379 member a92e0e07c3a85849 is healthy: got healthy result from http://172.16.60.216:2379 member c918e6150938757a is healthy: got healthy result from http://172.16.60.215:2379 cluster is healthy =========================================================================================== 溫馨提示: 如果/etc/etcd/etcd.conf配置錯誤,etcd服務啟動了,然后再次修改后重啟etcd,發現沒有生效! 查看日志命令為"journalctl -xe",發現下面錯誤信息: the server is already initialized as member before, starting as etcd member... ...... simple token is not cryptographically signed 解決辦法: 1) 刪除各個節點的/var/lib/etcd/default.etcd/目錄下的數據,即"rm -rf /var/lib/etcd/default.etcd/*" 2) 檢查/etc/etcd/etcd.conf文件是否配置正確 3) 重新啟動etcd服務,即"systemctl stop etcd && systemctl start etcd" , 這樣新配置就會重新生效了!
4)安裝calico網絡通信環境
三個節點最好都要先下載calico容器鏡像 (其實在首次創建calico容器創建時會自動下載calico容器鏡像,不過要等待一段時間,所以最好是提前下載好) 可以現在一個節點上下載這個鏡像,下載之后導出來,然后再導入到其他兩個節點上 [root@node1 ~]# docker pull quay.io/calico/node:v2.6.10 [root@node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE 172.16.60.214:5000/kevin_nginx latest 2a67965979c5 7 days ago 436 MB quay.io/calico/node v2.6.10 3b2408e59c95 5 months ago 280 MB 安裝calicoctl calico下載地址:https://github.com/projectcalico/calicoctl/releases 這里選擇v1.1.0版本(三台節點機都要安裝) [root@node1 ~]# wget https://github.com/projectcalico/calicoctl/releases/download/v1.1.0/calicoctl [root@node1 ~]# chmod 755 calicoctl [root@node1 ~]# mv calicoctl /usr/local/bin/ [root@node1 ~]# /usr/local/bin/calicoctl --version calicoctl version v1.1.0, build 882dd008 [root@node1 ~]# calicoctl --version calicoctl version v1.1.0, build 882dd008 [root@node1 ~]# calicoctl --help [root@node1 ~]# rsync -e "ssh -p22" -avpgolr calicoctl root@172.16.60.216:/usr/local/bin/ [root@node1 ~]# rsync -e "ssh -p22" -avpgolr calicoctl root@172.16.60.217:/usr/local/bin/ 然后分別在三個節點上創建calico容器 node1節點 [root@node1 ~]# docker run --net=host --privileged --name=calico-node -d --restart=always -e NODENAME=node1 -e CALICO_NETWORKING_BACKEND=bird -e CALICO_LIBNETWORK_ENABLED=true -e IP=172.16.60.215 -e ETCD_ENDPOINTS=http://127.0.0.1:2379 -v /var/log/calico:/var/log/calico -v /var/run/calico:/var/run/calico -v /lib/modules:/lib/modules -v /run:/run -v /run/docker/plugins:/run/docker/plugins -v /var/run/docker.sock:/var/run/docker.sock quay.io/calico/node:v2.6.10 node2節點 [root@node2 ~]# docker run --net=host --privileged --name=calico-node -d --restart=always -e NODENAME=node2 -e CALICO_NETWORKING_BACKEND=bird -e CALICO_LIBNETWORK_ENABLED=true -e IP=172.16.60.216 -e ETCD_ENDPOINTS=http://127.0.0.1:2379 -v /var/log/calico:/var/log/calico -v /var/run/calico:/var/run/calico -v /lib/modules:/lib/modules -v /run:/run -v /run/docker/plugins:/run/docker/plugins -v /var/run/docker.sock:/var/run/docker.sock quay.io/calico/node:v2.6.10 node3節點 [root@node3 ~]# docker run --net=host --privileged --name=calico-node -d --restart=always -e NODENAME=node3 -e CALICO_NETWORKING_BACKEND=bird -e CALICO_LIBNETWORK_ENABLED=true -e IP=172.16.60.217 -e ETCD_ENDPOINTS=http://127.0.0.1:2379 -v /var/log/calico:/var/log/calico -v /var/run/calico:/var/run/calico -v /lib/modules:/lib/modules -v /run:/run -v /run/docker/plugins:/run/docker/plugins -v /var/run/docker.sock:/var/run/docker.sock quay.io/calico/node:v2.6.10 然后查看各個節點的calico容器創建情況 (這里以node1節點為例,其他兩個節點查看一樣 ) [root@node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 24f5c8882a6e quay.io/calico/node:v2.6.10 "start_runit" 2 minutes ago Up 2 minutes calico-node [root@node1 ~]# ps -ef|grep calico root 2327 2325 0 22:53 ? 00:00:00 svlogd /var/log/calico/confd root 2328 2325 0 22:53 ? 00:00:00 confd -confdir=/etc/calico/confd -interval=5 -watch --log-level=info -node=http://127.0.0.1:2379 -client-key= -client-cert= -client-ca-keys= root 2329 2326 0 22:53 ? 00:00:00 svlogd /var/log/calico/libnetwork root 2330 2323 0 22:53 ? 00:00:00 svlogd -tt /var/log/calico/bird root 2331 2324 0 22:53 ? 00:00:00 svlogd -tt /var/log/calico/bird6 root 2333 2324 0 22:53 ? 00:00:00 bird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg root 2339 2322 0 22:53 ? 00:00:00 svlogd /var/log/calico/felix root 2341 2322 1 22:53 ? 00:00:03 calico-felix root 2342 2323 0 22:53 ? 00:00:00 bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg root 2582 1555 0 22:56 pts/0 00:00:00 grep --color=auto calico 接着查看calico狀態 [root@node1 ~]# calicoctl node status Calico process is running. IPv4 BGP status +---------------+-------------------+-------+----------+-------------+ | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +---------------+-------------------+-------+----------+-------------+ | 172.16.60.216 | node-to-node mesh | up | 15:46:49 | Established | | 172.16.60.217 | node-to-node mesh | up | 15:46:50 | Established | +---------------+-------------------+-------+----------+-------------+ IPv6 BGP status No IPv6 peers found. [root@node2 ~]# calicoctl node status Calico process is running. IPv4 BGP status +---------------+-------------------+-------+----------+-------------+ | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +---------------+-------------------+-------+----------+-------------+ | 172.16.60.215 | node-to-node mesh | up | 15:46:50 | Established | | 172.16.60.217 | node-to-node mesh | up | 15:46:54 | Established | +---------------+-------------------+-------+----------+-------------+ IPv6 BGP status No IPv6 peers found. [root@node3 etcd]# calicoctl node status Calico process is running. IPv4 BGP status +---------------+-------------------+-------+----------+-------------+ | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +---------------+-------------------+-------+----------+-------------+ | 172.16.60.215 | node-to-node mesh | up | 15:46:51 | Established | | 172.16.60.216 | node-to-node mesh | up | 15:46:54 | Established | +---------------+-------------------+-------+----------+-------------+ IPv6 BGP status No IPv6 peers found. ============================================= 停止calico服務 # docker stop calico-node
5)添加calico網絡
為各個節點的calico網絡添加可用的ip pool。這里采用ipip模式(即enabled為true) node1節點操作(該節點的容器網段為10.0.10.0/24。注意:子網掩碼是24,故必須是*.*.*.0/24;如果是16位子網掩碼,則是*.*.0.0/16) [root@node1 ~]# vim ipPool.yaml apiVersion: v1 kind: ipPool metadata: cidr: 17.16.10.0/24 spec: ipip: enabled: true nat-outgoing: true disabled: false 創建ip pool [root@node1 ~]# calicoctl create -f ipPool.yaml Successfully created 1 'ipPool' resource(s) [root@node2 ~]# vim ipPool.yaml apiVersion: v1 kind: ipPool metadata: cidr: 192.10.160.0/24 spec: ipip: enabled: true nat-outgoing: true disabled: false 創建ip pool [root@node2 ~]# calicoctl create -f ipPool.yaml Successfully created 1 'ipPool' resource(s) [root@node3 ~]# vim ipPool.yaml apiVersion: v1 kind: ipPool metadata: cidr: 173.20.19.0/24 spec: ipip: enabled: true nat-outgoing: true disabled: false 創建ip pool [root@node3 ~]# calicoctl create -f ipPool.yaml Successfully created 1 'ipPool' resource(s) ============================================= 溫馨提示: 如果是刪除一個ip pool,命令是"calicoctl delete -f ipPool.yaml" ============================================= 在任意一個節點上查看添加的ip pool情況 [root@node1 ~]# calicoctl get ipPool CIDR 17.16.10.0/24 173.20.19.0/24 192.10.160.0/24 fd80:24e2:f998:72d6::/64 [root@node1 ~]# calicoctl get ipPool -o wide CIDR NAT IPIP 17.16.10.0/24 true true 173.20.19.0/24 true true 192.10.160.0/24 true true fd80:24e2:f998:72d6::/64 false false 接着在上面創建的ip pool(10.0.10.1/24 、172.168.50.1/24、192.168.10.1/24 )里創建子網絡。 可以從三個中選擇一個或兩個或全部去創建子網絡。 如下創建了calico-net1,calico-net2和calico-net3三個不同的網絡。 創建命令可以在任意一個節點上執行即可。 由於三個節點使用的是同一套etcd,所以子網絡創建后,在其他兩個節點上都可以通過docker network ls命令查看到生成的網絡信息: [root@node1 ~]# docker network create --driver calico --ipam-driver calico-ipam --subnet 17.16.10.0/24 calico-net1 c031586cd4ee5d7008a4c1152cfb12b937a8f166b0c30febef8f9021b4f868ae [root@node1 ~]# docker network create --driver calico --ipam-driver calico-ipam --subnet 173.20.19.0/24 calico-net2 5b8903c49cc965aabc380cd4a034552f0e0c3494a5e7ab8e7d0a17baadc1047d [root@node1 ~]# docker network create --driver calico --ipam-driver calico-ipam --subnet 192.10.160.0/24 calico-net3 cd2a0ff8bc56261fb54cac566859c75fec87e87c99fa8c69b728b111f0138e05 參數解釋: --driver calico: 網絡使用 calico 驅動 --ipam-driver calico-ipam: 指定使用 calico 的 IPAM 驅動管理 IP --subnet:指定calico-net1、calico-net2、calico-net3的 IP 段 calico-net1、calico-net2、calico-net3是 global 網絡,etcd 會將它們三個同步到所有主機 在其他節點上查看docker網絡 [root@node3 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 63547f626d3c bridge bridge local c031586cd4ee calico-net1 calico global 5b8903c49cc9 calico-net2 calico global cd2a0ff8bc56 calico-net3 calico global a85c2efa2a9a host host local 60ee2962e292 none null local ====================================================== 溫馨提示:如要想要刪除docker網絡 [root@node2 ~]# docker network --help 刪除的前提是,使用這些網絡的docker容器必須刪除,也就是說這些網絡在沒有被使用的前提下才能被成功刪除! [root@node2 ~]# docker network rm calico-net1 calico-net1 [root@node2 ~]# docker network rm calico-net2 calico-net2 [root@node2 ~]# docker network rm calico-net3 calico-net3 [root@node1 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE a6a15884908d bridge bridge local 3021c55e600f host host local 6d3a0a8472c1 none null local ====================================================== 最后在各個節點上使用上面創建的三個子網去創建容器. [root@node1 ~]# docker run -itd --net calico-net1 --name=docker-test1 172.16.60.214:5000/kevin_nginx 99a9b16b0fc0b162f177d8e6f5964f09f2a8a7a8621ed2391479ee7e45ae1105 [root@node1 ~]# docker run -itd --net calico-net2 --name=docker-test11 172.16.60.214:5000/kevin_nginx 0e55b1fa6917e52d7a5d65dae7ff577c6286c4f499bee63b833dcdc86c837e42 [root@node1 ~]# docker run -itd --net calico-net3 --name=docker-test111 172.16.60.214:5000/kevin_nginx fa5245a6f679a037ed890a34fc488b3aea03633eb7306b51099c4534ef53cb0a [root@node2 ~]# docker run -itd --net calico-net1 --name=docker-test2 172.16.60.214:5000/kevin_nginx 3628f90a7360524619bbcbc184c1d837bc84134734ad154ab0eb52f1c82ba165 [root@node2 ~]# docker run -itd --net calico-net2 --name=docker-test22 172.16.60.214:5000/kevin_nginx 6554d28d76c8474534b9098756593f3dabd6accce1417671a4b457eb31b92347 [root@node2 ~]# docker run -itd --net calico-net3 --name=docker-test222 172.16.60.214:5000/kevin_nginx c742f2d730edd61e0af7030ced100c480b18292bfe5676518f7e4f307b548868 [root@node3 ~]# docker run -itd --net calico-net1 --name=docker-test3 172.16.60.214:5000/kevin_nginx 5b478d1e10fabc0f74a49c6ed95e4a34b988d019814a1b4db4988b31887f1e7b [root@node3 ~]# docker run -itd --net calico-net2 --name=docker-test33 172.16.60.214:5000/kevin_nginx 7688c3c44c434e597324cc28a291e4466fd1f9c5db4f6a372f52935fa0c7d238 [root@node3 ~]# docker run -itd --net calico-net3 --name=docker-test333 172.16.60.214:5000/kevin_nginx 5d9837140c08245aad0bb59c8841621e58251bdab96684642c2a277d778c4242 驗證容器之間的通信 [root@node1 ~]# docker exec -ti docker-test1 /bin/bash [root@19be6b264b6e /]# ifconfig cali0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 17.16.10.128 netmask 255.255.255.255 broadcast 0.0.0.0 [root@node2 ~]# docker exec -ti docker-test2 /bin/bash [root@0d1355e8d628 /]# ifconfig cali0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 17.16.10.0 netmask 255.255.255.255 broadcast 0.0.0.0 [root@node3 ~]# docker exec -ti docker-test3 /bin/bash [root@64a7bbc00490 /]# ifconfig cali0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 17.16.10.192 netmask 255.255.255.255 broadcast 0.0.0.0 [root@64a7bbc00490 /]# ping 17.16.10.128 PING 17.16.10.128 (17.16.10.128) 56(84) bytes of data. 64 bytes from 17.16.10.128: icmp_seq=1 ttl=62 time=0.528 ms 64 bytes from 17.16.10.128: icmp_seq=2 ttl=62 time=0.375 ms [root@64a7bbc00490 /]# ping 17.16.10.0 PING 17.16.10.0 (17.16.10.0) 56(84) bytes of data. 64 bytes from 17.16.10.0: icmp_seq=1 ttl=62 time=0.502 ms 64 bytes from 17.16.10.0: icmp_seq=2 ttl=62 time=0.405 ms [root@64a7bbc00490 /]# ping 172.16.60.215 PING 172.16.60.215 (172.16.60.215) 56(84) bytes of data. 64 bytes from 172.16.60.215: icmp_seq=1 ttl=63 time=0.294 ms 64 bytes from 172.16.60.215: icmp_seq=2 ttl=63 time=0.261 ms [root@64a7bbc00490 /]# ping 172.16.60.216 PING 172.16.60.216 (172.16.60.216) 56(84) bytes of data. 64 bytes from 172.16.60.216: icmp_seq=1 ttl=63 time=0.314 ms 64 bytes from 172.16.60.216: icmp_seq=2 ttl=63 time=0.255 ms [root@64a7bbc00490 /]# ping 172.16.60.217 PING 172.16.60.217 (172.16.60.217) 56(84) bytes of data. 64 bytes from 172.16.60.217: icmp_seq=1 ttl=63 time=0.605 ms 64 bytes from 172.16.60.217: icmp_seq=2 ttl=63 time=0.230 ms [root@node3 ~]# docker exec -ti docker-test33 /bin/bash [root@c40af6d5d6c3 /]# ifconfig cali0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 173.20.19.192 netmask 255.255.255.255 broadcast 0.0.0.0 [root@c40af6d5d6c3 /]# ping 17.16.10.0 PING 17.16.10.0 (17.16.10.0) 56(84) bytes of data. 溫馨提示: 同一網絡內的容器(即使不在同一節點主機上)可以使用容器名來訪問 [root@node1 ~]# docker exec -ti docker-test1 ping -c 2 docker-test2.calico-net1 PING docker-test2.calico-net1 (17.16.10.0) 56(84) bytes of data. 64 bytes from docker-test2.calico-net1 (17.16.10.0): icmp_seq=1 ttl=62 time=0.372 ms 64 bytes from docker-test2.calico-net1 (17.16.10.0): icmp_seq=2 ttl=62 time=0.335 ms [root@node1 ~]# docker exec -ti docker-test1 ping -c 2 docker-test3.calico-net1 PING docker-test3.calico-net1 (17.16.10.192) 56(84) bytes of data. 64 bytes from docker-test3.calico-net1 (17.16.10.192): icmp_seq=1 ttl=62 time=0.475 ms 64 bytes from docker-test3.calico-net1 (17.16.10.192): icmp_seq=2 ttl=62 time=0.385 ms [root@node2 ~]# docker exec -ti docker-test22 ping -c 2 docker-test11.calico-net2 PING docker-test11.calico-net2 (173.20.19.128) 56(84) bytes of data. 64 bytes from docker-test11.calico-net2 (173.20.19.128): icmp_seq=1 ttl=62 time=0.458 ms 64 bytes from docker-test11.calico-net2 (173.20.19.128): icmp_seq=2 ttl=62 time=0.318 ms [root@node2 ~]# docker exec -ti docker-test22 ping -c 2 docker-test33.calico-net2 PING docker-test33.calico-net2 (173.20.19.192) 56(84) bytes of data. 64 bytes from docker-test33.calico-net2 (173.20.19.192): icmp_seq=1 ttl=62 time=0.430 ms 64 bytes from docker-test33.calico-net2 (173.20.19.192): icmp_seq=2 ttl=62 time=0.342 ms [root@node3 ~]# docker exec -ti docker-test333 ping -c 2 docker-test111.calico-net3 PING docker-test111.calico-net3 (192.10.160.193) 56(84) bytes of data. 64 bytes from docker-test111.calico-net3 (192.10.160.193): icmp_seq=1 ttl=62 time=0.437 ms 64 bytes from docker-test111.calico-net3 (192.10.160.193): icmp_seq=2 ttl=62 time=0.349 ms [root@node3 ~]# docker exec -ti docker-test333 ping -c 2 docker-test222.calico-net3 PING docker-test222.calico-net3 (192.10.160.1) 56(84) bytes of data. 64 bytes from docker-test222.calico-net3 (192.10.160.1): icmp_seq=1 ttl=62 time=0.427 ms 64 bytes from docker-test222.calico-net3 (192.10.160.1): icmp_seq=2 ttl=62 time=0.335 ms 順便查看下各個節點上的路由情況 [root@node1 ~]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.16.60.1 0.0.0.0 UG 100 0 0 ens192 17.16.10.0 172.16.60.216 255.255.255.192 UG 0 0 0 tunl0 17.16.10.128 0.0.0.0 255.255.255.255 UH 0 0 0 cali61dbcdeb9d0 17.16.10.128 0.0.0.0 255.255.255.192 U 0 0 0 * 17.16.10.192 172.16.60.217 255.255.255.192 UG 0 0 0 tunl0 172.16.60.0 0.0.0.0 255.255.255.0 U 100 0 0 ens192 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 173.20.19.0 172.16.60.216 255.255.255.192 UG 0 0 0 tunl0 173.20.19.128 0.0.0.0 255.255.255.255 UH 0 0 0 cali896cb151672 173.20.19.128 0.0.0.0 255.255.255.192 U 0 0 0 * 173.20.19.192 172.16.60.217 255.255.255.192 UG 0 0 0 tunl0 192.10.160.0 172.16.60.216 255.255.255.192 UG 0 0 0 tunl0 192.10.160.128 172.16.60.217 255.255.255.192 UG 0 0 0 tunl0 192.10.160.192 0.0.0.0 255.255.255.192 U 0 0 0 * 192.10.160.193 0.0.0.0 255.255.255.255 UH 0 0 0 cali417e5d5af27 [root@node2 ~]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.16.60.1 0.0.0.0 UG 100 0 0 ens192 17.16.10.0 0.0.0.0 255.255.255.255 UH 0 0 0 cali5ccfdb2354a 17.16.10.0 0.0.0.0 255.255.255.192 U 0 0 0 * 17.16.10.128 172.16.60.215 255.255.255.192 UG 0 0 0 tunl0 17.16.10.192 172.16.60.217 255.255.255.192 UG 0 0 0 tunl0 172.16.60.0 0.0.0.0 255.255.255.0 U 100 0 0 ens192 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 173.20.19.0 0.0.0.0 255.255.255.255 UH 0 0 0 calia803e0ccc31 173.20.19.0 0.0.0.0 255.255.255.192 U 0 0 0 * 173.20.19.128 172.16.60.215 255.255.255.192 UG 0 0 0 tunl0 173.20.19.192 172.16.60.217 255.255.255.192 UG 0 0 0 tunl0 192.10.160.0 0.0.0.0 255.255.255.192 U 0 0 0 * 192.10.160.1 0.0.0.0 255.255.255.255 UH 0 0 0 cali708d6751d56 192.10.160.128 172.16.60.217 255.255.255.192 UG 0 0 0 tunl0 192.10.160.192 172.16.60.215 255.255.255.192 UG 0 0 0 tunl0 [root@node3 ~]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.16.60.1 0.0.0.0 UG 100 0 0 ens192 17.16.10.0 172.16.60.216 255.255.255.192 UG 0 0 0 tunl0 17.16.10.128 172.16.60.215 255.255.255.192 UG 0 0 0 tunl0 17.16.10.192 0.0.0.0 255.255.255.255 UH 0 0 0 cali459515b42a2 17.16.10.192 0.0.0.0 255.255.255.192 U 0 0 0 * 172.16.60.0 0.0.0.0 255.255.255.0 U 100 0 0 ens192 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 173.20.19.0 172.16.60.216 255.255.255.192 UG 0 0 0 tunl0 173.20.19.128 172.16.60.215 255.255.255.192 UG 0 0 0 tunl0 173.20.19.192 0.0.0.0 255.255.255.255 UH 0 0 0 cali9019232abff 173.20.19.192 0.0.0.0 255.255.255.192 U 0 0 0 * 192.10.160.0 172.16.60.216 255.255.255.192 UG 0 0 0 tunl0 192.10.160.128 0.0.0.0 255.255.255.192 U 0 0 0 * 192.10.160.129 0.0.0.0 255.255.255.255 UH 0 0 0 calic05cbc7f820 192.10.160.192 172.16.60.215 255.255.255.192 UG 0 0 0 tunl0
測試時遇到的一個坑:
如上步驟操作后,發現同一個網絡中容器之間ping不通,容器也ping不通各宿主機的ip. 明明已經關閉了節點的防火牆! 最后發現是因為節點的主機名和ETCD_NAME以及calico容器啟動時的NODENAME的名稱不一樣導致的! 需將節點主機名和ETCD_NAME以及NODENAME保持一樣的名稱就解決了. 或者說三者名稱可以不一樣,但是必須在/etc/hosts文件了做映射,將ETCD_NAME以及calico啟動的NODENAME映射到本節點的ip地址上.
測試結論:
1) 同一個網段中容器能相互ping的通 (即使不在同一個節點上,只要創建容器時使用的是同一個子網段);
2) 不在同一個子網段里的容器是相互ping不通的 (即使在同一個節點上,但是創建容器時使用的是不同子網段);
3) 宿主機能ping通它自身的所有容器ip,但不能ping通其他節點上的容器ip;
4) 所有節點的容器都能ping通其他節點宿主機的ip (包括容器自己所在的宿主機的ip)。
也就是說,Calico默認配置下,只允許位於同一個網絡中的容器之間通信,這樣即實現了容器的跨主機互連, 也能更好的達到網絡隔離效果。如果位於不同網絡下的容器要想通信,只能依賴Calico的Policy策略來實現了,它強大的Policy能夠實現幾乎任意場景的訪問控制!