远程 systemctl

远程 systemctl

当主机操作系统是 Ubuntu 16.04 或 RHEL 7.x 时,以下命令有效,帮助我们在 docker 容器内于主机上运行 systemctl 命令:

# nsenter --mount=/hostroot/proc/1/ns/mnt -- systemctl start dummy.service

但是在较新的主机操作系统 Ubuntu 20.04 和 RHEL 8.x 中,这不起作用,我们收到以下错误:

# nsenter --mount=/hostroot/proc/1/ns/mnt -- systemctl start dummy.service
Failed to connect to bus: No data available

我附加了一个简单示例和命令来运行和重现该问题:

我想从容器在主机上启动的示例服务:

# cat /etc/systemd/system/dummy.service
[Unit]
Description=dummy service
[Service]
ExecStart=/usr/bin/sleep infinity

我的容器的 Dockerfile:

# cat Dockerfile
FROM ubuntu:20.04
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt update -y --fix-missing
RUN apt install -y util-linux
STOPSIGNAL SIGRTMIN+3
CMD [ "/bin/bash" ]

构建图像:

# docker build -t trial .

删除所有过时的容器:

# docker rm -f trial

运行图像:

# docker run -it -d --net=host --privileged -v /:/hostroot -v /sys/fs/cgroup:/sys/fs/cgroup:ro --name trial trial

重现问题:

# docker exec -it trial bash
# nsenter --mount=/hostroot/proc/1/ns/mnt -- systemctl start dummy.service
Failed to connect to bus: No data available

我想知道是否有任何其他选项或任何需要改变的 docker run 命令才能使其正常工作。

答案1

我研究了好几个小时,似乎这个方法sd_bus_start已更改为包含其他检查。我无法缩小它所寻找的其他内容的范围,但是我能够想出一个更优雅的解决方案,使用远程 systemctl 命令而不是从主机挂载所有目录来完成相同的任务。

远程 systemctl

systemctl通过标志支持远程命令--host / -H。它使用 ssh 连接到远程主机,因此需要 ssh 密钥对。由于我们控制着我们所在的主机,因此设置起来非常简单。

Docker 命令(或 Kubernetes 参数)

这是可以使用的完整命令,我将在下面分解每个部分。容器的假设是它已systemctl安装ssh,容器正在主机网络上运行,并且root帐户的主目录已挂载(如果需要,您可以使用其他用途)。

(ls ~/.ssh/id_rsa || ssh-keygen -b 2048 -t rsa -f ~/.ssh/id_rsa -q -N "") 
  && (grep -qxF $(cat ~/.ssh/id_rsa.pub) ~/.ssh/authorized_keys || echo $(cat ~/.ssh/id_rsa.pub) > ~/.ssh/authorized_keys)
  && (grep -qxF "StrictHostKeyChecking no" ~/.ssh/config || echo "StrictHostKeyChecking no" >> ~/.ssh/config)
  && (grep -qxF "UserKnownHostsFile /dev/null" ~/.ssh/config || echo "UserKnownHostsFile /dev/null" >> ~/.ssh/config)
  && systemctl -H [email protected] start nfs-server.service

此命令查看~/.ssh/id_rsa文件是否存在,否则创建一个。

(ls ~/.ssh/id_rsa || ssh-keygen -b 2048 -t rsa -f ~/.ssh/id_rsa -q -N "")

现在,如果文件中尚不存在公钥,我们将公钥添加到授权密钥中。

(grep -qxF "$(cat ~/.ssh/id_rsa.pub)" ~/.ssh/authorized_keys || echo "$(cat ~/.ssh/id_rsa.pub)" > ~/.ssh/authorized_keys)

这可能可以通过将其放在 ssh 配置的一部分中来提高安全性127.0.0.1,但我们需要

(grep -qxF "StrictHostKeyChecking no" ~/.ssh/config || echo "StrictHostKeyChecking no" >> ~/.ssh/config) 
  && (grep -qxF "UserKnownHostsFile /dev/null" ~/.ssh/config || echo "UserKnownHostsFile /dev/null" >> ~/.ssh/config)

最后我们有了实际的systemctl命令。注意。-H [email protected]

systemctl -H [email protected] start nfs-server.service

为了实现最大程度的安全,最好先在容器外部设置密钥和用户(通过 Ansible 或类似方式),并且只允许systemctl -H在容器内执行命令。

相关内容