LXX的网络日志
人因梦想而伟大
Docker-06-Docker中的网络功能

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

这样,busybox1busybox2容器就建立了互联关系。

如果你有多个容器之间需要互相连接,推荐使用 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