Docker技术入门与实战 第二版-学习笔记-8-网络功能network-3-容器访问控制和自定义网桥
1)容器访问控制
容器的访问控制,主要通过 Linux 上的 iptables防火墙来进行管理和实现。 iptables是 Linux 上默认的防火墙软件,在大部分发行版中都自带。
容器访问外部网络
容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开:
- root@36078e6ba58f:/opt/webapp# sysctl net.ipv4.ip_forward
- net.ipv4.ip_forward =
为1,说明打开了;如果为0,说明没有开启转发,则需要手动打开,在容器内运行:
- 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容器中执行:
- 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: http://security.ubuntu.com trusty-security InRelease [65.9 kB]
- ...
- Get: http://archive.ubuntu.com trusty/multiverse amd64 Packages [169 kB]
- Fetched 13.3 MB in 45s ( kB/s)
- Reading package lists... Done
- root@9e11c1b9e90d:/# apt-get install iptables
- Reading package lists... Done
- ...
- Setting up libnfnetlink0:amd64 (1.0.-) ...
- Setting up libxtables10 (1.4.-1ubuntu1) ...
- Setting up iptables (1.4.-1ubuntu1) ...
- Processing triggers for libc-bin (2.19-0ubuntu6.) ...
- 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/ 127.0.0.11
- Chain POSTROUTING (policy ACCEPT)
- target prot opt source destination
- DOCKER_POSTROUTING all -- 0.0.0.0/ 127.0.0.11
- Chain DOCKER_OUTPUT ( references)
- target prot opt source destination
- DNAT tcp -- 0.0.0.0/ 127.0.0.11 tcp dpt: to:127.0.0.11:
- DNAT udp -- 0.0.0.0/ 127.0.0.11 udp dpt: to:127.0.0.11:
- Chain DOCKER_POSTROUTING ( references)
- target prot opt source destination
- SNAT tcp -- 127.0.0.11 0.0.0.0/ tcp spt: to::
- SNAT udp -- 127.0.0.11 0.0.0.0/ udp spt: to::
- 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-:/# brctl show
- bash: brctl: command not found
- root@linuxkit-:/# 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
- upgraded, newly installed, to remove and not upgraded.
- Need to get 29.2 kB of archives.
- After this operation, kB of additional disk space will be used.
- Get: http://archive.ubuntu.com/ubuntu/ trusty/main bridge-utils amd64 1.5-6ubuntu2 [29.2 kB]
- Fetched 29.2 kB in 3s ( B/s)
- Selecting previously unselected package bridge-utils.
- (Reading database ... files and directories currently installed.)
- Preparing to unpack .../bridge-utils_1.-6ubuntu2_amd64.deb ...
- Unpacking bridge-utils (1.5-6ubuntu2) ...
- Setting up bridge-utils (1.5-6ubuntu2) ...
- root@linuxkit-:/# brctl show
- bridge name bridge id STP enabled interfaces
- br-9dc30b4c7e39 .0242a6b606aa no veth2339518 //自定义的bridge网桥myNetwork1,有两个容器连接
- veth3ee80da
- br-f16ae5c303c6 .02427bc35a0e no //自定义的bridge网桥myNetwork1,无容器连接
- docker0 .0242333af167 no veth0fcbc17 //默认bridge网桥,有四个容器连接
- veth229300e
- veth611835f
- veth87e64f4
- root@linuxkit-:/#
注: brctl命令在 Debian、Ubuntu 中可以使用 apt-get install bridge-utils来安装。
每次创建一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。
使用本地主机上docker0 接口的 IP 作为所有容器的默认网关,不指定连接的网段,就默认使用docker0。
1》使用--bip修改默认网桥docker的IP地址和子网掩码
首先先查看当前docker0的IP地址和子网掩码:
- root@linuxkit-:/# ip addr show docker0
- : docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
- link/ether ::c4::a1: brd ff:ff:ff:ff:ff:ff
- inet 172.17.0.1/ brd 172.17.255.255 scope global docker0
- valid_lft forever preferred_lft forever
- inet6 fe80:::c4ff:fe78:a105/ 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-:/# ip addr show docker0
- : docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
- link/ether ::4a::0f:f1 brd ff:ff:ff:ff:ff:ff
- inet 192.188.0.1/ brd 192.188.255.255 scope global docker0
- valid_lft forever preferred_lft forever
- inet6 fe80:::4aff:fe48:ff1/ scope link
- valid_lft forever preferred_lft forever
发现果然成功更改成了192.188.0.1/
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-:/# brctl show
- bridge name bridge id STP enabled interfaces
- br-9dc30b4c7e39 .0242a6b606aa no veth2339518
- veth3ee80da
- br-f16ae5c303c6 .02427bc35a0e no
- docker0 .0242333af167 no veth0fcbc17
- veth229300e
- veth611835f
- veth87e64f4
- root@linuxkit-:/# brctl addbr bridge0 //添加一个名为bridge0的网桥
- root@linuxkit-:/# ip addr add 192.168.5.1/ dev bridge0 //设置其IP地址和子网掩码为192.168.5.1/24
- root@linuxkit-:/# ip link set dev bridge0 up //然后启动
- root@linuxkit-:/# brctl show
- bridge name bridge id STP enabled interfaces
- br-9dc30b4c7e39 .0242a6b606aa no veth2339518
- veth3ee80da
- br-f16ae5c303c6 .02427bc35a0e no
- bridge0 8000.000000000000 no
- docker0 .0242333af167 no veth0fcbc17
- veth229300e
- veth611835f
- veth87e64f4
- root@linuxkit-:/# ip addr show bridge0 /查看其IP地址和子网掩码
- : bridge0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN group default qlen
- link/ether 7e::cc:ff:d1:7c brd ff:ff:ff:ff:ff:ff
- inet 192.168.5.1/ scope global bridge0
- valid_lft forever preferred_lft forever
- inet6 fe80::7c37:ccff:feff:d17c/ 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/ --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-:/# brctl
- bash: brctl: command not found
- root@linuxkit-:/# 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-:/# apt-get update //更新源
- Get: http://security.ubuntu.com/ubuntu bionic-security InRelease [83.2 kB]
- ...
- Fetched 15.3 MB in 44s ( kB/s)
- Reading package lists... Done
- root@linuxkit-:/# apt-get install bridge-utils
- Reading package lists... Done
- ...
- root@linuxkit-:/# brctl show
- bridge name bridge id STP enabled interfaces
- br-67ae783934fe .02423cfe1d7e no
- docker0 .02420f4186a9 no
从上面可见,我们自定义网络的过程其实也生成了一个自定义网桥br-67ae783934fe,如果你想要容器是连接在该网桥上的,那么在run时就使用参数--network=myNetwork1设定即可
Docker技术入门与实战 第二版-学习笔记-8-网络功能network-3-容器访问控制和自定义网桥的更多相关文章
- Docker技术入门与实战 第二版-学习笔记-8-网络功能network-1-单个host上的容器网络
Docker 中的网络功能介绍 Docker 允许通过外部访问容器或容器互联的方式来提供网络服务 1) 外部访问容器 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -p或 -P参数 ...
- Docker技术入门与实战 第二版-学习笔记-8-网络功能network-2-相应配置
1) 快速配置指南(详细使用下面会讲) 其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效 下面2个命令选项既可以在启动服务时指定,也可以 Docker 容器启动(dock ...
- Docker技术入门与实战 第二版-学习笔记-10-Docker Machine 项目-2-driver
1>使用的driver 1〉generic 使用带有SSH的现有VM/主机创建机器. 如果你使用的是机器不直接支持的provider,或者希望导入现有主机以允许Docker Machine进行管 ...
- Docker技术入门与实战 第二版-学习笔记-7-数据管理(volume)
Docker 数据管理 为什么要进行数据管理呢?因为当我们在使用container时,可能会在里面创建一些数据或文件,但是当我们停掉或删除这个容器时,这些数据或文件也会同样被删除,这是我们并不想看见的 ...
- Docker技术入门与实战 第二版-学习笔记-5-容器-命令及限制内存与cpu资源
1.启动容器 启动容器有两种方式: 基于镜像新建一个容器并启动 将在终止状态(stopped)的容器重新启动 1)新建并启动——docker run 比如在启动ubuntu:14.04容器,并输出“H ...
- Docker技术入门与实战 第二版-学习笔记-10-Docker Machine 项目-1-cli
Docker Machine 是 Docker 官方编排(Orchestration)项目之一,负责在多种平台上快速安装 Docker 环境 Docker Machine是一种工具,它允许你在虚拟主机 ...
- Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解
前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY <源路径> .. ...
- Docker技术入门与实战 第二版-学习笔记-6-仓库
仓库(Repository)是集中存放镜像的地方 一个容易混淆的概念是注册服务器(Registry). 实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像. ...
- Docker技术入门与实战 第二版-学习笔记-2-镜像构建
3.利用 commit 理解镜像构成 在之前的例子中,我们所使用的都是来自于 Docker Hub 的镜像. 直接使用这些镜像是可以满足一定的需求,而当这些镜像无法直接满足需求时,我们就需要定制这些镜 ...
随机推荐
- REST风格的应用程序实现
莫笑我老土,因为我确实是最近才听说REST风格的,以前就是觉得 /category/product/pid 这样的地址非常的漂亮,但是那只是表象罢了,了解深入以后,发现必须有一个客户端的Ajax En ...
- Java - HashCode源码解析
Java提高篇(二六)-----hashCode hashCode的作用 要想了解一个方法的内在原理,我们首先需要明白它是干什么的,也就是这个方法的作用.在讲解数组时(java提高篇(十八)----- ...
- mongodb命令(持续更新)
$lt $lte $gt $gte< . <= . > . >= 1.分组求和db.collection.aggregate([{$group : {_id : null, s ...
- 数组无法使用 forEach() 方法 - 分号的重要性
问题描述: 函数的结构如上图所示,在调用该函数的时候,浏览器报错: 分析原因: 在 js 的语法中,如果语句独占一行,通常可以省略句末的分号 但实际上 js 解析代码的时候,只有在句末缺少分号就无法正 ...
- vue input输入框联想
以下是示例,样式可以自己修改.最后是效果图,其实也挺简单的,主要是用了watch监控input输入值的变化,如果数据是请后端请求可以,先请求数据. <template> <div c ...
- lamp配置多个虚拟站点
在同一ip下添加多个域名站点! 1.查看ip 命令:ifconfig 2.添加域名 命令:vi /etc/hosts 输入域名:如 192.168.160.127 www.test.com 192 ...
- kvm 创建新虚拟机命virt-install 使用说明
virt-install 命令说明 1.命令作用 建立(provision)新虚拟机 2.语法 virt-install [选项]... 3.说明(DESCRIPTION) vi ...
- css实现3D立方体旋转特效
先来看运行后出来的效果 它是在不停运行的一个立方体 先来看html部分的代码 <div class="rect-wrap"> <!--舞台元素,设置perspec ...
- 《Inside C#》笔记(一) .NET平台
C# 基于.NET运行时,所以有必要首先对.NET以及C#与.NET平台的关系有一定的了解. 一 .NET平台 .NET背后的基本思想是将原本独立工作的设备.网络服务整合在一个统一的平台上,从而可以为 ...
- 8.1、包,__init__.py,
包: 为了组织好模块,将多个模块组合为一个包,所以包用于存放python模块 包通常是一个文件夹,当文件夹当作包使用时,文件夹需要包含__init__.py文件 __init__.py的内容可以为空, ...