Skip to content

Add multi-arch Dockerfile for the API (amd64 + arm64) #28

@StephanMeijer

Description

@StephanMeijer

Summary

Create a Dockerfile for the DocSpec API that supports both linux/amd64 and linux/arm64 architectures.

Context

DocSpec is an Elixir umbrella project (Elixir 1.19 / OTP 27) that currently ships as pre-built native binaries and an escript, but has no container image for API deployment. A multi-arch Docker image would enable easy deployment on both x86 and ARM infrastructure (e.g., AWS Graviton, Apple Silicon dev machines, mixed Kubernetes clusters).

No Dockerfile exists in the repository today.

Existing Reference

The docspecio/api repo already has a working Dockerfile we can reuse as a starting point:

Dockerfile from docspecio/api
FROM elixir:1.19-alpine AS build
WORKDIR /usr/src/app

ENV MIX_ENV=prod

RUN apk add --no-cache git
RUN mix local.hex --force && mix local.rebar --force

COPY . .

RUN mix deps.get && mix release

FROM elixir:1.19-alpine

ENV MIX_ENV=prod

# Create non-root user
RUN addgroup -g 1000 appgroup && \
    adduser -u 1000 -G appgroup -D appuser

COPY --from=build --chown=appuser:appgroup /usr/src/app /usr/src/app

WORKDIR /usr/src/app

EXPOSE 4000

# Run as non-root user (use numeric UID for Kubernetes runAsNonRoot verification)
USER 1000

CMD ["_build/prod/rel/docspec_api/bin/docspec_api", "start"]
.dockerignore from docspecio/api
_build
.ci
.vscode
deps
*.json
_build/
cover/
*.coverdata
doc/
.fetch
erl_crash.dump
*.ez
docspec_*.tar
tmp/
.elixir_ls/
.DS_Store
helm/charts
test/

What we can reuse

  • Overall multi-stage structure (build → runtime) — works as-is
  • Alpine base (elixir:1.19-alpine) — already multi-arch compatible
  • Non-root user setup — good practice, keep it
  • .dockerignore — adapt for this repo (add burrito_out/, .git/, .github/, etc.)

What needs adapting

  • Release name — this repo's release will differ from docspec_api; update the CMD path accordingly
  • Runtime stage copies entire /usr/src/app — should ideally only copy _build/prod/rel/ to keep the image small
  • No explicit --platform usage — Alpine + docker buildx should handle multi-arch natively, but verify both arches in CI

Requirements

  • Multi-stage build — separate build and runtime stages to keep the final image small
  • Multi-arch support — must build and run on both linux/amd64 and linux/arm64 (use docker buildx / --platform)
  • Elixir release — compile a production Mix release (MIX_ENV=prod mix release) in the build stage
  • Runtime image — Alpine base with only the Erlang runtime needed to run the release (copy only the release, not the full source)
  • Versions — match the project's current toolchain: Elixir 1.19 / OTP 27 (see .tool-versions)
  • .dockerignore — include a .dockerignore to exclude _build, deps, burrito_out, .git, etc.

Acceptance Criteria

  • Dockerfile added at the repository root
  • .dockerignore added at the repository root
  • Image builds successfully for both linux/amd64 and linux/arm64
  • Container starts and the API is reachable on its configured port
  • Final image size is reasonable (target < 100 MB)
  • Runtime stage only contains the release (not full source tree)
  • Runs as non-root user

Notes

  • The project uses an umbrella layout under apps/.
  • Zig is listed in .tool-versions for Burrito native builds — it is not needed for the Docker/release build and should be excluded.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions