用于小丑容器

用于小丑容器

如何构建一个特权 LXC (1.0.3) 容器(我知道的那部分),然后成功地将其迁移到非特权运行?也就是说,我想debootstrap自己修改或调整lxc-ubuntu模板(通常在 下/usr/share/lxc/templates)才能使其正常工作。

这就是我问这个问题的原因。如果您查看lxc-ubuntu模板,您会注意到:

# Detect use under userns (unsupported)
for arg in "$@"; do
    [ "$arg" = "--" ] && break
    if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
        echo "This template can't be used for unprivileged containers." 1>&2
        echo "You may want to try the \"download\" template instead." 1>&2
        exit 1
    fi
done

不过,在引用的模板中使用LXC_MAPPED_GID和后,似乎没有什么特别的地方。事实上,它所做的只是调整文件所有权 ( + )。但模板中的扩展属性可能已经经过微调,以实现所需的任何“魔法”。LXC_MAPPED_UIDlxc-downloadchgrpchowndownload

在评论中Stéphane Graber 的这篇博文斯蒂芬告诉一位评论者

不幸的是,没有简单的方法可以做到这一点,您需要更新容器配置以匹配非特权容器的配置,将容器的目录移动到您希望其运行的非特权用户,然后使用 Serge 的 uidshift 程序来更改所有文件的所有权。

... 并:

但没有进一步的指示。

所以我的问题是:我如何才能将我自己构建的普通(特权)LXC 容器(拥有root和全部)迁移到非特权容器?即使您无法提供脚本等,如果知道要考虑哪些要点以及它们如何影响运行非特权 LXC 容器的能力,那就太好了。我可以自己想出一个脚本,并保证如果能找到解决方案,我会将其作为该问题的答案发布:)

笔记:虽然我使用的是 Ubuntu 14.04,但这是一个通用的问题。

答案1

我只是做了一些非常类似的事情,将 KVM 虚拟机移动到非特权 LXC 中。

我为此使用了系统容器(因此它们可以在启动时自动启动),但使用映射的 UID/GID(用户命名空间)。

  1. 编辑 /etc/subuid,subgid (我将 uid/gids 10M-100M 映射到 root 并每个容器使用 100K)
  2. 对于第一个容器,在 /var/lib/lxc/CTNAME/config 中使用 u/gids 10000000-10099999
  3. 将容器存储安装在 /var/lib/lxc/CTNAME/rootfs 上(或者,如果每个容器不使用单独的卷/数据集/任何内容,则不执行任何操作)
  4. chown 10000000:10000000 /var/lib/lxc/CTNAME/rootfs
  5. setfacl -mu:10000000:x /var/lib/lxc (或简单地 chmod o+x /var/lib/lxc)
  6. lxc-usernsexec -mb:0:10000000:100000 --/bin/bash

现在您位于第一个容器用户命名空间中。一切都一样,但您的进程认为它的 uid 是 0,而实际上在主机命名空间中它的 uid 是 10000000。检查 /proc/self/uid_map 以查看您的 uid 是否已映射。您会注意到您无法再从 /root 读取内容,并且它似乎由无人/无组拥有。

在用户命名空间中,我从原始主机进行 rsync。

在用户命名空间之外,您将看到 /var/lib/lxc/CTNAME/rootfs 中的文件现在不属于与原始安装相同的预期 uid,而是 10000000+remote_uid。这就是你想要的。

就是这样。当你同步数据时,从容器的 /etc/fstab 中删除所有内容,这样它就不会尝试挂载东西,并且它应该启动。可能还有其他事情需要更改,请检查容器化发行版的 LXC 模板的作用。您绝对可以删除容器中的内核、grub、ntp 和任何硬件探测包(您甚至不必运行它,您可以从用户命名空间 chroot 到容器)

如果您没有正在运行的远程虚拟机,您还可以将原始虚拟机存储挂载到主机命名空间中,并通过 rsync/SSH 返回到本地主机。效果是一样的。

如果您(看起来)只是想将特权容器更改为非特权容器,您不妨添加 uid/gid 映射,将上面的映射添加到容器配置中,然后执行以下操作:

for i in `seq 0 65535`; do
  find /var/lib/lxc/CTNAME/rootfs -uid $i -exec chown $((10000000+i)) \{\} \;
  find /var/lib/lxc/CTNAME/rootfs -gid $i -exec chgrp $((10000000+i)) \{\} \;
done

这应该是所有需要做的事情,现在您应该能够以非特权方式运行容器。上面的例子效率极低,uidshift 可能会做得更好(但我还没有使用它)。

HTH。

答案2

我想警告一下,当符号链接指向容器中的这些文件时,Borut Mrak 的示例代码也会更改主机系统上文件的所有权!根本不是你想要的!

如果您有专用的文件系统,您应该使用 -h 标志进行 chown/chgrp 和/或使用 -mount 进行查找。

这是我的更快更智能的版本:

find "/var/lib/lxc/$name/rootfs" -mount -uid '-65536' -printf '%U\n'|sort -n|uniq|while read i; do
        find "/var/lib/lxc/$name/rootfs" -mount -uid "$i" -exec chown -h "$((200000+i))" \{\} \;
done

find "/var/lib/lxc/$name/rootfs" -mount -gid '-65536' -printf '%G\n'|sort -n|uniq|while read i; do
        find "/var/lib/lxc/$name/rootfs" -mount -gid "$i" -exec chgrp -h "$((200000+i))" \{\} \;
done

答案3

阿尔卑斯Linux现在使用uidmapshift转换成lua将特权容器转换为非特权容器。看看initd脚本查看设置/创建的其他文件夹权限和要求。 ( /etc/subuid& /etc/subgid)

答案4

用于小丑容器

SUBUID_OFFSET=-65536
SUBGID_OFFSET=-65536
cd rootfs || exit 1
find .|while read i; do SUBUID=$(stat --format=%u $i); SUBGID=$(stat --format=%g $i); NEW_SUBUID=$((SUBUID+SUBUID_OFFSET)); NEW_SUBGID=$((SUBGID+SUBGID_OFFSET)); echo "chown -h $NEW_SUBUID.$NEW_SUBGID $i"; done

用于迁移linux系统

SUBUID=100000
SUBGID=100000
cd rootfs || exit 1
find .|while read i; do CURRENT_UID=$(stat --format=%u $i); CURRENT_GID=$(stat --format=%g $i); NEW_SUBUID=$((CURRENT_UID+SUBUID)); NEW_SUBGID=$((CURRENT_GID+SUBGID)); echo "chown -h $NEW_SUBUID.$NEW_SUBGID $i"; done

相关内容