Docker-in-Docker: Building Images inside a Running Container

Cloud Jun 30, 2023

Imagine you are heading Project X in your friend's start-up. Your team has 5 people and you sat up yesterday, night to build the application, and it's finally done and running within your docker container. Your teammates come to work today, and you want them to be able to run it too, but they seem to be running into all kinds of dependency problems. You're frustrated because this background work takes too much of your time, and the release is next week. What can you do?

You finally came up with a solution - docker-in-docker!

This is not the only situation where it helps; there are many other situations too, where you might need docker-in-docker; a few are:

  • Testing: You can ensure everything works by testing your application and its dependencies within a container. Then, you can save the configuration as an image that can be used by other team members or even deployed to production.
  • Running CI/CD tools like Jenkins.

Requirements:

  • A running container with docker installed in it (Method-1)
  • Access to host docker.sock (Method-2)
    • Attach a volume: /var/run/docker.sock:/var/run/docker.sock

Method-1 (Docker-in-Docker with Docker installed)

Step-1

Run the particular container and make sure it has docker installed. For the sake of simplicity, I am using the official Docker image here.

docker run -it --name build-container docker sh

Here,

  • t allocates a tty
  • i keeps it interactive

Step-2

Import your code. I am using this sample crypto price monitor react app for this post.

Source Code: https://github.com/thejungwon/docker-reactjs

git clone https://github.com/thejungwon/docker-reactjs
cd docker-reactjs
docker build -t docker-reactjs:latest .

Step-3

Once the image building finishes, you can export it as a tar file.

docker save docker-reactjs:latest > /tmp/docker-reactjs.tar

Step-4

Now exit out of the container and run the docker cp command for copying the tar image file.

exit
docker cp build-container:/tmp/docker-reactjs.tar .

Step-5

Now import the image from the tar file using docker load command.

docker load -i docker-reactjs.tar

After loading the image, you can run the container as usual.

docker run docker-reactjs:latest

Method-2 (Docker-in-Docker using Host's /var/run/docker.sock)

Step-1

Make sure you can make requests to the socket. Run the following command in the host machine to check that.

curl --unix-socket /var/run/docker.sock http://localhost/version

Here, --unix-socket helps you connect through the Unix domain socket (HTTP).

Step-2

To run docker inside docker attach the socket as a volume to the container.  For example:

docker run -v /var/run/docker.sock:/var/run/docker.sock \
    -ti docker

Here,

  • -v represents volume
  • t allocates a tty
  • i keeps it interactive
Caution: Play safe when giving the host's docker socket connection to a container. The container will have more privileges over your docker daemon.

Now you can run docker commands inside the container which will run on the host machine.

Step-3

After running the previous command, you should be inside the container. Once inside, you can run docker commands which run on host machine.

docker run hello-world

Let's try it out with a custom image. Create a Dockerfile with the following content in it.

FROM node:20-slim

LABEL maintainer="AmreshSinha <[email protected]>"

WORKDIR /usr/node
WORKDIR app

RUN pwd

# command executable and version
ENTRYPOINT ["node"]

Now build the app.

docker build -t test-image .

Conclusion

There are many more ways to go the docker-in-docker road other than the methods we discussed above. For example, dind or using another runtime like sysbox runtime for better security, etc.

We will discuss them in future posts. Till then... 👋

Tags

Amresh Sinha

Developer👨‍💻 | Student🎓 | Traveller✈️