【折腾记录】WSL、Linux与Docker的互通互联

wish
发布于 2024-12-03 / 22 阅读
0
0

【折腾记录】WSL、Linux与Docker的互通互联

问题1:WSL与宿主机的网络互通

前言

WSL1 是基于代理的虚拟化技术,它通过将 Linux 系统调用转换为 Windows 系统调用来实现与 Windows 内核的交互。WSL2 则使用了真正的虚拟机技术,它在 Windows 主机上运行一个轻量级的 Linux 内核。

WSL2 无法访问 Windows 的 localhost 网络是由 WSL2 的网络架构所致。WSL2 使用了一个虚拟网络适配器来与 Windows 主机进行通信,这导致 WSL2 无法直接访问 Windows 的 localhost 网络。因此,以往的 WSL2 在访问 Windows 网络时需要将其当作 LAN 的另一个设备,而 Windows 宿主则可以把 WSL 当作本机设备。这导致了很多问题,尤其是梯子方面的。

WSL2 2.0 引入的镜像网络可以解决 localhost 访问问题。启用镜像网络后,WSL2 和 Windows 主机将使用相同的网络,并且可以通过 localhost 访问本机系统上的服务。这意味着你可以在 WSL2 中访问本机系统上运行的应用程序,以及通过本机系统访问在 WSL2 中运行的应用程序。

配置

在 Windows 的资源管理器的地址栏输入:%UserProfile%,即可打开当前用户的主目录,创建文件:.wslconfig

[wsl2]
memory=4GB                        # 分配给 WSL 2 的内存大小
processors=2                      # 分配给 WSL 2 的 CPU 核心数
localhostForwarding=true          # 是否启用 localhost 转发
​
[experimental]
autoMemoryReclaim=gradual         # 开启自动回收内存,可在 gradual, dropcache, disabled 之间选择
networkingMode=mirrored           # 开启镜像网络
dnsTunneling=true                 # 开启 DNS Tunneling
firewall=true                     # 开启 Windows 防火墙
autoProxy=true                    # 开启自动同步代理
sparseVhd=true                    # 开启自动释放 WSL2 虚拟硬盘空间

重启WSL(关闭后需要等待8s)

管理员身份运行 PowerShell:

停止WSL: wsl --shutdown
启动WSL: wsl

之后就可以在 WSL 中使用 localhost 的方式来访问宿主机上的服务了。

curl http://localhost

其他命令

在 WSL 中查看宿主机的 IP:

cat /etc/resolv.conf

输出中 nameserver 后面的地址即是宿主机的 IP 地址。

版权声明

本文为博主 网无忌 原创文章,欢迎转载,但请务必标注原文链接。

本文链接:https://www.cnblogs.com/netWild/p/18503950

问题2:Docker容器间网络互通

掌握Docker网络配置:让你的容器与外界畅通无阻

头像 逼格高的汤圆 6 月 23 日 北京 阅读 2 分钟

Docker 网络实现详解

Docker 的网络实现其实是利用了 Linux 上的网络名字空间和虚拟网络设备(特别是 veth pair)。

基本原理

首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由的机制。

Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。Linux 通过在内核中进行数据复制从来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。对于本地系统和容器内系统来看就像是一个正常的以太网卡,只是它不需要真正同外部网络设备通信,速度要快很多。

Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 veth pair)。

创建网络参数

Docker 创建一个容器的时候,会执行如下操作:

  1. 创建一对虚拟接口,分别放到本地主机和新容器中;

  2. 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9;

  3. 容器一端添加到容器内,并修改名字作为 eth0,这个接口只在容器的名字空间可见;

  4. 从预设的地址中获取一个空闲地址分配给容器的 eth0,并配置默认路由由桥接网卡 veth65f9。

完成这些之后,容器就可以使用 eth0 通过默认网卡连接其他容器和其他网络。

可以在 docker run 的时候通过 --net 参数来指定容器的网络配置,有4个可选值:

  • --net=bridge:这是默认值,连接到默认的网桥。

  • --net=host:告诉 Docker 不要将容器网络移到隔离的名字空间中,即不要容器化容器的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如 D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用 --privileged=true,容器会被允许直接配置主机的网络堆栈。

  • --net=container:NAME_or_ID:让 Docker 将新建容器的进程放到一个已有容器的网络堆栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已有容器共享 IP 地址和端口等网络资源,两者进程可以直接通过 lo 环回接口通信。

  • --net=none:让 Docker 将新容器放到隔离的网络堆栈中,但是不进行网络配置。之后,用户可以自行进行配置。

网络配置细节

用户使用 --net=none 后,可以自行配置网络,让容器达到跟平常一样具有访问网络的权限。通过这个过程,可以了解 Docker 配置网络的细节。

首先,启动一个 /bin/bash 容器,指定 --net=none 参数。

$ sudo docker run -i -t --rm --net=none base /bin/bash
root@63f36fc01b5f:/#

在本地主机查找容器的进程 id,并为它创建网络命名空间。

<BASH>

$ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f

2778

$ sudo mkdir -p /var/run/netns

$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid

检查桥接网卡的 IP 和子网掩码信息。

<BASH>

$ ip addr show docker0

21: docker0: ...

inet 172.17.42.1/16 scope global docker0

创建一对 “veth pair” 接口 A 和 B,绑定 A 到网桥 docker0,并启用它。

<BASH>

$ sudo ip link add A type veth peer name B

$ sudo brctl addif docker0 A

$ sudo ip link set A up

将 B 放到容器的网络命名空间间,命名为 eth0,启动它并配置一个可用 IP(桥接网段)和默认网关。

<BASH>

$ sudo ip link set B netns $pid

$ sudo ip netns exec $pid ip link set dev B name eth0

$ sudo ip netns exec $pid ip link set eth0 up

$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0

$ sudo ip netns exec $pid ip route add default via 172.17.42.1

以上,就是 Docker 配置网络的具体过程。

当容器结束后,Docker 会清空容器,容器内的 eth0 会随网络命名空间一起被清除,A 接口也被自动从 docker0 卸载。

此外,用户可以使用 ip netns exec 命令来在指定网络名字空间中进行配置,从而配置容器内的网络。

问题3:Docker不同Container网络之间的互通/Container对宿主机Host网络服务的调用


解决方案:通过Nginx或Openresty反向代理

为了实现Docker容器之间以及容器与宿主机之间的网络互通和服务调用,我们可以采用Nginx或Openresty进行反向代理。以下是详细的步骤和原理解释:

  1. 新建Bridge网络

    • 创建一个新的Docker Bridge网络,用于隔离和管理容器之间的网络通信。

    • 示例命令:

    ​
      docker network create my_bridge_network
    ​
  2. 将Container的带端口服务代理到Bridge网络的固定IP上

    • 将容器的服务通过端口映射到Bridge网络的固定IP地址上,以便其他容器或宿主机可以通过该IP访问服务。

    • 示例命令:

    ​
      docker run --network my_bridge_network --ip 172.18.0.2 -p 8080:80 my_image
    ​
  3. 原理解释

    • Container网络之间的127.0.0.1是自身的不互通:在Docker中,每个容器的127.0.0.1指向容器自身,因此不同容器之间的相互调用无法使用127.0.0.1

    • 需要使用本地IP:为了实现容器之间的互通,需要使用本地IP地址,并且这些IP地址最好是固定的,以避免频繁改动配置。

    • Container不能直接调取Host网络上部署的服务:容器无法直接访问宿主机上的服务,因为它们处于不同的网络命名空间。

  4. 部署的服务,带着端口映射到Host网络上

    • 在宿主机上部署的服务通常需要通过端口映射到宿主机网络,以便外部网络可以访问。

    • 示例命令:

    ​
      docker run -p 9090:80 my_host_service_image
    ​
  5. 通过Nginx或Openresty将Container服务映射到固定的IP上

    • 在宿主机上部署Nginx或Openresty,配置反向代理规则,将容器的服务映射到固定的IP地址上。

    • 示例Nginx配置:

    ​
      server {
    ​
          listen 80;
    ​
          server_name my_container_service.local;
    ​
          location / {
    ​
              proxy_pass http://172.18.0.2:8080;
    ​
          }
    ​
      }
    ​
    • 通过这种方式,调用容器服务时不再需要频繁改动IP地址,只需通过Nginx或Openresty的反向代理即可实现访问。

通过上述步骤和配置,可以有效地实现Docker容器之间以及容器与宿主机之间的网络互通和服务调用,提高了网络管理的灵活性和便捷性。



评论