1. 前言
Kubernetes設計了一種特別的網絡模型,其跟原生Docker網絡模型有些偏離。在這種設計中,Kubernetes定義了一個抽象概念:Pod, 每個Pod是一系列容器的集合,而且有一個共享IP,所有容器共享相同的網絡命名空間。Pod不僅可以與物理機器間通信,而且還可以使跨網絡間容器能通信。Kubernetes的這種IP-per-pod的設計思想有很多好處,比如:從端口分配、網絡、命名、服務發現、負載均衡、應用程序配置以及遷移方面來看,這種模型使得開發人員、運維人員可以把Pod當做一個虛擬機或者是物理機,有很好的後向兼容能力。當前Google在它的雲平臺GCE上實現了這種IP-per-pod模型,但是如果在本地使用Kubernetes,那就得自己實現這種模型,本文主要講述就如何使用Openvswitch GRE實現這種模型。
2. 實現方案
本文用2臺主機運行CentOS 7, 實現可如下圖描述:
2.1 安裝Docker
安裝步驟參照如下腳本:
#Docker默認配置文件
DOCKER_CONFIG=/etc/sysconfig/docker
#下載最新Docker安裝文件
wget https://get.docker.com/builds/Linux/x86_64/docker-latest -O /usr/bin/docker
chmod +x /usr/bin/docker
#配置Docker unit文件
cat <<EOF >/usr/lib/systemd/system/docker.socket
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
source $DOCKER_CONFIG
cat <<EOF >/usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
[Service]
Type=notify
EnvironmentFile=-$DOCKER_CONFIG
ExecStart=/usr/bin/docker -d $OPTIONS
LimitNOFILE=1048576
LimitNPROC=1048576
[Install]
Also=docker.socket
EOF
systemctl daemon-reload
systemctl enable docker
systemctl start docker
2.2 安裝Openvswitch
下載Openvswitch並安裝:
wget http://cbs.centos.org/kojifiles/packages/openvswitch/2.3.1/2.el7/x86_64/openvswitch-2.3.1-2.el7.x86_64.rpm
rpm -ivh openvswitch-2.3.1-2.el7.x86_64.rpm
systemctl start openvswitch
systemctl enable openvswitch
2.3 設置Docker默認網橋
在這裏,我們按下面的步驟新建一個Linux網橋localbr0並替換默認網橋docker0,
#停止Docker Daemon進程
systemctl stop docker.socket
systemctl stop docker
#設置默認網橋docker0爲down,並刪除
ip link set dev docker0 down
brctl delbr docker0
#新建Linux網橋localbr0
brctl addbr localbr0
#在每臺主機上更改10.244.x.0/24,下面設置localbr0地址如:
#10.224.106.127
ip addr add 10.244.1.1/24 dev localbr0
#10.224.106.128
ip addr add 10.244.2.1/24 dev localbr0
ip link set dev localbr0 up
echo 'OPTIONS="--bridge localbr0 --iptables=false"'>>/etc/sysconfig/docker
systemctl start docker
2.4 設置Openvswitch網橋及GRE
#新建Openvswitch網橋
ovs-vsctl add-br ovsbr
#啓用SPT協議防止網橋環路
ovs-vsctl set bridge ovsbr stp_enable=true
#添加ovsbr到本地localbr0,使得容器流量通過OVS流經tunnel
brctl addif localbr0 ovsbr
ip link set dev ovsbr up
#創建GRE
ovs-vsctl add-port ovsbr tep0 -- set interface tep0 type=internal
#需在每個主機上修改tep0 IP地址
ip addr add 192.168.1.1/24 dev tep0
ip addr add 192.168.1.2/24 dev tep0
ip link set dev tep0 up
#使用GRE隧道連接每個主機上的Openvswitch網橋
#10.224.106.127
ovs-vsctl add-port ovsbr gre0 -- set interface gre0 type=gre options:remote_ip=10.224.106.128
#10.224.106.128
ovs-vsctl add-port ovsbr gre0 -- set interface gre0 type=gre options:remote_ip=10.224.106.127
#配置路由使得跨主機間容器的通信
ip route add 10.244.0.0/16 dev tep0
#爲了使得容器訪問Internet,在兩臺主機上配置NAT
iptables -t nat -A POSTROUTING -s 10.244.0.0/16 -o ens192 -j MASQUERADE
2.5 驗證
完成了以上的操作,這時以下應該能正常工作:
-
可以相互ping tep0的地址
[root@minion-1 ~]# ping 192.168.1.2 PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data. 64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.929 ms 64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.642 ms 64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.322 ms 64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.366 ms ^C --- 192.168.1.2 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3000ms rtt min/avg/max/mdev = 0.322/0.564/0.929/0.245 ms
-
可以相互ping localbr0的地址
[root@minion-1 ~]# ping 10.244.2.1 PING 10.244.2.1 (10.244.2.1) 56(84) bytes of data. 64 bytes from 10.244.2.1: icmp_seq=1 ttl=64 time=0.927 ms 64 bytes from 10.244.2.1: icmp_seq=2 ttl=64 time=0.337 ms 64 bytes from 10.244.2.1: icmp_seq=3 ttl=64 time=0.409 ms ^C --- 10.244.2.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 0.337/0.557/0.927/0.264 ms
-
兩臺主機上容器可以相互ping通
在主機10.224.106.127和10.224.106.128上執行如下命令運行一個新的容器:
docker run -ti ubuntu /bin/bash
然後10.224.106.127的容器ping 10.224.106.128的容器,
root@e38da4440eaf:/# ping 10.244.2.3 PING 10.244.2.3 (10.244.2.3) 56(84) bytes of data. 64 bytes from 10.244.2.3: icmp_seq=1 ttl=63 time=0.781 ms 64 bytes from 10.244.2.3: icmp_seq=2 ttl=63 time=0.404 ms ^C --- 10.244.2.3 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.404/0.592/0.781/0.190 ms
從10.224.106.128的容器ping 10.224.106.127的容器。
root@37b272af0d09:/# ping 10.244.1.3 PING 10.244.1.3 (10.244.1.3) 56(84) bytes of data. 64 bytes from 10.244.1.3: icmp_seq=1 ttl=63 time=1.70 ms 64 bytes from 10.244.1.3: icmp_seq=2 ttl=63 time=0.400 ms ^C --- 10.244.1.3 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 0.400/1.054/1.708/0.654 ms
3. 結論
本文通過Openvswitch GRE實現Kubernetes網絡模型,但是如果在大規模系統中,此方法顯得有點笨拙。例如,如果系統有n臺主機,且它們之間需要通信,則需建立n(n-1)/2條GRE隧道,雖然可以通過啓用SPT協議防止網橋環路,但維護n(n-1)/2條隧道仍然工作量很大。所以接下來考慮如何能自動化實現。
4. 參考資料
- https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/design/networking.md
- https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/ovs-networking.md
- https://docs.docker.com/installation/centos/
- https://goldmann.pl/blog/2014/01/21/connecting-docker-containers-on-multiple-hosts/
5. 作者簡介
楊章顯,現就職於Cisco,主要從事WebEx SaaS服務運維,系統性能分析等工作。特別關注雲計算,自動化運維,部署等技術,尤其是Go、OpenvSwitch、Docker及其生態圈技術,如Kubernetes、Flocker等Docker相關開源項目。Email: [email protected]