docker builds.md

Optimizing Docker build performance

Building Docker images can be one of the most time-consuming parts of your CI/CD pipeline. Namespace runners accelerate your Docker builds through build distribution, layer caching, and integration with your existing workflows.

Quick start

No configuration changes required

The fastest way to speed up your Docker builds is to simply switch to Namespace runners. Remote Builders are enabled by default and will immediately accelerate your builds.

jobs:
  build:
    runs-on: namespace-profile-default # was: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        # No docker/setup-buildx-action or docker/setup-qemu-action required!
      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: my-registry/my-app:latest

Note: If your workflow uses docker/setup-buildx-action, you need to remove or replace it.

That's it! Your builds are now running on high-performance Remote Builders with advanced caching.

Remote Builders

How Remote Builders transform your workflow

Remote Builders fundamentally change how Docker builds work in your CI/CD pipeline:

Monitoring your accelerated builds

Every build launched from your runners appears in the interface providing direct access to detailed logs, timing metrics, and performance analytics.

This visibility helps you understand exactly how much time Remote Builders are saving. When looking at a slow build step, you can directly jump into the logs to understand which work was performed.

Head to Build Observability → to learn how to monitor build performance and identify bottlenecks.

Private registry (nscr.io)

Your builds get instant access to your private container registry at nscr.io with zero setup required. Authentication is handled automatically.

1. Push to your private registry

- name: Build and push to private registry
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: ${{ env.NSC_CONTAINER_REGISTRY }}/my-app:${{ github.sha }}

2. Pull from your private registry

- name: Use base image from private registry
  run: docker pull ${{ env.NSC_CONTAINER_REGISTRY }}/my-app:${{ github.sha }}

You can find a tag overview with history and usage statistics for pushed images in the dashboard.

Local caching

While Remote Builders provide the best performance for most scenarios, in-runner builders (locally cached) excel when building massive images (10GB+). Keeping the build local skips network transfer time.

This section covers when to keep a build local. For caching container image pulls themselves, see Container Images.

To enable this feature, just open the runner profile configuration and add a cache volume. Next, select Locally cached for your Docker builds. Make sure to size your cache appropriately to benefit from a high cache hit ratio.

Caveats

Billing

Using local caching does not lead to any additional compute usage beyond the runner's execution time itself. In order to make use of the feature, including logging and tracing, each build made with local caching counts towards the total build usage.

Optimize cache mounts

A common strategy to improve your build performance is the adoption of build cache mounts, allowing you to persist cache data across container builds and reduce build times significantly.

With Namespace, your builds run in a shared, remote, high-performance builder by default, unlike on GitHub runners, where your docker builds run inside the runner. This sharing means that you'll see more cache hits across different builds, and hence faster builds.

Cache mounts allow multi-writer access by default. Some tools (e.g. apt) need exclusive access to its data. To achieve this, you can select sharing=locked which makes concurrent builds wait for another.

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt update && apt-get --no-install-recommends install -y gcc

Builds without output

When you want to test a build without pushing or loading it, use the cacheonly output type. This runs the full build and populates the cache, but skips the export step:

- uses: docker/build-push-action@v6
  with:
    context: .
    outputs: type=cacheonly

Enterprise scaling

Need to run hundreds of concurrent builds? Namespace supports full-fanout builds that can handle enterprise-scale build volumes without performance degradation.

Contact support@namespace.so to discuss custom scaling configurations for your build volume requirements.

Disable build caching

If you prefer to skip build caching altogether, you have two options:

  1. Revert the Docker build context to the default: Namespace configures Remote Builders as a separate buildx context. Before invoking a build that should not be cached, you can switch back to the default by calling docker buildx use default. E.g.
   jobs:
     build:
       steps:
         - name: Use default builder
           run: docker buildx use default

- name: Build and push
           uses: docker/build-push-action@v5
           with:
             context: .
             platforms: linux/amd64,linux/arm64
  1. Disable Remote Builders: You can request that runners created for a particular workflow job do not use Remote Builders.

To disable Remote Builders, just open the runner profile configuration and select No caching for your Docker builds.

Migrating from GitHub Actions

Remove setup-buildx-action

Because Namespace runners are configured out of the box to use Remote Builders, there is no need to set up or configure buildx separately. In fact, running docker/setup-buildx-action will overwrite the default configuration and prevent you from using Remote Builders.

You can just remove docker/setup-buildx-action from your workflow entirely, or replace it with namespacelabs/nscloud-setup-buildx-action:

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3 # [!code --]
  uses: namespacelabs/nscloud-setup-buildx-action@v0 # [!code ++]
- uses: docker/build-push-action@v5
  with:
    context: .

QEMU is not required

Multi-platform builds using Remote Builders don't use emulation for AMD64 and ARM64 builds, instead building on these platforms natively. This results in much better performance for multi-platform builds, and also means there is no need to set up QEMU.

When using Remote Builders, you can safely remove docker/setup-qemu-action, too:

steps:
  - uses: docker/setup-qemu-action@v3 # [!code --]
  - uses: docker/setup-buildx-action@v3 # [!code --]
  - uses: docker/build-push-action@v5
    with:
      context: .

Skip GitHub Actions caching

Traditional CI/CD requires complex caching strategies, but Namespace's build infrastructure makes this unnecessary. Namespace build solutions include maximum layer caching out of the box. Using traditional GitHub Actions caching like cache-from/cache-to is superfluous when using Namespace builders and typically adds delays through remote file operations.

You can remove them from your workflow definition:

- uses: docker/build-push-action@v5
  with:
    context: .
    cache-from: type=registry,ref=user/app:buildcache # [!code --]
    cache-to: type=registry,ref=user/app:buildcache,mode=max # [!code --]

What this means for you

Next steps

For advanced configuration see Runner Labels.