Docker 网络基础

DockerDockerBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

在本实验中,我们将探索 Docker 网络的基础知识。Docker 网络使容器能够相互通信并与外部世界进行交互。我们将涵盖各种网络类型、创建自定义网络、连接容器以及管理网络配置。通过动手实践,你将获得 Docker 网络概念和实践的坚实基础。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("`Docker`")) -.-> docker/ContainerOperationsGroup(["`Container Operations`"]) docker(("`Docker`")) -.-> docker/NetworkOperationsGroup(["`Network Operations`"]) linux(("`Linux`")) -.-> linux/RemoteAccessandNetworkingGroup(["`Remote Access and Networking`"]) docker/ContainerOperationsGroup -.-> docker/run("`Run a Container`") docker/ContainerOperationsGroup -.-> docker/exec("`Execute Command in Container`") docker/ContainerOperationsGroup -.-> docker/inspect("`Inspect Container`") docker/ContainerOperationsGroup -.-> docker/port("`List Container Ports`") docker/NetworkOperationsGroup -.-> docker/network("`Manage Networks`") linux/RemoteAccessandNetworkingGroup -.-> linux/ip("`IP Managing`") subgraph Lab Skills docker/run -.-> lab-389048{{"`Docker 网络基础`"}} docker/exec -.-> lab-389048{{"`Docker 网络基础`"}} docker/inspect -.-> lab-389048{{"`Docker 网络基础`"}} docker/port -.-> lab-389048{{"`Docker 网络基础`"}} docker/network -.-> lab-389048{{"`Docker 网络基础`"}} linux/ip -.-> lab-389048{{"`Docker 网络基础`"}} end

理解 Docker 网络类型

Docker 提供了多种内置的网络驱动。让我们从检查系统上的默认网络开始。

在你的终端中,运行以下命令以列出所有可用的 Docker 网络:

docker network ls

该命令会列出 Docker 在系统上创建的所有网络。你应该会看到类似以下的输出:

NETWORK ID     NAME      DRIVER    SCOPE
79dce413aafd   bridge    bridge    local
91199fc6ad2e   host      host      local
1078d2c781b6   none      null      local

让我们分解一下默认的网络类型:

  1. bridge:这是默认的网络驱动。当你启动一个容器而不指定网络时,它会自动连接到桥接网络。同一桥接网络上的容器可以通过它们的 IP 地址相互通信。

  2. host:该驱动移除了容器与 Docker 主机之间的网络隔离。容器共享主机的网络命名空间,这意味着它直接使用主机的 IP 地址和端口空间。这在某些场景下对优化性能非常有用。

  3. none:该驱动会禁用容器的所有网络功能。使用此网络类型的容器将无法访问外部网络或其他容器。当你希望完全隔离一个容器时,这非常有用。

SCOPE 列表示网络是仅限于单个主机(local),还是可以跨越 Docker Swarm 中的多个主机(swarm)。

检查默认的桥接网络

现在我们已经看到了网络列表,接下来让我们更详细地了解一下默认的桥接网络。这个网络是由 Docker 自动创建的,除非另有指定,否则容器会使用它。

运行以下命令来检查桥接网络:

docker network inspect bridge

该命令提供了关于桥接网络的详细信息,包括其子网、网关和连接的容器。你会看到类似以下的输出(为简洁起见已截断):

[
  {
    "Name": "bridge",
    "Id": "79dce413aafdd7934fa3c1d0cc97decb823891ce406442b7d51be6126ef06a5e",
    "Created": "2024-08-22T09:58:39.747333789+08:00",
    "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": {}
  }
]

让我们分解一下输出中的一些关键信息:

  • Subnet:此网络中容器使用的子网是 172.17.0.0/16。这意味着容器将被分配在此范围内的 IP 地址。
  • Gateway:此网络的网关是 172.17.0.1。这是容器用于与外部网络通信的 IP 地址。
  • Containers:此字段为空,因为我们尚未启动任何容器。
  • Options:这些是桥接网络的各种配置选项。例如,enable_icc 设置为 "true" 表示允许此网络上的容器间通信。

理解这些信息对于排查网络问题或配置容器以与特定 IP 范围通信至关重要。

创建自定义桥接网络

虽然默认的桥接网络适用于许多场景,但创建自定义网络可以实现更好的隔离和控制。当你希望将相关的容器分组或需要控制哪些容器可以相互通信时,自定义网络特别有用。

让我们创建一个名为 my-network 的自定义桥接网络:

docker network create --driver bridge my-network

该命令创建了一个新的桥接网络。--driver bridge 选项在这里实际上是可选的,因为桥接是默认驱动,但为了清晰起见,我们将其包含在内。

现在,让我们验证新网络是否已创建:

docker network ls

你应该会在网络列表中看到 my-network

NETWORK ID     NAME         DRIVER    SCOPE
1191cb61c989   bridge       bridge    local
91199fc6ad2e   host         host      local
47ac4e684a72   my-network   bridge    local
1078d2c781b6   none         null      local

我们的新网络 my-network 出现在列表中,确认它已成功创建。现在,这个网络可供容器连接。

将容器连接到网络

现在我们已经有了自定义网络,接下来让我们创建两个容器并将它们连接到该网络。我们将使用 nginx 镜像作为示例,它提供了一个轻量级的 Web 服务器。

运行以下命令来创建两个容器:

docker run -d --name container1 --network my-network nginx
docker run -d --name container2 --network my-network nginx

让我们分解这些命令:

  • -d:此标志以分离模式运行容器,意味着它在后台运行。
  • --name:为容器分配一个名称,便于后续引用。
  • --network:指定容器应连接到的网络。
  • nginx:这是我们用于创建容器的镜像名称。

这些命令创建了两个以分离模式(-d)运行的容器,分别命名为 container1container2,并且都连接到了我们的 my-network

让我们验证这些容器是否正在运行并连接到我们的网络:

docker ps

该命令列出了所有正在运行的容器。你应该会在输出中看到这两个容器:

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
1234567890ab   nginx     "/docker-entrypoint.…"   10 seconds ago   Up 9 seconds    80/tcp    container2
abcdef123456   nginx     "/docker-entrypoint.…"   20 seconds ago   Up 19 seconds   80/tcp    container1

此输出显示两个容器都在运行 Nginx 镜像,并在容器内部暴露了端口 80。

测试容器间通信

Docker 网络的一个关键优势是,同一网络上的容器可以使用其容器名称作为主机名相互通信。这使得在服务之间建立通信变得非常容易,而无需知道它们的 IP 地址。

让我们通过使用 container1container2 发送请求来测试这一点:

docker exec container1 curl -s container2

让我们分解这个命令:

  • docker exec:这告诉 Docker 在正在运行的容器内执行命令。
  • container1:这是我们要在其中执行命令的容器名称。
  • curl -s container2:这是我们在容器内执行的命令。它向 container2 发送一个 GET 请求,-s 标志使 curl 以静默模式运行。

该命令在 container1 内执行 curl 命令,向 container2 发送请求。你应该会在输出中看到默认的 Nginx 欢迎页面 HTML:

<!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>

这个成功的响应表明 container1 可以使用其容器名称与 container2 通信。Docker 的内置 DNS 服务器将容器名称解析为网络内的 IP 地址。

暴露容器端口

默认情况下,自定义网络中的容器可以相互通信,但它们无法从 Docker 主机外部访问。要使容器可以从主机或外部网络访问,我们需要暴露其端口。

让我们创建一个暴露端口的新容器:

docker run -d --name exposed-container -p 8080:80 --network my-network nginx

让我们分解这个命令:

  • -d:以分离模式运行容器。
  • --name exposed-container:将容器命名为 "exposed-container"。
  • -p 8080:80:将容器内的端口 80 映射到主机的端口 8080。
  • --network my-network:将容器连接到我们的自定义网络。
  • nginx:使用 Nginx 镜像。

该命令创建了一个名为 exposed-container 的新容器,将容器的端口 80 映射到主机的端口 8080,并将其连接到我们的 my-network

现在,你可以通过打开 Web 浏览器并访问 http://localhost:8080,或使用 curl 从主机访问该容器的 Nginx 服务器:

curl localhost:8080

你应该会看到与之前相同的 Nginx 欢迎页面 HTML。不过,这次我们是从主机直接访问容器,而不是从另一个容器访问。

使用主机网络

在某些场景中,如果你希望容器共享主机的网络栈,可以使用主机网络驱动。这会移除容器与主机之间的网络隔离,这对于某些应用程序非常有用,但由于可能导致端口冲突,因此应谨慎使用。

让我们创建一个使用主机网络的容器:

docker run -d --name host-networked --network host nginx

该命令创建了一个名为 host-networked 的新容器,并使用主机网络。请注意,在使用主机网络时不能使用 -p 参数,因为容器已经使用了主机的网络接口。

为了验证容器是否使用了主机网络,我们可以检查其网络设置:

docker inspect --format '{{.HostConfig.NetworkMode}}' host-networked

该命令检查容器并格式化输出以仅显示 NetworkMode。它应该输出 host,确认容器正在使用主机网络。

当使用主机网络时,容器共享主机的 IP 地址,并可以直接访问主机的所有网络接口。这对于最大化性能非常有用,但也意味着容器使用的任何端口都会直接在主机上打开,如果不小心处理,可能会导致冲突。

总结

在本实验中,我们探索了 Docker 网络的基础知识。我们涵盖了各种网络类型、创建自定义网络、连接容器、测试容器间通信、暴露容器端口以及使用主机网络。这些概念构成了 Docker 网络的基础,对于设计和管理的容器化应用程序至关重要。

我们学习了如何:

  • 列出并检查 Docker 网络
  • 创建自定义桥接网络
  • 将容器连接到网络
  • 测试容器之间的通信
  • 将容器端口暴露给主机
  • 为容器使用主机网络

理解这些网络概念将帮助你设计更健壮和安全的容器化应用程序。随着你继续使用 Docker,你会遇到更高级的网络场景,但我们在这里介绍的原则将为你进入容器编排和微服务架构的旅程奠定坚实的基础。

请记住,Docker 网络是一个强大的工具,它允许你为应用程序创建隔离的环境,同时仍然允许容器之间以及与外部世界进行受控的通信。练习这些概念并探索更高级的主题,以熟练掌握管理 Docker 网络。

您可能感兴趣的其他 Docker 教程