一、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)。
這樣即實現了容器的跨主機互連, 也能更好的達到網路隔離效果。