zoukankan      html  css  js  c++  java
  • Docker技术入门与实战 第二版-学习笔记-8-网络功能network-3-容器访问控制和自定义网桥

    1)容器访问控制

    容器的访问控制,主要通过 Linux 上的 iptables防火墙来进行管理和实现。 iptablesLinux 上默认的防火墙软件,在大部分发行版中都自带。

    容器访问外部网络

    容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开:

    root@36078e6ba58f:/opt/webapp# sysctl net.ipv4.ip_forward
    net.ipv4.ip_forward = 1

    为1,说明打开了;如果为0,说明没有开启转发,则需要手动打开,在容器内运行:

    sysctl -w net.ipv4.ip_forward=1

    如果在启动 Docker 服务的时候设定 --ip-forward = true, Docker 就会自动设定系统的 ip_forward参数为 1

    容器之间访问

    容器之间相互访问,需要两方面的支持:

    • 容器的网络拓扑是否已经互联--icc。默认情况下,所有容器都会被连接到 docker0网桥上,默认--icc=true,能够互相ping通。
    • 本地系统的防火墙软件 -- iptables是否允许通过

    在本博客的Docker技术入门与实战 第二版-学习笔记-8-网络功能network-1-单个host上的容器网络中有如何让两个网段的容器互联的例子

    1》访问所有端口

    当启动 Docker 服务时候,默认会添加一条转发策略到 iptables FORWARD 链 上。策略为通过(ACCEPT )还是禁止(DROP )取决于配置  --icc=true(缺省值,支持容器之间进行通信)还是 --icc=false(不支持),即能否ping通

    当然,如果手动指定--iptables=false则不会添加iptables规则

    可见,默认情况下,不同容器之间是允许网络互通的。如果为了安全考虑,可以在/etc/default/docker文件中配置DOCKER_OPTS=--icc=false来禁止它(具体实现在下一章的网桥部分介绍)

    2》访问指定端口

    在通过--icc=false关闭网络访问后,还可以通过--link=CONTAINER_NAME:ALIAS选项来访问容器的开放端口

    例如,在启动 Docker 服务时,可以同时使用--icc=false --iptables=true参数来关闭允许互相的网络访问,并让Docker可以修改系统中的iptables规则

    此时,查看iptables规则,在上一篇博客生成的ubuntu5容器中执行:

    root@9e11c1b9e90d:/# iptables -t nat -nL
    bash: iptables: command not found
    
    root@9e11c1b9e90d:/# apt-get install iptables
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    E: Unable to locate package iptables
    
    root@9e11c1b9e90d:/# apt-get update        
    Ign http://archive.ubuntu.com trusty InRelease                                 
    Get:1 http://security.ubuntu.com trusty-security InRelease [65.9 kB]           
    ...    
    Get:21 http://archive.ubuntu.com trusty/multiverse amd64 Packages [169 kB]     
    Fetched 13.3 MB in 45s (292 kB/s)                                              
    Reading package lists... Done
    
    root@9e11c1b9e90d:/# apt-get install iptables
    Reading package lists... Done
    ...
    Setting up libnfnetlink0:amd64 (1.0.1-2) ...
    Setting up libxtables10 (1.4.21-1ubuntu1) ...
    Setting up iptables (1.4.21-1ubuntu1) ...
    Processing triggers for libc-bin (2.19-0ubuntu6.14) ...
    
    root@9e11c1b9e90d:/# iptables -t nat -nL
    iptables v1.4.21: can't initialize iptables table `filter': Permission denied (you must be root)

    解决办法是docker run时使用参数 --privileged,然后再跑一遍:

    root@9e11c1b9e90d:/# exit
    exit
    
    userdeMacBook-Pro:~ user$ docker exec -it --privileged ubuntu5 /bin/bash   
    Error response from daemon: Container 9e11c1b9e90dc7fe3cbdff59580e849517b254cc20081d0026cd57c4b2407f88 is not running
    
    userdeMacBook-Pro:~ user$ docker start ubuntu5
    ubuntu5
    
    userdeMacBook-Pro:~ user$ docker exec -it --privileged ubuntu5 /bin/bash  
    root@9e11c1b9e90d:/# iptables -t nat -nL
    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination         
    
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination         
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination         
    DOCKER_OUTPUT  all  --  0.0.0.0/0            127.0.0.11          
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination         
    DOCKER_POSTROUTING  all  --  0.0.0.0/0            127.0.0.11          
    
    Chain DOCKER_OUTPUT (1 references)
    target     prot opt source               destination         
    DNAT       tcp  --  0.0.0.0/0            127.0.0.11           tcp dpt:53 to:127.0.0.11:36705
    DNAT       udp  --  0.0.0.0/0            127.0.0.11           udp dpt:53 to:127.0.0.11:49094
    
    Chain DOCKER_POSTROUTING (1 references)
    target     prot opt source               destination         
    SNAT       tcp  --  127.0.0.11           0.0.0.0/0            tcp spt:36705 to::53
    SNAT       udp  --  127.0.0.11           0.0.0.0/0            udp spt:49094 to::53
    root@9e11c1b9e90d:/# 

    之后,启动容器(docker run)时使用--link=CONTAINER_NAME:ALIAS选项。Docker会在iptables中为两个容器分别添加一条ACCEPT规则,允许相互访问互相开放的端口(取决于Dockerfile的EXPOSRE行)

    当添加了--link=CONTAINER_NAME:ALIAS之后,iptables规则就变了(但是上面没有能够看见规则,但是使用cat /etc/hosts查看的确是连接到了db???)

    注意: --link=CONTAINER_NAME:ALIAS中的 CONTAINER_NAME目前必须是 Docker 分配的名字,或使用 --name参数指定的名字。主机名则不会被识别。

    2)映射容器端口到宿主主机的实现

    默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。

    容器访问外部实现

    容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。这是使用iptables的源地址伪装操作实现的。

    Linux系统查看主机的 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 的好处是它能动态从网卡获取地址。

    外部访问容器实现(-p 或 -P)

    3)配置 docker0 网桥

    Docker 默认指定了 docker0接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了 MTU(接口允许接收的最大传输单元),通常 是 1500 Bytes,或宿主主机网络路由上支持的默认值。这些值都可以在服务启动的 时候进行配置。

    也可以在配置文件中配置 DOCKER_OPTS,然后重启服务。 由于目前 Docker 网桥是 Linux 网桥,用户可以使用 brctl show 来查看网桥和端口连接信息,当主机是Linux系统时。

    在连接网络为host的容器中查看

    root@linuxkit-025000000001:/# brctl show
    bash: brctl: command not found
    root@linuxkit-025000000001:/# apt-get install bridge-utils
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    The following NEW packages will be installed:
      bridge-utils
    0 upgraded, 1 newly installed, 0 to remove and 6 not upgraded.
    Need to get 29.2 kB of archives.
    After this operation, 146 kB of additional disk space will be used.
    Get:1 http://archive.ubuntu.com/ubuntu/ trusty/main bridge-utils amd64 1.5-6ubuntu2 [29.2 kB]
    Fetched 29.2 kB in 3s (9716 B/s)                    
    Selecting previously unselected package bridge-utils.
    (Reading database ... 11765 files and directories currently installed.)
    Preparing to unpack .../bridge-utils_1.5-6ubuntu2_amd64.deb ...
    Unpacking bridge-utils (1.5-6ubuntu2) ...
    Setting up bridge-utils (1.5-6ubuntu2) ...
    root@linuxkit-025000000001:/# brctl show
    bridge name              bridge id              STP enabled    interfaces
    br-9dc30b4c7e39          8000.0242a6b606aa      no             veth2339518    //自定义的bridge网桥myNetwork1,有两个容器连接
                                                                   veth3ee80da
    br-f16ae5c303c6          8000.02427bc35a0e      no                            //自定义的bridge网桥myNetwork1,无容器连接
    docker0                  8000.0242333af167      no             veth0fcbc17    //默认bridge网桥,有四个容器连接
                                                                   veth229300e
                                                                   veth611835f
                                                                   veth87e64f4
    root@linuxkit-025000000001:/# 

    注: brctl命令在 DebianUbuntu 中可以使用 apt-get install bridge-utils来安装。

    每次创建一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。

    使用本地主机上docker0 接口的 IP 作为所有容器的默认网关,不指定连接的网段,就默认使用docker0。

    1》使用--bip修改默认网桥docker的IP地址和子网掩码

    首先先查看当前docker0的IP地址和子网掩码:

    root@linuxkit-025000000001:/# ip addr show docker0
    5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:c4:78:a1:05 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:c4ff:fe78:a105/64 scope link 
           valid_lft forever preferred_lft forever

    然后到daemon上去添加"bip": "192.188.0.1/16",如下图:

    然后重新启动连接host网络的ubuntu6容器,查看docker0的IP:

    userdeMBP:~ user$ docker start ubuntu6
    ubuntu6
    userdeMBP:~ user$ docker exec -it --privileged ubuntu6 /bin/bash
    root@linuxkit-025000000001:/# ip addr show docker0
    5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:4a:48:0f:f1 brd ff:ff:ff:ff:ff:ff
        inet 192.188.0.1/16 brd 192.188.255.255 scope global docker0
           valid_lft forever preferred_lft forever
        inet6 fe80::42:4aff:fe48:ff1/64 scope link 
           valid_lft forever preferred_lft forever

    发现果然成功更改成了192.188.0.1/16

    4) 自定义网桥

    除了默认的 docker0 网桥,用户也可以指定网桥来连接各个容器。

    在启动 Docker 服务的时候,使用 -b BRIDGE或 --bridge=BRIDGE来指定使用 的网桥

    如果服务已经运行,那需要先停止服务,并删除旧的网桥:

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

    添加自定义网段:

    ⚠️下面的方法是默认你在Linux系统下的操作方法,我是打开了一个连接了host网络的容器来给大家示范了一下步骤:

    root@linuxkit-025000000001:/# brctl show
    bridge name            bridge id            STP enabled    interfaces
    br-9dc30b4c7e39        8000.0242a6b606aa    no            veth2339518
                                                        veth3ee80da
    br-f16ae5c303c6        8000.02427bc35a0e    no        
    docker0                8000.0242333af167    no            veth0fcbc17
                                                        veth229300e
                                                        veth611835f
                                                        veth87e64f4
    root@linuxkit-025000000001:/# brctl addbr bridge0  //添加一个名为bridge0的网桥
    root@linuxkit-025000000001:/# ip addr add 192.168.5.1/24 dev bridge0  //设置其IP地址和子网掩码为192.168.5.1/24
    root@linuxkit-025000000001:/# ip link set dev bridge0 up  //然后启动
    root@linuxkit-025000000001:/# brctl show
    bridge name            bridge id            STP enabled    interfaces
    br-9dc30b4c7e39        8000.0242a6b606aa    no            veth2339518
                                                        veth3ee80da
    br-f16ae5c303c6        8000.02427bc35a0e    no        
    bridge0                8000.000000000000    no        
    docker0                8000.0242333af167    no            veth0fcbc17
                                                        veth229300e
                                                        veth611835f
                                                        veth87e64f4
    root@linuxkit-025000000001:/# ip addr show bridge0  /查看其IP地址和子网掩码
    40: bridge0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
        link/ether 7e:37:cc:ff:d1:7c brd ff:ff:ff:ff:ff:ff
        inet 192.168.5.1/24 scope global bridge0
           valid_lft forever preferred_lft forever
        inet6 fe80::7c37:ccff:feff:d17c/64 scope link 
           valid_lft forever preferred_lft forever

    然后配置 Docker 服务,默认桥接到创建的网桥上

    $ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
    $ sudo service docker start

    启动 Docker 服务。 新建一个容器,可以看到它已经桥接到了bridge0

     

    Mac系统上怎么自定义一个网桥:

    从上面的步骤我们可以看出来,和运行docker network命令得到的结果是一样的:

    首先查看目前拥有的网络:

    userdeMBP:~ user$ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    f9b3e9b815d5        bridge              bridge              local
    0012b4fcfb27        host                host                local
    7612dc76f9c0        none                null                local

    运行docker network create创建一个myNetwork1的网络,网段为172.20.11.0/24,网关为172.20.11.1:

    userdeMBP:~ user$ docker network create --driver bridge --subnet 172.20.11.0/24 --gateway 172.20.11.1 myNetwork1
    67ae783934fe80ace7e464ee876fddb351b0750ae51ae099508ce665dde828dd
    userdeMBP:~ user$ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    f9b3e9b815d5        bridge              bridge              local
    0012b4fcfb27        host                host                local
    67ae783934fe        myNetwork1          bridge              local
    7612dc76f9c0        none                null                local
    userdeMBP:~ user$ docker network inspect 67ae783934fe
    [
        {
            "Name": "myNetwork1",
            "Id": "67ae783934fe80ace7e464ee876fddb351b0750ae51ae099508ce665dde828dd",
            "Created": "2018-12-21T08:11:55.621127909Z",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.20.11.0/24",
                        "Gateway": "172.20.11.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Ingress": false,
            "ConfigFrom": {
                "Network": ""
            },
            "ConfigOnly": false,
            "Containers": {},
            "Options": {},
            "Labels": {}
        }
    ]

    然后果然成功生成该网络

    然后我们打开一个连接--network=host的ubuntu:18.04容器来查看此时的网桥信息:

    userdeMBP:~ user$ docker run -it --name=ubuntu1 --network=host ubuntu:18.04 /bin/bash
    Unable to find image 'ubuntu:18.04' locally
    18.04: Pulling from library/ubuntu
    32802c0cfa4d: Pull complete 
    da1315cffa03: Pull complete 
    fa83472a3562: Pull complete 
    f85999a86bef: Pull complete 
    Digest: sha256:6d0e0c26489e33f5a6f0020edface2727db9489744ecc9b4f50c7fa671f23c49
    Status: Downloaded newer image for ubuntu:18.04
    
    root@linuxkit-025000000001:/# brctl
    bash: brctl: command not found
    
    root@linuxkit-025000000001:/# apt-get install bridge-utils
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    E: Unable to locate package bridge-utils
    
    root@linuxkit-025000000001:/# apt-get update //更新源
    Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [83.2 kB]
    ...                                                                                                                                         
    Fetched 15.3 MB in 44s (349 kB/s)                                                                                                                                                                                                  
    Reading package lists... Done
    
    root@linuxkit-025000000001:/# apt-get install bridge-utils
    Reading package lists... Done
    ...
    
    root@linuxkit-025000000001:/# brctl show
    bridge name            bridge id            STP enabled    interfaces
    br-67ae783934fe        8000.02423cfe1d7e    no        
    docker0                8000.02420f4186a9    no

    从上面可见,我们自定义网络的过程其实也生成了一个自定义网桥br-67ae783934fe,如果你想要容器是连接在该网桥上的,那么在run时就使用参数--network=myNetwork1设定即可

     
  • 相关阅读:
    40个GitHub上最受欢迎的iOS开源项目
    Swift应用开源项目推荐
    swift在github上开源的地址
    必须Mark!43个优秀的Swift开源项目推荐
    Swift中编写单例的正确方式
    Android提高第十一篇之模拟信号示波器
    Android平台音频信号FFT的实现
    ios UINavigationController
    工作记录8:iOS 传值问题总结(7种传值完美介绍)
    利用协议代理实现导航控制器UINavigationController视图之间的正向传值和反向传值
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/10156605.html
Copyright © 2011-2022 走看看