深入理解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



Welcome to nginx!



Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

-                    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统一认证服务的应用。

深入理解Docker网络通信原理_第1张图片

精彩回顾

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

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

你可能感兴趣的:(docker,linux,运维)