Skip to content

Containers

The containers section of appmecca.yaml defines what Docker images to build from your repository. Each entry produces one Docker image that gets pushed to the AppMecca private image registry.

Basic Example

containers:
  - name: myapp
    dockerfile: Dockerfile
    context: .

This builds one image called myapp using the Dockerfile in the repository root.

All Fields

Field Required Default Description
name Yes — Name for this container. Names the image in the registry.
dockerfile Yes Dockerfile Path to the Dockerfile, relative to the repo root. See the note below — it is required in practice.
context No . Docker build context directory, relative to the repo root.
args No {} Build arguments passed to docker build --build-arg.
build_args_from_vars No [] Stored variables (mecca var set) to also pass as build arguments. See below.
target No — Build target for multi-stage Dockerfiles (docker build --target).

Unknown keys are silently ignored

Any key AppMecca does not recognise is dropped with no error and no warning. A misspelled dockerfle: does not fail the build — it falls back to the default Dockerfile and the pre-flight check then rejects the container for having no dockerfile. Check spelling first when a setting seems to do nothing.

name

The container name identifies the image inside the AppMecca image registry, scoped to your app and environment:

appmecca/{environment}/{app}/{name}

You never type this path — AppMecca resolves it for you at build and deploy time.

Naming rules

Container names must be lowercase and can contain letters, numbers, and hyphens. Avoid very long names — they are folded into generated resource names that have length limits.

dockerfile

Path to the Dockerfile relative to the repository root.

dockerfile is required in practice

The schema defaults this to Dockerfile, but the repository pre-flight check that runs on mecca register rejects any container entry that does not declare dockerfile explicitly. Always write it out.

containers:
  # Dockerfile in repo root (default)
  - name: myapp
    dockerfile: Dockerfile

  # Dockerfile in a subdirectory
  - name: frontend
    dockerfile: frontend/Dockerfile

context

The Docker build context — the directory that Docker can access during the build. Defaults to . (the repository root).

containers:
  - name: frontend
    dockerfile: frontend/Dockerfile
    context: frontend/

When to change the context

If your Dockerfile is in a subdirectory and only needs files from that subdirectory, set the context to match. This keeps the Docker build context small and builds faster.

If your Dockerfile needs files from the repo root (like a shared requirements.txt), keep the context as . and use the full path in your COPY commands.

build_args_from_vars

Variables you set with mecca var set reach the build as secrets: a RUN step reads one with --mount=type=secret,id=NAME (the value is in /run/secrets/NAME), and the value is not stored in the image.

RUN --mount=type=secret,id=NPM_TOKEN \
    NPM_TOKEN="$(cat /run/secrets/NPM_TOKEN)" npm ci

List a stored variable here only when it is not a secret and your Dockerfile needs it as an ARG. It is then passed as a build argument too, and its value is stored in the image.

containers:
  - name: web
    dockerfile: Dockerfile
    build_args_from_vars: [PUBLIC_API_URL]

Each entry must be letters, digits and underscores, not starting with a digit.

Release 6.4 transition

In release 6.4, a stored variable your Dockerfile declares with ARG is still passed as a build argument even when it is not listed here, with a warning in the build log and in mecca queue status. From release 6.5 that build is refused.

args

Build arguments passed to Docker via --build-arg. These are available in your Dockerfile as ARG values. Never put a secret here: anyone who can pull the image can read build arguments from its history.

containers:
  - name: backend
    dockerfile: Dockerfile
    args:
      NODE_ENV: production
      API_VERSION: "2.0"

In your Dockerfile:

ARG NODE_ENV=development
ARG API_VERSION

RUN echo "Building for ${NODE_ENV}, API version ${API_VERSION}"

target

For multi-stage Dockerfiles, specifies which build stage to use as the final image. This maps to docker build --target.

containers:
  - name: myapp
    dockerfile: Dockerfile
    target: production

In your Dockerfile:

FROM node:20-slim AS builder
RUN npm ci && npm run build

FROM node:20-slim AS production
COPY --from=builder /app/dist/ /app/
CMD ["node", "/app/server.js"]

FROM node:20-slim AS development
COPY . /app/
CMD ["npm", "run", "dev"]

Multiple Containers

You can build multiple containers from a single repository. This is common for full-stack applications with separate frontend and backend images.

containers:
  - name: frontend
    dockerfile: frontend/Dockerfile
    context: frontend/

  - name: backend
    dockerfile: backend/Dockerfile
    context: backend/
    args:
      PYTHON_VERSION: "3.12"

Each container becomes its own image in the registry, namespaced by app and environment.

When you trigger a build, all containers defined in appmecca.yaml are built in sequence. You can't build just one.

Image tagging

Every image is tagged with the Git commit hash (e.g., abc1234) and latest. This means you can always trace a running container back to exactly which code it was built from.

Monorepo Patterns

Separate directories

The most common pattern for monorepos — each service has its own directory:

containers:
  - name: web
    dockerfile: services/web/Dockerfile
    context: services/web/

  - name: api
    dockerfile: services/api/Dockerfile
    context: services/api/

  - name: worker
    dockerfile: services/worker/Dockerfile
    context: services/worker/

Shared root context

If your services share code (like a common library), use the repo root as the context:

containers:
  - name: web
    dockerfile: services/web/Dockerfile
    context: .

  - name: api
    dockerfile: services/api/Dockerfile
    context: .

In this case, both Dockerfiles can COPY from anywhere in the repository.

Dockerfile Best Practices

Include a health check endpoint for anything that serves HTTP

Any service that declares a port should expose an endpoint returning HTTP 200 when it is healthy, and a matching health_check: block in appmecca.yaml. That is how AppMecca decides your new container is ready to receive traffic during a deploy.

Background workers with no port need neither — omit health_check: for them, which turns health checking off for that service entirely.

Use multi-stage builds

Multi-stage builds produce smaller images and faster deployments:

# Build stage — has all the build tools
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Runtime stage — only has what's needed to run
FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/build/ ./build/
COPY --from=builder /app/package*.json ./
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "build"]

Pin your base images

Use specific version tags, not latest:

# Good — reproducible builds
FROM python:3.12-slim
FROM node:20-slim

# Bad — might change unexpectedly
FROM python:latest
FROM node:latest

Use EXPOSE

While AppMecca reads the port from appmecca.yaml (not from EXPOSE), including EXPOSE in your Dockerfile is good documentation:

EXPOSE 8000

Next Steps

  • Services — Configure how your containers run (ports, health checks, commands)
  • Multi-Container Builds — Deep dive into building multiple containers