Docker support in Pants 2.7

With Pants 2.7 comes a new experimental backend for building Docker images and linting Dockerfiles. This backend offers a seamless experience when bundling your code and files into Docker images - In a single invocation, Pants will build the code artifacts that need to be embedded into the Docker image, and then build the image itself.

Getting started

You represent your Dockerfiles to Pants using the new docker_image target type in your Pants BUILD files.

But you don't need to create these by hand! The Pants tailor goal will give you a head start by creating or updating the relevant BUILD files for you:

./pants tailor ::

With your docker_image() targets in place, you simply run

./pants package path/to/Dockerfile

to build the Docker image for that Dockerfile. Of course you can also use wildcards, so for example you can run

./pants package ::

to build all packageable targets in your repo, such as PEX binaries, Python distributions, archives, AWS Lambdas, and now also Docker images!

There is also support for linting your Dockerfiles, to check for errors and get suggestions for potential mistakes or bad practices. This feature relies on hadolint, and you invoke it just like any other linter in Pants, for example:

./pants lint path/to/Dockerfile

Read more about the Docker backend and how to enable it in the Pants documentation .

An example

To give a feel for how it works, here is a basic example, from the documentation.

Consider these files:

# src/docker/helloworld/BUILD
files(
    name="msg",
    sources=["msg.txt"]
)

docker_image(
    name="helloworld",
    dependencies=[":msg", "src/python/helloworld:bin"],
)
# src/docker/helloworld/Dockerfile
FROM python:3.8
ENTRYPOINT ["/bin/helloworld"]
COPY src/docker/helloworld/msg.txt /var/msg
COPY src.python.helloworld/bin.pex /bin/helloworld
# src/docker/helloworld/msg.txt
Hello, Docker!
# src/python/helloworld/BUILD
python_library(interpreter_constraints=["=3.8"])

pex_binary(
    name="bin",
    entry_point="main.py",
)
# src/python/helloworld/main.py
import os

if os.path.exists("/var/msg"):
    with open("/var/msg") as fp:
        msg = fp.read().strip()
else:
    msg = "Hello"
print(msg)

When you run package on the Dockerfile:

$ ./pants package src/docker/helloworld/Dockerfile
[...]
18:07:29.66 [INFO] Completed: Building src.python.helloworld/bin.pex
18:07:31.83 [INFO] Completed: Building docker image helloworld:latest
18:07:31.83 [INFO] Built docker image: helloworld:latest
To try out the image interactively:
    docker run -it --rm helloworld:latest [entrypoint args...]
To push your image:
    docker push helloworld:latest

Pants sees that the docker_image target depends on a pex_binary target, so it builds the executable .pex file first, and then builds the Docker image, placing that .pex file (as well as the direct .txt file dependency) in the build's context so that the COPY instructions can see them.

You can check that the packaged image works as expected:

$ docker run -it --rm helloworld:latest
Hello, Docker!

This underscores the big advantage of letting Pants build your Docker images: It can automatically and incrementally build any artifacts that your image needs prior to assembling the context and building the Docker image. So with a single package command you can ensure all your images are up to date, without having to worry about first handling upstream dependencies. Pants takes care of that for you!

In fact, in the 2.8.0 version Pants will have the ability to infer those upstream dependencies for you, by looking at the COPY statements in your Dockerfiles. So the explicit dependencies on the docker_image target in the example above can be deleted. Keep an eye out for this and other great features in the next Pants release.

Background

As a software developer in the Tooling department at Svenska Spel, I am part of creating the infrastructure required to deliver our products into production, as safely, reliably and quickly as possible. To do this, we rely on many tools developed both in-house and by third parties, which we integrate into a complete CI/CD platform. A big part of this platform runs Python code, and almost all of it in Docker containers.

It was in search of better tooling to support our Python code base that I came across Pants, and was drawn in by the features and welcoming community. The lack of Docker support was an invitation for us to contribute something back.

Conclusion

As an experimental backend, it is still not feature complete, and is being actively worked upon. Please do not hesitate to reach out with your use case for Docker support in Pants. We want this to work for as many as possible.

We are really excited by all the possibilities we can realize using the Pants+Docker combo!

Show Comments