防偽碼:不經(jīng)一番寒徹骨,怎得梅花撲鼻香。
docker技術(shù)剖析--docker網(wǎng)絡(luò)
一、 Docker 中的網(wǎng)絡(luò)功能介紹
默認(rèn)情況下,容器可以建立到外部網(wǎng)絡(luò)的連接,但是外部網(wǎng)絡(luò)無法連接到容器。
Docker 允許通過外部訪問容器或容器互聯(lián)的方式來提供網(wǎng)絡(luò)服務(wù)
外部訪問容器:
容器中可以運(yùn)行一些網(wǎng)絡(luò)應(yīng)用,要讓外部也可以訪問這些應(yīng)用,可以通過 -P 或 -p 參數(shù)來指定端口映射。
練習(xí)環(huán)境:運(yùn)行一個(gè)容器,提供web服務(wù)和ssh服務(wù)
宿主機(jī)啟用路由轉(zhuǎn)發(fā)(net.ipv4.ip_forward=1)
通過docker commit或dockerfile生成一個(gè)web應(yīng)用的鏡像,這里我通過docker dockerfile構(gòu)建鏡像模板
1) 創(chuàng)建一個(gè)sshd_dockerfile工作目錄
編輯run.sh文件
#!/bin/sh
/usr/sbin/httpd -D DFOREGROUND
/usr/sbin/sshd -D
在主機(jī)上生成ssh秘鑰對,并創(chuàng)建authorized_keys文件
在sshd_dockerfile目錄下,使用docker build命令來創(chuàng)建鏡像,注意:在最后還有一個(gè)”.”,表示使用當(dāng)前目錄中的dockerfile
執(zhí)行docker images查看新生成的鏡像
當(dāng)使用–P(大寫)標(biāo)記時(shí),Docker 會(huì)隨機(jī)映射一個(gè)隨機(jī)的端口到內(nèi)部容器開放的網(wǎng)絡(luò)端口。
注:-P使用時(shí)需要指定--expose選項(xiàng)或dockerfile中用expose指令容器要暴露的端口,指定需要對外提供服務(wù)的端口
使用 docker ps 可以看到,本地主機(jī)的32770被映射到了容器的22端口,本地主機(jī)的32769被映射到了容器的80端口,本地主機(jī)的32768被映射到了容器的443 端口。
此時(shí)訪問本機(jī)的 32770端口即可訪問容器內(nèi) ssh 應(yīng)用。
注:192.168.12.128是宿主主機(jī)地址。
查看容器運(yùn)行的httpd進(jìn)程
此時(shí)訪問本機(jī)的 32769端口即可訪問容器內(nèi) web 應(yīng)用
-p(小寫)則可以指定要映射的端口,并且,在一個(gè)指定端口上只可以綁定一個(gè)容器。支持的格式有
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
注意:
容器有自己的內(nèi)部網(wǎng)絡(luò)和 ip 地址(使用 docker inspect 可以獲取所有的變量。)
-p 標(biāo)記可以多次使用來綁定多個(gè)端口
映射所有接口地址:
使用 hostPort:containerPort 格式,將本地的10111端口映射到容器的 22 端口,本地的801端口映射到容器的80端口可以執(zhí)行
測試訪問:
1) ssh測試:
使用xshell工具:
測試web訪問
映射到指定地址的指定端口
可以使用 ip:hostPort:containerPort 格式,指定映射使用一個(gè)特定地址,比如宿主機(jī)網(wǎng)卡配置的一個(gè)地址192.168.12.128
映射到指定地址的任意端口
使用 ip::containerPort 綁定192.168.12.128的任意端口到容器的80端口,本地主機(jī)會(huì)自動(dòng)分配一個(gè)口。--name為啟動(dòng)的容器指定一個(gè)容器名。
注:還可以使用 udp 標(biāo)記來指定 udp 端口
# docker run -d -p 127.0.0.1:5000:5000/udp –name db4 commit:v1
查看映射端口配置
使用 docker port 來查看當(dāng)前映射的端口配置,也可以查看到綁定的地址
Docker NAT iptables實(shí)現(xiàn)
默認(rèn)情況下,容器可以主動(dòng)訪問到外部網(wǎng)絡(luò)的連接,但是外部網(wǎng)絡(luò)無法訪問到容器
容器訪問外部實(shí)現(xiàn)
容器所有到外部網(wǎng)絡(luò)的連接,源地址都會(huì)被 NAT 成本地系統(tǒng)的 IP 地址(即docker0地址)。這是使用 iptables 的源地址偽裝操作實(shí)現(xiàn)的
查看主機(jī)的 NAT 規(guī)則
其中,上述規(guī)則將所有源地址在 172.17.0.0/16 網(wǎng)段,目標(biāo)地址為其他網(wǎng)段(外部網(wǎng)絡(luò))的流量動(dòng)態(tài)偽裝為從系統(tǒng)網(wǎng)卡發(fā)出。MASQUERADE 跟傳統(tǒng) SNAT 的好處是它能動(dòng)態(tài)從網(wǎng)卡獲取地址。
外部訪問容器實(shí)現(xiàn)
容器允許外部訪問,可以在 docker run 時(shí)候通過 -p 或 -P 參數(shù)來啟用,不管用那種辦法,其實(shí)也是在本地的 iptable 的 nat 表中添加相應(yīng)的規(guī)則
使用 -P 時(shí):
# iptables -t nat –nvL
使用 -p 80:80 時(shí):
# iptables -t nat –nvL
docker0 網(wǎng)橋
Docker服務(wù)默認(rèn)會(huì)創(chuàng)建一個(gè) docker0 網(wǎng)橋(其上有一個(gè) docker0 內(nèi)部接口),它在內(nèi)核層連通了其他的物理或虛擬網(wǎng)卡,這就將所有容器和本地主機(jī)都放到同一個(gè)物理網(wǎng)絡(luò)。
Docker 默認(rèn)指定了 docker0 接口的 IP 地址和子網(wǎng)掩碼,讓主機(jī)和容器之間可以通過網(wǎng)橋相互通信
由于目前 Docker 網(wǎng)橋是 Linux 網(wǎng)橋,用戶可以使用 brctl show 來查看網(wǎng)橋和端口連接信息。
注:brctl 命令在centos中可以使用yum install bridge-utils 來安裝
每次創(chuàng)建一個(gè)新容器的時(shí)候,Docker 從可用的地址段中選擇一個(gè)空閑的 IP 地址分配給容器的eth0端口。使用本地主機(jī)上 docker0 接口的 IP 作為所有容器的默認(rèn)網(wǎng)關(guān)。
Docker 網(wǎng)絡(luò)配置
Docker 四種網(wǎng)絡(luò)模式
docker run 創(chuàng)建 Docker 容器時(shí),可以用 --net 選項(xiàng)指定容器的網(wǎng)絡(luò)模式,Docker 有以下 4 種網(wǎng)絡(luò)模式:
host 模式,使用 --net=host 指定。
container 模式,使用 --net=container:NAMEorID 指定。
none 模式,使用 --net=none 指定。
bridge 模式,使用 --net=bridge 指定,默認(rèn)設(shè)置。
如果啟動(dòng)容器的時(shí)候使用 host 模式,那么這個(gè)容器將不會(huì)獲得一個(gè)獨(dú)立的 Network Namespace,而是和宿主機(jī)共用一個(gè) Network Namespace。容器將不會(huì)虛擬出自己的網(wǎng)卡,配置自己的 IP 等,而是使用宿主機(jī)的 IP 和端口。
例如,我們在192.168.1.102/24 的機(jī)器上用 host 模式啟動(dòng)一個(gè)含有 web 應(yīng)用的 Docker 容器,監(jiān)聽 tcp 80 端口。當(dāng)我們在容器中執(zhí)行任何類似 ifconfig 命令查看網(wǎng)絡(luò)環(huán)境時(shí),看到的都是宿主機(jī)上的信息。而外界訪問容器中的應(yīng)用,則直接使用192.168.1.102:80 即可,不用任何 NAT 轉(zhuǎn)換,就如直接跑在宿主機(jī)中一樣。但是,容器的其他方面,如文件系統(tǒng)、進(jìn)程列表等還是和宿主機(jī)隔離的。
啟動(dòng)容器前,執(zhí)行pgrep http查看宿主機(jī)httpd進(jìn)程
上面顯示結(jié)果說明宿主機(jī)沒有httpd進(jìn)程運(yùn)行
用 host 模式啟動(dòng)一個(gè)含有 web 應(yīng)用的 Docker 容器
用瀏覽器訪問宿主機(jī)地址的80端口
注意防火墻:
container 模式
這個(gè)模式指定新創(chuàng)建的容器和已經(jīng)存在的一個(gè)容器共享一個(gè) Network Namespace,而不是和宿主機(jī)共享。新創(chuàng)建的容器不會(huì)創(chuàng)建自己的網(wǎng)卡,配置自己的 IP,而是和一個(gè)指定的容器共享 IP、端口范圍等。同樣,兩個(gè)容器除了網(wǎng)絡(luò)方面,其他的如文件系統(tǒng)、進(jìn)程列表等還是隔離的。兩個(gè)容器的進(jìn)程可以通過 lo 網(wǎng)卡設(shè)備通信。
運(yùn)行一個(gè)容器:查看容器的IP
將容器切換到后臺(tái)運(yùn)行:ctrl+p ctrl+q
在運(yùn)行一個(gè)容器使用container模式:查看新容器的地址
bridge模式
當(dāng) docker 啟動(dòng)時(shí),會(huì)在主機(jī)上創(chuàng)建一個(gè) docker0 的虛擬網(wǎng)卡。他隨機(jī)挑選 RFC1918 私有網(wǎng)絡(luò)中的一段地址給 docker0 。比如 172.17.0.1/16,16 位掩碼的網(wǎng)段可以擁有 65534 個(gè)地址可以使用,這對主機(jī)和容器來說應(yīng)該足夠了。
docker0 不是普通的網(wǎng)卡,他是橋接到其他網(wǎng)卡的虛擬網(wǎng)卡,容器使用它來和主機(jī)相互通信。當(dāng)創(chuàng)建一個(gè) docker 容器的時(shí)候,它就創(chuàng)建了一個(gè)對接口,當(dāng)數(shù)據(jù)包發(fā)送到一個(gè)接口時(shí),另外一個(gè)接口也可以收到相同的數(shù)據(jù)包,它們是綁在一起的一對孿生接口。這對接口在容器中那一端的的名字是 eth0 ,宿主主機(jī)端的會(huì)指定一個(gè)唯一的名字,比如 vethAQI2QT 這樣的名字。
所有的 veth* 的接口都會(huì)橋接到 docker0 ,這樣 docker 就創(chuàng)建了在主機(jī)和所有容器之間一個(gè)虛擬共享網(wǎng)
bridge 模式是 Docker 默認(rèn)的網(wǎng)絡(luò)設(shè)置,此模式會(huì)為每一個(gè)容器分配 Network Namespace、設(shè)置 IP 等,并將一個(gè)主機(jī)上的 Docker 容器連接到一個(gè)虛擬網(wǎng)橋上。當(dāng) Docker server 啟動(dòng)時(shí),會(huì)在主機(jī)上創(chuàng)建一個(gè)名為 docker0 的虛擬網(wǎng)橋,此主機(jī)上啟動(dòng)的 Docker 容器會(huì)連接到這個(gè)虛擬網(wǎng)橋上。虛擬網(wǎng)橋的工作方式和物理交換機(jī)類似,這樣主機(jī)上的所有容器就通過交換機(jī)連在了一個(gè)二層網(wǎng)絡(luò)中。接下來就要為容器分配 IP 了,Docker 會(huì)從 RFC1918 所定義的私有 IP 網(wǎng)段中,選擇一個(gè)和宿主機(jī)不同的IP地址和子網(wǎng)分配給 docker0,連接到 docker0 的容器就從這個(gè)子網(wǎng)中選擇一個(gè)未占用的 IP 使用。如一般 Docker 會(huì)使用 172.17.0.0/16 這個(gè)網(wǎng)段,并將 172.17.0.1/16 分配給 docker0 網(wǎng)橋(在主機(jī)上使用 ifconfig 命令是可以看到 docker0 的,可以認(rèn)為它是網(wǎng)橋的管理接口,在宿主機(jī)上作為一塊虛擬網(wǎng)卡使用)
Docker完成以上網(wǎng)絡(luò)配置的過程大致是這樣的:
1.在主機(jī)上創(chuàng)建一對虛擬網(wǎng)卡veth pair設(shè)備。veth設(shè)備總是成對出現(xiàn)的,它們組成了一個(gè)數(shù)據(jù)的通道,數(shù)據(jù)從一個(gè)設(shè)備進(jìn)入,就會(huì)從另一個(gè)設(shè)備出來。因此,veth設(shè)備常用來連接兩個(gè)網(wǎng)絡(luò)設(shè)備。
2.Docker將veth pair設(shè)備的一端放在新創(chuàng)建的容器中,并命名為eth0。另一端放在主機(jī)中,以veth65f9這樣類似的名字命名,并將這個(gè)網(wǎng)絡(luò)設(shè)備加入到docker0網(wǎng)橋中,可以通過brctl show命令查看。
注:brctl 工具依賴 bridge-utils 軟件包
3.從docker0子網(wǎng)中分配一個(gè)IP給容器使用,并設(shè)置docker0的IP地址為容器的默認(rèn)網(wǎng)關(guān)。
容器內(nèi)部訪問外網(wǎng)以及容器和主機(jī)之間的端口映射都是通過Iptables實(shí)現(xiàn)的,可以查看Iptables表分析。
查看當(dāng)前 docker0地址
在容器運(yùn)行時(shí),每個(gè)容器都會(huì)分配一個(gè)特定的虛擬機(jī)口并橋接到 docker0。每個(gè)容器都會(huì)配置同 docker0 ip 相同網(wǎng)段的專用 ip 地址,docker0 的 IP 地址被用于所有容器的默認(rèn)網(wǎng)關(guān)。
運(yùn)行一個(gè)容器:
查看當(dāng)前運(yùn)行的容器:
通過brctl show命令查看
以上, docker0 扮演著veth986582c容器的虛擬接口 vethxx interface 橋接的角色。
執(zhí)行docker network inspect bridge查看橋接網(wǎng)絡(luò)的詳細(xì)信息
自定義網(wǎng)橋
除了默認(rèn)的 docker0 網(wǎng)橋,用戶也可以指定網(wǎng)橋來連接各個(gè)容器。在啟動(dòng) Docker 服務(wù)的時(shí)候,使用 -b BRIDGE 或 --bridge=BRIDGE 來指定使用的網(wǎng)橋。
Docker 允許你管理 docker0 橋接或者通過-b選項(xiàng)自定義橋接網(wǎng)卡,需要安裝bridge-utils軟件包。
基本步驟如下:
1.確保 docker 的進(jìn)程是停止的
2.創(chuàng)建自定義網(wǎng)橋
3.給網(wǎng)橋分配特定的 ip
4.以 -b 的方式指定網(wǎng)橋
具體操作步驟:
如果服務(wù)已經(jīng)運(yùn)行,那需要先停止服務(wù),并刪除舊的網(wǎng)橋
然后創(chuàng)建一個(gè)網(wǎng)橋 bridge0,給網(wǎng)橋分配特定的 ip
查看確認(rèn)網(wǎng)橋創(chuàng)建并啟動(dòng)
或
修改/etc/sysconfig/docker文件
修改前:
修改后:添加前面所新建的網(wǎng)橋
啟動(dòng) Docker 服務(wù)。
新建一個(gè)容器,可以看到它已經(jīng)橋接到了 bridge0 上。
進(jìn)入容器,查看容器的IP
docker 服務(wù)啟動(dòng)成功并綁定容器到新的網(wǎng)橋,新建一個(gè)容器,你會(huì)看到它的 ip 是我們的設(shè)置的新 ip段, docker 會(huì)自動(dòng)檢測到它。用 brctl show 可以看到容器啟動(dòng)或則停止后網(wǎng)橋的配置變化,在容器中使用 ip a 和 ip r 來查看 ip 地址配置和路由信息。
讓我們回顧一些基礎(chǔ)知識:
機(jī)器需要一個(gè)網(wǎng)絡(luò)接口來發(fā)送和接受數(shù)據(jù)包,路由表來定義如何到達(dá)哪些地址段。這里的網(wǎng)絡(luò)接口可以不是物理接口。事實(shí)上,每個(gè) linux 機(jī)器上的 lo 環(huán)回接口( docker 容器中也有)就是一個(gè)完全的linux 內(nèi)核虛擬接口,它直接復(fù)制發(fā)送緩存中的數(shù)據(jù)包到接收緩存中。 docker 讓宿主主機(jī)和容器使用特殊的虛擬接口來通信 -- 通信的 2 端叫“ peers“,他們在主機(jī)內(nèi)核中連接在一起,所以能夠相互通信。創(chuàng)建他們很簡單,前面介紹過了。
docker 創(chuàng)建容器的步驟如下:
創(chuàng)建一對虛擬接口
其中宿主主機(jī)一端使用一個(gè)名字比如 veth65f9 ,他是唯一的 , 另外一端橋接到默認(rèn)的 docker0, 或其它你指定的橋接網(wǎng)卡。
主機(jī)上的 veth65f9 這種接口映射到新的新容器中的名稱通常是eth0, 在容器這個(gè)隔離的 networknamespace 中,它是唯一的,不會(huì)有其他接口名字和它沖突。
從主機(jī)橋接網(wǎng)卡的地址段中獲取一個(gè)空閑地址給eth0使用,并設(shè)定默認(rèn)路由到橋接網(wǎng)卡。
完成這些之后,容器就可以使用這eth0虛擬網(wǎng)卡來連接其他容器和其他網(wǎng)絡(luò)。
你也可以為特殊的容器設(shè)定特定的參數(shù),在 docker run 的時(shí)候使用 --net ,它有 4 個(gè)可選參數(shù):
--net=bridge :默認(rèn)連接到 docker0 網(wǎng)橋。
--net=host :告訴 docker 不要將容器放到隔離的網(wǎng)絡(luò)堆棧中。盡管容器還是有自己的文件系統(tǒng)、進(jìn)程列表和資源限制。但使用 ip addr 命令這樣命令就可以知道實(shí)際上此時(shí)的的容器處于和 docker 宿主主機(jī)的一樣的網(wǎng)絡(luò)級別,它擁有完全的宿主主機(jī)接口訪問權(quán)限。雖然它不允許容器重新配置主機(jī)的網(wǎng)絡(luò)堆棧,除非 --privileged=true,—但是容器進(jìn)程可以跟其他 root 進(jìn)程一樣可以打開低數(shù)字的端口,可以訪問本地網(wǎng)絡(luò)服務(wù)比如 D-bus ,還可以讓容器做一些意想不到的事情,比如重啟主機(jī),使用這個(gè)選項(xiàng)的時(shí)候要非常小心!
--net=container:NAME_or_ID :告訴 docker 將新容器的進(jìn)程放到一個(gè)已經(jīng)存在的容器的網(wǎng)絡(luò)堆棧中,新容器進(jìn)程有它自己的文件系統(tǒng)、進(jìn)程列表和資源限制,但它會(huì)和那個(gè)已經(jīng)存在的容器共享 ip 地址和端口,他們之間來可以通過環(huán)回接口通信。
--net=none :告訴 docker 將新容器放到自己的網(wǎng)絡(luò)堆棧中,但是不要配置它的網(wǎng)絡(luò)。
下面通過配置一個(gè)以 --net=none 啟動(dòng)的容器,使他達(dá)到跟平常一樣具有訪問網(wǎng)絡(luò)的權(quán)限。來介紹docker 是如何連接到容器中的。
啟動(dòng)一個(gè)運(yùn)行 /bin/bash的容器,并指定 --net=none
再開啟一個(gè)新的終端,查找這個(gè)容器的進(jìn)程 id ,然后創(chuàng)建它的命名空間,后面的 ip netns會(huì)用到
檢查橋接網(wǎng)卡的 ip 和子網(wǎng)掩碼
創(chuàng)建一對” peer“接口 A 和 B ,綁定 A 到網(wǎng)橋,并啟用它
將 B 放到容器的網(wǎng)絡(luò)命名空間,命名為eth0, 配置一個(gè)空閑的 ip
自此,你又可以像平常一樣使用網(wǎng)絡(luò)了
當(dāng)你退出容器后, docker 清空容器,容器的eth0隨網(wǎng)絡(luò)命名空間一起被摧毀, A 接口也被自動(dòng)從docker0 取消注冊。不用其他命令,所有東西都被清理掉了!
注意 ip netns exec 命令,它可以讓我們像 root 一樣配置網(wǎng)絡(luò)命名空間。但在容器內(nèi)部無法使用,因?yàn)榻y(tǒng)一的安全策略, docker 限制容器進(jìn)程配置自己的網(wǎng)絡(luò)。使用 ip netns exec 可以讓我們不用設(shè)置 --privileged=true 就可以完成一些可能帶來危險(xiǎn)的操作。
DNS/HOSTNAME自定義
Docker 沒有為每個(gè)容器專門定制鏡像,那么怎么自定義配置容器的主機(jī)名和 DNS 配置呢?秘訣就是它利用虛擬文件來掛載到來容器的 3 個(gè)相關(guān)配置文件。
在容器中使用 mount 命令可以看到掛載信息:注(mount命令軟件包util-linux)
# mount
...
這種機(jī)制可以讓宿主主機(jī) DNS 信息發(fā)生更新后,所有 Docker 容器的 dns 配置通過 /etc/resolv.conf文件立刻得到更新。
如果用戶想要手動(dòng)指定容器的配置,可以利用下面的選項(xiàng)。
-h HOSTNAME or --hostname=HOSTNAME 設(shè)定容器的主機(jī)名,它會(huì)被寫到容器內(nèi)的/etc/hostname 和 /etc/hosts。但它在容器外部看不到,既不會(huì)在 docker ps 中顯示,也不會(huì)在其他的容器的 /etc/hosts 看到。
--link=CONTAINER_NAME:ALIAS 選項(xiàng)會(huì)在創(chuàng)建容器的時(shí)候,添加一個(gè)其他容器的主機(jī)名到
/etc/hosts 文件中,讓新容器的進(jìn)程可以使用主機(jī)名 ALIAS 就可以連接它。
--dns=IP_ADDRESS 添加 DNS 服務(wù)器到容器的 /etc/resolv.conf 中,讓容器用這個(gè)服務(wù)器來解析所有不在 /etc/hosts 中的主機(jī)名。
--dns-search=DOMAIN 設(shè)定容器的搜索域,當(dāng)設(shè)定搜索域?yàn)?.example.com 時(shí),在搜索一個(gè)名為 host的主機(jī)時(shí), DNS 不僅搜索 host,還會(huì)搜索 host.example.com。注意:如果沒有上述最后 2 個(gè)選項(xiàng),Docker 會(huì)默認(rèn)用主機(jī)上的 /etc/resolv.conf 來配置容器。
具體其他選項(xiàng)可以查看docker run --help幫助
docker中的容器互聯(lián)--linking 系統(tǒng)
docker 有一個(gè) linking 系統(tǒng)可以連接多個(gè)容器。它會(huì)創(chuàng)建一對父子關(guān)系,父容器可以看到所選擇的子容器的信息。該系統(tǒng)會(huì)在源和接收容器之間創(chuàng)建一個(gè)隧道,接收容器可以看到源容器指定的信息
自定義容器的命名
linking系統(tǒng)依據(jù)容器的名稱來執(zhí)行,因此,首先需要自定義一個(gè)好記的容器命名。當(dāng)我們創(chuàng)建容器的時(shí)候,系統(tǒng)會(huì)隨機(jī)分配一個(gè)名字。當(dāng)然我們也可以自己來命名容器,這樣做有 2 個(gè)好處:
當(dāng)我們自己指定名稱的時(shí)候,比較好記,比如一個(gè) web 應(yīng)用我們可以給它起名叫 web
當(dāng)我們要連接其他容器時(shí)候,可以作為一個(gè)有用的參考點(diǎn),比如連接 web 容器到 db 容器
使用 --name 標(biāo)記可以為容器自定義命名。使用 docker ps 來驗(yàn)證設(shè)定的命名,也可以使用 docker inspect 來查看容器的名字docker inspect -f "{{ .Name }}" 容器id
注意:容器的名稱是唯一的。如果已經(jīng)命名了一個(gè)叫 web 的容器,當(dāng)你要再次使用 web 這個(gè)名稱的時(shí)候,需要先用 docker rm 來刪除之前創(chuàng)建的同名容器。
在執(zhí)行 docker run 的時(shí)候如果添加 --rm 標(biāo)記,則容器在終止后會(huì)立刻刪除。注意, --rm 和 -d 參數(shù)不能同時(shí)使用。
容器互聯(lián)
使用--link參數(shù)可以讓容器之間安全的進(jìn)行交互。
下面先創(chuàng)建一個(gè)新的數(shù)據(jù)庫容器。
docker run -dit --name dbserver鏡像id
然后創(chuàng)建一個(gè)新的 web 容器,并將它連接到 db 容器
--link 標(biāo)記的格式: --link name:alias , name 是我們要鏈接的容器的名稱, alias 是這個(gè)鏈接的別名。
使用docker ps來查看容器的連接
我們可以看到我們命名的容器, dbserver 和 web , dbserver 容器的 names 列有 dbserver 也有 web/dbserver 。這表示 web 容器鏈接到 db 容器,他們是一個(gè)父子關(guān)系。在這個(gè) link 中, 2 個(gè)容器中有一對父子關(guān)系。 docker 在 2 個(gè)容器之間創(chuàng)建了一個(gè)安全的連接,而且不用映射dbserver容器的端口到宿主主機(jī)上。所以在啟動(dòng) db 容器的時(shí)候也不用 -p 和 -P 標(biāo)記。使用 link 之后我們就可以不用暴露數(shù)據(jù)庫端口到網(wǎng)絡(luò)上。
注意:你可以鏈接多個(gè)子容器到父容器,比如我們可以鏈接多個(gè) web 到 db 容器上。
Docker 會(huì)添加子容器的 host 信息到父容器的 /etc/hosts 的文件。
下面是父容器 web 的 hosts 文件
這里有 2 個(gè) hosts,第一個(gè)是 web 容器,web 容器用 id 作為他的主機(jī)名,第二個(gè)是 dbserver 容器的 ip 和主機(jī)名??梢栽?web 容器中安裝 ping 命令來測試跟dbserver容器的連通。
注意:官方的鏡像默認(rèn)沒有安裝 ping,需要自行安裝,軟件包名iputils
用 ping 來測試db容器,
附:在bridge模式下,連在同一網(wǎng)橋上的容器可以相互通信(若出于安全考慮,也可以禁止它們之間通信,方法是在DOCKER_OPTS變量中設(shè)置--icc=false,這樣只有使用--link才能使兩個(gè)容器通信)。
多臺(tái)物理主機(jī)之間的容器互聯(lián)(暴露容器到真實(shí)網(wǎng)絡(luò)中)
docker 默認(rèn)的橋接網(wǎng)卡是 docker0 。它只會(huì)在本機(jī)橋接所有的容器網(wǎng)卡,舉例來說容器的虛擬網(wǎng)卡在主機(jī)上看一般叫做 vethxxx,而 docker 只是把所有這些網(wǎng)卡橋接在一起,如下:
這樣就可以把這個(gè)網(wǎng)絡(luò)看成是一個(gè)私有的網(wǎng)絡(luò),通過 nat 連接外網(wǎng),如果要讓外網(wǎng)連接到容器中,就需要做端口映射,即 -p 參數(shù)。
如果在企業(yè)內(nèi)部應(yīng)用,或則做多個(gè)物理主機(jī)的集群,可能需要將多個(gè)物理主機(jī)的容器組到一個(gè)物理網(wǎng)絡(luò)中來,那么就需要將這個(gè)網(wǎng)橋橋接到我們指定的網(wǎng)卡上。
主機(jī) A 和主機(jī) B 的網(wǎng)卡一都連著物理交換機(jī)的同一個(gè) vlan 101, 這樣網(wǎng)橋一和網(wǎng)橋三就相當(dāng)于在同一個(gè)物理網(wǎng)絡(luò)中了,而容器一、容器三、容器四也在同一物理網(wǎng)絡(luò)中了,他們之間可以相互通信,而且可以跟同一 vlan 中的其他物理機(jī)器互聯(lián)。
這樣就直接把容器暴露到物理網(wǎng)絡(luò)上了,多臺(tái)物理主機(jī)的容器也可以相互聯(lián)網(wǎng)了。需要注意的是,這樣就需要自己來保證容器的網(wǎng)絡(luò)安全了。
不同容器之間的通信可以借助于 pipework 這個(gè)工具
pipework是由Docker的工程師Jérôme Petazzoni開發(fā)的一個(gè)Docker網(wǎng)絡(luò)配置工具,由200多行shell實(shí)現(xiàn),方便易用。
下載地址:wget https://github.com/jpetazzo/pipework.git
unzip pipework-master.zip
cp -p /root/pipework-master/pipework /usr/local/bin/
安裝相應(yīng)依賴軟件
yum install bridge-utils -y
配置橋接網(wǎng)絡(luò)
重啟network服務(wù)并查看IP地址
把 docker 的橋接指定為 br0,這樣跨主機(jī)不同容器之間通過 pipework 新建 docker 容器的網(wǎng)卡橋接到 br0,這樣跨主機(jī)容器之間就可以通信了。
CentOS 7/RHEL 7系統(tǒng)
#systemctl stop docker
修改/etc/sysconfig/docker
#systemctl start docker
pipework
把 docker 默認(rèn)橋接指定到了 br0,則最好在創(chuàng)建容器的時(shí)候加上--net=none,防止自動(dòng)分配的 IP 在局域網(wǎng)中有沖突。
使用鏡像運(yùn)行一個(gè)容器
注:默認(rèn)不指定網(wǎng)卡設(shè)備名,則默認(rèn)添加為 eth1
注:另外 pipework 不能添加靜態(tài)路由,如果有需求則可以在 run 的時(shí)候加上 --privileged=true 權(quán)限在容器中手動(dòng)添加,但這種安全性有缺陷,可以通過 ip netns 操作
route -n
訪問容器提供的web服務(wù):
pipework可以在下面用三個(gè)場景來使用和工作原理。
1、將Docker容器配置到本地網(wǎng)絡(luò)環(huán)境中
為了使本地網(wǎng)絡(luò)中的機(jī)器和Docker容器更方便的通信,我們經(jīng)常會(huì)有將Docker容器配置到和主機(jī)同一網(wǎng)段的需求。這個(gè)需求其實(shí)很容易實(shí)現(xiàn),我們只要將Docker容器和主機(jī)的網(wǎng)卡橋接起來,再給Docker容器配上IP就可以了。
下面我們來操作一下,我主機(jī)A地址為192.168.1.102/24,網(wǎng)關(guān)為192.168.1.1,需要給Docker容器的地址配置為192.168.1.150/24。在主機(jī)A上做如下操作:
安裝pipework
下載地址:wget https://github.com/jpetazzo/pipework.git
unzip pipework-master.zip
cp -p /root/pipework-master/pipework /usr/local/bin/
啟動(dòng)Docker容器。
docker run -itd --name test1 鏡像 /bin/bash
配置容器網(wǎng)絡(luò),并連到網(wǎng)橋br0上。網(wǎng)關(guān)在IP地址后面加@指定。
pipework
br0 test1 192.168.1.150/24@192.168.1.1
將主機(jī)enp0s3橋接到br0上,并把enp0s3的IP配置在br0上。
ip addr add 192.168.1.102/24 dev br0
ip addr del 192.168.1.102/24 dev enp0s3
brctl addif br0 enp0s3
ip route del default
ip route add default via192.168.1.1 dev br0
注:如果是遠(yuǎn)程操作,中間網(wǎng)絡(luò)會(huì)斷掉,所以放在一條命令中執(zhí)行。
ip addr add 192.168.1.102/24 dev br0; \ ip addr del 192.168.1.102/24 dev enp0s3; \ brctl addif br0 enp0s3; \
ip route del default; \ ip route add default via192.168.1.1 dev br0
完成上述步驟后,我們發(fā)現(xiàn)Docker容器已經(jīng)可以使用新的IP和主機(jī)網(wǎng)絡(luò)里的機(jī)器相互通信了。
進(jìn)入容器內(nèi)部查看容器的地址:
pipework工作原理分析
那么容器到底發(fā)生了哪些變化呢?我們docker attach到test1上,發(fā)現(xiàn)容器中多了一塊eth1的網(wǎng)卡,并且配置了192.168.1.150/24的IP,而且默認(rèn)路由也改為了192.168.1.1。這些都是pipework幫我們配置的。
首先pipework檢查是否存在br0網(wǎng)橋,若不存在,就自己創(chuàng)建。
創(chuàng)建veth pair設(shè)備,用于為容器提供網(wǎng)卡并連接到br0網(wǎng)橋。
使用docker inspect找到容器在主機(jī)中的PID,然后通過PID將容器的網(wǎng)絡(luò)命名空間鏈接到/var/run/netns/目錄下。這么做的目的是,方便在主機(jī)上使用ip netns命令配置容器的網(wǎng)絡(luò)。因?yàn)?,在Docker容器中,我們沒有權(quán)限配置網(wǎng)絡(luò)環(huán)境。
將之前創(chuàng)建的veth pair設(shè)備分別加入容器和網(wǎng)橋中。在容器中的名稱默認(rèn)為eth1,可以通過pipework的-i參數(shù)修改該名稱。
然后就是配置新網(wǎng)卡的IP。若在IP地址的后面加上網(wǎng)關(guān)地址,那么pipework會(huì)重新配置默認(rèn)路由。這樣容器通往外網(wǎng)的流量會(huì)經(jīng)由新配置的eth1出去,而不是通過eth0和docker0。(若想完全拋棄自帶的網(wǎng)絡(luò)設(shè)置,在啟動(dòng)容器的時(shí)候可以指定--net=none)
以上就是pipework配置Docker網(wǎng)絡(luò)的過程,這和Docker的bridge模式有著相似的步驟。事實(shí)上,Docker在實(shí)現(xiàn)上也采用了相同的底層機(jī)制。
通過源代碼,可以看出,pipework通過封裝Linux上的ip、brctl等命令,簡化了在復(fù)雜場景下對容器連接的操作命令,為我們配置復(fù)雜的網(wǎng)絡(luò)拓?fù)涮峁┝艘粋€(gè)強(qiáng)有力的工具。當(dāng)然,如果想了解底層的操作,我們也可以直接使用這些Linux命令來完成工作,甚至可以根據(jù)自己的需求,添加額外的功能。
2、單主機(jī)Docker容器VLAN劃分
pipework不僅可以使用Linux bridge連接Docker容器,還可以與OpenVswitch結(jié)合,實(shí)現(xiàn)Docker容器的VLAN劃分。下面,就來簡單演示一下,在單機(jī)環(huán)境下,如何實(shí)現(xiàn)Docker容器間的二層隔離。
為了演示隔離效果,我們將4個(gè)容器放在了同一個(gè)IP網(wǎng)段中。但實(shí)際他們是二層隔離的兩個(gè)網(wǎng)絡(luò),有不同的廣播域。
安裝openvswitch
安裝基礎(chǔ)環(huán)境
yum install gcc make python-devel openssl-devel kernel-devel graphviz \
kernel-debug-devel autoconf automake rpm-build redhat-rpm-config \
libtool
下載openvswitch的包
wget http://openvswitch.org/releases/openvswitch-2.3.1.tar.gz
解壓與打包
之后會(huì)在~/rpmbuild/RPMS/x86_64/里有2個(gè)文件
安裝第一個(gè)就行
啟動(dòng)
或
systemctl start openvswitch
查看狀態(tài)
或
可以看到是正常運(yùn)行狀態(tài)
安裝pipework過程略,參考前面的操作
創(chuàng)建交換機(jī),把物理網(wǎng)卡加入ovs1
在主機(jī)A上創(chuàng)建4個(gè)Docker容器,test1、test2、test3、test4
將test1,test2劃分到一個(gè)vlan中,
將test3,test4劃分到另一個(gè)vlan中
vlan在mac地址后加@指定,此處mac地址省略。(注:有空格)
完成上述操作后,使用docker attach連到容器中,然后用ping命令測試連通性,發(fā)現(xiàn)test1和test2可以相互通信,但與test3和test4隔離。這樣,一個(gè)簡單的VLAN隔離容器網(wǎng)絡(luò)就已經(jīng)完成。
驗(yàn)證:
由于Openvwitch本身支持VLAN功能,所以這里pipework所做的工作和之前介紹的基本一樣,只不過將Linux bridge替換成了OpenVswitch,在將veth pair的一端加入ovs0網(wǎng)橋時(shí),指定了tag。底層操作如下:
ovs-vsctl add-port ovs0 veth* tag=100
3 、多主機(jī)Docker容器的VLAN劃分
上面介紹完了單主機(jī)上VLAN的隔離,下面我們將情況延伸到多主機(jī)的情況。有了前面兩個(gè)例子做鋪墊,這個(gè)也就不難了。為了實(shí)現(xiàn)這個(gè)目的,我們把宿主機(jī)上的網(wǎng)卡橋接到各自的OVS網(wǎng)橋上,然后再為容器配置IP和VLAN就可以了。我們實(shí)驗(yàn)環(huán)境如下,主機(jī)A和B各有一塊網(wǎng)卡enp0s3,IP地址分別為10.10.101.105/24、10.10.101.106/24。在主機(jī)A上創(chuàng)建兩個(gè)容器test1、test2,分別在VLAN
100和VLAN 200上。在主機(jī)B上創(chuàng)建test3、test4,分別在VLAN 100和VLAN 200 上。最終,test1可以和test3通信,test2可以和test4通信。
拓?fù)鋱D如下所示
在主機(jī)A上
創(chuàng)建Docker容器
docker run -itd --name test1 ubuntu /bin/bash
docker run -itd --name test2 ubuntu /bin/bash
劃分VLAN
pipework ovs0 test1 192.168.0.1/24 @100
pipework ovs0 test2 192.168.0.2/24 @200
將eth0橋接到ovs0上
ip addr add 10.10.101.105/24 dev ovs0
ip addr del 10.10.101.105/24 dev eth0;
ovs-vsctl add-port ovs0 eth0
ip route del default
ip route add default gw 10.10.101.254 dev ovs0
在主機(jī)B上
創(chuàng)建Docker容器
docker run -itd --name
test3 ubuntu /bin/bash
docker run -itd --name test4 ubuntu /bin/bash
劃分VLAN
pipework ovs0 test1 192.168.0.3/24 @100
pipework ovs0 test2 192.168.0.4/24 @200
將eth0橋接到ovs0上
ip addr add 10.10.101.106/24 dev ovs0
ip addr del 10.10.101.106/24 dev eth0;
ovs-vsctl add-port ovs0 eth0
ip route del default
ip route add default gw 10.10.101.254 dev ovs0
完成上面的步驟后,主機(jī)A上的test1和主機(jī)B上的test3容器就劃分到了一個(gè)VLAN中,并且與主機(jī)A上的test2和主機(jī)B上的test4隔離(主機(jī)eth0網(wǎng)卡需要設(shè)置為混雜模式,連接主機(jī)的交換機(jī)端口應(yīng)設(shè)置為trunk模式,即允許VLAN
100和VLAN 200的包通過)。
注:除此之外,pipework還支持使用macvlan設(shè)備、設(shè)置網(wǎng)卡MAC地址等功能。不過,pipework有一個(gè)缺陷,就是配置的容器在關(guān)掉重啟后,之前的設(shè)置會(huì)丟失。
其中promisc表示網(wǎng)卡混雜模式
其他參數(shù)的含義:
UP: 表示網(wǎng)卡開啟狀態(tài);
BROADCAST: 表示支持廣播;
promisc: 表示網(wǎng)卡混雜模式;
RUNNING: 表示網(wǎng)卡的網(wǎng)線被接上;
MULTICAST: 表示支持組播;
MTU: 表示MaximumTrasmission Unit 最大傳輸單元(字節(jié)),即此接口一次所能傳輸?shù)淖畲蠓獍?/span>
RX: 表示網(wǎng)絡(luò)由激活到目前為止接收的數(shù)據(jù)包;
TX: 表示網(wǎng)絡(luò)由激活到目前為止發(fā)送的數(shù)據(jù)包;
collisions: 表示網(wǎng)絡(luò)信號沖突的情況;
txqueuelen: 表示傳輸緩沖區(qū)長度大?。?/span>
設(shè)置網(wǎng)卡工作模式
#ifconfig 網(wǎng)卡名 promisc 設(shè)置混雜
#ifconfig 網(wǎng)卡名 -promisc 取消混雜
網(wǎng)卡工作模式有4種,分別是:
廣播(Broadcast)模式
多播(Multicast)模式
單播模式(Unicast)
混雜模式(Promiscuous)
在混雜模式下的網(wǎng)卡能夠接收一切通過它的數(shù)據(jù),而不管該數(shù)據(jù)目的地址是否是它。如果通過程序?qū)⒕W(wǎng)卡的工作模式設(shè)置為
“混雜模式”,那么網(wǎng)卡將接受所有流經(jīng)它的數(shù)據(jù)幀,這實(shí)際上就是Sniffer工作的基本原理:讓網(wǎng)卡接收一切他所能接收的數(shù)據(jù)。Sniffer就是一種 能將本地網(wǎng)卡狀態(tài)設(shè)成混雜(promiscuous)狀態(tài)的軟件,當(dāng)網(wǎng)卡處于這種"混雜"方式時(shí),它對所有遇到的每一個(gè)數(shù)據(jù)幀都
產(chǎn)生一個(gè)硬件中斷以便提醒操作系統(tǒng)處理流經(jīng)該物理媒體上的每一個(gè)報(bào)文包??梢?,Sniffer工作在網(wǎng)絡(luò)環(huán)境中的底層,它會(huì)攔截所有的正在網(wǎng)絡(luò)上傳送的數(shù)據(jù),并且通過相應(yīng)的軟件處理,可以實(shí)時(shí)分析這些數(shù)據(jù)的內(nèi)容,進(jìn)而分析所處的網(wǎng)絡(luò)狀態(tài)和整體布局。
謝謝觀看,真心的希望能幫到您!
本文出自 “一盞燭光” 博客,謝絕轉(zhuǎn)載!
更多建議: