How to Build Production Docker Images for Akash Console Services: Complete Guide

Use the build.sh helper script in packages/docker/script/ to orchestrate multi-stage Docker builds for Node.js and Next.js services, with optional Docker BuildKit support for accelerated, cache-optimized image creation.

Akash Console is a monorepo containing multiple backend APIs and frontend applications that are packaged as independent Docker images for production deployment. To build production Docker images for Akash Console services, you use a centralized build pipeline located in packages/docker/ that supports both automated helper scripts and manual Docker Compose workflows. This guide walks through the exact commands, Dockerfile structures, and optimization techniques used in the akash-network/console repository.

Multi-Stage Dockerfile Architecture

The repository maintains two optimized Dockerfile templates in packages/docker/ that handle different service types.

Node-Only Services

Backend services like the API, tx-signer, notifications, indexer, and provider-proxy use packages/docker/Dockerfile.node. This multi-stage Dockerfile uses node:24.13.0-alpine as the base image, installs dependencies in a development stage, compiles the application in a builder stage, and copies the artifacts into a minimal production stage that runs under a non-root user.

Next.js Frontend Services

Frontend applications including deploy-web, stats-web, and provider-console use packages/docker/Dockerfile.nextjs. This file extends the Node multi-stage pattern with an additional production-nginx stage that adds an Nginx front-end with a self-signed TLS certificate, serving the static Next.js export.

Building Images with the Helper Script

The recommended workflow uses packages/docker/script/build.sh, which automates git SHA detection, caching logic, and registry pushing.

Build a Single Service

To build a specific service such as the API with a custom version tag:

./packages/docker/script/build.sh \
  -r gcr.io/cloudmos-explorer/console-api \
  -t v2.5.0 \
  -a api

The script extracts the latest commit SHA that touched the service (lines 68-78 in build.sh) and checks whether an image for that SHA already exists in the registry using docker manifest inspect. If found, it pulls and retags the existing image rather than rebuilding.

Build All Services

While the script processes one service per invocation, you can sequence builds for all services by running the command for each application:

REPO=gcr.io/cloudmos-explorer/console
TAG=v2.5.0

for app in api tx-signer notifications indexer provider-proxy deploy-web stats-web provider-console; do
  ./packages/docker/script/build.sh -r "$REPO-$app" -t "$TAG" -a "$app"
done

Force Rebuilds and BuildKit Optimization

To ignore cached SHA images and force a fresh build, add the -f flag:

./packages/docker/script/build.sh -r $REPO -t $TAG -a api -f

For faster builds with shared cache scopes, enable Docker BuildKit:

USE_DOCKER_BUILDKIT=1 \
  ./packages/docker/script/build.sh -r $REPO -t $TAG -a api

When USE_DOCKER_BUILDKIT=1 is set, the script invokes the ensure_builder and docker_buildx_bake functions in [packages/docker/script/dc.sh](https://github.com/akash-network/console/blob/main/packages/docker/script/dc.sh), switching from standard docker compose build to docker buildx bake with configurable BUILDKIT_CACHE_SCOPE parameters.

Direct Docker Compose Builds

For debugging or custom build arguments, bypass the helper script and invoke Docker Compose directly using packages/docker/docker-compose.build.yml:

WORKSPACE=apps/api \
DEPLOYMENT_ENV=prod \
docker compose -f packages/docker/docker-compose.build.yml build api

For Next.js services requiring custom build-time secrets like Sentry tokens:

WORKSPACE=apps/deploy-web \
DEPLOYMENT_ENV=prod \
docker compose -f packages/docker/docker-compose.build.yml \
  build --build-arg SENTRY_AUTH_TOKEN=xxxx deploy-web

The WORKSPACE argument maps to the monorepo path (e.g., apps/api, apps/deploy-web), which the Dockerfile uses to locate the correct package.json and source files.

Production Image Internals

Both Dockerfiles produce minimal production images by copying only compiled artifacts from the builder stage. The Node Dockerfile creates a non-root user for security, while the Next.js Dockerfile includes an Nginx configuration for TLS termination. The final images are tagged with the user-supplied version and optionally latest, then pushed to the configured registry (lines 122-133 in build.sh).

Summary

  • Two Dockerfile patterns handle the monorepo: Dockerfile.node for backend services and Dockerfile.nextjs for frontend applications, both located in packages/docker/.
  • Use build.sh as the primary entry point for production builds; it handles SHA detection, caching, tagging, and pushing to registries like GCR.
  • Enable BuildKit with USE_DOCKER_BUILDKIT=1 to leverage docker buildx bake and cache scopes defined in dc.sh for faster CI/CD pipelines.
  • Specify the WORKSPACE environment variable when building manually to point Docker to the correct application within the monorepo structure.
  • Force rebuilds with the -f flag when you need to bypass the SHA-based cache and regenerate images from source.

Frequently Asked Questions

How does the build script avoid redundant rebuilds?

The script calculates the latest git SHA that modified the specific service directory and queries the registry via docker manifest inspect to check if an image tagged with that SHA already exists. If found, the script pulls that image and applies the new version tag rather than recompiling, significantly reducing build times for unchanged code.

Can I build images for local testing without pushing to a registry?

Yes. Omit the registry push by using the direct Docker Compose method with the docker-compose.build.yml file. Set your WORKSPACE and run docker compose -f packages/docker/docker-compose.build.yml build <service-name> to create images locally without executing the push logic contained in build.sh.

What is the difference between docker-compose.build.yml and docker-compose.prod.yml?

The docker-compose.build.yml file defines the build context, Dockerfile paths, and WORKSPACE arguments necessary to compile images. The docker-compose.prod.yml and docker-compose.prod-with-db.yml files are runtime configurations used for deploying pre-built images; they specify container orchestration, environment variables, and networking for production workloads.

How do I add custom build arguments like Sentry integration?

Pass additional build arguments through the direct Docker Compose invocation using the --build-arg flag. For example, docker compose -f packages/docker/docker-compose.build.yml build --build-arg SENTRY_AUTH_TOKEN=your_token deploy-web. The helper script (build.sh) does not currently expose arbitrary build arguments, making direct Compose the preferred method for custom tokens or flags.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →