1 概述
php
docker0是net橋,自動建立,默認容器網絡只作snat,沒作dnat,容器能訪問外網,但不能被外網訪問。默認跨物理主機不能通訊。須要在net橋作dnat或者經過隧道方式,實現網絡的訪問。前端
docker啓動容器後會自動在宿主機建立NAT橋,網段默認爲172.17.0.0/16,容器啓動後,宿主機的防火牆會建立不少和docker相關的規則,使用命令iptables -t nat -vnL進行查看,如下的規則,說明只要源地址是172.16.0.16/16,且轉發出去的網絡不通過docker0橋,即不是內部轉發,就作地址假裝,即SNAT,target爲MASQUERADE node
Chain POSTROUTING (policy ACCEPT 1485 packets, 128K bytes)mysql
pkts bytes target prot opt in out source destination web
4 160 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0sql
NAT橋的特徵是當容器被關聯到docker0,網關指向172.17.0.1(docker0),且該容器須要和外部通信時,不通過docker0橋轉發,而是經過和外部網絡通信的網卡進行轉發,如本機還有地址192.168.0.66,能夠與外部訪問,則容器主動發出去的報文要被192.168.0.66轉發出去,且容器的對外訪問地址會被轉換爲192.168.0.66,所以能夠和外部訪問,外部回包後,192.168.0.66要經過dnat把地址轉轉換,才能把外部回來的報文返回給容器docker
可是,外部訪問的包,除非外部主機的網關指向了容器所在的物理網卡192.168.0.66,不然默認不能正常訪問到其餘主機docker容器。json
SNAT默認是容器能夠訪問外部,外部能夠回包,可是若是是外部主動訪問,則報文不可到達容器數組
兩個物理主機間的容器要相互訪問,即誇主機間容器訪問,此時須要作dnat(端口映射)才能實現,可是端口映射通常只映射有限的端口,如把一臺容器的80把映射出去(即暴露容器,或者叫發佈),和宿主機的80口關聯(也能夠是宿主機其餘端口)。安全
要是的跨主機間的容器無障礙互相訪問,即在二層間通訊,能夠經過隧道網絡實現,可是有個特例,若是跨主機容器都是同一私有ip,訪問會異常,爲了防止這種狀況出現,須要改變不一樣主機容器的默認地址,即默認爲172.17.0.0/16,此時可使用在不一樣物理主機,設置容器的地址爲172.16.1.0/24和172.17.2.0/24等不一樣網段,即人爲改變docker0橋的地址,作好不一樣宿主機的容器的網段規劃。這種狀況也稱爲疊加網絡
docker的網絡通常有兩個場景:
1.單主機虛擬網絡:提供容器隔離
2.多主機虛擬網絡:使用疊加網絡,確保多個物理主機間的容器能在二層間通訊,可是這個一般要藉助於其餘網絡構建工具,如k8s的服務註冊或者發現工具。
docker本地的網絡拓撲以下圖
一個容器,默認有本地接口(lookback口)和私有接口(如容器的eth0的172.17.0.2對應的口),注意虛擬網卡是成對出現的,如容器內部有eth0,而宿主機上出來docker0做爲網關,還有會隨機生成veth1e10b1f@if5這種網卡的名稱與容器的eth0配對。至關因而有兩根網線,一個插到容器,一個插到宿主機上。能夠經過安裝工具包bridge-utils來查看,命令brctl show
2 四種網絡模型
4種網絡模式的通訊方式以下截圖
1.橋接式容器,bridged container,爲本地網絡模式,默認是這種方式,不管是隔離橋,nat橋,僅主機橋,物理橋,只不過是橋的方式不同,都叫橋接式網絡,本質上,都是關聯到一個橋上。
2.封閉式容器,closed container.只有本地迴環口的容器。一般用於批處理操做或者運行備份的操做,沒有網絡需求的主機
3.加入式容器,joined container,也叫聯盟式容器,如兩個容器,A和B,使用同一組迴環口和相同的私有網卡對外訪問,可是容器除了網卡以外,其餘的網絡名稱空間是不同的。這種模型用途是,如LAMP架構中,php要和mysql通訊,若是網絡是橋接模式,則容器只能經過tcp通訊,若是是加入式網絡,php使用私有網絡,mysql使用迴環口,至關於兩個容器是一個主間上,則php和mysql可經過io通訊(使用迴環口)。php對外服務,可是mysql僅提供給php訪問,不給外部訪問。這種形式,使得容器至關於同一主機。
4.開放式容器,open container.容器共享宿主機的名稱空間,直接使用宿主機的名稱空間,這種方式不安全,由於對容器的網絡
docker使用網絡的方式
Docker安裝完成後,會自動建立三個網絡,可以使用「docker network ls」命令查看,都是本地
bridge :橋接式網絡,,默認指docker0,即bridged container
host :開放式網絡,主機橋,表示使用主機的網絡,即open container,主機網絡
none:封閉式網絡,指沒有網絡,不使用網絡,即closed container ,本地迴環口
建立容器時,可爲docker run命令使用--net選項指定要加入的網絡
封閉式容器:
不參與網絡通訊,運行於此類容器中的進程僅能訪問本地環回接口 v僅適用於進程無須網絡通訊的場景中,例如備份、進程診斷及各類離線任務等
docker run --rm --net none busybox:latest ifconfig -a
橋接式容器通常擁有兩個接口:一個環回接口和一個鏈接至主機上某橋設備的以太網接口
docker daemon啓動時默認會建立一個名爲docker0的網絡橋,而且建立的容器爲橋接式容器,其以太網接口橋接至docker0 . -默認--net bridge即爲將容器接口添加至 docker0橋
docker0橋爲NAT橋,所以,橋接式容器可經過此橋接口訪問外部網絡,但防火牆規則阻止了一切從外部網絡訪問橋接式容器的請求 ,若是要實現外部訪問容器,須要將容器的端口暴露,即便用dnat規則來暴露
使用docker network create 建立docker橋,能夠新建docker橋
docker run命令使用 ,跟網絡相關的選項以下:
「--hostname HOSTNAME」選項爲容器指定主機名,例如
docker run --rm --net bridge --hostname bbox.magedu.com busybox:latest nslookup bbox.magedu.com .
「--dns DNS_SERVER_IP」選項可以爲容器指定所使用的 dns服務器地址,以下爲172.16.0.1,例如
docker run --rm --dns 172.16.0.1 busybox:latest
「--add-host HOSTNAME:IP」選項可以爲容器指定本地主機名解析,表示在本機的/etc/hosts文件中寫入主機名docker.com解析爲ip 172.16.0.100,如
docker run --rm --dns 172.16.0.1 --add-host "docker.com:172.16.0.100" busybox cat /etc/hosts
不少時候,網絡相關參數,能夠在容器建立時,加入以上的參數,直接設定,不須要容器啓動後再進行添加
暴露端口的方法
Docker0爲NAT橋,所以容器通常得到的是私有網絡地址 v能夠把容器想像爲宿主機NAT服務背後的主機 v若是開放容器或其上的服務爲外部網絡訪問,須要在宿主機上爲其定義DNAT規則,例如 對宿主機某 IP地址的訪問所有映射給某容器地址
.主機 IP容器 IP
l -A PREROUTING -d主機 IP -j DNAT --to-destination容器 IP
.對宿主機某 IP地址的某端口的訪問映射給某容器地址的某端口
-p選項的使用格式 ,有四種寫法
-p <containerPort> .指明容器端口,將指定的容器端口映射至主機全部地址的一個動態端口 ,宿主機上的主機爲隨機生成
例子
啓動容器b1,暴露80口,-f表示httpd運行於前端
[root@docker ~]# docker run -it --name b1 --net bridge --rm --hostname www.sunny.com --dns 8.8.8.8 --add-host www.ghbsunny.cn:1.1.1.1 -v /docker/data/volumes/sunny:/data/htdocs -p 80 busybox /bin/httpd -f -h /data/htdocs
經過port命令查看被隨機分配的口爲32769與容器的80口對應
[root@docker ~]# docker port b1
80/tcp -> 0.0.0.0:32769
0.0.0.0表示宿主機的任意ip
[root@docker ~]#
在其餘主機上,訪問docker宿主機10.10.10.72的32769端口便可訪問到容器的80口
[root@monitor 73 ~]# curl 10.10.10.72:32769
hello sunny~
[root@monitor 73 ~]#
即此時容器b1的80口能夠被外部訪問了
-p <hostPort>:<containerPort> .將容器端口 <containerPort>映射至指定的主機端口 <hostPort> .
例子
將容器的80口暴露爲宿主機的80口
[root@docker ~]# docker run -it --name b1 --net bridge --rm --hostname www.sunny.com --dns 8.8.8.8 --add-host www.ghbsunny.cn:1.1.1.1 -v /docker/data/volumes/sunny:/data/htdocs -p 80:80 busybox /bin/httpd -f -h /data/htdocs
查看端口對應關係
[root@docker ~]# docker port b1
80/tcp -> 0.0.0.0:80
0.0.0.0表示宿主機的任意ip
[root@docker ~]#
在其餘主機上訪問
[root@monitor 73 ~]# curl 10.10.10.72
hello sunny~
[root@monitor 73 ~]#
-p <ip>::<containerPort> .將指定的容器端口 <containerPort>映射至宿主主機指定 <ip>的動態端口 .
例子
把容器的80口暴露爲宿主機的ip 10.10.10.72的隨機端口
[root@docker ~]# docker run -it --name b1 --net bridge --rm --hostname www.sunny.com --dns 8.8.8.8 --add-host www.ghbsunny.cn:1.1.1.1 -v /docker/data/volumes/sunny:/data/htdocs -p 10.10.10.72::80 busybox /bin/httpd -f -h /data/htdocs
查看
[root@docker ~]# docker port b1
80/tcp -> 10.10.10.72:32768
[root@docker ~]#
此時容器的80口被映射爲宿主機ip10.10.10.72的32768端口
測試
[root@monitor 73 ~]# curl 10.10.10.72:32768
hello sunny~
[root@monitor 73 ~]#
-p <ip>:<hostPort>:<containerPort> 將指定的容器端口<containerPort>映射至宿主機指定的<ip>的端口<hostPort>
例子
把容器的80口映射爲宿主機的ip 10.10.10.72的8090口
[root@docker ~]# docker run -it --name b1 --net bridge --rm --hostname www.sunny.com --dns 8.8.8.8 --add-host www.ghbsunny.cn:1.1.1.1 -v /docker/data/volumes/sunny:/data/htdocs -p 10.10.10.72:8090:80 busybox /bin/httpd -f -h /data/htdocs
查看
[root@docker ~]# docker port b1
80/tcp -> 10.10.10.72:8090
[root@docker ~]#
測試
[root@monitor 73 ~]# curl 10.10.10.72:8090
hello sunny~
[root@monitor 73 ~]#
端口暴露,實際上就是動態生成dnat規則,使得外部能夠訪問宿主機內部的容器服務,「動態端口」指隨機端口,具體的映射結果可使用docker port命令查看
「-P」選項(大寫P)或「--publish-all」將容器的全部計劃要暴露端口所有映射至主機端口
計劃要暴露的端口使用使用--expose選項指定 .例如 .
docker run -d -P --expose 2222 --expose 3333 --name web busybox:latest /bin/httpd -p 2222 -f
表示把容器的2222和3333端口隨機暴露
.查看映射結果
[root@docker ~]# docker port web
3333/tcp -> 0.0.0.0:32770
2222/tcp -> 0.0.0.0:32771
[root@docker ~]#
聯盟式網絡
聯盟式容器是指使用某個已存在容器的網絡接口的容器,接口被聯盟內的各容器共享使用;所以,聯盟式容器彼此間徹底無隔離
例如 .建立一個監聽於 2222端口的 http服務容器
docker run -it --rm -p 2222 --name b1 --dns 8.8.8.8 --add-host www.ghbsunny.cn:1.1.1.1 -v /docker/data/volumes/sunny:/container/data busybox /bin/httpd -p 2222 -f -h /container/data
建立一個聯盟式容器,並查看其監聽的端口 .注意--net後面的container是關鍵詞,而container後面的web爲容器名稱,即新的容器要加入b1這個容器的網絡,查看到此時容器的網絡相關屬性都是和web這個容器同樣
[root@docker ~]# docker run -it --rm --net container:b1 --name joined busybox:latest
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
1.1.1.1 www.ghbsunny.cn
172.17.0.2 882d643c642d
/ # cat /etc/resolv.conf
search localdomain
nameserver 8.8.8.8
/ #
若是要使得加載的卷也是同樣的,添加選項--volumes-from
[root@docker ~]# docker run -it --rm --net container:b1 --volumes-from b1 --name joined busybox:latest
/ # ls
bin dev home root tmp var
container etc proc sys usr
/ # cd container/
/container #
注意,聯盟式的網絡的不一樣容器,僅僅是網絡屬性相同,其餘的資源,若是要共享,要加入相關選項。即其餘名稱空間,如User,Mount等仍是隔離的。
聯盟式容器彼此間存在端口衝突的可能性,所以,一般只會在多個容器上的程序須要程序loopback接口互相通訊,或者對某已存在的容器的容量屬性進行監控時才使用此種網絡模式的網絡模型
以下例子,使用exec命令查看對比兩個容器運行進程
[root@docker ~]# docker exec b1 ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -p 2222 -f -h /container/data
6 root 0:00 ps aux
[root@docker ~]# docker exec joined ps aux
PID USER TIME COMMAND
1 root 0:00 sh
7 root 0:00 ps aux
[root@docker ~]#
開放式容器
開放式共享主機網絡名稱空間的容器,它們對主機的網絡名稱空間擁有所有的訪問權限,包括訪問那些關鍵性服務,這對宿主機安全性有很大潛在威脅
爲docker run命令使用「--net host」選項便可建立開放式容器,例如:
docker run -it --rm --net host --name b3 busybox:latest /bin/sh
建立一個橋
新建一個橋,四種橋,不使用默認的docker0,使用選項docker network create
docker橋建立後,須要有一個dhcp分配服務器ip,用ip-range指定dhcp範圍,在多主機網絡模型可使用-d overlay來建立疊加網絡,實現多主機間網絡通訊,這裏僅介紹普通的網絡
可用用 docker network create --help 查看相關參數選項
例子以下
建立名稱爲br0的橋(默認爲docker0),--driver指定爲對應的網絡類型,不指定driver,默認爲bridge的模式,注意,新增的網卡,不要和物理機的網絡衝突,不然網絡會異常,如本機有物理網卡是10.10.10.0/24,,那麼新增的網絡就不要指定--ip-range爲這個網絡
如下例子因爲地址分配範圍是從10.10.20.0開始分配,網卡爲10.10.20.1 ,因此,第一個加入到這個網絡的容器ip爲10.10.20.0,第二個加入到這個網絡的容器ip爲10.10.20.2。可是新增的網卡,不能訪問宿主機以外的網絡,若是要跨網絡互通,須要在宿主機的防火牆作nat。docker0默認是能夠訪問外部網絡。
[root@docker ~]# docker network create --subnet 10.10.0.0/16 --ip-range 10.10.20.0/24 --gateway 10.10.20.1 br0
此時默認新生成的br0爲橋接式網絡
刪除新增橋命令爲
docker network rm br0
注意,新增的網卡,在宿主機上,網卡名稱會改變,爲任意名稱,不是br0,這裏能夠經過在宿主機上配置,更改網卡名稱,不建議更改,以下
先把新增網卡關閉(不關閉更名,會提示設備繁忙),而後更名,最後開啓
[root@docker ~]# ip link set name br0 dev br-eda8e223510b
RTNETLINK answers: Device or resource busy
[root@docker ~]# ip link set dev br-eda8e223510b down
[root@docker ~]# ip link set name br0 dev br-eda8e223510b
[root@docker ~]# ip link set dev br0 up
更改前
更改後
可是,更名後,新建容器加入到這個接口名被更改的網絡名網卡時,會報錯,以下
因此不建議更名,宿主機的新增網卡名稱保持原來的隨機生成名稱便可
接口名和網絡名不必定一致,宿主機網卡名稱建議使用默認的就能夠,不更改,以下
若是要使得一個容器擁有多個網絡,那麼可使用connect命令來實現
執行命令以下
docker run --name b3 -it --rm --net br0 busybox
移除容器內部的某一個網卡
這裏移除容器b6的br0網卡
docker network disconnect br0 b6
配置docker守護進程的屬性信息的方法:/etc/docker/daemon.json
每個可設置的鍵是dockerd的可用的選項,操做系統不一樣,選項也不同,其值爲選項的參數;但有些參數不可用於此文件中,例如add-registry, insecure-registry;有些選項的參數是數組的格式,須要放置於[];
官方手冊(完整的可用參數列表):
https://docs.docker.com/engine/reference/commandline/dockerd/#run-multiple-daemons
dockerd守護進程的C/S,其默認僅監聽Unix SOcket格式的地址,/var/run/docker.sock;若是使用TCP套接字,
/etc/docker/daemon.json:
"hosts": ["tcp://0.0.0.0:2375"]
也可向dockerd直接傳遞「-H|--host」選項;
例子
修改默認橋分配的地址,如更改docker0,不使用默認的172.17.0.0/16的網絡
自定義docker0橋的網絡屬性信息:修改/etc/docker/daemon.json文件,注意,每對鍵值對最後用逗號隔開,每行一對,最後一行不能有逗號
{
"bip": "10.20.1.5/16"
}
注意這裏的bip就是bridge ip,爲默認的宿主機docker0對應的網卡ip.其餘參數能夠不指定,會根據這個參數進行生成。
配置完成後,重啓docker服務
systemctl restart docker.service
docker0的ip信息以下
注意,修改/etc/docker/daemon.json文件後,重啓docker服務,那麼即便把對應的信息去掉,但不更改,重啓服務,配置仍是會保留爲去掉原來的配置信息
以下
修改ip的配置已經去掉,重啓服務後,仍是同樣的docker0爲10.20.1.5的ip,不是默認的172.17.0.1這個ip。
docker0的ip信息依舊爲10.20.1.5,以下