Minimalistic file system for booting guests (qemu, lxc, etc.)
There are many pain with rootless libvirt_lxc
containers.
They cannot use /dev/loop
, overlay
, user xattr
, etc.
This toolbox was primarily developed as a way to downgrade privileges to rootless inside a rootfull lxc-libvirt
container.
- Configurable
/sbin/init
-p5.lcboot.init
script.- hooking in "tolerant" mode -
p5.lcboot.tolerant
script. - re-
unshare
namespaces -uts
,ipc
,user
(uid
/gid
mapping),mount
,cgroup
(isolate it),network
.
- hooking in "tolerant" mode -
- Trivial
/dev/initctl
provider implementation -p5.lcboot.initctl
(/sbin/initctl
) script. /sbin/overlay
-p5.lcboot.overlay
helper script./sbin/mount-idmapped
binary.
- Provide
p5.lcboot
image into/
of your container (read-only if you wish). - Provide target (next hop, real guest) root into
/mnt/root
of your container (read-only if you wish). - Provide read/write cache directory (ram, host fs, etc.) into
/mnt/cache
of your container. - Set container entry point to
/sbin/init
. - Enjoy.
- Set container entry point to
/bin/sh
. - Use
--help
key for anyp5.lcboot.*
executable ("python3/scripts" directory in source code). - Check out the sources, there is nothing complicated there. =)
- Configure boot via your own
/mnt/init.yml
.
# "Next hop" root file system path.
# For example, may be mounted to guest via `/dev/loop` readonly source.
# And/or may usually be (re)mounted several times during "setup.before" step.
root: /mnt/root # default is {path: "/mnt/root", mode: "pivot"}
# Let's enable uid/gid mapping for unshare system call (disabled by default).
id_map:
users: 0 1000000 65536
groups:
- 0 1000000 # `internal` `external` (size = 1 by default)
- 1 1000001 1 # `internal` `external` `size`
- internal: 2
external: 1000002
# size: 1 # default too
- internal: 3
external: 1000003
size: 65533
initctl: false # default; replace to `true` if you want to spawn `/dev/initctl` (via `p5.lcboot.initctl`) right now
# First step is "setup".
# At this step `p5.lcboot.init` will:
# - mount /mnt/root/proc`;
# - invoke `unshare` system call;
# - mount new `/mnt/root/sys`, `/mnt/root/dev`.
# After this step `p5.lcboot.init` will change root to `/mnt/root` via `pivot_root` system call.
# You may change root.mode to `chroot` or `none`.
setup:
# Let's set `setup` mode. Replace it to `none` for skip it and do some in `before` and `exec.before`.
mode: auto # default
# Custom "setup" instructions before this step.
# In this case we hope that `/mnt/root` is already populated by container owner,
# but we want to remap some uids/gids and apply some fs layers.
before:
# Let's remap users/groups on `/mnt/root`.
- mount-idmapped --map-mount=b:0:1000000:65536 /mnt/root /mnt/root
# Remount `/mnt/root` as `overlayfs` with:
# - `lower` ro source layers: `/mnt/root` under `mnt/layers/0` under `/mnt/layers/1`;
# - `upper` rw layer: `/mnt/cache/overlay/upper`;
# - `workdir`: `/mnt/cache/overlay/temp/w`;
# - destination: `/mnt/root`.
- overlay -- /mnt/layers/0 /mnt/layers/1
# Last step is "exec".
exec:
# Of course, you can do something before `exec`.
before:
- echo "Hello, 'next hop' root!"
- ["echo", "We are ready to boot `systemd` now."]
- command: bash -e # we have `bash` on "next hop" root
input: |
echo 'Yeah! Only now '"it's"' interpreted by real shell ('"$0"')!'
echo 'This script received via stdin.'
echo "Date is `date`"
- - sh
- -ec
- "echo 'This script received via `cli` key.'; echo Shell is \"$0\"; echo \"Date is `date`\""
# Let's set custom `exec` system call command.
# Also, you can override it or append arguments via `cli`, use `--help` key.
command: /lib/systemd/systemd --system # "/sbin/init" by default