目录
Docker网络
外部访问容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过-P或-p参数来指定端口映射。
当使用-P标记时,Docker会随机映射一个端口到内部容器开放的网络端口。 使用docker container ls可以看到,本地主机的 32768 被映射到了容器的 80 端口。此时访问本机的 32768 端口即可访问容器内 NGINX 默认页面。
映射所有接口地址
使用hostPort:containerPort格式本地的 80 端口映射到容器的 80 端口,此时默认会绑定本地所有接口上的所有地址。
docker run -d -p 80:80 nginx:alpine
映射到指定地址的指定端口
使用ip:hostPort:containerPort格式指定映射使用一个特定地址,例如:
docker run -d -p 127.0.0.1:80:80 nginx:alpine
映射到指定地址的任意端口
使用ip::containerPort绑定localhost的任意端口到容器的80端口,本地主机会自动分配一个端口,例如:
docker run -d -p 127.0.0.1::80 nginx:alpine
使用udp标记来指定udp端口
docker run -d -p 127.0.0.1:80:80/udp nginx:alpine
查看映射端口配置
使用docker port来查看当前映射的端口配置,也可以查看到绑定的地址
docker port CONTAINER [PRIVATE_PORT[/PROTO]]
-p标记可以多次使用来绑定多个端口
docker run -d \
-p 80:80 \
-p 443:443 \
nginx:alpine
容器互联
新建网络
docker network create -d bridge [net_name]
-d参数指定Docker网络类型,有bridge overlay,其中overlay网络类型用于Swarm mode
连接容器
运行一个容器并连接到新建的my_net网络
docker run -it --rm --name busybox1 --network my_net busybox sh
打开新的终端,再运行一个容器并加入到 my_net网络
再打开一个新的终端查看容器信息
通过 ping来证明busybox1容器和busybox2容器建立了互联关系
如果有多个容器之间需要互相连接,推荐使用Docker
Compose
配置DNS
Docker容器的 DNS 配置通过 /etc/resolv.conf文件立刻得到更新
配置全部容器的 DNS ,也可以在 /etc/docker/daemon.json 文件中增加以下内容来设置,每次启动的容器 DNS 自动配置为 114.114.114.114 和8.8.8.8。
{
"dns" : [
"114.114.114.114",
"8.8.8.8"
]
}
使用以下命令来证明其已经生效
docker run -it --rm ubuntu:18.04 cat etc/resolv.conf
如果想要手动指定容器的配置,可以在使用docker run命令启动容器时加入如下参数:
- -h HOSTNAME或者--hostname=HOSTNAME设定容器的主机名,它会被写到容器内的/etc/hostname 和 /etc/hosts。但它在容器外部看不到,既不会在docker container ls中显示,也不会在其他的容器的/etc/hosts看到
- --dns=IP_ADDRESS添加 DNS 服务器到容器的/etc/resolv.conf中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名
- --dns-search=DOMAIN设定容器的搜索域,当设定搜索域为.example.com时,在搜索一个名为host的主机时,DNS 不仅搜索 host,还会搜索host.example.com
- 如果在容器启动时没有指定最后两个参数,Docker会默认用主机上的/etc/resolv.conf来配置容器
Docker的网络模式
查看网络
docker network ls
网络模式 | 简介 |
---|---|
Bridge | 为每一个容器分配、设置 IP 等,并将容器连接到一个 docker0 虚拟网桥,默认为该模式。 |
Host | 容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。 |
None | 容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,IP 等。 |
Container | 新创建的容器不会创建自己的网卡和配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。 |
Bridge 模式
在创建容器时通过参数 --net bridge 或者 --network bridge 指定即可,当然这也是创建容器默认使用的网络模式,也就是说这个参数是可以省略的。
当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上,附加在其上的任何网卡之间都能自动转发数据包。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过brctl show命令查看
守护进程会创建一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名
同时,守护进程还会从网桥 docker0
的私有地址空间中分配一个 IP 地址和子网给该容器,并设置 docker0 的 IP 地址为容器的默认网关
查看所有 bridge 网络模式下的容器
docker network inspect bridge
Host 模式
host 网络模式需要在创建容器时通过参数--net host或者--network host指定;
采用 host 网络模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换;
host 网络模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。
None 模式
- none 网络模式是指禁用网络功能,只有 lo 接口 local 的简写,代表 127.0.0.1,即 localhost 本地环回接口。在创建容器时通过参数--net none或者--network none指定;
- none 网络模式即不为 Docker Container 创建任何的网络环境,容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。
Container 模式
- Container 网络模式是 Docker 中一种较为特别的网络的模式。在创建容器时通过参数 --net container:已运行的容器名称|ID 或者 --network container:已运行的容器名称|ID 指定
- 处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信
Container 网络模式即新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。
Docker高级网络配置
快速配置
Docker 网络相关的命令列表,其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效。
-b BRIDGE
或--bridge=BRIDGE
指定容器挂载的网桥--bip=CIDR
定制docker0
的掩码-H SOCKET...
或--host=SOCKET... Docker
服务端接收命令的通道--icc=true|false
是否支持容器之间进行通信--ip-forward=true|false
请看下文容器之间的通信--iptables=true|false
是否允许 Docker 添加iptables
规则--mtu=BYTES
容器网络中的MTU
下面2个命令选项既可以在启动服务时指定,也可以在启动容器时指定。在 Docker服务启动的时候指定则会成为默认值,后面执行 docker run 时可以覆盖设置的默认值。
--dns=IP_ADDRESS...
使用指定的DNS服务器--dns-search=DOMAIN...
指定DNS搜索域
这些选项只有在 docker run 执行时使用,因为它是针对容器的特性内容。
-h HOSTNAME
或--hostname=HOSTNAME
配置容器主机名--link=CONTAINER_NAME:ALIAS
添加到另一个容器的连接--net=bridge|none|container:NAME_or_ID|host
配置容器的桥接模式-p SPEC
或 --publish=SPEC` 映射容器端口到宿主主机-P or --publish-all=true|false
映射容器所有端口到宿主主机
容器访问控制
通过 Linux 上的 iptables 防火墙来进行管理和实现。iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。
容器访问外部网络
容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。
sysctl net.ipv4.ip_forward
如果为 0,说明没有开启转发,则需要手动打开。
sysctl -w net.ipv4.ip_forward=1
如果在启动 Docker 服务的时候设定 --ip-forward=true, Docker 就会自动设定系统的 ip_forward 参数为 1。
容器之间访问
容器之间相互访问,需要两方面的支持。
- 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到 docker0 网桥上。
- 本地系统的防火墙软件 -- iptables 是否允许通过。
访问所有端口
- 当启动 Docker 服务(即 dockerd)的时候,默认会添加一条转发策略到本地主机 iptables 的 FORWARD 链上。策略为通过(ACCEPT)还是禁止(DROP)取决于配置--icc=true(缺省值)还是 --icc=false。当然,如果手动指定 --iptables=false 则不会添加 iptables 规则。
- 默认情况下,不同容器之间是允许网络互通的。如果为了安全考虑,可以在 /etc/docker/daemon.json 文件中配置 {"icc": false} 来禁止它。
访问指定端口
在通过 -icc=false 关闭网络访问后,还可以通过 --link=CONTAINER_NAME:ALIAS 选项来访问容器的开放端口。
启动容器(docker run)时使用 --link=CONTAINER_NAME:ALIAS 选项。Docker 会在 iptable 中为 两个容器分别添加一条 ACCEPT 规则,允许相互访问开放的端口(取决于 Dockerfile 中的 EXPOSE 指令)。 当添加了 --link=CONTAINER_NAME:ALIAS 选项后,添加了 iptables 规则。
端口映射实现
默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。
容器访问外部实现
容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址。这是使用 iptables 的源地址伪装操作实现的。
查看主机的 NAT 规则。
sudo iptables -t nat -nL
上述规则将所有源地址在 172.17.0.0/16 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。
外部访问容器实现
容器允许外部访问,可以在 docker run 时候通过 -p 或 -P 参数来启用。
可以通过 -p IP:host_port:container_port 或 -p IP::port 来指定允许访问容器的主机上的 IP、接口等
如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件 /etc/docker/daemon.json 中添加如下内容
{
"ip": "0.0.0.0"
}
配置docker0网桥
Docker 服务默认会创建一个 docker0
网桥(其上有一个 docker0
内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
Docker 默认指定了 docker0
接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了 MTU(接口允许接收的最大传输单元),通常是 1500 Bytes,或宿主主机网络路由上支持的默认值。这些值都可以在服务启动的时候进行配置。
--bip=CIDR
IP 地址加掩码格式,例如 192.168.1.5/24--mtu=BYTES
覆盖默认的 Docker mtu 配置
也可以在配置文件中配置 DOCKER_OPTS,然后重启服务。
由于目前 Docker 网桥是 Linux 网桥,用户可以使用 brctl show
来查看网桥和端口连接信息。
sudo apt-get install bridge-utils
sudo brctl show
每次创建一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。使用本地主机上 docker0
接口的 IP 作为所有容器的默认网关。
自定义网桥
在启动 Docker 服务的时候,使用 -b BRIDGE
或--bridge=BRIDGE
来指定使用的网桥。
如果服务已经运行,那需要先停止服务,并删除旧的网桥。
sudo systemctl stop docker
sudo ip link set dev docker0 down
sudo brctl delbr docker0
创建一个网桥 bridge0
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 配置文件 /etc/docker/daemon.json 中添加如下内容,即可将 Docker 默认桥接到创建的网桥上。
{
"bridge": "bridge0",
}
编辑网络配置文件
Docker 1.2.0 开始支持在运行中的容器里编辑 /etc/hosts, /etc/hostname 和 /etc/resolv.conf 文件。 但是这些修改是临时的,只在运行的容器中保留,容器终止或重启后并不会被保存下来,也不会被 docker commit 提交。