深入理解Docker网络通信原理

如果你想掌握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",
            "com.docker.network.bridge.name": "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    local

saturno网络使用的是桥接默认网络所使用的驱动桥。如果我们用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

推荐书单

《Java微服务架构实战(SpringBoot+SpringCloud+Docker+RabbitMQ)》

购买链接:https://item.jd.com/12793864.html

Java微服务架构是当下流行的软件架构设计方案,可以快速地进行代码编写与开发,维护起来也非常方便。利用微架构技术,可以轻松地实现高可用、分布式、高性能的项目结构开发,同时也更加安全。

《名师讲坛:Java微服务架构实战(SpringBoot+SpringCloud+Docker+RabbitMQ)》一共15章,核心内容为SpringBoot、SpringCloud、Docker、RabbitMQ消息组件。其中,SpringBoot 是SpringMVC技术的延伸,使用它进行程序开发会更简单,服务整合也会更容易。SpringCloud是当前微架构的核心技术方案,属于SpringBoot的技术延伸,它可以整合云服务,基于RabbitMQ和GITHUB进行微服务管理。除此以外,该书还重点分析了OAuth统一认证服务的应用。

精彩回顾

偏向锁、轻量级锁、重量级锁,Synchronized底层源码终极解析!

详细&全面的RxJava架构原理与设计讲解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值