27

Here's my problem: I want to build a chroot environment inside a docker container. The problem is that debootstrap cannot run, because it cannot mount proc in the chroot:

W: Failure trying to run: chroot /var/chroot mount -t proc proc /proc

(in the log the problem turns out to be: mount: permission denied)

If I run --privileged the container, it (of course) works... I'd really really really like to debootstrap the chroot in the Dockerfile (much much cleaner). Is there a way I can get it to work?

Thanks a lot!

fbrusch
  • 567
  • 2
  • 6
  • 7

9 Answers9

10

You could use the fakechroot variant of debootstrap, like this:

fakechroot fakeroot debootstrap --variant=fakechroot ...

Cheers!

Luis Alejandro
  • 355
  • 4
  • 5
  • When building a foreign chroot, how would I call the second stage (from a script)? I have tried a few things, each of them aborts with a different error message. – user149408 Apr 07 '23 at 09:55
  • Update: I got it to work, see my answer. The trick is to use `fakeroot` but not `fakechroot` – the latter is apparently buggy and not always consistent in its behavior. – user149408 Apr 09 '23 at 12:21
5

No, this is not currently possible.

Issue #1916 (which concerns running privileged operations during docker build) is still an open issue. There was discussion at one point of adding a command-line flag and RUNP command but neither of these have been implemented.

Nathan Osman
  • 71,149
  • 71
  • 256
  • 361
4

Adding --cap-add=SYS_ADMIN --security-opt apparmor:unconfined to the docker run command works for me.

See moby/moby issue 16429

  • in combination with `--privileged` flag or config this will work, but OP has specified they would like to avoid this. – MrMesees Feb 18 '19 at 08:38
2

This still doesn't work (2018-05-31).

Currently the only option is debootstrap followed by docker import - Import from a local directory

# mkdir /path/to/target
# debootstrap bionic /path/to/target
# tar -C /path/to/target -c . | docker import - ubuntu:bionic
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
2

debootstrap version 1.0.107, which is available since Debian 10 Buster (July 2019) or in Debian 9 Stretch-Backports has native support for Docker and allows building a Debian root image without requiring privileges.

  • Dockerfile:
FROM debian:buster-slim AS builder
RUN apt-get -qq update \
&& apt-get -q install --assume-yes debootstrap
ARG MIRROR=http://deb.debian.org/debian
ARG SUITE=sid
RUN debootstrap --variant=minbase "$SUITE" /work "$MIRROR"
RUN chroot /work apt-get -q clean

FROM scratch
COPY --from=builder /work /
CMD ["bash"]
  • docker build -t my-debian .
  • docker build -t my-debian:bullseye --build-arg SUITE=bullseye .
pmhahn
  • 101
  • 3
  • Thanks for that info. It's a bit disconcerting though that the warning reported by the OP still gets printed, but does not stop debootstrap as before. – SamTheEagle Nov 30 '22 at 13:48
0

There is a fun workaround, but it involves running Docker twice. The first time, using a standard docker image like ubuntu:latest, only run the first stage of debootstrap by using the --foreign option.

debootstrap --foreign bionic /path/to/target

Then don't let it do anything that would require privileged and isn't needed anyway by modifying the functions that will be used in the second stage.

sed -i '/setup_devices ()/a return 0' /path/to/target/debootstrap/functions
sed -i '/setup_proc ()/a return 0' /path/to/target/functions

The last step for that docker run is to have that docker execution tar itself up to a directory that is included as a volume.

tar --exclude='dev/*' -cvf /guestpath/to/volume/rootfs.tar -C /path/to/target .

Ok, now prep for a second run. First load your tar file as a docker image.

cat /hostpath/to/volume/rootfs.tar | docker import - my_image:latest

Then, run docker using FROM my_image:latest and run the second debootstrap stage.

/debootstrap/debootstrap --second-stage

That might be obtuse, but it does work without requiring --priveledged. You are effectively replacing running chroot with running a 2nd docker container.

corbin
  • 1,446
  • 2
  • 27
  • 40
0

This does not address the OP requirements for doing chroot in a container without --privileged set, but it is an alternative method that may be of use.

See Docker Moby for hetergenous rootfs builds. It creates a native temp directory and creates a rootfs in it using debootstrap which needs sudo. THEN it creates a docker image using

FROM scratch
ADD rootfs.tar.xz /
CMD ["/bin/bash"]

This is a common recipe for running a pre-made rootfs in a docker image. Once the image is built, it does not need special permissions. AND it's supported by the docker devel team.

dturvene
  • 2,284
  • 1
  • 20
  • 18
0

After numerous try-and-error cycles, I got this to work (note that this is a foreign chroot, i.e. for a different guest architecture – for a native one things may be even simpler):

apt-get -y install debootstrap fakechroot fakeroot qemu-user-static binfmt-support
mkdir -p $CROSS_ROOT
fakeroot -s .fakeroot.state debootstrap --variant=buildd --include=fakechroot,fakeroot,build-essential,ca-certificates,debian-archive-keyring,git,sudo --arch=${CROSS_ARCH} --foreign ${CROSS_RELEASE} $CROSS_ROOT $CROSS_MIRROR
mkdir -p $CROSS_ROOT/usr/bin
ln /usr/bin/qemu-*-static $CROSS_ROOT/usr/bin/
fakeroot -i .fakeroot.state -s .fakeroot.state chroot $CROSS_ROOT /debootstrap/debootstrap --second-stage --verbose

The fakechroot package in the above is a leftover from previous tests and might not be necessary here.

The only limitation is that you might not be able to bind-mount /proc and /sys once the chroot is set up. Anything that needs one of these dirs might not work inside the chroot.

This was tested on a GitLab CI runner (which, as I understand, runs in non-privileged mode), on Debian buster. (Github Actions runners seem to be less restrictive – I ported this setup from GHA to GL and had to make a number of adaptations.)

Main takeaway: fakechroot should not be needed (as you can easily chroot on a non-privileged Docker container), but fakeroot is – as this prevents debootstrap from stumbling on permission errors when trying to mount /sys or /proc. Because we are not using fakeroot, --variant can be one of the standard ones (not fakechroot, as this variant will refuse to work without fakechroot).

user149408
  • 5,385
  • 4
  • 33
  • 69
-1

Short answer, without privileged mode no there isn't a way.

Docker is targeted at micro-services and is not a drop in replacement for virtual machines. Having multiple installations in one container definitely not congruent with that. Why not use multiple docker containers instead?

Usman Ismail
  • 17,999
  • 14
  • 83
  • 165
  • I built an application that run code snippets (mostly students' solutions to exercises) into caged environments. I run some hundred of node.js scripts at the same time, the best solution I found was chroot+aufs (I initially tried with docker as the execution cage, but had some limitations, like not being able to share file descriptors among the controller process and the spawned caged children, which I use for IPC). I used to do that all in a Virtualbox machine, but now I was trying to take advantage of the awesome docker ecosystem (provisioning, deploying etc). – fbrusch Oct 16 '14 at 16:13
  • 1
    I am not clear why you said 'file descriptors' instead of files... but you can share files across containers with shared volumes – Rondo Oct 18 '14 at 02:52
  • 5
    Please answer the question, not complain why people need to do it. Sometimes you can't choose your tools and need to do something. Sometimes you simply want to learn about it. – hazydev Jan 07 '16 at 00:17