Skip to content

Create a container image for remote actions

On EngFlow, most remote actions run inside containers. Containers provide isolation between actions and bundle everything you need to run remote actions in your custom environment.

When using remote execution with a Linux or Windows platform, you'll need to specify a container image to use. You'll usually want to prepare a custom image, but there are some publicly available images you can use, too. If you already have a container image used by your CI runners, make sure it meets the requirements, and use that. Ideally, your local and remote environments are similar so actions may run either locally or remotely.

You don't need a container image for macOS remote builds; macOS does not support containers.

Requirements for a container image

Your container image should have everything your remote actions need to run successfully except for files provided to your actions as inputs.

In most cases, you'll need to install a C/C++ toolchain, but if you use a fully hermetic toolchain in your Bazel workspace, you don't need to also install the toolchain in your container image.

Commands must be able to run within your container as a regular user, not as root on Linux or Administrator on Windows.

Your container image needs:

  • A complete shell environment with Bash, coreutils, and other tools. Most Linux base images have this by default.
  • A C/C++ toolchain. On most Linux distributions, you can install build-essential or clang. Any GCC- or Clang-like compiler compatible with Bazel should work. Even if you aren't building C++ code, many rule sets depend on this.
  • Any other run-time environments and tools needed by your actions.
  • HOME must be set to a writable directory. Actions should avoid writing files outside the working directory or /tmp, but many tools assume they can create files in HOME.
  • Optional: a user named engflow with uid=108 and a group named engflow with gid=114. The EngFlow server runs commands with this uid and gid, and some actions expect them to have names in /etc/passwd and /etc/group.
  • msys2 installed in the default location at C:\msys64. C:\msys64\usr\bin must be in PATH. Many rules, wrappers, and genrules require a Bash shell and related tools.
  • A C/C++ toolchain. You can either use one of the msys2 toolchains, Microsoft Visual Studio Build Tools (MSVC), or any other compiler that accepts similar flags. Even if you aren't building C++ code, many rule sets depend on this.
  • Any other run-time environments and tools needed by your actions.

By default, EngFlow runs containers as the user ContainerUser.

Publicly available images

If your actions don't have specific requirements, the bazel-toolchains project provides pre-configured toolchains and container images based on Ubuntu 16.04.

Building your own image

To build your own container image, you can start with one of the Dockerfiles shown below. To build, run:

docker build --tag engflow-container-image:latest .
FROM debian:latest
ENV DEBIAN_FRONTEND noninteractive

RUN groupadd \
  --gid 114 \
  engflow && \
  useradd \
  --home-dir /home/engflow \
  --create-home \
  --uid 108 \
  --gid 114 \
ENV HOME=/home/engflow

RUN apt-get update --quiet --quiet --yes && \
  apt-get install --quiet --quiet --fix-broken --yes \
  clang \
  curl \
  python3 \
  python-is-python3 \
  zip && \
  rm -rf /var/lib/apt/lists/*

Refer to for a complete example.

Our Windows Dockerfile is longer, relying on several Powershell scripts to build and install dependencies. Those are too long to show here.

Storing your image

We recommend storing your container image in a Docker registry close to the region where your cluster primarily operates. This minimizes the time a newly started worker instance takes to fetch your image. It also reduces network costs. You have several options:

  • Create a private AWS Elastic Container Registry (ECR) or a Google Cloud Artifact Registry (GAR) in the same region and availability zone as your cluster. If this is created in your cluster's AWS account or GCP project, your cluster will automatically have pull access.
  • Create a private registry in another cloud account, preferably in the same region and availability zone. Work with EngFlow customer success engineers to authenticate your cluster with this registry.
  • Use a public registry, like Docker Hub.

After you've chosen a registry, you can tag and push your image with the commands below, adjusting for your host, registry, and repository names.

docker tag engflow-container-image:latest "$TAG"
docker push "$TAG"

If your container image is larger than 4 GiB, please let EngFlow customer success engineers know. They may need to adjust the service configuration to ensure good performance.

Configuring Bazel to use your container image

When you configure Bazel remote execution, you'll need to set a container-image execution property in your platform target, which will be based on this tag.

First, find the image's SHA-256 sum. Run the command below, adjusting the last argument to match the tag you ran docker push with.

docker inspect --format="docker://{{index .RepoDigests 0}}" "$TAG"

That should print a URL like:

Text Only

You can add this to your platform target as below:

Text Only
    name = "linux_x64",
    constraint_values = [...],
    exec_properties = {
        "container-image": "docker://HOST_NAME/REGISTRY_NAME/REPO_NAME:latest@sha256:YOUR_IMAGE_SHA256",