使用 `systemd-nspawn` 这个命令我们可以很方便的创建一个 Linux 容器,需要的只是一个使用 systemd 作为 init 的 Linux 发行版的根文件系统。通过创建容器,我们可以获得一个可以随便折腾而不用担心损坏的 Linux 环境。这里用 Ubuntu 16.04 和 CentOS 7 为例,整个过程可以说是非常简单(虽然比起 Docker 还是麻烦了点)
对于 Ubuntu,可以直接从源里下载到它的根文件系统。下载一份,并解压到 `/var/lib/machines/ubuntu1604`:
sudo mkdir -p /var/lib/machines/ubuntu1604 wget http://mirrors.ustc.edu.cn/ubuntu-cdimage/ubuntu-base/releases/16.04.3/release/ubuntu-base-16.04.1-base-amd64.tar.gz -O /tmp/rootfs.tgz sudo tar xpzf /tmp/rootfs.tgz -C /var/lib/machines/ubuntu1604
OK,到此为止我们就得到了一个可以被 `systemd-nspawn` 启动的 rootfs,不过我们还需要一些配置,例如修改 root 密码等等:
chroot /var/lib/machines/ubuntu1604 /usr/bin/passwd root echo ubuntu > /var/lib/machines/ubuntu1604/etc/hostname
下面只需要用 `systemd-nspawn` 来“启动”这个容器:
systemd-nspawn -b -D /var/lib/machines/ubuntu1604 --bind=/lib/firmware
这样就完成了!相当简单吧~输出内容大概是这样:
Spawning container ubuntu1604 on /var/lib/machines/ubuntu1604. Press ^] three times within 1s to kill container. systemd 229 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ -LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN) Detected virtualization systemd-nspawn. Detected architecture x86-64. Welcome to Ubuntu 16.04.1 LTS! Set hostname to. Failed to install release agent, ignoring: No such file or directory [ OK ] Listening on Journal Socket (/dev/log). [ OK ] Started Dispatch Password Requests to Console Directory Watch. [ OK ] Started Forward Password Requests to Wall Directory Watch. [ OK ] Reached target Paths. [ OK ] Reached target Remote File Systems (Pre). [ OK ] Reached target Remote File Systems. [ OK ] Listening on /dev/initctl Compatibility Named Pipe. [ OK ] Created slice System Slice. [ OK ] Reached target Slices. [ OK ] Created slice system-getty.slice. [ OK ] Reached target Swap. [ OK ] Reached target Encrypted Volumes. [ OK ] Listening on Journal Socket. Mounting Huge Pages File System... [ OK ] Reached target Sockets. Starting Remount Root and Kernel File Systems... Mounting POSIX Message Queue File System... Starting Journal Service... Mounting FUSE Control File System... [ OK ] Mounted POSIX Message Queue File System. [ OK ] Mounted Huge Pages File System. [ OK ] Mounted FUSE Control File System. [ OK ] Started Remount Root and Kernel File Systems. [ OK ] Reached target Local File Systems (Pre). [ OK ] Reached target Local File Systems. Starting Load/Save Random Seed... [ OK ] Started Load/Save Random Seed. [ OK ] Started Journal Service. Starting Flush Journal to Persistent Storage... [ OK ] Started Flush Journal to Persistent Storage. Starting Create Volatile Files and Directories... [ OK ] Started Create Volatile Files and Directories. Starting Update UTMP about System Boot/Shutdown... [ OK ] Reached target System Time Synchronized. [ OK ] Started Update UTMP about System Boot/Shutdown. [ OK ] Reached target System Initialization. [ OK ] Started Daily Cleanup of Temporary Directories. [ OK ] Reached target Basic System. Starting Permit User Sessions... Starting LSB: Set the CPU Frequency Scaling governor to "ondemand"... Starting /etc/rc.local Compatibility... [ OK ] Started Daily apt activities. [ OK ] Reached target Timers. [ OK ] Started Permit User Sessions. [ OK ] Started /etc/rc.local Compatibility. [ OK ] Started Console Getty. [ OK ] Reached target Login Prompts. [ OK ] Started LSB: Set the CPU Frequency Scaling governor to "ondemand". [ OK ] Reached target Multi-User System. [ OK ] Reached target Graphical Interface. Starting Update UTMP about System Runlevel Changes... [ OK ] Started Update UTMP about System Runlevel Changes. Ubuntu 16.04.1 LTS ubuntu console ubuntu login:
值得注意的是,这个容器和虽然看起来很像那么一回事儿,但是它的内核和网络仍然是使用的宿主机的,如果宿主机已经运行了 sshd,容器里尝试运行则会提示端口被占用,不过 `systemd-nspawn` 提供了桥接网络之类的功能,具体方法可以 Google。关闭容器很简单,在里面执行 `systemctl poweroff` 即可。
CentOS 稍微复杂一点,因为他没有直接提供最小的 rootfs,我们要自己从 ISO 中解压安装,整个过程如下:
# 切换到超级用户 sudo -s # 建立一些文件夹 mkdir -p /var/lib/machines/centos7 mkdir -p /tmp/iso mkdir -p /tmp/squashfs mkdir -p /tmp/rootfs # 挂载 CentOS 7 的系统盘 mount /mnt/Disk2/OS/Linux/CentOS-7-x86_64-Minimal-1708.iso /tmp/iso mount /tmp/iso/LiveOS/squashfs.img /tmp/squashfs mount /tmp/squashfs/LiveOS/rootfs.img /tmp/rootfs # 复制系统文件,速度看你的硬盘,可能会比较慢_(:з」∠)_ cp -pr /tmp/rootfs/* /var/lib/machines/centos7 # 卸载一些不会再用到的镜像 umount /tmp/{rootfs,squashfs} # 安装一下 yum mkdir -p /var/lib/machines/centos7/mnt/iso mount --bind /tmp/iso /var/lib/machines/centos7/mnt/iso chroot /var/lib/machines/centos7 /usr/bin/rpm -ivh --nodeps /mnt/iso/Packages/rpm-4.11.3-25.el7.x86_64.rpm chroot /var/lib/machines/centos7 /usr/bin/rpm -ivh --nodeps /mnt/iso/Packages/yum-3.4.3-154.el7.centos.noarch.rpm # 配置一下基本系统,执行最小安装 echo "[cdrom] name=Install CD-ROM baseurl=file:///mnt/iso enabled=0 gpgcheck=1 gpgkey=file:///mnt/iso/RPM-GPG-KEY-CentOS-7" > /var/lib/machines/centos7/etc/yum.repos.d/cdrom.repo chroot /var/lib/machines/centos7 /usr/bin/yum --disablerepo=\* --enablerepo=cdrom -y reinstall yum chroot /var/lib/machines/centos7 /usr/bin/yum --disablerepo=\* --enablerepo=cdrom -y groupinstall "Minimal Install" # 删掉 ISO 源 rm /var/lib/machines/centos7/etc/yum.repos.d/cdrom.repo # 卸载 ISO umount /var/lib/machines/centos7/mnt/iso /tmp/iso # 设置一下 root 密码之类的 chroot /var/lib/machines/centos7 /usr/bin/passwd root # 进入虚拟环境,执行这段脚本 systemd-nspawn -D /var/lib/machines/centos7 --bind=/lib/firmware << _END_POSTINSTALL_ # 换源,先备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup curl https://lug.ustc.edu.cn/wiki/_export/code/mirrors/help/centos\?codeblock=3 > /etc/yum.repos.d/CentOS-Base.repo # 更新 yum makecache # 安装一个缺失的依赖,为什么会缺我也不知道… yum install lvm2-libs -y # 这些服务是作为一个容器不需要的,把他们关掉 systemctl disable auditd.service systemctl disable kdump.service systemctl disable multipathd.service systemctl disable network.service systemctl disable smartd.service systemctl disable lvm2-monitor.service systemctl disable sshd.service # 设置 locale,如果需要中文就用 zh_CN.UTF-8 echo LANG=en_US.UTF-8 > /etc/locale.conf # 设置主机名 echo CentOS-7 > /etc/hostname _END_POSTINSTALL_ # 然后就可以开机了((( systemd-nspawn -b -D /var/lib/machines/centos7 --bind=/lib/firmware
参考资料: