I'm trying to start a docker container inside the docker build process.
I'm trying to build and pack one project inside a Docker container but its build process internally requires a running docker to actually build some unrelated image and there is no way excluding that step from the build process.
So far I got to the point where I was able to install docker inside docker build process, but I can't start the docker container (tried multiple base images).
Here is one of the ways I tried to use Docker during build process:
FROM maven:3.9.9-eclipse-temurin-11 as builder
RUN apt-get update --yes --quiet && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
apt-transport-https ca-certificates curl software-properties-common gnupg
RUN install -m 0755 -d /etc/apt/keyrings
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
RUN chmod a+r /etc/apt/keyrings/docker.asc
RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
RUN apt update --yes --quiet
RUN apt-cache policy docker-ce
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
USER root
RUN usermod -aG docker root
# Fixing the bug: https://forums.docker.com/t/etc-init-d-docker-62-ulimit-error-setting-limit-invalid-argument-problem/139424
RUN sed -i 's/ulimit -Hn/ulimit -n/g' /etc/init.d/docker
RUN service docker start
RUN docker run hello-world
Last line throws the following error:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.
So, I tried to exclude that line, bash into the container and see what's going on.
I see that service docker start
actually starts a service for a second or so end then the process fails. Quick logs investigation show the following:
time="2024-10-12T15:21:02.998983540Z" level=info msg="containerd successfully booted in 0.042406s"
time="2024-10-12T15:21:04.001703179Z" level=error msg="failed to mount overlay: operation not permitted" storage-driver=overlay2
time="2024-10-12T15:21:04.001745444Z" level=error msg="exec: \"fuse-overlayfs\": executable file not found in $PATH" storage-driver=fuse-overlayfs
time="2024-10-12T15:21:04.001816599Z" level=warning msg="Unable to setup quota: operation not permitted\n"
time="2024-10-12T15:21:04.008983779Z" level=info msg="Loading containers: start."
time="2024-10-12T15:21:04.016718098Z" level=info msg="unable to detect if iptables supports xlock: 'iptables --wait -L -n': `iptables v1.8.10 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)`" error="exit status 4"
time="2024-10-12T15:21:04.026966817Z" level=info msg="stopping event stream following graceful shutdown" error="<nil>" module=libcontainerd namespace=moby
time="2024-10-12T15:21:04.027063083Z" level=info msg="stopping healthcheck following graceful shutdown" module=libcontainerd
time="2024-10-12T15:21:04.027108245Z" level=info msg="stopping event stream following graceful shutdown" error="context canceled" module=libcontainerd namespace=plugins.moby
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to register "bridge" driver: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables v1.8.10 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)
(exit status 4)
So, it seems that I have some network misconfiguration, but can't figure out what exactly.
You can't do this the way you describe it.
For Java applications, a very old-school approach (before multi-stage builds existed) was to build the jar file on the host system. Since one of the major selling points of Java is that the compiled class files are platform-independent, you don't necessarily need a matching toolchain in the image. Your Dockerfile could be just
FROM eclipse-temurin:21-jre
COPY target/app-*.jar /app.jar
CMD ["java", "-jar", "/app.jar"]
and then you'd have a two-step build process on the host
sudo mvn package
sudo docker build .
If you can separate out the tool invocation from the rest of your build process, you could also potentially use a multi-stage build for this. Say you'd invoke the tool like
sudo docker run --rm -u "$(id -u)" -v "$PWD:/data" \
some-image \
some-tool -i /data/data.in -o /data/data.out
Then you could have a dedicated Docker build stage to run this
FROM some-image AS build-tool
WORKDIR /data
COPY data.in ./
RUN some-tool -i data.in -o data.out
FROM maven:3.9.9-eclipse-temurin-11 as builder
...
COPY --from=build-tool /data/data.out src/main/resources
...
You can't really run another image from within a Dockerfile without this multi-stage build setup, though. You especially can't run another Docker daemon. The Docker daemon is a little tricky to run from inside a container; the most common way to do it is to run the docker:dind
image, but even that comes with the proviso that it must run as a privileged container. There's no option to run a privileged build or a privileged build step, though, so the nested Docker daemon won't work.