docker 基礎之網絡管理

docker網絡基礎

docker使用到的與linux網絡有關的主要技術python

  • Network Namespace(網絡命名空間)
  • Veth設備對
  • Iptables/NetFilter
  • 網橋
  • 路由

 

標準的dokcer支持如下4種網絡模式linux

  • host模式: 使用--net=host指定
  • container模式:使用--net=container:NAME_or_ID指定
  • none模式: 使用 --net=none指定
  • bridge模式:使用--net=bridge指定,爲默認設置
    • docker第一次啓動時會建立一個虛擬網橋,默認爲docker0,在私有網絡空間中給這個網橋分配一個子網,由docker建立出來的每個容器,會建立一個虛擬的以太網設備(veth設備對),其中一端關聯到網橋,一端使用linux的網絡命名空間技術映射爲容器內的eth0設備,而後從網橋的地址段內給eth0接口分配一個ip地址  

 

容器訪問外部網絡

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

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

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

 

從外部訪問容器

容器中能夠運行一些網絡應用,要讓外部也能夠訪問這些應用,能夠經過 -P 或 -p 參數來指定端口映射。數據庫

當使用 -P 標記時,Docker 會隨機映射一個 49000~49900 的端口到內部容器開放的網絡端口。
-p(小寫的)則能夠指定要映射的端口,而且,在一個指定端口上只能夠綁定一個容器。支持的格式有 json

ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。

 

映射全部接口地址ubuntu

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

$ sudo docker run -d -p 5000:5000 training/webapp python app.py

此時默認會綁定本地全部接口上的全部地址。安全


映射到指定地址的指定端口
能夠使用 ip:hostPort:containerPort 格式指定映射使用一個特定地址,好比 localhost 地址 127.0.0.1bash

$ sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

 

映射到指定地址的任意端口

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

$ sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py

 

還能夠使用 udp 標記來指定 udp 端口

$ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

 

查看映射端口配置

使用 docker port 來查看當前映射的端口配置,也能夠查看到綁定的地址

$ docker port nostalgic_morse 5000    #container NAMES
127.0.0.1:49155.

 

注意:
容器有本身的內部網絡和 ip 地址(使用 docker inspect 能夠獲取全部的變量,Docker 還能夠有一個可變的網絡配置。)

-p 標記能夠屢次使用來綁定多個端口,例如:

$ sudo docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py

 

容器互聯

官網示例

先建立一個新的 Docker 網絡。

$ docker network create -d bridge my-net
-d 參數指定 Docker 網絡類型,有 bridge overlay。其中 overlay 網絡類型用於 Swarm mode\


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

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

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

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

進入容器,經過互相ping 容器名稱來判斷是否互聯

  

本身測試示例

#查看全部網絡:
docker network ls

#建立本身的網絡
docker network create -d bridge my-bridge-network

#檢查網絡(若是你檢查網絡,會發現裏面什麼都沒有)
docker network inspect my-bridge-network

 

添加一個容器到自定義的網絡

#指定網絡 運行(將db添加爲自定義的網絡)
docker run -d --net=my-bridge-network --name db training/postgres     #--name 爲定義的名字
 
 
#再次檢查網絡(會發現多了一個容器)
docker network inspect my-bridge-network

#查看網絡狀況
docker inspect --format='{{json .NetworkSettings.Networks}}' db

#查看ip地址
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' db

#啓動另外一個容器:並不在一個網段,未加入到自定義的網絡 名稱爲web
docker run -d --name web training/webapp python app.py

進入交互模式,而且ping web的地址進行測試

docker exec -it db bash #此時是ping 不通的

#將web加入自定義的網絡
$ docker network connect my-bridge-network web

docker exec -it db bash   #而後在去交互模式ping web,就能夠通訊了

 

容器互聯-linking系統 

docker有一個linking 系統能夠鏈接多個容器。它會建立一對父子關係,父容器能夠看到所選擇的 子容器的信息。

注意
容器的名 稱 是 惟 一的。若是 你 命名了一個 叫 web的容器,當 你 要 再次 使用 web這個名 稱 的 時候 , 你 須要用 docker rm來 刪 除以前建立的容器,也能夠 再 執行 docker run的 時候 加--rm標記來 中止舊 的容器, 並刪 除, rm 和 -d 參 數是 不兼 容的

 

使用--name標記能夠爲容器命名

$ sudo docker run -d -P --name web training/webapp python app.py

 

使用docker ps -l 來驗證咱們設定的命名

$ sudo docker ps -l

 

links可讓容器之間安全的交互,使用--link標記。

#先建立一個新的數據庫容器,
$ sudo docker run -d --name db training/postgres
 #建立一個新的web容器,並將它link到db容器 
$ docker run -d -P --name web --link db:db training/webapp python app.py

# --link標記的格式:--link name:alias,name是咱們要連接的容器的名稱,alias是這個連接的別名(會在新建的容器中/etc/hosts添加一條記錄 ip db 此處的db爲指定的alias別名

使用docker ps來查看容器的連接

 能夠看到命名的容器,db和web,db容器的names列有db也有web/db。這表示web容 器連接到db容器,他們是一個父子關係。在這個link中,2個容器中有一對父子關係。docker在2個 容器之間建立了一個安全的鏈接,並且不用映射他們的端口到宿主主機上。在啓動db容器的時候也不 用-p和-P標記。使用link以後咱們就能夠不用暴露數據庫端口到網絡上。

 

docker 經過2種方式爲父子關係的容器公開鏈接信息:

• 環境變量
• 更新/etc/hosts文件

#使用env命令來查看容器的環境變量 
$ sudo docker run --rm --name web2 --link db:db training/webapp env

#除了環境變量,docker還添加host信息到父容器的/etc/hosts的文件。下面是父容器web的hosts文件 
$ sudo docker run -t -i --rm --link db:db training/webapp /bin/bash 
root@aed84ee21bde:/opt/webapp# cat /etc/hosts

 

這裏有2個hosts,第一個是web容器,web容器用id做爲他的主機名,第二個是db容器的ip和主機名

root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping 
root@aed84ee21bde:/opt/webapp# ping db 
PING db (172.17.0.5): 48 data bytes 
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms 
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms 
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms 
用ping來ping db容器,它會解析成172.17.0.5

注意:官方的ubuntu鏡像默認沒有安裝ping
注意:你能夠連接多個子容器到父容器,好比咱們能夠連接多個web到db容器上。

 

docker高級網絡配置

快速配置指南

下面是一個跟docker網絡相關的命令列表,有些命令選項只有 在docker服務啓動的時候才能夠執行,並且不能立刻生效。

• -b BRIDGE or --bridge=BRIDGE —   橋接配置--bip=CIDR —              定製docker0的掩碼-H SOCKET... or --host=SOCKET... — 它告訴docker從哪一個通道來接收run container stop container這樣的命令,也是docker api的地址--icc=true|false           
• --ip-forward=true|false      
• --iptables=true|false         
• --mtu=BYTES —            
• --dns=IP_ADDRESS...         
• --dns-search=DOMAIN...       
• -h HOSTNAME or --hostname=HOSTNAME — 主機名配置--link=CONTAINER_NAME:ALIAS     — link 系統--net=bridge|none|container:NAME_or_ID|host     —橋接配置-p SPEC or --publish=SPEC       — 映射容器端口到宿主主機-P or --publish-all=true|false     — 映射容器端口到宿主主機

 

配置容器dns服務的方法

 

  • -h HOSTNAME or --hostname=HOSTNAME 設定容器的主機名,它會被寫到/etc/hostname,/etc/hosts中的ip地址自動寫成分配的ip地址, 在/bin/bash中顯示該主機名。但它不會在docker ps中顯示,也不會在其餘的容器的/etc/hosts中顯示。
  • --link=CONTAINER_NAME:ALIAS 這選項會在建立容器的時候添加一個其餘容器CONTAINE_NAME的主機名到/etc/hosts文件中, 讓新容器的進程能夠使用主機名ALIAS就能夠鏈接它。
  • --dns=IP_ADDRESS 添加dns服務器到容器的/etc/resolv.conf中,讓容器用這ip地址來解析全部不在/etc/hosts中的主 機名。 
  • --dns-search=DOMAIN 設定容器的搜索域,當設定搜索域爲.example.com時,會在搜索一個host主機名時,dns不只搜索 host,還會搜索host.example.com

注意:若是 沒 有上 述最 後 2個 選 項, docker會用主機上的 /etc/resolv.conf來配置容器, 它 是 默 認配置。


建立本身的橋接

#中止舊網橋並刪除 
$ sudo service docker stop 
$ sudo ip link set dev docker0 down 
$ sudo brctl delbr docker0

# 建立本身的網橋 
$ 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

# 告訴docker橋接設置,並啓動docker服務(在ubuntu上) 
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker 
$ sudo service docker start

docker服務啓動成功並綁定容器到新的網橋,建一個容器,你會看到它的ip是咱們的設置的新ip 段,docker會自動檢測到它。

用brctl show能夠看到容器啓動或則中止後網橋的配置變化,在容器中使 用ip a 和ip r 來查看ip地址配置和路由信息


建立一個點到點鏈接(network namespace)

#建立一個名爲nestest的 network namespace
ip netns add netest

#列出系統中存在的network namespace
ip netns list

#刪除一個network namespace
ip netns delete nstest

#在network namespace中執行一條命令
ip netns exec <network namespace name > command

如:
ip netns exec <network namespace name > ip addr

#在network namespace中啓動一個bash
ip netns exec <network namespace name > /bin/bash

 

默認docker會將全部容器鏈接到由docker0提供的虛擬子網,你也能夠使用本身建立的網橋。但如 果你想要2個特殊的容器之間能夠直連通訊,而不用去配置複雜的主機網卡橋接。
解決辦法很簡單:建立一對接口,把2個容器放到這對接口中,配置成點到點鏈路類型。這2個容 器就能夠直接通訊了。配置以下:

# 在2個終端中啓動2個容器 
$ sudo docker run -i -t --rm --net=none base /bin/bash 
root@1f1f4c1f931a:/#
$ sudo docker run -i -t --rm --net=none base /bin/bash 
root@12e343489d2f:/#


#找到他們的process IDs ,而後建立他們的 namespace entries
$ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a 
2989 
$ sudo 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           #2989爲一個network namespace此處是將網卡放到network namespace中的命令 $ 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    #分配ip $ 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通,併成功創建鏈接。點到點鏈路不須要子網和子網掩碼,使用ip route 來鏈接單個ip地址到指定的網絡接口。

若是 沒 有 特 殊 須要 你不 須要指定 --net=none來建立點到點 鏈路 。 還有一個辦法就是建立一個只跟主機通訊的容器,除非有特殊需求,你能夠僅用--icc=false來限制 主機間的通訊。

相關文章
相關標籤/搜索