问题描述
有用户提出了一个问题,他想在Docker容器内运行systemd,并希望找到一个确切且可接受的解决方案。他注意到有很多绕过方法可以在Docker容器内运行systemd,但大多数方法似乎会损害容器和主机的安全性。他想知道大多数人是如何处理在容器内运行systemd特定任务的问题的。
解决方案
请注意以下操作可能涉及特权和安全问题,请根据具体情况谨慎操作。
在Docker容器内运行systemd是一个有争议的话题,因为这涉及到容器的隔离性和安全性。但如果确实有这个需求,以下是一些解决方案,供用户参考。
方案1
准备工作
确保你已经安装了Docker并具备基本的Docker使用经验。
步骤
- 在容器中运行systemd,可以使用以下命令:
bash
docker run -it --rm \
-e container=docker \
--tmpfs /run \
--tmpfs /tmp \
-v /sys/fs/cgroup:/sys/fs/cgroup:ro \
--cap-add SYS_ADMIN \
centos /sbin/init
这个命令将以交互式方式启动一个CentOS容器,并运行systemd。在某些较旧的Docker版本中,可能需要添加其他标志。 - 验证容器内systemd的运行状态:
bash
systemctl status
如果一切正常,你应该能够看到systemd的状态。
注意事项
- 上述命令使用
--privileged
特权来启动容器,这可能会引起一些安全问题。特别是,-v /sys/fs/cgroup:/sys/fs/cgroup:ro
将主机的cgroup文件系统挂载到容器中,这可能会导致一些安全风险。 - 容器内的systemd需要一些特权来运行,这可能与容器的本来目的相悖,因为Docker容器通常是以轻量级、隔离的方式运行的。
- 尽量避免在生产环境中使用这种方法,除非你对安全性和特权问题有充分的了解。
方案2
步骤
- 以Arch Linux为例,使用以下命令在容器内运行systemd:
bash
docker run -it --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
--name=ArchLinux archlinux /bin/sh -c "if [ -x /etc/docker-start ]; then exec /etc/docker-start; else exec /bin/sh; fi" - 在容器内执行以下命令,以配置systemd运行环境:
bash
echo 'Server = https://THE_FASTEST_MIRROR_FOR_YOU/archlinux/$repo/os/$arch' >/etc/pacman.d/mirrorlist
pacman -Sy --noconfirm systemd systemd-sysvcompat
passwd -d root
echo -en '#!/bin/sh\numount /etc/hostname; umount /etc/hosts; umount /etc/resolv.conf; exec /usr/lib/systemd/systemd' >/etc/docker-start
chmod 700 /etc/docker-start
echo -e 'nameserver 8.8.8.8' >/etc/resolv.conf
exit - 启动容器并连接到容器:
bash
docker start -ia ArchLinux
注意事项
- 使用
--privileged
特权来运行容器可能会引起安全问题,因此尽量避免在生产环境中使用。 - 这种方法可能不够稳定,并且可能与Docker的设计初衷不符。如果可能的话,建议重新审视需求,考虑其他方式来达到目标。
方案3
步骤
- 创建一个Dockerfile,以Fedora为基础镜像,并按照以下内容构建镜像:
“`Dockerfile
FROM fedora:rawhide
MAINTAINER “Dan Walsh” dwalsh@redhat.com
ENV container docker
RUN yum -y update; yum clean all
RUN yum -y install systemd; yum clean all
RUN (cd /lib/systemd/system/sysinit.target.wants/; \
for i in ; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/; \
rm -f /etc/systemd/system/.wants/; \
rm -f /lib/systemd/system/local-fs.target.wants/; \
rm -f /lib/systemd/system/sockets.target.wants/udev; \
rm -f /lib/systemd/system/sockets.target.wants/initctl; \
rm -f /lib/systemd/system/basic.target.wants/; \
rm -f /lib/systemd/system/anaconda.target.wants/*
VOLUME [ “/sys/fs/cgroup” ]
CMD [“/usr/sbin/init”]
2. 使用Docker构建镜像:
bash
docker build -t systemd_image .
3. 基于该镜像创建一个容器,并运行systemd:
bash
docker run –privileged -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd_image
“`
注意事项
- 这个方案参考了一个2014年的博客,由于Docker和systemd的发展速度,这个博客可能已经过时。
- 尽管理论上可以在容器中运行systemd,但建议尽量避免,因为它可能与Docker的设计初衷和容器的隔离性相冲突。
- 将多个服务运行在一个容器内可能导致可扩展性和管理问题,因为Docker更倾向于水平