Docker 网络
# Docker 中的网络功能介绍
Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。
外部访问容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P
或 -p
参数来指定端口映射。
当使用 -P
标记时,Docker 会随机映射一个 49000~49900
的端口到内部容器开放的网络端口。
使用 docker container ls
可以看到,本地主机的 49155 被映射到了容器的 5000 端口。此时访问本机的 49155 端口即可访问容器内 web 应用提供的界面。
[root@docker .bash_history]# docker run -d -P nginx
6dd45a7361c1bf4612be01d544b2ea316bcad4ff728c811741038b26b4065bc9
[root@docker .bash_history]# docker container ls -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6dd45a7361c1 nginx "nginx -g 'daemon of…" 19 seconds ago Up 19 seconds 0.0.0.0:32779->80/tcp wizardly_driscoll
同样的,可以通过 docker logs
命令来查看应用的信息。
[root@docker .bash_history]# docker logs -f wizardly_driscoll
192.168.138.1 - - [20/Sep/2020:20:39:33 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36" "-"
2020/09/20 20:39:33 [error] 6#6: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.138.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.138.99:32779", referrer: "http://192.168.138.99:32779/"
192.168.138.1 - - [20/Sep/2020:20:39:33 +0000] "GET /favicon.ico HTTP/1.1" 404 571 "http://192.168.138.99:32779/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36" "-"
-p
则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort
。
-
映射所有接口地址
使用 hostPort:containerPort
格式本地的 80 端口映射到容器的 80 端口,可以执行
[root@docker .bash_history]# docker run -d -p 80:80 nginx
4e0ec996b57b88df5cef229835a247c835a6231ea7cacfc92a7fa0cfbbd5e556
此时默认会绑定本地所有接口上的所有地址。
-
映射到指定地址的指定端口
可以使用 ip:hostPort:containerPort
格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1,或者0.0.0.0
[root@docker ~]# docker run -d -p 0.0.0.0:5000:80 nginx
-
映射到指定地址的任意端口
使用 ip::containerPort
绑定 localhost
or0.0.0.0
的任意端口到容器的 80 端口,本地主机会自动分配一个端口。
[root@docker ~]# docker run -d -p 0.0.0.0::80 nginx
还可以使用 udp
标记来指定 udp
端口
[root@docker ~]# docker run -d -p 127.0.0.1:80:80/udp nginx
-
查看映射端口配置
使用 docker port
来查看当前映射的端口配置,也可以查看到绑定的地址
[root@docker .bash_history]# docker port nervous_mirzakhani 80
0.0.0.0:32780
注意:
-
容器有自己的内部网络和 ip 地址(使用
docker inspect
可以获取所有的变量,Docker 还可以有一个可变的网络配置。) -
-p
标记可以多次使用来绑定多个端口
例如
[root@docker ~]# docker run -d \
-p 5000:5000 \
-p 3000:80 \
training/webapp \
python app.py
容器互联
如果你之前有 Docker
使用经验,你可能已经习惯了使用 --link
参数来使容器互联。
随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link
参数。
-
新建网络
下面先创建一个新的 Docker 网络。
[root@docker ~]# docker network create -d bridge test-net
-d
参数指定 Docker 网络类型,有 bridge
overlay
。其中 overlay
网络类型用于 Swarm mode,在本小节中你可以忽略它。
-
连接容器
运行一个容器并连接到新建的 my-net
网络
[root@docker ~]# docker run -it --rm --name busybox1 --network test-net busybox sh
打开新的终端,再运行一个容器并加入到 my-net
网络
[root@docker ~]# docker run -it --rm --name busybox2 --network test-net busybox sh
再打开一个新的终端查看容器信息
[root@docker .bash_history]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77db48cc4067 busybox "sh" 12 seconds ago Up 11 seconds busybox2
7c3cdca41207 busybox "sh" 27 seconds ago Up 26 seconds busybox1
0ddd83c7b908 nginx "nginx -g 'daemon of…" 22 minutes ago Up 22 minutes 0.0.0.0:32780->80/tcp nervous_mirzakhani
下面通过 ping
来证明 busybox1
容器和 busybox2
容器建立了互联关系。
在 busybox1
容器输入以下命令
/ # ping busybox2
PING busybox2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.066 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.123 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.077 ms
用 ping 来测试连接 busybox2
容器,它会解析成 172.18.0.3
。
同理在 busybox2
容器执行 ping busybox1
,也会成功连接到。
/ # ping busybox1
PING busybox1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.104 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.102 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.097 ms
这样,busybox1
容器和 busybox2
容器建立了互联关系。
-
Docker Compose
如果你有多个容器之间需要互相连接,推荐使用 Docker Compose
配置 DNS
如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件。
在容器中使用 mount
命令可以看到挂载信息:
$ mount
/dev/mapper/centos-root on /etc/resolv.conf type xfs (rw,relatime,attr2,inode64,noquota)
/dev/mapper/centos-root on /etc/hostname type xfs (rw,relatime,attr2,inode64,noquota)
/dev/mapper/centos-root on /etc/hosts type xfs (rw,relatime,attr2,inode64,noquota)
这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过 /etc/resolv.conf
文件立刻得到更新。
配置全部容器的 DNS ,也可以在 /etc/docker/daemon.json
文件中增加以下内容来设置。
{
"dns" : [
"223.5.5.5",
"8.8.8.8"
]
}
这样每次启动的容器 DNS 自动配置为 223.5.5.5
和 8.8.8.8
。使用以下命令来证明其已经生效。
[root@docker .bash_history]# docker run -it --rm nginx cat etc/resolv.conf
nameserver 223.5.5.5
nameserver 8.8.8.8
如果用户想要手动指定容器的配置,可以在使用 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
来配置容器。