Building Container Images With Local Dependencies Outside Build Context

I'll illustrate this example with python apps but a similar project structure and way of specifying dependencies can be found in other languages.

my-project
├── apps
│   └── my-app
│       ├── Dockerfile
│       └── pyproject.toml
└── lib
    └── my-lib

pyproject.toml contains something along the lines of:

[tool.poetry.dependencies]
my-lib = { path = "../../lib/my-lib", develop = false }

To build a container image for my-app we would need to specify the entire my-project as build context or use ugly scripts to temporarily put together the things we need in the same build context. This can impact build performance if the project grows very large or .dockerignore files aren't used to exclude stuff like virtual environments. It can also be error-prone as code from other apps can easily end up in our image if we aren't careful when copying the files.

Fortunately this can all be avoided by using buildx for building images. buildx allows us to use multiple build contexts and mount the files from them while building the image. In our example Dockerfile would contain something like this:

# Workdir needs to be at least two levels deep here. In this case it also needs to
# be 3 levels deep from the root so it doesn't override /lib.
WORKDIR /my-project/my-app/deps

RUN --mount=target=../../lib,from=lib poetry install

Now we can run something like this:

docker buildx build --build-context lib=../../lib .

and voilà, we have our image!

Share:

If you've come this far with the article you may want to know a thing or two about me if you don't already. You can also read other blog posts or about stuff I've learned recently.

This website is open source. If you've come across a mistake please let me know there. For other types of feedback you can reach out to me through email or social-media.