Docker中的网络功能
Docker 允许通过外部访问容器或容器互联的方式来提供网络服务
访问外部容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P
或者 -p
参数来指定端口映射。
当使用 -P
标记时,Docker会随机映射一个端口到内部容器开放的网络端口。
使用 docker -container ls
可以看到,本地主机的32768
端口被映射到了容器的80
端口。此时访问本机的32768
端口即可看到nginx的页面。
xin@xin:~$ docker run -d -P --name devtest nginx:latest
xin@xin:~$ docker container ls -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c8fbcf3f109 nginx:latest "nginx -g 'daemon of…" 7 seconds ago Up 6 seconds 0.0.0.0:32768->80/tcp devtest
-p
则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有:ip:hostPort:containerPort | ip::containerPort |hostPort:containerPort
。
映射所有接口地址
使用 hostPort:containerPort
更是将本地的7110
端口映射到容器的80
端口,我们可以使用下面的命令:
xin@xin:~$ docker run -d -p 7110:80 --name devtest nginx:latest
此时默认会绑定本地所有接口上的所有地址
映射到指定地址的指定端口
可以使用ip:hostPort:containerPort
格式指定映射使用一个特定地址,比如localhost
地址127.0.0.1
:
xin@xin:~$ docker run -d -p 127.0.0.1:7110:80 --name devtest nginx:latest
映射到指定地址的任意端口
使用ip::containerPort
绑定localhost的任意端口到容器的80端口,本地主机会自动分配一个端口:
xin@xin:~$ docker run -d -p 127.0.0.1::80 --name devtest nginx:latest
我们还可以使用udp
标记来指定udp
端口:
xin@xin:~$ docker run -d -p 127.0.0.1::80/udp --name devtest nginx:latest
查看映射端口配置
使用 docker port 来查看当前映射的端口配置,也可以查看到绑定的地址:
xin@xin:~$ docker port devtest 80
127.0.0.1:7110
注意:
- 容器有自己的内部网络和 ip 地址( 使用 docker inspect 可以获取所有的变量,Docker 还可以有一个可变的网络配置。)
- -p 标记可以多次使用来绑定多个端口
例如:
xin@xin:~$ docker run -d -p 7110:80 -p 7111:7200 --name devtest nginx:latest
容器互联
Docker的网络子系统是可插拔的,使用驱动程序。默认情况下存在多个驱动程序,并提供核心网络功能:
bridge
:默认网络驱动程序。如果未指定驱动程序,则这是我们要创建的网络类型。当我们的应用程序在需要通信的独立容器中运行时,通常会使用bridge。host
:对于独立容器,删除容器和Docker主机之间的网络隔离,并直接使用主机的网络。host 仅适用于Docker 17.06及更高版本上的群集服务。overlay
:覆盖网络将多个Docker守护程序连接在一起,并使群集服务能够相互通信。我们还可以使用overlay网络来促进群集服务和独立容器之间的通信,或者在不同Docker守护程序上的两个独立容器之间进行通信。此策略无需在这些容器之间执行OS级别的路由。macvlan
:Macvlan网络允许我们为容器分配MAC地址,使其显示为网络上的物理设备。Docker守护程序通过其MAC地址将流量路由到容器。macvlan 在处理期望直接连接到Macvlan网络的传统应用程序时,使用驱动程序有时是最佳选择,而不是通过Docker主机的网络堆栈进行路由。none
:对于此容器,禁用所有网络。通常与自定义网络驱动程序一起使用。none不适用于群组服务。
网络驱动摘要
- 当我们需要多个容器在同一个Docker主机上进行通信时,用户定义的bridge网络是最佳选择。
- 当网络堆栈不应与Docker主机隔离时,主机网络最佳,但我们希望隔离容器的其他方面。
- 当我们需要在不同Docker主机上运行的容器进行通信时,或者当多个应用程序使用swarm服务协同工作时,覆盖网络是最佳选择。
- 当我们从VM设置迁移或需要我们的容器看起来像网络上的物理主机(每个都具有唯一的MAC地址)时,Macvlan网络是最佳的。
- 第三方网络插件允许我们将Docker与专用网络堆栈集成。
新建网络
下面先创建一个新的Docker网络,使用此docker network create
命令可以创建用户定义的bridge网络:
xin@xin:~$ docker network create -d bridge my-net
-d
参数指定Docker网络的类型。
你还可以指定子网,IP地址范围,网关和其他选项。详细信息请输出docker network create --help
将容器连接到用户定义的bridge网络
创建新容器时,可以指定一个或多个--network
参数。将busybox容器连接到my-net网络。
xin@xin:~$ docker create --name busybox1 --network my-net busybox:latest
当网络创建好了之后,我们可以运行这个容器:
xin@xin:~$ docker container start my-busybox1
按照上面通用的步骤,我们继续启动一个busybox容器:
xin@xin:~$ docker create --name busybox2 --network my-net busybox:latest
xin@xin:~$ docker container start busybox2
现在我们进入busybox1和busybox2容器,并且使用ping来证明busybox1
容器和bosybox2
容器建立了互联关系:
xin@xin:~$ docker exec -it busybox1 sh
/ # ping busybox2
PING busybox2 (172.20.0.3): 56 data bytes
64 bytes from 172.20.0.3: seq=0 ttl=64 time=0.107 ms
64 bytes from 172.20.0.3: seq=1 ttl=64 time=0.076 ms
xin@xin:~$ docker exec -it busybox2 sh
/ # ping busybox1
PING busybox1 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.067 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.055 ms
可以看到当我ping busybox1
时,它会解析成172.20.0.2
,ping busybox2
时会解析成172.20.0.1
。
这样,busybox1
和busybox2
容器就建立了互联关系。
如果你有多个容器之间需要互相连接,推荐使用 Docker Compose。
配置 DNS
如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件。
在容器中使用 mount 命令可以看到挂载信息:
root@b9db9f138e54:/# mount
...
tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)
...
这种机制可以让宿主主机 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 。使用以下命令来证明其已经生效。
xin@xin:~$ docker run -it --rm nginx:latest bash
root@f7424ff3563f:/# cat /etc/resolv.conf
# Generated by NetworkManager
search DHCP HOST
nameserver 202.96.128.166
nameserver 223.6.6.6
如果用户想要手动指定容器的配置,可以在使用 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 来配置容器。
小结
- 通过-P命令可以随机生成容器的端口,也可以通过特定的格式来指定容器的端口
- 创建网络并且指定容器使用的网络可以使容器的网络互通
- 最简单指定容器的DNS方式是编辑/etc/docker/daemon.json并且配置好dns