1)容器访问控制

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

容器访问外部网络

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

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

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

  1. sysctl -w net.ipv4.ip_forward=

如果在启动 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容器中执行:

  1. root@9e11c1b9e90d:/# iptables -t nat -nL
  2. bash: iptables: command not found
  3.  
  4. root@9e11c1b9e90d:/# apt-get install iptables
  5. Reading package lists... Done
  6. Building dependency tree
  7. Reading state information... Done
  8. E: Unable to locate package iptables
  9.  
  10. root@9e11c1b9e90d:/# apt-get update
  11. Ign http://archive.ubuntu.com trusty InRelease
  12. Get: http://security.ubuntu.com trusty-security InRelease [65.9 kB]
  13. ...
  14. Get: http://archive.ubuntu.com trusty/multiverse amd64 Packages [169 kB]
  15. Fetched 13.3 MB in 45s ( kB/s)
  16. Reading package lists... Done
  17.  
  18. root@9e11c1b9e90d:/# apt-get install iptables
  19. Reading package lists... Done
  20. ...
  21. Setting up libnfnetlink0:amd64 (1.0.-) ...
  22. Setting up libxtables10 (1.4.-1ubuntu1) ...
  23. Setting up iptables (1.4.-1ubuntu1) ...
  24. Processing triggers for libc-bin (2.19-0ubuntu6.) ...
  25.  
  26. root@9e11c1b9e90d:/# iptables -t nat -nL
  27. iptables v1.4.21: can't initialize iptables table `filter': Permission denied (you must be root)

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

  1. root@9e11c1b9e90d:/# exit
  2. exit
  3.  
  4. userdeMacBook-Pro:~ user$ docker exec -it --privileged ubuntu5 /bin/bash
  5. Error response from daemon: Container 9e11c1b9e90dc7fe3cbdff59580e849517b254cc20081d0026cd57c4b2407f88 is not running
  6.  
  7. userdeMacBook-Pro:~ user$ docker start ubuntu5
  8. ubuntu5
  9.  
  10. userdeMacBook-Pro:~ user$ docker exec -it --privileged ubuntu5 /bin/bash
  11. root@9e11c1b9e90d:/# iptables -t nat -nL
  12. Chain PREROUTING (policy ACCEPT)
  13. target prot opt source destination
  14.  
  15. Chain INPUT (policy ACCEPT)
  16. target prot opt source destination
  17.  
  18. Chain OUTPUT (policy ACCEPT)
  19. target prot opt source destination
  20. DOCKER_OUTPUT all -- 0.0.0.0/ 127.0.0.11
  21.  
  22. Chain POSTROUTING (policy ACCEPT)
  23. target prot opt source destination
  24. DOCKER_POSTROUTING all -- 0.0.0.0/ 127.0.0.11
  25.  
  26. Chain DOCKER_OUTPUT ( references)
  27. target prot opt source destination
  28. DNAT tcp -- 0.0.0.0/ 127.0.0.11 tcp dpt: to:127.0.0.11:
  29. DNAT udp -- 0.0.0.0/ 127.0.0.11 udp dpt: to:127.0.0.11:
  30.  
  31. Chain DOCKER_POSTROUTING ( references)
  32. target prot opt source destination
  33. SNAT tcp -- 127.0.0.11 0.0.0.0/ tcp spt: to::
  34. SNAT udp -- 127.0.0.11 0.0.0.0/ udp spt: to::
  35. 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 规则:

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

其中,上述规则将所有源地址在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的容器中查看

  1. root@linuxkit-:/# brctl show
  2. bash: brctl: command not found
  3. root@linuxkit-:/# apt-get install bridge-utils
  4. Reading package lists... Done
  5. Building dependency tree
  6. Reading state information... Done
  7. The following NEW packages will be installed:
  8. bridge-utils
  9. upgraded, newly installed, to remove and not upgraded.
  10. Need to get 29.2 kB of archives.
  11. After this operation, kB of additional disk space will be used.
  12. Get: http://archive.ubuntu.com/ubuntu/ trusty/main bridge-utils amd64 1.5-6ubuntu2 [29.2 kB]
  13. Fetched 29.2 kB in 3s ( B/s)
  14. Selecting previously unselected package bridge-utils.
  15. (Reading database ... files and directories currently installed.)
  16. Preparing to unpack .../bridge-utils_1.-6ubuntu2_amd64.deb ...
  17. Unpacking bridge-utils (1.5-6ubuntu2) ...
  18. Setting up bridge-utils (1.5-6ubuntu2) ...
  19. root@linuxkit-:/# brctl show
  20. bridge name bridge id STP enabled interfaces
  21. br-9dc30b4c7e39 .0242a6b606aa no veth2339518 //自定义的bridge网桥myNetwork1,有两个容器连接
  22. veth3ee80da
  23. br-f16ae5c303c6 .02427bc35a0e no //自定义的bridge网桥myNetwork1,无容器连接
  24. docker0 .0242333af167 no veth0fcbc17 //默认bridge网桥,有四个容器连接
  25. veth229300e
  26. veth611835f
  27. veth87e64f4
  28. root@linuxkit-:/#

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

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

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

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

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

  1. root@linuxkit-:/# ip addr show docker0
  2. : docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
  3. link/ether ::c4::a1: brd ff:ff:ff:ff:ff:ff
  4. inet 172.17.0.1/ brd 172.17.255.255 scope global docker0
  5. valid_lft forever preferred_lft forever
  6. inet6 fe80:::c4ff:fe78:a105/ scope link
  7. valid_lft forever preferred_lft forever

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

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

  1. userdeMBP:~ user$ docker start ubuntu6
  2. ubuntu6
  3. userdeMBP:~ user$ docker exec -it --privileged ubuntu6 /bin/bash
  4. root@linuxkit-:/# ip addr show docker0
  5. : docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
  6. link/ether ::4a::0f:f1 brd ff:ff:ff:ff:ff:ff
  7. inet 192.188.0.1/ brd 192.188.255.255 scope global docker0
  8. valid_lft forever preferred_lft forever
  9. inet6 fe80:::4aff:fe48:ff1/ scope link
  10. valid_lft forever preferred_lft forever

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

4) 自定义网桥

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

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

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

  1. $ sudo service docker stop
  2. $ sudo ip link set dev docker0 down
  3. $ sudo brctl delbr docker0

添加自定义网段:

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

  1. root@linuxkit-:/# brctl show
  2. bridge name bridge id STP enabled interfaces
  3. br-9dc30b4c7e39 .0242a6b606aa no veth2339518
  4. veth3ee80da
  5. br-f16ae5c303c6 .02427bc35a0e no
  6. docker0 .0242333af167 no veth0fcbc17
  7. veth229300e
  8. veth611835f
  9. veth87e64f4
  10. root@linuxkit-:/# brctl addbr bridge0 //添加一个名为bridge0的网桥
  11. root@linuxkit-:/# ip addr add 192.168.5.1/ dev bridge0 //设置其IP地址和子网掩码为192.168.5.1/24
  12. root@linuxkit-:/# ip link set dev bridge0 up //然后启动
  13. root@linuxkit-:/# brctl show
  14. bridge name bridge id STP enabled interfaces
  15. br-9dc30b4c7e39 .0242a6b606aa no veth2339518
  16. veth3ee80da
  17. br-f16ae5c303c6 .02427bc35a0e no
  18. bridge0 8000.000000000000 no
  19. docker0 .0242333af167 no veth0fcbc17
  20. veth229300e
  21. veth611835f
  22. veth87e64f4
  23. root@linuxkit-:/# ip addr show bridge0 /查看其IP地址和子网掩码
  24. : bridge0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN group default qlen
  25. link/ether 7e::cc:ff:d1:7c brd ff:ff:ff:ff:ff:ff
  26. inet 192.168.5.1/ scope global bridge0
  27. valid_lft forever preferred_lft forever
  28. inet6 fe80::7c37:ccff:feff:d17c/ scope link
  29. valid_lft forever preferred_lft forever

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

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

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

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

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

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

  1. userdeMBP:~ user$ docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. f9b3e9b815d5 bridge bridge local
  4. 0012b4fcfb27 host host local
  5. 7612dc76f9c0 none null local

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

  1. userdeMBP:~ user$ docker network create --driver bridge --subnet 172.20.11.0/ --gateway 172.20.11.1 myNetwork1
  2. 67ae783934fe80ace7e464ee876fddb351b0750ae51ae099508ce665dde828dd
  3. userdeMBP:~ user$ docker network ls
  4. NETWORK ID NAME DRIVER SCOPE
  5. f9b3e9b815d5 bridge bridge local
  6. 0012b4fcfb27 host host local
  7. 67ae783934fe myNetwork1 bridge local
  8. 7612dc76f9c0 none null local
  9. userdeMBP:~ user$ docker network inspect 67ae783934fe
  10. [
  11. {
  12. "Name": "myNetwork1",
  13. "Id": "67ae783934fe80ace7e464ee876fddb351b0750ae51ae099508ce665dde828dd",
  14. "Created": "2018-12-21T08:11:55.621127909Z",
  15. "Scope": "local",
  16. "Driver": "bridge",
  17. "EnableIPv6": false,
  18. "IPAM": {
  19. "Driver": "default",
  20. "Options": {},
  21. "Config": [
  22. {
  23. "Subnet": "172.20.11.0/24",
  24. "Gateway": "172.20.11.1"
  25. }
  26. ]
  27. },
  28. "Internal": false,
  29. "Attachable": false,
  30. "Ingress": false,
  31. "ConfigFrom": {
  32. "Network": ""
  33. },
  34. "ConfigOnly": false,
  35. "Containers": {},
  36. "Options": {},
  37. "Labels": {}
  38. }
  39. ]

然后果然成功生成该网络

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

  1. userdeMBP:~ user$ docker run -it --name=ubuntu1 --network=host ubuntu:18.04 /bin/bash
  2. Unable to find image 'ubuntu:18.04' locally
  3. 18.04: Pulling from library/ubuntu
  4. 32802c0cfa4d: Pull complete
  5. da1315cffa03: Pull complete
  6. fa83472a3562: Pull complete
  7. f85999a86bef: Pull complete
  8. Digest: sha256:6d0e0c26489e33f5a6f0020edface2727db9489744ecc9b4f50c7fa671f23c49
  9. Status: Downloaded newer image for ubuntu:18.04
  10.  
  11. root@linuxkit-:/# brctl
  12. bash: brctl: command not found
  13.  
  14. root@linuxkit-:/# apt-get install bridge-utils
  15. Reading package lists... Done
  16. Building dependency tree
  17. Reading state information... Done
  18. E: Unable to locate package bridge-utils
  19.  
  20. root@linuxkit-:/# apt-get update //更新源
  21. Get: http://security.ubuntu.com/ubuntu bionic-security InRelease [83.2 kB]
  22. ...
  23. Fetched 15.3 MB in 44s ( kB/s)
  24. Reading package lists... Done
  25.  
  26. root@linuxkit-:/# apt-get install bridge-utils
  27. Reading package lists... Done
  28. ...
  29.  
  30. root@linuxkit-:/# brctl show
  31. bridge name bridge id STP enabled interfaces
  32. br-67ae783934fe .02423cfe1d7e no
  33. docker0 .02420f4186a9 no

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

 

Docker技术入门与实战 第二版-学习笔记-8-网络功能network-3-容器访问控制和自定义网桥的更多相关文章

  1. Docker技术入门与实战 第二版-学习笔记-8-网络功能network-1-单个host上的容器网络

    Docker 中的网络功能介绍 Docker 允许通过外部访问容器或容器互联的方式来提供网络服务 1) 外部访问容器 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -p或 -P参数 ...

  2. Docker技术入门与实战 第二版-学习笔记-8-网络功能network-2-相应配置

    1) 快速配置指南(详细使用下面会讲) 其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效 下面2个命令选项既可以在启动服务时指定,也可以 Docker 容器启动(dock ...

  3. Docker技术入门与实战 第二版-学习笔记-10-Docker Machine 项目-2-driver

    1>使用的driver 1〉generic 使用带有SSH的现有VM/主机创建机器. 如果你使用的是机器不直接支持的provider,或者希望导入现有主机以允许Docker Machine进行管 ...

  4. Docker技术入门与实战 第二版-学习笔记-7-数据管理(volume)

    Docker 数据管理 为什么要进行数据管理呢?因为当我们在使用container时,可能会在里面创建一些数据或文件,但是当我们停掉或删除这个容器时,这些数据或文件也会同样被删除,这是我们并不想看见的 ...

  5. Docker技术入门与实战 第二版-学习笔记-5-容器-命令及限制内存与cpu资源

    1.启动容器 启动容器有两种方式: 基于镜像新建一个容器并启动 将在终止状态(stopped)的容器重新启动 1)新建并启动——docker run 比如在启动ubuntu:14.04容器,并输出“H ...

  6. Docker技术入门与实战 第二版-学习笔记-10-Docker Machine 项目-1-cli

    Docker Machine 是 Docker 官方编排(Orchestration)项目之一,负责在多种平台上快速安装 Docker 环境 Docker Machine是一种工具,它允许你在虚拟主机 ...

  7. Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解

    前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY  <源路径> .. ...

  8. Docker技术入门与实战 第二版-学习笔记-6-仓库

    仓库(Repository)是集中存放镜像的地方 一个容易混淆的概念是注册服务器(Registry). 实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像. ...

  9. Docker技术入门与实战 第二版-学习笔记-2-镜像构建

    3.利用 commit 理解镜像构成 在之前的例子中,我们所使用的都是来自于 Docker Hub 的镜像. 直接使用这些镜像是可以满足一定的需求,而当这些镜像无法直接满足需求时,我们就需要定制这些镜 ...

随机推荐

  1. REST风格的应用程序实现

    莫笑我老土,因为我确实是最近才听说REST风格的,以前就是觉得 /category/product/pid 这样的地址非常的漂亮,但是那只是表象罢了,了解深入以后,发现必须有一个客户端的Ajax En ...

  2. Java - HashCode源码解析

    Java提高篇(二六)-----hashCode hashCode的作用 要想了解一个方法的内在原理,我们首先需要明白它是干什么的,也就是这个方法的作用.在讲解数组时(java提高篇(十八)----- ...

  3. mongodb命令(持续更新)

    $lt $lte $gt $gte< . <= . > . >= 1.分组求和db.collection.aggregate([{$group : {_id : null, s ...

  4. 数组无法使用 forEach() 方法 - 分号的重要性

    问题描述: 函数的结构如上图所示,在调用该函数的时候,浏览器报错: 分析原因: 在 js 的语法中,如果语句独占一行,通常可以省略句末的分号 但实际上 js 解析代码的时候,只有在句末缺少分号就无法正 ...

  5. vue input输入框联想

    以下是示例,样式可以自己修改.最后是效果图,其实也挺简单的,主要是用了watch监控input输入值的变化,如果数据是请后端请求可以,先请求数据. <template> <div c ...

  6. lamp配置多个虚拟站点

    在同一ip下添加多个域名站点! 1.查看ip 命令:ifconfig 2.添加域名 命令:vi /etc/hosts 输入域名:如 192.168.160.127   www.test.com 192 ...

  7. kvm 创建新虚拟机命virt-install 使用说明

    virt-install 命令说明 1.命令作用      建立(provision)新虚拟机   2.语法   virt-install [选项]... 3.说明(DESCRIPTION)   vi ...

  8. css实现3D立方体旋转特效

    先来看运行后出来的效果 它是在不停运行的一个立方体 先来看html部分的代码 <div class="rect-wrap"> <!--舞台元素,设置perspec ...

  9. 《Inside C#》笔记(一) .NET平台

    C# 基于.NET运行时,所以有必要首先对.NET以及C#与.NET平台的关系有一定的了解. 一 .NET平台 .NET背后的基本思想是将原本独立工作的设备.网络服务整合在一个统一的平台上,从而可以为 ...

  10. 8.1、包,__init__.py,

    包: 为了组织好模块,将多个模块组合为一个包,所以包用于存放python模块 包通常是一个文件夹,当文件夹当作包使用时,文件夹需要包含__init__.py文件 __init__.py的内容可以为空, ...