从 systemd-nspawn 容器访问主机服务

从 systemd-nspawn 容器访问主机服务

我有一组由systemd-nspawn容器应该与外部网络(半)隔离,但同时应该能够访问主机上运行的非容器化服务,如 DBMS(参见图表systemd-networkd)。网络由两端管理。

我尝试过 systemd-nspawn 以下几种最常见的私有网络模式:

虚拟以太网

-n, --network-veth为每个容器创建一对连接的虚拟以太网适配器,一个在主机端,另一个在容器内。这似乎没什么用,因为不清楚 DBMS 应该监听哪个地址以及容器应该连接到哪个地址。

--network-bridge=功能基本相同,但会将虚拟适配器添加到指定的网桥。网桥应该已经设置并分配了 IP:

# /etc/systemd/network/br0.netdev 
[NetDev]
Name=br0
Kind=bridge

 

# /etc/systemd/network/br0.network 
[Match]
Name=br0

[Network]
Address=169.254.1.1/16

该配置已被证明是有效的,但需要额外的桥接配置,并且在涉及容器的外部网络访问时通常会出现问题。

--network-zone=功能相同,但会自动管理桥接接口。以下是桥接的默认设置:

[root@host ~]# ip addr show vz-containers
26: vz-containers: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 169.254.120.107/16 brd 169.254.255.255 scope link vz-containers
       valid_lft forever preferred_lft forever
    inet 10.0.0.1/24 brd 10.0.0.255 scope global vz-containers
       valid_lft forever preferred_lft forever
    inet 10.0.1.1/24 brd 10.0.1.255 scope global vz-containers
       valid_lft forever preferred_lft forever

似乎它被分配了一个随机地址169.254.0.0/16,以及两个静态地址10.0.0.110.0.1.1。通过这两个地址可以从容器访问主机。但不清楚这些地址来自哪里,我不确定这在 systemd 的未来版本中不会改变。为了确保万无一失,我们可以为桥接接口分配一个额外的静态 IP:

# /etc/systemd/network/80-container-vz.network - full override, systemd < 232 
[Match]
Name=vz-*
Driver=bridge

[Network]
# Default to using a /24 prefix, giving up to 253 addresses per virtual network.
Address=0.0.0.0/24
Address=169.254.1.1/24
# the rest is left as in the original /usr/lib/systemd/network/80-container-vz.network

 

# /etc/systemd/network/80-container-vz.network.d/override.conf - drop-in, systemd ≥ 232
[Network]
Address=169.254.1.1/24

这种方法效果很好,不会对外部网络连接造成问题,但也需要对桥接配置进行额外的调整。此外,这两种方法(桥接和区域)都需要配置静态条目/etc/hosts,因为systemd-resolved和相关模块(mymachines和NSS 模块)在这里没有太大帮助:myhostnameresolve

# /etc/hosts
169.254.1.1 host

幸运的是,所有容器都共享相同的基本操作系统映像,因此这并不难。

问题是,以上所有操作能否以更简单的方式完成?还是我应该等到systemd-nspawn出现一些神奇的选项,例如“使主机可通过 <foo> 主机名在容器中访问”?

答案1

遇到了同样的复杂情况 - 我的答案与 Kiraly 的答案大致相同,但配置 100% 由主机控制。

可以复制和修改库存/lib/systemd/network/80-container-ve.network,以在特定的静态 IP 上设置主机地址(您还需要更新[Match]

然后 - 设置一个只有 1 个地址的 DHCP 池。这样它就可以预测了 - 并且容器不需要静态配置,它只需在启动时选择正确的地址。

所以 - 像这样

/etc/systemd/network/50-mycont.network

[Match]
# Hard match for the container interface name - no wildcards
Name=ve-mycont
Driver=veth

[Network]
# Static address for host
Address=10.0.60.49/28
LinkLocalAddressing=yes
DHCPServer=yes
IPMasquerade=yes
LLDP=yes
EmitLLDP=customer-bridge

[DHCPServer]
PoolOffset=2
PoolSize=1
# Little DHCP - container will have address 10.0.60.50

答案2

目前还不清楚这些地址来自哪里

如果您使用的是 systemd-networkd,则配置文件来自带有 .network 扩展名的配置文件。这些文件位于 /etc/systemd/network/run/systemd/network/usr/lib/systemd/network- 如果您未在 /etc 中修改任何内容,则后者是默认设置。... systemd-networkd 的文档是这里。您的网络上可能有一个 DHCP 服务器,并且根据您使用的网络模式,IP 地址可能会从该 DHCP 服务器分配。

问题是,能否以更简单的方式完成上述所有工作?

大多数数据库都是基于网络的,它们监听主机上的特定端口。根据您的网络配置,您的主机应该有一个带有 IP 地址的接口,该接口位于主机端,但可以从容器访问。请记住,防火墙和伪装也可能发挥重要作用。建立连接后,请确保您的数据库服务器也在监听给定的接口。

使主机在容器中可以通过主机名访问

由于您可以控制主机端 IP 地址,因此您可以/etc/hosts像以前一样将条目放入 中。我不知道有任何更简单的解决方案或任何外部解决方案。

答案3

由于(截至 2024 年 2 月)仍然没有适当的解决方案,我找到了一种相当优雅的方法,只需在容器内部进行最少的定制即可完成此工作。

  1. 添加以下两行/etc/hosts(地址稍后将被替换;“host”一词是分配给容器主机的符号主机名):

    0.0.0.0 host
    :: host
    
  2. /etc/systemd/system/host-address.service在容器内创建包含以下内容的文件:

    [Unit]
    Description=Add IP address of host system to /etc/hosts
    After=network-online.target
    
    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c 'exec sed -i -r "s#^[0-9.]+(\\\\s*host)\\$#$(ip -4 route show default | cut -d" " -f3 | head -n1)\\1#" /etc/hosts'
    ExecStart=/bin/sh -c 'exec sed -i -r "s#^[0-9A-Fa-f:]+(\\\\s*host)\\$#$(ip -6 route show default | cut -d" " -f3 | head -n1)\\1#" /etc/hosts'
    RemainAfterExit=yes
    
    [Install]
    WantedBy=network-online.target
    
  3. 通过运行以下命令启用并启动添加的服务:
    systemctl enable --now host-address.service

  4. /etc/hosts现在应该包含容器主机的 IPv4 和 IPv6 地址,并且ping host等应该可以工作

请注意,这不需要在任何时候手动分配任何 IP 地址。它只是将 systemd-networkd 已添加的信息添加到容器的系统状态中,而大多数工具都比路由配置更容易访问该位置。由于该单元被命令在 之后运行network-online.target,因此它将在 之后启动systemd-networkd-wait-online.service,因此在 systemd-networkd 在接口上设置了网络信息之后host0,使此配置重新启动安全并且希望非常可靠。

相关内容