Overview

How to build Docker images containing artifacts built by Pants

Docker images are a common deployment format.

Docker images typically bundle build artifacts, such as PEX files, wheels, loose files, and so on, with other runtime requirements, such as a Python interpreter.

Pants makes it easy to embed the artifacts it builds into your Docker images, for easy deployment.

Enabling the Docker backend

To use Pants's Docker support you must enable the appropriate backend:

backend_packages = [
  ...
  "pants.backend.experimental.docker",
  ...
]

We expect the Docker backend to graduate out of the "experimental" area soon!

Adding docker_image targets

A docker image is built from a recipe specified by a Dockerfile. When you build docker images with Pants, instead of running docker on the Dockerfile directly, you let Pants do that for you.

Pants uses docker_image targets to indicate which Dockerfiles you want Pants to know about, and to add any necessary metadata.

You can autogenerate initial BUILD files for your Docker images, using tailor:

$ ./pants tailor
Created src/docker/app1/BUILD:
  - Added docker_image target src/docker/app1:docker
Created src/docker/app2/BUILD:
  - Added docker_image target src/docker/app2:docker

Or you can add them manually, such as:

docker_image(name='docker')

Adding dependencies to your docker_image targets

A Dockerfile executes in a context - a set of files that the commands in the Dockerfile can reference, e.g., by copying them into the image).

When you run docker directly, the context is usually a directory within your repo. That directory must contain the Dockerfile (typically at the root of the context) and any files that the build requires. If those files are themselves the product of a build step, or if they are sources from elsewhere in the repo, then you have to copy them into the context.

Pants, however, takes care of assembling the context for you. It does so using the dependencies of the docker_image target.

A docker_image can depend on loose files belonging to files targets, and on artifacts packaged from a variety of targets, such as pex_binary , python_distribution, archive, or any other target that can be built via the package goal.

The context is assembled as follows:

  • The sources of files targets are assembled at their relative path from the repo root.
  • The artifacts of any packageable targets are built, as if by running ./pants package, and placed in the context under a subdirectory named for the target's path from the repo root.

Building a Docker image

You build Docker images using the package goal:

$ ./pants package path/to/Dockerfile

Example

To see this in action, look at the following example:

files(
    name="msg",
    sources=["msg.txt"]
)

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

pex_binary(
    name="bin",
    entry_point="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)
$ ./pants package src/docker/hw/Dockerfile
[...]
18:07:29.66 [INFO] Completed: Building src.python.hw/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
$ docker run -it --rm helloworld:latest
Hello, Docker!

Tagging the image

By default the built image gets a latest tag. To select another value to use, provide a version value to docker_image:

docker_image(
    name="helloworld",
    version="1.2.0",
    dependencies=[":msg", "src/python/hw:bin"],
)

📘

Generating Tags

Generating custom tags at runtime based on Git state or image inputs requires you to write some custom plugin code. Don't hesitate to reach out for help with this.
We are looking into adding this functionality into the core Docker plugin in the future.

Linting Dockerfiles

Pants can run hadolint on your Dockerfiles to check for errors and mistakes:

$ ./pants lint src/docker/hw/Dockerfile

This must first be enabled by adding the following configuration:

[GLOBAL]
backend_packages.add = ["pants.backend.experimental.docker.lint.hadolint"]

Did this page help you?