如果你想掌握Docker网络,这篇文章是为你准备的。
关注《Java学研大本营》
几个月前,作者通过一个实际例子展示了理解和利用Docker卷的原因。
在这篇文章中,作者将尝试在Docker网络方面做同样的事情。
如果你想掌握Docker网络,这篇文章是为你准备的。
在一个网络中的容器
由于容器的隔离性质,它们并不共享主机网络,然而Docker为它们提供了网络。
当Docker Runtime启动时,它会创建3个默认网络。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5c65c2b3031b bridge bridge local
cf446ef29441 host host local
50fd86384bb9 none null local下面,让我们逐个理解它们。
桥梁网络
首先,我们可以通过检查网络来检查配置。
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "5c65c2b3031b6d10f357f74f6cb5bf04af13819fca28b5458e00bb6b1d1718ec",
"Created": "2022-06-27T23:49:43.227773167Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]我们可以看到,通过网关172.17.0.1响应的网络,此刻还没有添加容器。
桥接网络提供桥接驱动,所以在这个网络中创建的容器会收到一个IP地址。
为了确认这一点,我们创建一个NGINX容器。
$ docker run --name nginx --network bridge -d nginx这只是一个运行在容器80端口的NGINX网络应用程序,并提供传统的HTML页面 "欢迎来到NGINX"。
容器被添加到网络上了吗?
$ docker network inspect bridge
...
"Containers": {
"bb283ee626dbc631281fc0c27a1f02f075ab1908800965008a315cedd7f9d438": {
"Name": "nginx",
"EndpointID": "f12f67c1d7488f708027c2e948b204ce09743721095d4514c9c24bedf8167191",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},是的。我们可以看到,最近创建的容器被添加到了桥接网络中,并得到了IP地址172.17.0.2。
我们如何使用它的 IP 与这样的容器进行通信,换句话说,我们能否点击 http://172.17.0.2 并看到 "欢迎来到 NGINX" HTML结果?
$ wget http://172.17.0.2 -O -
Connecting to 172.17.0.2:80...并没有:(
容器不共享主机网络
同样,容器不共享 "主机 "网络。这意味着只有在同一网络(桥)中的其他容器可以相互交谈。
好吧,那我们可以运行另一个容器,然后打到NGINX上吗?
$ docker run \
--network bridge \
alpine \
sh -c "wget http://172.17.0.2 -O -"
Connecting to 172.17.0.2 (172.17.0.2:80)
writing to stdout
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
- 100% |********************************| 615 0:00:00 ETA
written to stdout耶! 那是相当整洁的。
桥接已经是默认网络
只是为了节省时间,每当我们创建容器时,它们就会被自动添加到桥接网络中。
$ docker run --name nginx -d nginx
$ docker run alpine sh -c "wget http://172.17.0.2 -O -"它就刚刚工作了。这多酷啊!
使用容器名称而不是IP地址
但记住IP地址并不总是好事,对吗?使用容器的名称而不是它的IP怎么样?
$ docker run --network bridge alpine sh -c "wget http://nginx -O -"
wget: bad address 'nginx'啊哦:(,桥梁网络不能将名字解析为IP地址。
但今天,是我们的幸运日。Docker允许我们使用桥接驱动器,并创建用户定义的自定义网络,就像这样做一样简单。
$ docker network create saturno
NETWORK ID NAME DRIVER SCOPE
5c65c2b3031b bridge bridge local
cf446ef29441 host host local
50fd86384bb9 none null local
4216c3a16815 saturno bridge localsaturno网络使用的是桥接默认网络所使用的驱动桥。如果我们用docker network inspect saturno (docker网络检查saturno这个网络),我们可以看到它还没有容器,并且使用了172.18.0.1这个网关IP。
让我们在saturno网络上创建容器。
$ docker run --name nginx --network saturno -d nginx通过再次检查网络,容器已经得到了172.18.0.2的IP。因此,让我们再打一下这个容器。
$ docker run --network saturno alpine sh -c "wget http://172.18.0.2 -O -"它是有效的。但我们还是想用它的名字来检查。
$ docker run --network saturno alpine sh -c "wget http://nginx -O -"多么美好的一天,它工作了!
主机网络
当我们需要将容器暴露在主机网络中时,这个网络很有用。
$ docker --name nginx --network host -d nginx$ docker network inspect host
[
{
"Name": "host",
"Id": "cf446ef29441aeaaee2a40cfcf9ad120aedb7c51cf2dbc20cc23e567101d217c",
"Created": "2022-01-13T21:57:00.2326735Z",
"Scope": "local",
"Driver": "host",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"668c12bbabb8cd28e8cc8666d074fc929214f7b9ddfddfa3d76c8476652c4091": {
"Name": "nginx",
"EndpointID": "738ea09ee3d450e9f655440a303a52f219d9ca22fe011eb62dffe7d0351f31de",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]我们可以看到添加到网络中的容器,但它没有IP地址,这意味着其他容器不能与它对话,只能与主机对话。
# Linux only
$ wget http://localhost -O -它工作了。
注意:这个网络只在Linux上工作。在Mac或Windows的Docker Desktop中,我们必须使用另一种方式将容器暴露在主机上。
选项-p
另一种将容器暴露给主机的方法是使用标志-p,它本身不是主机网络,但它**将[容器端口]发布到[主机端口]**。
$ docker run --name nginx -p 80:80 -d nginx
$ wget http://localhost -O -它工作了!
无网络
任何时候我们需要创建一个完全隔离的容器,不与任何其他容器交谈,我们可以把它添加到none网络中,它使用null驱动。
$ docker run --name nginx --network none -d nginx
$ docker network inspect none
[
{
"Name": "none",
"Id": "50fd86384bb9cc90d953a624a5ab70b869357027d3cdc7ebc9b4043798dd4f6a",
"Created": "2022-01-13T21:57:00.224557375Z",
"Scope": "local",
"Driver": "null",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"90a6691b818e164bd2e1f67e8f3a62ce71eaddbe9ac215c370a8a6766204a2b0": {
"Name": "nginx",
"EndpointID": "0ed9e33f051f2df2c37b96fc2fdf7df074b73359117a12a81ae4c28ef0ec6877",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]这个网络没有网关IP,因此不要将IP地址与容器相关联。
奖励点:即时连接容器
有时,我们已经在默认网络中运行了容器,但由于某些原因,我们想用名字进行通信。
$ docker run --name nginx -d nginx
$ docker run --name ruby -dit ruby irb他们生活在默认的bridge桥接网络中,他们可以使用IP互相交谈,但不能使用他们的名字,记得吗?
$ docker network create saturno最明显的解决办法是:首先阻止他们,然后利用saturno网络创建新的。正确吗?
算是吧。但是,没有必要停止容器!只要把它们连接到现有的网络上就可以了。只要把它们连接到现有的网络就可以了。
$ docker network connect saturno nginx
$ docker network connect saturno ruby
$ docker network inspect saturno
"Containers": {
"15bcd3a425024c627a57bddb878a11fcd3f43cb4da4576ef05d89b45a96f49ad": {
"Name": "nginx",
"EndpointID": "e0ef0bb83b1e553215cf24dcc6c20355a5ca5367e2d02f120b00b4a77c975964",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
},
"6ab4256e8c808ebd16f2e9643e5636df03f58dbfc4778a939df0b286b829babd": {
"Name": "ruby",
"EndpointID": "ab3a590379938f8654a0aada7cfab97cc47eb92f3fe89656a2feccc9bd52cbe1",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16",
"IPv6Address": ""
}
},哦,我的天哪,它让我的一天都那么美好!
总结
这篇文章试图解释Docker网络的主要方面。我希望它能帮助你了解更多,并根据你的需要使用它。
Docker的官方网站上有一个很好的网络介绍,以及简单的教程。(官网地址:https://docs.docker.com/network/)
参考文章:https://dev.to/leandronsp/mastering-the-docker-networking-2h57
















