天天看點

Linux docker的4種容器網絡的配置與核心名稱空間的建立

文章目錄

    • docker的4種網絡模式
      • bridge模式
      • container模式
      • host模式
      • none模式
    • 名稱空間的建立
      • ip netns建立
      • netns的操作
      • 轉移裝置
        • veth pair
        • 建立veth pair
        • 實作Network Namespace間通信
        • veth裝置重命名
    • 四種網絡模式配置
      • bridge模式配置
      • none模式配置
      • container模式配置
      • host模式配置
    • 容器的常用操作
      • 手動指定容器要使用的DNS
      • 手動往/etc/hosts檔案中注入主機名到IP位址的映射
      • 開放容器端口
      • 自定義docker0橋的網絡屬性資訊
      • docker遠端連接配接
      • docker建立自定義橋

docker的4種網絡模式

網絡模式 配置 說明
host -network host 容器和主控端共享Network namespace
container –network container:NAME_OR_ID 容器和另外一個容器共享Network namespace
none –network none 容器有獨立的Network namespace,但并沒有對其進行任何網絡設定,如配置設定veth pair 和網橋連接配接,配置IP等
bridge –network bridge 預設模式

bridge模式

當Docker程序啟動時,會在主機上建立一個名為docker0的虛拟網橋,此主機上啟動的Docker容器會連接配接到這個虛拟網橋上。虛拟網橋的工作方式和實體交換機類似,這樣主機上的所有容器就通過交換 機連在了一個二層網絡中。

從docker0子網中配置設定一個IP給容器使用,并設定docker0的IP位址為容器的預設網關。在主機上建立一對虛拟網卡veth pair裝置,Docker将veth pair裝置的一端放在新建立的容器中,并命名為eth0(容器的網卡),另一端放在主機中,以vethxxx這樣類似的名字命名,并将這個網絡裝置加入到docker0網橋中。可以通過brctl show指令檢視。

bridge模式是docker的預設網絡模式,不寫–network參數,就是bridge模式。使用docker run -p時,docker實際是在iptables做了DNAT規則,實作端口轉發功能。可以使用iptables -t nat -vnL檢視。

#打開ip轉發
[[email protected] ~]# cat /proc/sys/net/ipv4/ip_forward
1
#建立一個容器
[[email protected] ~]# docker run -it nginx /bin/bash
[[email protected] ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
b3843c8ae4d9        nginx               "/bin/bash"         36 minutes ago      Up 36 minutes       80/tcp              bold_spence

[[email protected] ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 72 packets, 13929 bytes)
pkts bytes target     prot opt in     out     source               destination         
   5   260 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 72 packets, 13929 bytes)
pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 707 packets, 52946 bytes)
pkts bytes target     prot opt in     out     source               destination         
   0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 707 packets, 52946 bytes)
pkts bytes target     prot opt in     out     source               destination         
   0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           

Chain DOCKER (2 references)
pkts bytes target     prot opt in     out     source               destination         
   0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
#建立centos容器,通路nginx容器
[[email protected] ~]# docker run -it centos /bin/bash
[[email protected] /]# curl http://172.17.0.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
   body {
       width: 35em;
       margin: 0 auto;
       font-family: Tahoma, Verdana, Arial, sans-serif;
   }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
           

container模式

這個模式指定新建立的容器和已經存在的一個容器共享一個 Network Namespace,而不是和主控端共享。新建立的容器不會建立自己的網卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口範圍等。同樣,兩個容器除了網絡方面,其他的如檔案系統、程序清單等還是隔離的。兩個容器的程序可以通過 lo 網卡裝置通信。

#建立centos容器用container模式
[[email protected] ~]# docker run -it --network=container:8491d65371b4 centos /bin/bash

#在centos容器裡沒有ip
[[email protected] ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
92ed3b3c2687        centos              "/bin/bash"              3 minutes ago       Up 3 minutes                            jovial_snyder
8491d65371b4        nginx               "nginx -g 'daemon of…"   9 minutes ago       Up 9 minutes        80/tcp              optimistic_montalcini
[[email protected] ~]# docker inspect 92ed3b3c2687
...
"NetworkSettings": {
            "Bridge": "",
            "SandboxID": "",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {}
        }
...

#在centos容器裡建立檔案
[[email protected] /]# ls  
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[[email protected] /]# mkdir 123
[[email protected] /]# ls
123  dev  home	lib64	    media  opt	 root  sbin  sys  usr
bin  etc  lib	lost+found  mnt    proc  run   srv   tmp  var

#nginx容器裡并沒有出現123
[email protected]:/# ls
bin  boot  dev	etc  home  lib	lib64  media  mnt  opt	proc  root  run  sbin  srv  sys  tmp  usr  var
           

host模式

如果啟動容器的時候使用host模式,那麼這個容器将不會獲得一個獨立的Network Namespace,而是和主控端共用一個Network Namespace。容器将不會虛拟出自己的網卡,配置自己的IP等,而是使用主控端的IP和端口。但是,容器的其他方面,如檔案系統、程序清單等還是和主控端隔離的。

使用host模式的容器可以直接使用主控端的IP位址與外界通信,容器内部的服務端口也可以使用主控端的端口,不需要進行NAT,host最大的優勢就是網絡性能比較好,但是docker host上已經使用的端口就不能再用了,網絡的隔離性不好。

#主控端沒有80端口
[[email protected] ~]# ss -antl
State       Recv-Q Send-Q         Local Address:Port                        Peer Address:Port              
LISTEN      0      128                        *:22                                     *:*                  
LISTEN      0      100                127.0.0.1:25                                     *:*                  
LISTEN      0      5                          *:873                                    *:*                  
LISTEN      0      128                       :::22                                    :::*                  
LISTEN      0      100                      ::1:25                                    :::*                  
LISTEN      0      5                         :::873                                   :::*                  
#建立host模式的nginx
[[email protected] ~]# docker run -d --network=host nginx
b52a048ed2e01e0ba25896b8b7e724789d91e6f634cc4dfb7421a8d9f8ef1e57
#主控端有了80端口
[[email protected] ~]# ss -antl
State       Recv-Q Send-Q         Local Address:Port                        Peer Address:Port              
LISTEN      0      128                        *:80                                     *:*                  
LISTEN      0      128                        *:22                                     *:*                  
LISTEN      0      100                127.0.0.1:25                                     *:*                  
LISTEN      0      5                          *:873                                    *:*                  
LISTEN      0      128                       :::22                                    :::*                  
LISTEN      0      100                      ::1:25                                    :::*                  
LISTEN      0      5                         :::873                                   :::*   
           

通路主控端機ip也可以通路到nginx

Linux docker的4種容器網絡的配置與核心名稱空間的建立

none模式

使用none模式,Docker容器擁有自己的Network Namespace,但是,并不為Docker容器進行任何網絡配置。也就是說,這個Docker容器沒有網卡、IP、路由等資訊。需要我們自己為Docker容器添加網卡、配置IP等。

這種網絡模式下容器隻有lo回環網絡,沒有其他網卡。none模式可以在容器建立時通過–network none來指定。這種類型的網絡沒有辦法聯網,封閉的網絡能很好的保證容器的安全性。

應用場景:

啟動一個容器處理資料,比如轉換資料格式

一些背景的計算和處理任務

#建立none模式的centos容器
[[email protected] ~]# docker run --network=none -it centos /bin/bash
[[email protected] /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
#沒有ip位址
#檢視容器資訊
[[email protected] ~]# docker inspect f4c096312345
...
            "Networks": {
                "none": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "f312ddeef6847b34befd9207049ff97c6a16fa9cb299ae2d2d97814a6226d442",
                    "EndpointID": "efde2a34fee8d5bc99340685269bdb21abe081dc5bc833c3ec97b38288d5aead",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "DriverOpts": null
                }
#沒有關于ipv4的資訊

           

名稱空間的建立

ip netns建立

[[email protected] ~]# ip netns list
[[email protected] ~]# ip netns add ns0
[[email protected] ~]# ip netns list
ns0
           

新建立的 Network Namespace 會出現在/var/run/netns/目錄下。如果相同名字的 namespace 已經存在,指令會報Cannot create namespace file “/var/run/netns/ns0”: File exists的錯誤。

[[email protected] ~]# ls /var/run/netns/
ns0

[[email protected] ~]# ip netns add ns0
Cannot create namespace file "/var/run/netns/ns0": File exists
           

對于每個 Network Namespace 來說,它會有自己獨立的網卡、路由表、ARP 表、iptables 等和網絡相關的資源。

netns的操作

ip指令提供了ip netns exec子指令可以在對應的 Network Namespace 中執行指令。

檢視新建立 Network Namespace 的網卡資訊

[[email protected] ~]# ip netns exec ns0 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
           

可以看到,新建立的Network Namespace中會預設建立一個lo回環網卡,此時網卡處于關閉狀态。此時,嘗試去 ping 該lo回環網卡,會提示Network is unreachable

[[email protected] ~]# ip netns exec ns0 ping 127.0.0.1
connect: Network is unreachable 
           

通過下面的指令啟用lo回環網卡:

[[email protected] ~]# ip netns exec ns0 ip link set lo up
[[email protected] ~]# ip netns exec ns0 ping 127.0.0.1   
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.073 ms
           

轉移裝置

我們可以在不同的 Network Namespace 之間轉移裝置(如veth)。由于一個裝置隻能屬于一個 Network Namespace ,是以轉移後在這個 Network Namespace 内就看不到這個裝置了。

其中,veth裝置屬于可轉移裝置,而很多其它裝置(如lo、vxlan、ppp、bridge等)是不可以轉移的。

veth pair

veth pair 全稱是 Virtual Ethernet Pair,是一個成對的端口,所有從這對端口一 端進入的資料包都将從另一端出來,反之也是一樣。

引入veth pair是為了在不同的 Network Namespace 直接進行通信,利用它可以直接将兩個 Network Namespace 連接配接起來。

建立veth pair

[[email protected] ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:b9:3c:6d brd ff:ff:ff:ff:ff:ff
    inet 192.168.220.20/24 brd 192.168.220.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::59a:c315:2825:665f/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    link/ether 02:42:fe:7e:5c:ed brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:feff:fe7e:5ced/64 scope link 
       valid_lft forever preferred_lft forever

[[email protected] ~]# ip link add type veth
[[email protected] ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:b9:3c:6d brd ff:ff:ff:ff:ff:ff
    inet 192.168.220.20/24 brd 192.168.220.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::59a:c315:2825:665f/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    link/ether 02:42:fe:7e:5c:ed brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:feff:fe7e:5ced/64 scope link 
       valid_lft forever preferred_lft forever
10: [email protected]: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether a2:d8:72:1d:30:c2 brd ff:ff:ff:ff:ff:ff
11: [email protected]: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 4e:c3:09:83:e9:ee brd ff:ff:ff:ff:ff:ff
           

可以看到,此時系統中新增了一對veth pair,将veth0和veth1兩個虛拟網卡連接配接了起來,此時這對 veth pair 處于”未啟用“狀态。

實作Network Namespace間通信

下面我們利用veth pair實作兩個不同的 Network Namespace 之間的通信。剛才我們已經建立了一個名為ns0的 Network Namespace,下面再建立一個資訊Network Namespace,命名為ns1

[[email protected] ~]# ip netns add ns1
[[email protected] ~]# ip netns list
ns1
ns0
           

然後我們将veth0加入到ns0,将veth1加入到ns1

[[email protected] ~]# ip link set veth0 netns ns0
[[email protected] ~]# ip link set veth1 netns ns1
           

然後我們分别為這對veth pair配置上ip位址,并啟用它們

[[email protected] ~]# ip netns exec ns0 ip link set veth0 up
[[email protected] ~]# ip netns exec ns0 ip addr add 10.0.0.1/24 dev veth0
[[email protected] ~]# ip netns exec ns0 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
10: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether a2:d8:72:1d:30:c2 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 10.0.0.1/24 scope global veth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a0d8:72ff:fe1d:30c2/64 scope link 
       valid_lft forever preferred_lft forever

[[email protected] ~]# ip netns exec ns1 ip link set lo up
[[email protected] ~]# ip netns exec ns1 ip link set veth1 up
[[email protected] ~]# ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth1
[[email protected] ~]# ip netns exec ns1 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
11: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 4e:c3:09:83:e9:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.0.2/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::4cc3:9ff:fe83:e9ee/64 scope link 
       valid_lft forever preferred_lft forever

           

檢視這對veth pair的狀态

[[email protected] ~]# ip netns exec ns0 ip a
10: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 32:c4:23:dd:a7:1c brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 10.0.0.1/24 scope global veth0
       valid_lft forever preferred_lft forever
    inet6 fe80::30c4:23ff:fedd:a71c/64 scope link 
       valid_lft forever preferred_lft forever
       

[[email protected] ~]# ip netns exec ns1 ip a
11: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether a2:52:52:cd:54:62 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.0.2/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a052:52ff:fecd:5462/64 scope link 
       valid_lft forever preferred_lft forever
           

從上面可以看出,我們已經成功啟用了這個veth pair,并為每個veth裝置配置設定了對應的ip位址。我們嘗試在ns1中通路ns0中的ip位址:

[[email protected] ~]# ip netns exec ns1 ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.072 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.082 ms   
           

可以看到,veth pair成功實作了兩個不同Network Namespace之間的網絡互動。

veth裝置重命名

[[email protected] ~]# ip netns exec ns0 ip link set veth0 down
[[email protected] ~]# ip netns exec ns0 ip link set dev veth0 name eth0
[[email protected] ~]# ip netns exec ns0 ifconfig -a
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.0.1  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::30c4:23ff:fedd:a71c  prefixlen 64  scopeid 0x20<link>
        ether 32:c4:23:dd:a7:1c  txqueuelen 1000  (Ethernet)
        RX packets 12  bytes 928 (928.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 20  bytes 1576 (1.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[[email protected] ~]# ip netns exec ns0 ip link set eth0 up
           

四種網絡模式配置

bridge模式配置

[[email protected] ~]# docker run -it --name t1 --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02  
          inet addr:10.0.0.2  Bcast:10.0.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:508 (508.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # exit
[[email protected] ~]# docker container ls -a


# 在建立容器時添加--network bridge與不加--network選項效果是一緻的
[[email protected] ~]# docker run -it --name t1 --network bridge --rm busybox    
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02  
          inet addr:10.0.0.2  Bcast:10.0.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:508 (508.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # exit
           

none模式配置

[[email protected] ~]# docker run -it --name t1 --network none --rm busybox      
/ # ifconfig -a
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # exit
           

container模式配置

啟動第一個容器

[email protected] ~]# docker run -it --name b1 --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02  
          inet addr:10.0.0.2  Bcast:10.0.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:508 (508.0 B)  TX bytes:0 (0.0 B)
           

啟動第二個容器

[[email protected] ~]# docker run -it --name b2 --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:03  
          inet addr:10.0.0.3  Bcast:10.0.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:508 (508.0 B)  TX bytes:0 (0.0 B)        
           

可以看到名為b2的容器IP位址是10.0.0.3,與第一個容器的IP位址不是一樣的,也就是說并沒有共享網絡,此時如果我們将第二個容器的啟動方式改變一下,就可以使名為b2的容器IP與B1容器IP一緻,也即共享IP,但不共享檔案系統。

[[email protected] ~]# docker run -it --name b2 --rm --network container:b1 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02  
          inet addr:10.0.0.2  Bcast:10.0.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:648 (648.0 B)  TX bytes:0 (0.0 B)        
           

此時我們在b1容器上建立一個目錄

/ # mkdir /tmp/data
/ # ls /tmp
data  
           

到b2容器上檢查/tmp目錄會發現并沒有這個目錄,因為檔案系統是處于隔離狀态,僅僅是共享了網絡而已。

在b2容器上部署一個站點

/ # echo 'hello world' > /tmp/index.html
/ # ls /tmp
index.html
/ # httpd -h /tmp
/ # netstat -antl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 :::80                   :::*                    LISTEN    
           

在b1容器上用本地位址去通路此站點

/ # wget -O - -q 127.0.0.1:80
hello world
           

由此可見,container模式下的容器間關系就相當于一台主機上的兩個不同程序

host模式配置

啟動容器時直接指明模式為host

[[email protected] ~]# docker run -it --name b2 --rm --network host busybox        
/ # ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:06:25:98:91  
          inet addr:10.0.0.1  Bcast:10.0.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:6ff:fe25:9891/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:55 errors:0 dropped:0 overruns:0 frame:0
          TX packets:82 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:8339 (8.1 KiB)  TX bytes:7577 (7.3 KiB)

ens33     Link encap:Ethernet  HWaddr 00:0C:29:01:78:90  
          inet addr:192.168.10.144  Bcast:192.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fe01:7890/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:55301 errors:0 dropped:0 overruns:0 frame:0
          TX packets:26269 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:63769938 (60.8 MiB)  TX bytes:2672449 (2.5 MiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:42 errors:0 dropped:0 overruns:0 frame:0
          TX packets:42 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:4249 (4.1 KiB)  TX bytes:4249 (4.1 KiB)

vethffa4d46 Link encap:Ethernet  HWaddr 06:4F:68:16:6E:B0  
          inet6 addr: fe80::44f:68ff:fe16:6eb0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:648 (648.0 B)
           

此時如果我們在這個容器中啟動一個http站點,我們就可以直接用主控端的IP直接在浏覽器中通路這個容器中的站點了。

容器的常用操作

檢視容器的主機名

[[email protected] ~]# docker run -it --name t1 --network bridge --rm busybox
/ # hostname
7769d784c6da  
           

在容器啟動時注入主機名

[[email protected] ~]# docker run -it --name t1 --network bridge --hostname wangqing --rm busybox
/ # hostname
wangqing
/ # 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
10.0.0.2        wangqing    # 注入主機名時會自動建立主機名到IP的映射關系
/ # cat /etc/resolv.conf 
# Generated by NetworkManager
search localdomain
nameserver 192.168.10.2     # DNS也會自動配置為主控端的DNS
/ # ping www.baidu.com
PING www.baidu.com (182.61.200.7): 56 data bytes
64 bytes from 182.61.200.7: seq=0 ttl=127 time=26.073 ms
64 bytes from 182.61.200.7: seq=1 ttl=127 time=26.378 ms  
           

手動指定容器要使用的DNS

[[email protected] ~]# docker run -it --name t1 --network bridge --hostname wangqing --dns 114.114.114.114 --rm busybox
/ # cat /etc/resolv.conf 
search localdomain
nameserver 114.114.114.114
/ # nslookup -type=a www.baidu.com
Server:         114.114.114.114
Address:        114.114.114.114:53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com
Name:   www.a.shifen.com
Address: 182.61.200.6
Name:   www.a.shifen.com
Address: 182.61.200.7
           

手動往/etc/hosts檔案中注入主機名到IP位址的映射

[[email protected] ~]# docker run -it --name t1 --network bridge --hostname wangqing --add-host www.a.com:1.1.1.1 --rm busybox      
/ # 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.a.com
10.0.0.2        wangqing
           

開放容器端口

執行docker run的時候有個-p選項,可以将容器中的應用端口映射到主控端中,進而實作讓外部主機可以通過通路主控端的某端口來通路容器内應用的目的。

-p選項能夠使用多次,其所能夠暴露的端口必須是容器确實在監聽的端口。

-p選項的使用格式:

  • -p

    将指定的容器端口映射至主機所有位址的一個動态端口

  • -p :

    将容器端口映射至指定的主機端口

  • -p ::

    将指定的容器端口映射至主機指定的動态端口

  • -p ::

    将指定的容器端口映射至主機指定的端口

動态端口指的是随機端口,具體的映射結果可使用docker port指令檢視。

[[email protected] ~]# docker run --name web --rm -p 80 nginx
           

以上指令執行後會一直占用着前端,我們新開一個終端連接配接來看一下容器的80端口被映射到了主控端的什麼端口上

[[email protected] ~]# docker port web
80/tcp -> 0.0.0.0:32769
           

由此可見,容器的80端口被暴露到了主控端的32769端口上,此時我們在主控端上通路一下這個端口看是否能通路到容器内的站點

[[email protected] ~]# curl http://127.0.0.1:32769
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
           

iptables防火牆規則将随容器的建立自動生成,随容器的删除自動删除規則。

将容器端口映射到指定IP的随機端口

[[email protected] ~]# docker run --name web --rm -p 192.168.10.144::80 nginx
           

在另一個終端上檢視端口映射情況

[[email protected] ~]# docker port web
80/tcp -> 192.168.10.144:32768
           

将容器端口映射到主控端的指定端口

[[email protected] ~]# docker run --name web --rm -p 80:80 nginx
           

在另一個終端上檢視端口映射情況

[[email protected] ~]# docker port web
80/tcp -> 0.0.0.0:80
           

自定義docker0橋的網絡屬性資訊

自定義docker0橋的網絡屬性資訊需要修改/etc/docker/daemon.json配置檔案

{
    "bip": "192.168.1.5/24",
    "fixed-cidr": "192.168.1.5/25",
    "fixed-cidr-v6": "2001:db8::/64",
    "mtu": 1500,
    "default-gateway": "10.20.1.1",
    "default-gateway-v6": "2001:db8:abcd::89",
    "dns": ["10.20.1.2","10.20.1.3"]
}
           

核心選項為bip,即bridge ip之意,用于指定docker0橋自身的IP位址;其它選項可通過此位址計算得出

docker遠端連接配接

dockerd守護程序的C/S,其預設僅監聽Unix Socket格式的位址(/var/run/docker.sock),如果要使用TCP套接字,則需要修改/etc/docker/daemon.json配置檔案,添加如下内容,然後重新開機docker服務:

"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
           

在用戶端上向dockerd直接傳遞“-H|–host”選項指定要控制哪台主機上的docker容器

docker -H 192.168.10.145:2375 ps
           

docker建立自定義橋

建立一個額外的自定義橋,差別于docker0

[[email protected] ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
413997d70707        bridge              bridge              local
0a04824fc9b6        host                host                local
4dcb8fbdb599        none                null                local

[[email protected] ~]# docker network create -d bridge --subnet "192.168.2.0/24" --gateway "192.168.2.1" br0
b340ce91fb7c569935ca495f1dc30b8c37204b2a8296c56a29253a067f5dedc9

[[email protected] ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b340ce91fb7c        br0                 bridge              local
413997d70707        bridge              bridge              local
0a04824fc9b6        host                host                local
4dcb8fbdb599        none                null                local
           

使用新建立的自定義橋來建立容器:

[[email protected] ~]# docker run -it --name b1 --network br0 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:02:02  
          inet addr:192.168.2.2  Bcast:192.168.2.255     Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:926 (926.0 B)  TX bytes:0 (0.0 B)
           

再建立一個容器,使用預設的bridge橋:

[email protected] ~]# docker run --name b2 -it busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02  
          inet addr:10.0.0.2  Bcast:10.0.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:508 (508.0 B)  TX bytes:0 (0.0 B)