Docker容器學習梳理--容器間網路通訊設定(Pipework和Open vSwitch)
自從Docker容器出現以來,容器的網路通訊就一直是被關注的焦點,也是生產環境的迫切需求。容器的網路通訊又可以分為兩大方面:單主機容器上的相互通訊,和跨主機的容器相互通訊。下面將分別針對這兩方面,對容器的通訊原理進行簡單的分析,幫助大家更好地使用docker。前面已經在Docker容器學習梳理--基礎知識(2)這一篇中詳細介紹了Docker的網路配置以及pipework工具。
docker單主機容器通訊
基於對netnamespace的控制,docker可以為在容器建立隔離的網路環境,在隔離的網路環境下,容器具有完全獨立的網路棧,與宿主機隔離, 也可以使容器共享主機或者其他容器的網路名稱空間,基本可以滿足開發者在各種場景下的需要。 按docker官方的說法,docker容器的網路有五種模式: 1)bridge模式,--net=bridge(預設) 這是dokcer網路的預設設定,為容器建立獨立的網路名稱空間,容器具有獨立的網絡卡等所有單獨的網路棧,是最常用的使用方式。 在dockerrun啟動容器的時候,如果不加--net引數,就預設採用這種網路模式。安裝完docker,系統會自動新增一個供docker使用的網橋docker0,我們建立一個新的容器時, 容器通過DHCP獲取一個與docker0同網段的IP地址,並預設連線到docker0網橋,以此實現容器與宿主機的網路互通。 2)host模式,--net=host 這個模式下創建出來的容器,直接使用容器宿主機的網路名稱空間。 將不擁有自己獨立的NetworkNamespace,即沒有獨立的網路環境。它使用宿主機的ip和埠。 3)none模式,--net=none 為容器建立獨立網路名稱空間,但不為它做任何網路配置,容器中只有lo,使用者可以在此基礎上,對容器網路做任意定製。 這個模式下,dokcer不為容器進行任何網路配置。需要我們自己為容器新增網絡卡,配置IP。 因此,若想使用pipework配置docker容器的ip地址,必須要在none模式下才可以。 4)其他容器模式(即container模式),--net=container:NAME_or_ID 與host模式類似,只是容器將與指定的容器共享網路名稱空間。 這個模式就是指定一個已有的容器,共享該容器的IP和埠。除了網路方面兩個容器共享,其他的如檔案系統,程序等還是隔離開的。 5)使用者自定義:docker1.9版本以後新增的特性,允許容器使用第三方的網路實現或者建立單獨的bridge網路,提供網路隔離能力。
這些網路模式在相互網路通訊方面的對比如下所示:
南北向通訊指容器與宿主機外界的訪問機制,東西向流量指同一宿主機上,與其他容器相互訪問的機制。
host模式
由於容器和宿主機共享同一個網路名稱空間,換言之,容器的IP地址即為宿主機的IP地址。所以容器可以和宿主機一樣,使用宿主機的任意網絡卡,實現和外界的通訊。其網路模型可以參照下圖
採用host模式的容器,可以直接使用宿主機的IP地址與外界進行通訊,若宿主機具有公有IP,那麼容器也擁有這個公有IP。同時容器內服務的埠也可以使用宿主機的埠, 無需額外進行NAT轉換,而且由於容器通訊時,不再需要通過linuxbridge等方式轉發或者資料包的拆封,效能上有很大優勢。 當然,這種模式有優勢,也就有劣勢,主要包括以下幾個方面: 1)最明顯的就是容器不再擁有隔離、獨立的網路棧。容器會與宿主機競爭網路棧的使用,並且容器的崩潰就可能導致宿主機崩潰,在生產環境中,這種問題可能是不被允許的。 2)容器內部將不再擁有所有的埠資源,因為一些埠已經被宿主機服務、bridge模式的容器埠繫結等其他服務佔用掉了。
bridge模式
bridge模式是docker預設的,也是開發者最常使用的網路模式。在這種模式下,docker為容器建立獨立的網路棧,保證容器內的程序使用獨立的網路環境, 實現容器之間、容器與宿主機之間的網路棧隔離。同時,通過宿主機上的docker0網橋,容器可以與宿主機乃至外界進行網路通訊。 其網路模型可以參考下圖:
從上面的網路模型可以看出,容器從原理上是可以與宿主機乃至外界的其他機器通訊的。同一宿主機上,容器之間都是連線掉docker0這個網橋上的,它可以作為虛擬交換機使容器可以相互通訊。 然而,由於宿主機的IP地址與容器vethpair的IP地址均不在同一個網段,故僅僅依靠vethpair和namespace的技術,還不足以使宿主機以外的網路主動發現容器的存在。為了使外界可以方位容器中的程序,docker採用了埠繫結的方式,也就是通過iptables的NAT,將宿主機上的埠 埠流量轉發到容器內的埠上。 舉一個簡單的例子,使用下面的命令建立容器,並將宿主機的3306埠繫結到容器的3306埠: dockerrun-tid--namedb-p3306:3306MySQL 在宿主機上,可以通過iptables-tnat-L-n,查到一條DNAT規則: DNATtcp--0.0.0.0/00.0.0.0/0tcpdpt:3306to:172.17.0.5:3306 上面的172.17.0.5即為bridge模式下,建立的容器IP。 很明顯,bridge模式的容器與外界通訊時,必定會佔用宿主機上的埠,從而與宿主機競爭埠資源,對宿主機埠的管理會是一個比較大的問題。同時,由於容器與外界通訊是基於三層上iptablesNAT,效能和效率上的損耗是可以預見的。
none模式
在這種模式下,容器有獨立的網路棧,但不包含任何網路配置,只具有lo這個loopback網絡卡用於程序通訊。也就是說,none模式為容器做了最少的網路設定, 但是俗話說得好“少即是多”,在沒有網路配置的情況下,通過第三方工具或者手工的方式,開發這任意定製容器的網路,提供了最高的靈活性
其他容器(container)模式
其他網路模式是docker中一種較為特別的網路的模式。在這個模式下的容器,會使用其他容器的網路名稱空間,其網路隔離性會處於bridge橋接模式與host模式之間。 當容器共享其他容器的網路名稱空間,則在這兩個容器之間不存在網路隔離,而她們又與宿主機以及除此之外其他的容器存在網路隔離。其網路模型可以參考下圖:
在這種模式下的容器可以通過localhost來同一網路名稱空間下的其他容器,傳輸效率較高。而且這種模式還節約了一定數量的網路資源,但它並沒有改變容器與外界通訊的方式。 在一些特殊的場景中非常有用,例如,kubernetes的pod,kubernetes為pod建立一個基礎設施容器,同一pod下的其他容器都以其他容器模式共享這個基礎設施容器的網路名稱空間, 相互之間以localhost訪問,構成一個統一的整體。
使用者定義網路模式
在使用者定義網路模式下,開發者可以使用任何docker支援的第三方網路driver來定製容器的網路。並且,docker1.9以上的版本預設自帶了bridge和overlay兩種型別的自定義網路driver。可以用於整合calico、weave、openvswitch等第三方廠商的網路實現。 除了docker自帶的bridgedriver,其他的幾種driver都可以實現容器的跨主機通訊。而基於bdrigedriver的網路,docker會自動為其建立iptables規則, 保證與其他網路之間、與docker0之間的網路隔離。 例如,使用下面的命令建立一個基於bridgedriver的自定義網路: dockernetworkcreatebri1 則docker會自動生成如下的iptables規則,保證不同網路上的容器無法互相通訊。 -ADOCKER-ISOLATION-ibr-8dba6df70456-odocker0-jDROP -ADOCKER-ISOLATION-idocker0-obr-8dba6df70456-jDROP 除此之外,bridgedriver的所有行為都和預設的bridge模式完全一致。而overlay及其他driver,則可以實現容器的跨主機通訊。
docker跨主機容器通訊
早期大家的跨主機通訊方案主要有以下幾種: 1)容器使用host模式:容器直接使用宿主機的網路,這樣天生就可以支援跨主機通訊。雖然可以解決跨主機通訊問題,但這種方式應用場景很有限,容易出現埠衝突,也無法做到隔離網路環境, 一個容器崩潰很可能引起整個宿主機的崩潰。 2)埠繫結:通過繫結容器埠到宿主機埠,跨主機通訊時,使用主機IP+埠的方式訪問容器中的服務。顯而易見,這種方式僅能支援網路棧的四層及以上的應用,並且容器與宿主機緊耦合, 很難靈活的處理,可擴充套件性不佳。 3)docker外定製容器網路:在容器通過docker建立完成後,然後再通過修改容器的網路名稱空間來定義容器網路。典型的就是很久以前的pipework,容器以none模式建立,pipework通過進入容器 的網路名稱空間為容器重新配置網路,這樣容器網路可以是靜態IP、vxlan網路等各種方式,非常靈活,容器啟動的一段時間內會沒有IP,明顯無法在大規模場景下使用,只能在實驗室中測試使用。 4)第三方SDN定義容器網路:使用OpenvSwitch或Flannel等第三方SDN工具,為容器構建可以跨主機通訊的網路環境。這些方案一般要求各個主機上的docker0網橋的cidr不同,以避免出現IP衝突 的問題,限制了容器在宿主機上的可獲取IP範圍。並且在容器需要對叢集外提供服務時,需要比較複雜的配置,對部署實施人員的網路技能要求比較高。 上面這些方案有各種各樣的缺陷,同時也因為跨主機通訊的迫切需求,docker1.9版本時,官方提出了基於vxlan的overlay網路實現,原生支援容器的跨主機通訊。同時,還支援通過libnetwork的 plugin機制擴充套件各種第三方實現,從而以不同的方式實現跨主機通訊。就目前社群比較流行的方案來說,跨主機通訊的基本實現方案有以下幾種: 1)基於隧道的overlay網路:按隧道型別來說,不同的公司或者組織有不同的實現方案。docker原生的overlay網路就是基於vxlan隧道實現的。ovn則需要通過geneve或者stt隧道來實現的。flannel 最新版本也開始預設基於vxlan實現overlay網路。 2)基於包封裝的overlay網路:基於UDP封裝等資料包包裝方式,在docker叢集上實現跨主機網路。典型實現方案有weave、flannel的早期版本。 3)基於三層實現SDN網路:基於三層協議和路由,直接在三層上實現跨主機網路,並且通過iptables實現網路的安全隔離。典型的方案為ProjectCalico。同時對不支援三層路由的環境,ProjectCalico還提供了基於IPIP封裝的跨主機網路實現
Dokcer通過使用Linux橋接提供容器之間的通訊,docker0橋接介面的目的就是方便Docker管理。當Docker daemon啟動時需要做以下操作
a)如果docker0不存在則建立 b)搜尋一個與當前路由不衝突的ip段 c)在確定的範圍中選擇ip d)繫結ip到docker0
CentOS7安裝docker
[[email protected]~]#yuminstalldockerbridge-utils-y [[email protected]~]#systemctlstartdocker;systemctlenabledocker
列出當前主機網橋
[[email protected]~]#brctlshow bridgenamebridgeidSTPenabledinterfaces docker08000.0242b1a59b05no
檢視當前 docker0 ip
[[email protected]~]#ifconfigdocker0 docker0:flags=4099<UP,BROADCAST,MULTICAST>mtu1500 inet172.17.0.1netmask255.255.0.0broadcast0.0.0.0 ether02:42:b1:a5:9b:05txqueuelen0(Ethernet) RXpackets0bytes0(0.0B) RXerrors0dropped0overruns0frame0 TXpackets0bytes0(0.0B) TXerrors0dropped0overruns0carrier0collisions0
在容器執行時,每個容器都會分配一個特定的虛擬機器口並橋接到docker0。每個容器都會配置同docker0 ip相同網段的專用ip 地址,docker0的IP地址被用於所有容器的預設閘道器。
一般啟動的容器中ip預設是172.17.0.1/24網段的。
[[email protected]~]#dockerimages REPOSITORYTAGIMAGEIDCREATEDSIZE docker.io/centoslatestff426288ea903weeksago207.2MB [[email protected]~]# [[email protected]~]#dockerrun-itd--namemy-testcentos/bin/bash 11607da07401f75dc481458934e8cd3353896ebaba418c2f2d436619ffbd8772 [[email protected]~]#dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 11607da07401centos"/bin/bash"24secondsagoUp23secondsmy-test [[email protected]~]#dockerinspect11607da07401|grep-iipaddr "SecondaryIPAddresses":null, "IPAddress":"172.17.0.2", "IPAddress":"172.17.0.2", [[email protected]~]#
那麼能不能在建立容器的時候指定特定的ip呢?這是當然可以實現的!
注意:宿主機的ip路由轉發功能一定要開啟,否則所建立的容器無法聯網!
[[email protected]~]#cat/proc/sys/net/ipv4/ip_forward 1 [[email protected]~]#dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 11607da07401centos"/bin/bash"4minutesagoUp4minutesmy-test [[email protected]~]#dockerrun-itd--name=test1centos 4fb496dac251f60bcffaceea340847687ed4d7c9db20a351296bc9143c73d74b [[email protected]~]#dockerexec-ittest1/bin/bash [[email protected]/]#pingwww.baidu.com PINGwww.a.shifen.com(115.239.211.112)56(84)bytesofdata. 64bytesfrom115.239.211.112(115.239.211.112):icmp_seq=1ttl=48time=12.4ms 64bytesfrom115.239.211.112(115.239.211.112):icmp_seq=2ttl=48time=11.1ms ^C ---www.a.shifen.compingstatistics--- 2packetstransmitted,2received,0%packetloss,time1001ms rttmin/avg/max/mdev=11.186/11.823/12.461/0.646ms [[email protected]/]# 關閉ip路由轉發功能,容器即不能聯網 [[email protected]~]#echo0>/proc/sys/net/ipv4/ip_forward [[email protected]~]#cat/proc/sys/net/ipv4/ip_forward 0 [[email protected]/]#pingwww.baidu.com ping:www.baidu.com:Nameorservicenotknown//ping不通~
一、建立容器使用特定範圍的IP
Docker會嘗試尋找沒有被主機使用的ip段,儘管它適用於大多數情況下,但是它不是萬能的,有時候我們還是需要對ip進一步規劃。 Docker允許你管理docker0橋接或者通過-b選項自定義橋接網絡卡,需要安裝bridge-utils軟體包。操作流程如下: a)確保docker的程序是停止的 b)建立自定義網橋 c)給網橋分配特定的ip d)以-b的方式指定網橋 具體操作過程如下(比如建立容器的時候,指定ip為10.10.172.202/24網段的): [[email protected]~]#servicedockerstop [[email protected]~]#iplinksetdevdocker0down [[email protected]~]#brctldelbrdocker0 [[email protected]~]#brctladdbrbr0 [[email protected]~]#ipaddradd10.10.172.202/24devbr0//注意,這個10.10.172.202就是所建容器的閘道器地址。通過dockerinspectcontainer_id能檢視到 [[email protected]~]#iplinksetdevbr0up [[email protected]~]#ipaddrshowbr0 [[email protected]~]#vim/etc/sysconfig/docker//即將虛擬的橋介面由預設的docker0改為br0 將 OPTIONS='--selinux-enabled--log-driver=journald' 改為 OPTIONS='--selinux-enabled--log-driver=journald-b=br0'//即新增-b=br0 [[email protected]~]#servicedockerrestart -------------------------------------------------------------------------------------- 上面是centos7下的操作步驟,下面提供下ubuntu下的操作步驟: $sudoservicedockerstop $sudoiplinksetdevdocker0down $sudobrctldelbrdocker0 $sudobrctladdbrbr0 $sudoipaddradd10.10.172.202/24devbr0 $sudoiplinksetdevbr0up $ipaddrshowbr0 $echo'DOCKER_OPTS="-b=br0"'>>/etc/default/docker $sudoservicedockerstart -------------------------------------------------------------------------------------- 然後建立容器,檢視下容器ip是否為設定的10.10.172.202/24網段的 [[email protected]~]#dockerimages REPOSITORYTAGIMAGEIDCREATEDSIZE docker.io/ubuntulatest0458a4468cbc7daysago111.7MB docker.io/centoslatestff426288ea903weeksago207.2MB [[email protected]~]#dockerrun-t-i--nametest1centos/bin/bash [[email protected]/]# [[email protected]~]#dockerrun-t-i--nametest2docker.io/ubuntu/bin/bash [[email protected]/]# [[email protected]~]#dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 0514266c80e0docker.io/ubuntu"/bin/bash"47minutesagoUp5minutestest2 61a2cdea34f5centos"/bin/bash"46minutesagoUp46minutestest1 [[email protected]~]#dockerinspect--format='{{.NetworkSettings.IPAddress}}'0514266c80e0 10.10.172.16 [[email protected]~]#dockerinspect--format='{{.NetworkSettings.IPAddress}}'61a2cdea34f5 10.10.172.15 [[email protected]~]#brctlshow bridgenamebridgeidSTPenabledinterfaces br08000.005056866833noeth0 veth0pl20732 veth0pl21198
使用pipework給容器設定一個固定的ip
可以利用pipework為容器指定一個固定的ip,操作方法非常簡單,如下: [[email protected]~]#brctladdbrbr0 [[email protected]~]#iplinksetdevbr0up [[email protected]~]#ipaddradd10.10.172.202/24devbr0//這個ip相當於br0網橋的閘道器ip,可以隨意設定。 [[email protected]~]#dockerrun-ti-d--net=none--name=my-test1docker.io/nginx/bin/bash [[email protected]~]#pipeworkbr0-ieth0my-test110.10.172.190/[email protected] [[email protected]~]#dockerexec-timy-test1/bin/bash [email protected]:/#apt-getupdate [email protected]:/#apt-getinstallnet-tools-y [email protected]:/#ifconfig eth0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500 inet10.10.172.190netmask255.255.255.0broadcast10.10.172.255 inet6fe80::e4fe:e6ff:fedb:b4bcprefixlen64scopeid0x20<link> ethere6:fe:e6:db:b4:bctxqueuelen1000(Ethernet) RXpackets5656bytes10813699(10.3MiB) RXerrors0dropped0overruns0frame0 TXpackets4849bytes336703(328.8KiB) TXerrors0dropped0overruns0carrier0collisions0 lo:flags=73<UP,LOOPBACK,RUNNING>mtu65536 inet127.0.0.1netmask255.0.0.0 inet6::1prefixlen128scopeid0x10<host> looptxqueuelen0(LocalLoopback) RXpackets0bytes0(0.0B) RXerrors0dropped0overruns0frame0 TXpackets0bytes0(0.0B) TXerrors0dropped0overruns0carrier0collisions0 再啟動一個容器 [[email protected]~]#dockerrun-ti-d--net=none--name=my-test2docker.io/nginx/bin/bash [[email protected]~]#pipeworkbr0-ieth0my-test210.10.172.191/[email protected] 這樣,my-test1容器和my-test2容器在同一個宿主機上,所以它們固定後的ip是可以相互ping通的。
二、不同主機間的容器通訊(pipework config docker container ip)
我的centos7測試機上的docker是yum安裝的,預設自帶pipework工具,所以就不用在另行安裝它了。 ----------------------------------------------------------------------------------------------- 如果沒有pipework工具,可以安裝下面步驟進行安裝: #gitclonehttps://github.com/jpetazzo/pipework.git #sudocp-rppipework/pipework/usr/local/bin/ 安裝相應依賴軟體(網橋) #yuminstallbridge-utils-y ----------------------------------------------------------------------------------------------- 檢視Docker宿主機上的橋接網路 [[email protected]~]#brctlshow bridgenamebridgeidSTPenabledinterfaces docker08000.0242b1a59b05no 有兩種方式做法: 1)可以選擇刪除docker0,直接把docker的橋接指定為br0; 2)也可以選擇保留使用預設docker0的配置,這樣單主機容器之間的通訊可以通過docker0; 跨主機不同容器之間通過pipework將容器的網絡卡橋接到br0上,這樣跨主機容器之間就可以通訊了。 如果保留了docker0,則容器啟動時不加--net=none引數,那麼本機容器啟動後就是預設的docker0自動分配的ip(預設是172.17.1.0/24網段),它們之間是可以通訊的; 跨宿主機的容器建立時要加--net=none引數,待容器啟動後通過pipework給容器指定ip,這樣跨宿主機的容器ip是在同一網段內的同網段地址,因此可以通訊。 一般來說:最好在建立容器的時候加上--net=none,防止自動分配的IP在區域網中有衝突。若是容器建立後自動獲取ip,下次容器啟動會ip有變化,可能會和物理網段中的ip衝突 --------------------------------------------------------------------------------------------------- 例項說明如下: 宿主機資訊 ip:10.10.172.202(網絡卡裝置為eth0) gateway:10.10.172.1 netmask:255.255.255.0 作業系統: CentOSLinuxrelease7.2.1511(Core) 1)刪除虛擬橋接卡docker0的配置 [[email protected]~]#servicedockerstop [[email protected]~]#iplinksetdevdocker0down [[email protected]~]#brctldelbrdocker0 [[email protected]~]#brctladdbrbr0 [[email protected]~]#iplinksetdevbr0up [[email protected]~]#ipaddrdel10.10.172.202/24deveth0//刪除宿主機網絡卡的IP(如果是使用這個地址進行的遠端連線,這一步操作後就會斷掉;如果是使用外網地址連線的話,就不會斷開) [[email protected]~]#ipaddradd10.10.172.202/24devbr0//將宿主主機的ip設定到br0 [[email protected]~]#brctladdifbr0eth0//將宿主機網絡卡掛到br0上 [[email protected]~]#iproutedeldefault//刪除預設的原路由,其實就是eth0上使用的原路由10.10.172.1(這步小心,注意刪除後要保證機器能遠端連線上,最好是通過外網ip遠端連的。別刪除路由後,遠端連線不上,中斷了) [[email protected]~]#iprouteadddefaultvia10.10.172.1devbr0//為br0設定路由,此時CRT就可以遠端連線伺服器了。 [[email protected]~]#brctlshow [[email protected]~]#vim/etc/sysconfig/docker//即將虛擬的橋介面由預設的docker0改為br0 將 OPTIONS='--selinux-enabled--log-driver=journald' 改為 OPTIONS='--selinux-enabled--log-driver=journald-b=br0'//即新增-b=br0 [[email protected]~]#servicedockerstart 啟動一個手動設定網路的容器 [[email protected]~]#dockerrun-itd--net=none--name=my-test1docker.io/centos [[email protected]network-scripts]#dockerps CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES ba99871b4c45docker.io/centos"/bin/bash"7minutesagoUp9secondsmy-test1 為my-test1容器設定一個與橋接物理網路同地址段的ip(如下,"[email protected]") 預設不指定網絡卡裝置名,則預設新增為eth0。可以通過-i引數新增網絡卡裝置名 [[email protected]~]#pipeworkbr0-ieth0my-test110.10.172.190/[email protected]//閘道器為宿主機的IP地址或者是宿主機的閘道器地址 同理,在其他機器上啟動容器,並類似上面用pipework設定一個同網段類的ip,這樣跨主機的容器就可以相互ping通了! -------------------------------------------------------------------------------------------------- 2)保留預設虛擬橋接卡docker0的配置 [[email protected]~]#cd/etc/sysconfig/network-scripts/ [[email protected]network-scripts]#cpifcfg-eth0ifcfg-eth0.bak [[email protected]network-scripts]#cpifcfg-eth0ifcfg-br0 [[email protected]network-scripts]#vimifcfg-eth0//增加BRIDGE=br0,刪除IPADDR,NETMASK,GATEWAY,DNS的設定 ...... BRIDGE=br0 [[email protected]network-scripts]#vimifcfg-br0//修改DEVICE為br0,Type為Bridge,把eth0的網路設定設定到這裡來(裡面應該有ip,閘道器,子網掩碼或DNS設定) ...... TYPE=Bridge DEVICE=br0 [[email protected]network-scripts]#servicenetworkrestart [[email protected]network-scripts]#servicedockerrestart 開啟一個容器並指定網路模式為none(這樣,建立的容器就不會通過docker0自動分配ip了,而是根據pipework工具自定ip指定) [[email protected]network-scripts]#dockerimages REPOSITORYTAGIMAGEIDCREATEDSIZE docker.io/centoslatestff426288ea903weeksago207.2MB [[email protected]network-scripts]#dockerrun-itd--net=none--name=my-centosdocker.io/centos/bin/bash ed945a089b689e1fee01225ea957172bf0a38e4c243d870d009891871872a450 接著給容器配置網路 [[email protected]network-scripts]#pipeworkbr0-ieth0my-centos10.10.172.191/[email protected] [[email protected]network-scripts]#dockerattached945a089b68 [[email protected]network-scripts]#dockerexec-ited945a089b68/bin/bash#推薦使用exec連線容器 [[email protected]/]#ifconfigeth0//若沒有ifconfig命令,可以yum安裝net-tools工具 eth0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500 inet10.10.172.191netmask255.255.255.0broadcast10.10.172.255 inet6fe80::b8e8:27ff:fe7f:ce43prefixlen64scopeid0x20<link> etherba:e8:27:7f:ce:43txqueuelen1000(Ethernet) RXpackets7060bytes13523313(12.8MiB) RXerrors0dropped0overruns0frame0 TXpackets5139bytes359449(351.0KiB) TXerrors0dropped0overruns0carrier0collisions0 [[email protected]/]#route-n KernelIProutingtable DestinationGatewayGenmaskFlagsMetricRefUseIface 0.0.0.010.10.172.10.0.0.0UG000eth0 10.10.172.00.0.0.0255.255.255.0U000eth0 另外pipework不能新增靜態路由,如果有需求則可以在run的時候加上--privileged=true許可權在容器中手動新增,但這種方法安全性有缺陷。 除此之外,可以通過ipnetns(--help參考幫助)新增靜態路由,以避免建立容器使用--privileged=true選項造成一些不必要的安全問題: 如下獲取指定容器的pid [[email protected]network-scripts]#dockerinspect--format="{{.State.Pid}}"ed945a089b68 19532 [[email protected]network-scripts]#ln-s/proc/19532/ns/net/var/run/netns/19532 [[email protected]network-scripts]#ipnetnsexec19532iprouteadd192.168.21.0/24deveth0via10.10.172.1 [[email protected]network-scripts]#ipnetnsexec19532iproute//新增成功 192.168.21.0/24via10.10.172.1deveth0 同理,在其它宿主機進行相應的配置,新建容器並使用pipework新增虛擬網絡卡橋接到br0,如此建立的容器間就可以相互通訊了。
-----------------------------------------------幾個報錯出來---------------------------------------------
1)重啟網絡卡報錯如下: #systemctlrestartnetwork ...... Nov2322:09:08hdcoe02systemd[1]:network.service:controlprocessexited,code=exitedstatus=1 Nov2322:09:08hdcoe02systemd[1]:FailedtostartLSB:Bringup/downnetworking. Nov2322:09:08hdcoe02systemd[1]:Unitnetwork.serviceenteredfailedstate.</span> 解決辦法: #systemctlenableNetworkManager-wait-online.service #systemctlstopNetworkManager #systemctlrestartnetwork.service 2)建立容器,出現下面告警 WARNING:IPv4forwardingisdisabled.Networkingwillnotwork. 解決辦法: #vim/usr/lib/sysctl.d/00-system.conf 新增如下程式碼: net.ipv4.ip_forward=1 執行以下命令,讓其配置立即生效 #sysctl-p
-----------------------------------------------------------------------------------------------------------------------------------
其實除了上面使用的pipework工具還,還可以使用虛擬交換機(Open vSwitch)進行docker容器間的網路通訊,廢話不多說,下面說下Open vSwitch的使用:
一、在Server1和Server2上分別安裝openvswitch [[email protected]~]#yuminstalldockerbridge-utilwgetopenssl-develkernel-devel-y [[email protected]~]#yumgroupinstall"DevelopmentTools"-y [[email protected]~]#adduserovswitch [[email protected]~]#su-ovswitch [[email protected]~]$wgethttp://openvswitch.org/releases/openvswitch-2.3.0.tar.gz [[email protected]~]$tar-zxvpfopenvswitch-2.3.0.tar.gz [[email protected]~]$mkdir-p~/rpmbuild/SOURCES [[email protected]~]$sed's/openvswitch-kmod,//g'openvswitch-2.3.0/rhel/openvswitch.spec>openvswitch-2.3.0/rhel/openvswitch_no_kmod.spec [[email protected]~]$cpopenvswitch-2.3.0.tar.gzrpmbuild/SOURCES/ [[email protected]~]$rpmbuild-bb--withoutcheck~/openvswitch-2.3.0/rhel/openvswitch_no_kmod.spec [[email protected]~]$exit [[email protected]~]#yumlocalinstall/home/ovswitch/rpmbuild/RPMS/x86_64/openvswitch-2.3.0-1.x86_64.rpm [[email protected]~]#mkdir/etc/openvswitch [[email protected]~]#setenforce0 [[email protected]~]#systemctlstartopenvswitch.service [[email protected]~]#chkconfigopenswitchon [[email protected]~]#systemctlstatusopenvswitch.service-l 二、在Slave1和Slave2上建立OVSBridge並配置路由 1)在Slave1宿主機上設定docker容器內網ip網段172.17.1.0/24 [[email protected]~]#vim/proc/sys/net/ipv4/ip_forward 1 [[email protected]~]#ovs-vsctladd-brobr0 [[email protected]~]#ovs-vsctladd-portobr0gre0--setInterfacegre0type=greoptions:remote_ip=10.10.172.204 [[email protected]~]#brctladdbrkbr0 [[email protected]~]#brctladdifkbr0obr0 [[email protected]~]#iplinksetdevdocker0down [[email protected]~]#iplinkdeldevdocker0 [[email protected]~]#brctlshow bridgenamebridgeidSTPenabledinterfaces kbr08000.f24f08040741noobr0 編輯/usr/lib/systemd/system/docker.service檔案,新增docker啟動選項"--bip=172.17.1.1/24"來指定docker0地址即可 [[email protected]~]#cat/usr/lib/systemd/system/docker.service [Unit] Description=DockerApplicationContainerEngine Documentation=http://docs.docker.com After=network.targetrhel-push-plugin.socketregistries.service Wants=docker-storage-setup.service Requires=docker-cleanup.timer [Service] Type=notify NotifyAccess=all EnvironmentFile=-/run/containers/registries.conf EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network Environment=GOTRACEBACK=crash Environment=DOCKER_HTTP_HOST_COMPAT=1 Environment=PATH=/usr/libexec/docker:/usr/bin:/usr/sbin ExecStart=/usr/bin/dockerd-current\ --add-runtimedocker-runc=/usr/libexec/docker/docker-runc-current\ --default-runtime=docker-runc\ --exec-optnative.cgroupdriver=systemd\ --userland-proxy-path=/usr/libexec/docker/docker-proxy-current\ --bip=172.17.1.1/24\ $OPTIONS\ $DOCKER_STORAGE_OPTIONS\ $DOCKER_NETWORK_OPTIONS\ $ADD_REGISTRY\ $BLOCK_REGISTRY\ $INSECURE_REGISTRY\ $REGISTRIES ExecReload=/bin/kill-sHUP$MAINPID LimitNOFILE=1048576 LimitNPROC=1048576 LimitCORE=infinity TimeoutStartSec=0 Restart=on-abnormal MountFlags=slave KillMode=process [Install] WantedBy=multi-user.target [[email protected]~]# [[email protected]~]#vim/etc/sysconfig/network-scripts/route-eth0 172.17.2.0/24via10.10.172.204deveth0 [[email protected]~]#systemctlrestartnetwork.service
檢視宿主機網絡卡資訊
[[email protected]~]#ipaddr 1:lo:<LOOPBACK,UP,LOWER_UP>mtu65536qdiscnoqueuestateUNKNOWN link/loopback00:00:00:00:00:00brd00:00:00:00:00:00 inet127.0.0.1/8scopehostlo valid_lftforeverpreferred_lftforever inet6::1/128scopehost valid_lftforeverpreferred_lftforever 2:eth0:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1500qdiscmqstateUPqlen1000 link/ether00:50:56:86:3e:d8brdff:ff:ff:ff:ff:ff inet10.10.172.203/24brd10.10.172.255scopeglobaleth0 valid_lftforeverpreferred_lftforever inet6fe80::250:56ff:fe86:3ed8/64scopelink valid_lftforeverpreferred_lftforever 4:ovs-system:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link/ether06:19:20:ae:f6:61brdff:ff:ff:ff:ff:ff 10:obr0:<BROADCAST,MULTICAST>mtu1500qdiscnoopmasterkbr0stateDOWN link/etherf2:4f:08:04:07:41brdff:ff:ff:ff:ff:ff 11:kbr0:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link/etherf2:4f:08:04:07:41brdff:ff:ff:ff:ff:ff 12:docker0:<NO-CARRIER,BROADCAST,MULTICAST,UP>mtu1500qdiscnoqueuestateDOWN link/ether02:42:ca:6c:84:a0brdff:ff:ff:ff:ff:ff inet172.17.1.1/24scopeglobaldocker0 valid_lftforeverpreferred_lftforever [[email protected]~]#
2)在Slave2宿主機上設定docker容器內網ip網段172.17.2.0/24 [[email protected]~]#vim/proc/sys/net/ipv4/ip_forward 1 [[email protected]~]#ovs-vsctladd-brobr0 [[email protected]~]#ovs-vsctladd-portobr0gre0--setInterfacegre0type=greoptions:remote_ip=10.10.172.203 [[email protected]~]#brctladdbrkbr0 [[email protected]~]#brctladdifkbr0obr0 [[email protected]~]#iplinksetdevdocker0down [[email protected]~]#iplinkdeldevdocker0 [[email protected]~]#brctlshow bridgenamebridgeidSTPenabledinterfaces kbr08000.f6ff0062b849noobr0 編輯/usr/lib/systemd/system/docker.service檔案,新增docker啟動選項"--bip=172.17.2.1/24"來指定docker0地址即可 [[email protected]~]#cat/usr/lib/systemd/system/docker.service [Unit] Description=DockerApplicationContainerEngine Documentation=http://docs.docker.com After=network.targetrhel-push-plugin.socketregistries.service Wants=docker-storage-setup.service Requires=docker-cleanup.timer [Service] Type=notify NotifyAccess=all EnvironmentFile=-/run/containers/registries.conf EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network Environment=GOTRACEBACK=crash Environment=DOCKER_HTTP_HOST_COMPAT=1 Environment=PATH=/usr/libexec/docker:/usr/bin:/usr/sbin ExecStart=/usr/bin/dockerd-current\ --add-runtimedocker-runc=/usr/libexec/docker/docker-runc-current\ --default-runtime=docker-runc\ --exec-optnative.cgroupdriver=systemd\ --userland-proxy-path=/usr/libexec/docker/docker-proxy-current\ --bip=172.17.2.1/24\ $OPTIONS\ $DOCKER_STORAGE_OPTIONS\ $DOCKER_NETWORK_OPTIONS\ $ADD_REGISTRY\ $BLOCK_REGISTRY\ $INSECURE_REGISTRY\ $REGISTRIES ExecReload=/bin/kill-sHUP$MAINPID LimitNOFILE=1048576 LimitNPROC=1048576 LimitCORE=infinity TimeoutStartSec=0 Restart=on-abnormal MountFlags=slave KillMode=process [Install] WantedBy=multi-user.target [[email protected]~]# [[email protected]~]#vim/etc/sysconfig/network-scripts/route-eth0 172.17.1.0/24via10.10.172.203deveth0 [[email protected]~]#systemctlrestartnetwork.service
檢視宿主機網絡卡資訊:
[[email protected]~]#ipaddr 1:lo:<LOOPBACK,UP,LOWER_UP>mtu65536qdiscnoqueuestateUNKNOWN link/loopback00:00:00:00:00:00brd00:00:00:00:00:00 inet127.0.0.1/8scopehostlo valid_lftforeverpreferred_lftforever inet6::1/128scopehost valid_lftforeverpreferred_lftforever 2:eth0:<BROADCAST,MULTICAST,UP,LOWER_UP>mtu1500qdiscmqstateUPqlen1000 link/ether00:50:56:86:22:d8brdff:ff:ff:ff:ff:ff inet10.10.172.204/24brd10.10.172.255scopeglobaleth0 valid_lftforeverpreferred_lftforever inet6fe80::250:56ff:fe86:22d8/64scopelink valid_lftforeverpreferred_lftforever 4:ovs-system:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link/etherbe:d4:64:ee:cb:29brdff:ff:ff:ff:ff:ff 8:obr0:<BROADCAST,MULTICAST>mtu1500qdiscnoopmasterkbr0stateDOWN link/etherf6:ff:00:62:b8:49brdff:ff:ff:ff:ff:ff 9:kbr0:<BROADCAST,MULTICAST>mtu1500qdiscnoopstateDOWN link/etherf6:ff:00:62:b8:49brdff:ff:ff:ff:ff:ff 10:docker0:<NO-CARRIER,BROADCAST,MULTICAST,UP>mtu1500qdiscnoqueuestateDOWN link/ether02:42:03:28:ae:dbbrdff:ff:ff:ff:ff:ff inet172.17.2.1/24scopeglobaldocker0 valid_lftforeverpreferred_lftforever [[email protected]~]#
三、啟動容器測試 Server1和Server2上修改docker啟動的虛擬網絡卡繫結為kbr0,重啟docker程序 1)在Server1宿主機上啟動容器,然後登陸容器內檢視ip,就會發現ip是上面設定值172.17.1.0/24網段的。 [[email protected]~]#dockerrun-idt--namemy-server1docker.io/centos/bin/bash [[email protected]~]#dockerexecmy-server1ifconfigeth0 eth0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500 inet172.17.1.2netmask255.255.255.0broadcast0.0.0.0 inet6fe80::42:acff:fe11:102prefixlen64scopeid0x20<link> ether02:42:ac:11:01:02txqueuelen0(Ethernet) RXpackets6555bytes13556099(12.9MiB) RXerrors0dropped0overruns0frame0 TXpackets5456bytes423669(413.7KiB) TXerrors0dropped0overruns0carrier0collisions0 2)在Server2宿主機上啟動容器,然後登陸容器內檢視ip,就會發現ip是上面設定值172.17.2.0/24網段的 [[email protected]~]#dockerrun-idt--namemy-server1docker.io/centos/bin/bash [[email protected]~]#dockerexecmy-server1ifconfigeth0 eth0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500 inet172.17.2.2netmask255.255.255.0broadcast0.0.0.0 inet6fe80::42:acff:fe11:202prefixlen64scopeid0x20<link> ether02:42:ac:11:02:02txqueuelen0(Ethernet) RXpackets5979bytes13412345(12.7MiB) RXerrors0dropped0overruns0frame0 TXpackets5136bytes366985(358.3KiB) TXerrors0dropped0overruns0carrier0collisions0 [[email protected]~]#dockerexec-itmy-server1/bin/bash [[email protected]/]#ping172.17.1.2 PING172.17.1.2(172.17.1.2)56(84)bytesofdata. 64bytesfrom172.17.1.2:icmp_seq=1ttl=62time=0.926ms ^C ---172.17.1.2pingstatistics--- 1packetstransmitted,1received,0%packetloss,time0ms rttmin/avg/max/mdev=0.926/0.926/0.926/0.000ms [[email protected]/]#exit exit [[email protected]~]# 然後在上面啟動的容內互ping對方容器,發現是可以ping通的。
注:docker宿主機IP轉發功能要啟用,不然docker容器不能正常上網的。
轉載於:https://blog.51cto.com/dengaosky/2067727