Last active
October 22, 2017 22:47
-
-
Save euank/3cafdd8a318b1722f3d84f1d962272ac to your computer and use it in GitHub Desktop.
Based on https://github.com/moby/moby/issues/34672#issuecomment-331527204, what if it was rslave in both parts?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
[ $UID == 0 ] || (echo "Must be root" && exit 1) | |
# c1 and c2 represent two different docker containers starting at once | |
c1=1 | |
c2=2 | |
function ovlOpts() { | |
echo -n "lowerdir=$tmpdir/lower,upperdir=$tmpdir/$1/diff,workdir=$tmpdir/$1/work" | |
} | |
tmpdir=$(mktemp -d) # 'overlay2' graphdriver dir | |
# overlay2 driver in its setup code does this | |
# https://github.com/moby/moby/blob/ba317637de9b9918cdc2139466dd51c6200bd158/daemon/graphdriver/overlay2/overlay.go#L178 | |
echo "Graphdriver setup making $tmpdir rslave" | |
mount --bind "$tmpdir" "$tmpdir" | |
mount --make-rslave "$tmpdir" | |
echo "Containers creating rootfs's in $tmpdir" | |
mkdir -p "${tmpdir}/$c1/"{diff,merged,work} | |
mkdir -p "${tmpdir}/$c2/"{diff,merged,work} | |
mkdir -p "$tmpdir/lower" | |
# https://github.com/moby/moby/blob/ba317637de9b9918cdc2139466dd51c6200bd158/daemon/graphdriver/overlay2/overlay.go#L589 | |
# Container 1 starts setting up | |
echo "c1: dockerd creates mounts" | |
mount -t overlay overlay -o "$(ovlOpts $c1)" "$tmpdir/$c1/merged" | |
# Container 2 sets up | |
echo "c2: dockerd creates mounts" | |
mount -t overlay overlay -o "$(ovlOpts $c2)" "$tmpdir/$c2/merged" | |
# Container 2 runs 'runc init' code in parallel | |
( | |
# https://github.com/opencontainers/runc/blob/8b47a242a9aebdfe1c0c2b6513368f736d505bf0/libcontainer/nsenter/nsexec.c#L823 | |
unshare -m --propagation unchanged -- bash <<EOF | |
echo "c2: 'runc init' now in new mount namespace" | |
# Now runc init remounts / | |
# https://github.com/opencontainers/runc/blob/e385f67a0e45fa1d8ef8154e2aea5128ea1d331b/libcontainer/rootfs_linux.go#L599-L605 | |
# Due to how the config conversion works, config.RootPropagation is never 0, | |
# and defaults instead to MS_PRIVATE | MS_REC. I'll PR a fix | |
mount --make-rslave / | |
echo "c2: runc init initial view of mounts: " | |
cat /proc/self/mountinfo | grep "${tmpdir}" | |
echo -e "===\n\n" | |
sleep 0.7 | |
echo "c2: still in runc init, current view of mounts: " | |
cat /proc/self/mountinfo | grep "${tmpdir}" | |
echo -e "===\n\n" | |
sleep 0.3 | |
echo -e "c2: init done; unmounting old root\n" | |
# .. and then pivot root happens which cleans up our old root | |
# It's hard to do in shell, so we'll just pretend an umount of / is close enough | |
# https://github.com/opencontainers/runc/blob/e385f67a0e45fa1d8ef8154e2aea5128ea1d331b/libcontainer/rootfs_linux.go#L676 | |
cd / | |
umount -l . | |
EOF | |
) & | |
sleep 0.5 | |
# While container2 is doing its init, container 1 unmounts and remounts its overlay | |
echo "c1: dockerd still setting up, remounting graphdriver" | |
umount "$tmpdir/$c1/merged" | |
mount -t overlay overlay -o "$(ovlOpts $c1)" "$tmpdir/$c1/merged" && echo "c1: re-mount succeeded" || echo "c1: re-mount failed" | |
echo | |
# Boom, EBUSY on 4.13+ because `unshare -m` above has a private copy of the mount | |
# Wait long enough to cleanup | |
sleep 0.7 | |
# Cleanup | |
umount "$tmpdir/$c2/merged" | |
umount "$tmpdir" | |
rm -rf "$tmpdir" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment