Skip to main content
The environment image is the one thing every person running a deployment would otherwise have to install. Everything the steps call must be in it.

Starting points

deploy/aws.Dockerfile

Rules of the container

  • The repository is mounted at /workspace, which is also the working directory. Set WORKDIR /workspace so relative paths in steps behave.
  • Steps run with /bin/sh. Alpine’s sh is BusyBox ash; install bash if your scripts need it and put #!/usr/bin/env bash at the top.
  • Reset the entrypoint of images that ship with the CLI as ENTRYPOINT. Keel starts the container with its own command; an entrypoint that wraps every command in aws breaks that.
  • Disable interactive prompts — CLOUDSDK_CORE_DISABLE_PROMPTS=1, AWS_PAGER="", DEBIAN_FRONTEND=noninteractive. There is nobody at the keyboard.
  • There is no Docker daemon inside the container. A step cannot docker build or docker push. Use the cloud’s remote builder (Cloud Build, CodeBuild, ACR Tasks, Kaniko in a cluster) or build images in CI and have the deployment reference a tag — pass it as a deploy-time variable. Remote builders may default to the legacy Docker builder: a Dockerfile using FROM --platform=$BUILDPLATFORM, TARGETOS/TARGETARCH, RUN --mount, or heredocs needs BuildKit. On Cloud Build, add env: [DOCKER_BUILDKIT=1] to the gcr.io/cloud-builders/docker step; without it the build fails with failed to parse platform : "" is an invalid component.
  • The container is disposable. Nothing written outside /workspace survives the run. Nothing written inside /workspace is committed anywhere; in Keel Cloud the clone is deleted, in Keel Dev it is your working tree.

Build context and caching

The context is what COPY can see. Most environment images copy nothing from the repository, so a narrow context (deploy) keeps builds fast and avoids invalidating layers when application code changes. When you use the repository root, add a .dockerignore that excludes .git, node_modules, build output, and .keel. Keel tags the image per deployment — keel/dev-<deployment> in Keel Dev, keel/cloud-<repo>-<deployment> in Keel Cloud — so Docker’s layer cache carries across runs. A Dockerfile that has not changed rebuilds in seconds. Order instructions from least to most frequently changing, as usual.

Multiple deployments, one image

Deployments that need the same tools can share a Dockerfile; there is no requirement for one image per deployment. Deployments with different tools should have separate, smaller images rather than one image with everything.

Testing the image without Keel

This is close to what a run sees, minus the variables. It is the fastest way to debug a missing tool.