Dcoker學習筆記(三) 網絡配置和數據卷

容器與外部網絡的鏈接

容器在啓動時能夠經過 -P 或 -p 參數來指定端口映射。docker

當使用 -P 標記時,Docker 會隨機映射一個 49000~49900 的端口到內部容器開放的網絡端口。json

-p 則指定要映射的端口,而且,在一個指定端口上只能夠綁定一個容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPortubuntu

映射全部接口地址

使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口,能夠執行安全

$ docker run -d -p 127.0.0.1:5000:5000 ubuntu
映射到指定地址的任意端口

使用 ip::containerPort 綁定 localhost 的任意端口到容器的 5000 端口,本地主機會自動分配一個端口。bash

$ docker run -d -p 127.0.0.1::5000 ubuntu

使用 udp 標記來指定 udp 端口服務器

docker run -d -p 127.0.0.1:5000:5000/udp ubuntu

容器互聯

隨着 Docker 網絡的完善,強烈建議將容器加入自定義的 Docker 網絡來鏈接多個容器。網絡

新建網絡

新建 docker 網絡tcp

$ docker network create -d bridge my-net

-d 參數指定 Docker 網絡類型,有 bridge overlay。其中 overlay 網絡類型用於 Swarm modeoop

鏈接容器

運行一個容器並鏈接到新建的 my-net 網絡code

$ docker run -it --rm --name busybox1 --network my-net busybox sh

打開新的終端,再運行一個容器並加入到 my-net 網絡

$ docker run -it --rm --name busybox2 --network my-net busybox sh

配置DNS

容器訪問控制

容器的訪問機制,主要經過 Linux上的 Iptables 防火牆來實現。

容器訪問外部網絡

容器想要訪問外部網絡,就須要本地系統轉發支持,肩擦好轉發是否打開。

$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

若是爲0,shaming沒有開啓轉發,須要手動打開。

$sysctl -w net.ipv4.ip_forward=1

若是啓動 Docker 服務的時候設定--ip-forward=true ,Docker就會自動設定系統的 ip_forward
參數替換爲1。

容器之間的訪問

容器之間相互訪問,須要兩方面的支持。

  • 容器的網絡拓撲是否已經互聯。默認狀況下,全部容器都會被鏈接到 docker0 網橋上。
  • 本地系統的防火牆軟件 -- iptables 是否容許經過。

訪問全部端口

啓動 Docker 服務(即 dockerd)的時候,默認會添加一條轉發策略到本地主機 iptables 的 FORWARD 鏈上。策略爲經過(ACCEPT)仍是禁止(DROP)取決於配置--icc=true(缺省值)仍是 --icc=false。固然,若是手動指定 --iptables=false 則不會添加 iptables 規則。

可見,默認狀況下,不一樣容器之間是容許網絡互通的。若是爲了安全考慮,能夠在 /etc/docker/daemon.json文件中配置 {"icc": false} 來禁止它。

訪問指定端口

在經過 -icc=false 關閉網絡訪問後,還能夠經過 --link=CONTAINER_NAME:ALIAS 選項來訪問開放端口。

能夠同時使用 icc=false --iptables=true 參數來關閉容許相互的網絡訪問,並讓 Docker 能夠修改系統中的 iptables 規則。

使用 --link=CONTAINER_NAME:ALIAS選項。Docker 會在 iptable 中爲 兩個容器分別添加一條 ACCEPT 規則,容許相互訪問開放的端口(取決於 Dockerfile 中的 EXPOSE 指令)。

注意:--link=CONTAINER_NAME:ALIAS 中的 CONTAINER_NAME 目前必須是 Docker 分配的名字,或使用 --name 參數指定的名字。主機名則不會被識別。

Docker 網絡相關的命令列表。

其中有些命令選項只有在 Docker 服務啓動的時候才能配置,並且不能立刻生效。

  • -b BRIDGE 或 --bridge=BRIDGE 指定容器掛載的網橋
  • --bip=CIDR 定製 docker0 的掩碼
  • -H SOCKET... 或 --host=SOCKET... Docker 服務端接收命令的通道
  • --icc=true|false 是否支持容器之間進行通訊
  • --ip-forward=true|false 請看下文容器之間的通訊
  • --iptables=true|false 是否容許 Docker 添加 iptables 規則
  • --mtu=BYTES 容器網絡中的 MTU
    下面2個命令選項既能夠在啓動服務時指定,也能夠在啓動容器時指定。在 Docker 服務啓動的時候指定則會成爲默認值,後面執行 docker run 時能夠覆蓋設置的默認值。

  • --dns=IP_ADDRESS... 使用指定的DNS服務器
  • --dns-search=DOMAIN... 指定DNS搜索域
    最後這些選項只有在 docker run 執行時使用,由於它是針對容器的特性內容。

  • -h HOSTNAME 或 --hostname=HOSTNAME 配置容器主機名
  • --link=CONTAINER_NAME:ALIAS 添加到另外一個容器的鏈接
  • --net=bridge|none|container:NAME_or_ID|host 配置容器的橋接模式
  • -p SPEC 或 --publish=SPEC 映射容器端口到宿主主機
  • -P or --publish-all=true|false 映射容器全部端口到宿主主機

容器訪問控制

容器的訪問控制,主要經過 Linux 上的 iptables 防火牆來進行管理和實現。 iptables 是 Linux 上默認的防火牆軟件,在大部分發行版中都自帶。

容器訪問外部網絡

容器要想訪問外部網絡,須要本地系統的轉發支持。在Linux 系統中,檢查轉發是否打開。

$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

若是爲 0,說明沒有開啓轉發,則須要手動打開。

$sysctl -w net.ipv4.ip_forward=1

若是在啓動 Docker 服務的時候設定 --ip-forward=true, Docker 就會自動設定系統的 ip_forward 參數爲 1。

容器之間的訪問

容器之間相互訪問,須要兩方面的支持。

  • 容器的網絡拓撲是否已經互聯。默認狀況下,全部容器都會被鏈接到 docker0 網橋上。
  • 本地系統的防火牆軟件 -- iptables 是否容許經過。
訪問全部端口

當啓動 Docker 服務(即 dockerd)的時候,默認會添加一條轉發策略到本地主機 iptables 的 FORWARD 鏈上。策略爲經過(ACCEPT)仍是禁止(DROP)取決於配置--icc=true(缺省值)仍是 --icc=false。固然,若是手動指定 --iptables=false 則不會添加 iptables 規則。

默認狀況下,不一樣容器之間是容許網絡互通的。若是爲了安全考慮,能夠在 /etc/docker/daemon.json 文件中配置 {"icc": false} 來禁止它。

訪問指定端口

在經過 -icc=false 關閉網絡訪問後,還能夠經過 --link=CONTAINER_NAME:ALIAS 選項來訪問容器的開放端口。

能夠同時使用 icc=false --iptables=true 參數來關閉容許相互的網絡訪問,並讓 Docker 能夠修改系統中的 iptables 規則。

使用 --link=CONTAINER_NAME:ALIAS 選項。Docker 會在 iptable 中爲 兩個容器分別添加一條 ACCEPT 規則,容許相互訪問開放的端口(取決於 Dockerfile 中的 EXPOSE 指令)。

注意:--link=CONTAINER_NAME:ALIAS 中的 CONTAINER_NAME 目前必須是 Docker 分配的名字,或使用 --name 參數指定的名字。主機名則不會被識別。

映射容器端口到宿主機

默認狀況下,容器能夠主動訪問到外部網絡鏈接,可是外部鏈接沒法訪問到容器。

容器訪問外部實現

容器全部到外部網絡的鏈接,源地址都會被 NAT 成本地系統的 IP 地址。這是使用 iptables 的源地址假裝操做實現的。

查看主機的 NAT 規則:

$ sudo iptables -t nat -nL
...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16       !172.17.0.0/16
...

其中,上述規則將全部源地址在 172.17.0.0/16 網段,目標地址爲其餘網段(外部網絡)的流量動態假裝爲從系統網卡發出。MASQUERADE 跟傳統 SNAT 的好處是它能動態從網卡獲取地址。

外部訪問容器實現

容器容許外部訪問,能夠在 docker run 時候經過 -p 或 -P 參數來啓用。

無論用那種辦法,其實也是在本地的 iptable 的 nat 表中添加相應的規則。

使用 -P 時:

$ iptables -t nat -nL
...
Chain DOCKER (2 references)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:49153 to:172.17.0.2:80

使用 -p 80:80 時:

$ iptables -t nat -nL
Chain DOCKER (2 references)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

注意:

  • 這裏的規則映射了 0.0.0.0,意味着將接受主機來自全部接口的流量。用戶能夠經過 -p IP:host_port:container_port 或 -p IP::port 來指定容許訪問容器的主機上的 IP、接口等,以制定更嚴格的規則。

  • 若是但願永久綁定到某個固定的 IP 地址,能夠在 Docker 配置文件 /etc/docker/daemon.json 中添加以下內容。

{
  "ip": "0.0.0.0"
}

### 配置 docker0 網橋

Docker 服務默認會建立一個 docker0 網橋(其上有一個 docker0 內部接口),它在內核層連通了其餘的物理或虛擬網卡,這就將全部容器和本地主機都放到同一個物理網絡。

Docker 默認指定了 docker0 接口 的 IP 地址和子網掩碼,讓主機和容器之間能夠經過網橋相互通訊,它還給出了 MTU(接口容許接收的最大傳輸單元),一般是 1500 Bytes,或宿主主機網絡路由上支持的默認值。這些值均可以在服務啓動的時候進行配置。

  • -bip=CIDR IP地址加掩碼格式,例如 192.168.1.5/24
  • --mtu=BYTES覆蓋默認的 Docker mtu 配置

也能夠在配置文件中配置 DOCKER_OPTS,而後重啓服務。

因爲目前 Docker 網橋是 Linux 網橋,用戶可使用 brctl show 來查看網橋和端口鏈接信息。

$ sudo brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.3a1d7362b4ee       no              veth65f9
                                             vethdda6

注:brctl 命令在 Debian、Ubuntu 中可使用 sudo apt-get install bridge-utils 來安裝。

每次建立一個新容器的時候,Docker 從可用的地址段中選擇一個空閒的 IP 地址分配給容器的 eth0 端口。使用本地主機上 docker0 接口的 IP 做爲全部容器的默認網關。

$ sudo docker run -i -t --rm base /bin/bash
$ ip addr show eth0
24: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 32:6f:e0:35:57:91 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::306f:e0ff:fe35:5791/64 scope link
       valid_lft forever preferred_lft forever
$ ip route
default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.3

自定義網橋

除了默認的 docker0 網橋,用戶也能夠指定網橋來鏈接各個容器。

在啓動 Docker 服務的時候,使用 -b BRIDGE或--bridge=BRIDGE 來指定使用的網橋。

若是服務已經運行,那須要先中止服務,並刪除舊的網橋。

$ sudo systemctl stop docker
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0

而後建立一個網橋 bridge0

$ sudo brctl addbr bridge0
$ sudo ip addr add 192.168.5.1/24 dev bridge0
$ sudo ip link set dev bridge0 up

查看確認網橋建立並啓動。

$ ip addr show bridge0
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
    link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff
    inet 192.168.5.1/24 scope global bridge0
       valid_lft forever preferred_lft forever

在 Docker 配置文件 /etc/docker/daemon.json 中添加以下內容,便可將 Docker 默認橋接到建立的網橋上。

{
  "bridge": "bridge0",
}

啓動 Docker 服務。

新建一個容器,能夠看到它已經橋接到了 bridge0 上。

能夠繼續用 brctl show 命令查看橋接的信息。另外,在容器中可使用 ip addrip route 命令來查看 IP 地址配置和路由信息。

編輯網絡配置文件

Docker 1.2.0 開始支持在運行中的容器裏編輯 /etc/hosts, /etc/hostname/etc/resolv.conf 文件。

可是這些修改是臨時的,只在運行的容器中保留,容器終止或重啓後並不會被保存下來,也不會被 docker commit 提交。

建立一個點到點的鏈接

默認狀況下,Docker 會將全部容器鏈接到由 docker0 提供的虛擬子網中。

用戶有時候須要兩個容器之間能夠直連通訊,而不用經過主機網橋進行橋接。

解決辦法很簡單:建立一對 peer 接口,分別放到兩個容器中,配置成點到點鏈路類型便可。

首先啓動 2 個容器:

$ docker run -i -t --rm --net=none base /bin/bash
root@1f1f4c1f931a:/#
$ docker run -i -t --rm --net=none base /bin/bash
root@12e343489d2f:/#

找到進程號,而後建立網絡命名空間的跟蹤文件。

$ docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a
2989
$ docker inspect -f '{{.State.Pid}}' 12e343489d2f
3004
$ sudo mkdir -p /var/run/netns
$ sudo ln -s /proc/2989/ns/net /var/run/netns/2989
$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004

建立一對 peer 接口,而後配置路由

$ sudo ip link add A type veth peer name B

$ sudo ip link set A netns 2989
$ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A
$ sudo ip netns exec 2989 ip link set A up
$ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A

$ sudo ip link set B netns 3004
$ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B
$ sudo ip netns exec 3004 ip link set B up
$ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B

如今這 2 個容器就能夠相互 ping 通,併成功創建鏈接。點到點鏈路不須要子網和子網掩碼。

此外,也能夠不指定 --net=none 來建立點到點鏈路。這樣容器還能夠經過原先的網絡來通訊。

利用相似的辦法,能夠建立一個只跟主機通訊的容器。可是通常狀況下,更推薦使用 --icc=false 來關閉容器之間的通訊。

相關文章
相關標籤/搜索