Subchapter 8.8
references/dockerfile-generation.mdMarkdown4 KBView on GitHub
Generate Dockerfiles for components targeting Container Apps (or B1+ App Service) that have no existing Dockerfile. Read this when iac-generation-rules.md Step 6b applies.
Dockerfile.azure)deployStrategy.containerized: trueDockerfile.azure only if BuildKit stripping is neededCopy dependency manifests and install BEFORE copying source (preserves layer cache):
COPY {manifest files} ./
RUN {install command}
COPY . .| Principle | Rule |
|---|---|
| Pin version | node:{major}-slim, NOT node:latest |
| Slim variants | -slim or -alpine for smaller images |
| Multi-stage | Go, .NET, Java, Rust: build in SDK image, copy binary to runtime |
| Match runtime | Read engines, python_requires, go.mod, <TargetFramework> |
EXPOSE port, app’s listening port, and Container App targetPort must all match. Mismatch = silent health probe failure. Read app config for listening port, set EXPOSE {port}, add ENV PORT={port} if app reads PORT from env.
-slim base: RUN groupadd -r app && useradd -r -g app app; Alpine base: RUN addgroup -S app && adduser -S app -G app. Then USER appCOPY .env or secrets — use .dockerignoreCMD ["node", "server.js"] not CMD ["npm", "start"]Always generate alongside Dockerfile. Exclude: .git, node_modules, __pycache__, *.pyc, .env, .env.*, .azure, .copilot-azure, infra, *.md.
| Mistake | Fix |
|---|---|
COPY . . before deps | Copy manifests first, install, then source |
npm install in prod | npm ci --omit=dev |
| Wrong EXPOSE port | Read actual listening port from app source |
NEXT_PUBLIC_* env vars are embedded in the client JS bundle at npm run build time — runtime Container App env vars have zero effect on client-side code. For multi-container deploys where a Next.js frontend references another component’s API:
ARG NEXT_PUBLIC_API_URL before the RUN npm run build step--build-arg NEXT_PUBLIC_API_URL=https://{api-fqdn} to az acr buildDetect from .env* files containing NEXT_PUBLIC_* pointing to another service (e.g., NEXT_PUBLIC_API_URL=http://localhost:3001).
⛔ ACR az acr build uses the classic Docker builder — NOT BuildKit. Do NOT assume ACR supports BuildKit.
When to generate Dockerfile.azure: If buildRequirements.hasBuildKitSyntax == true OR the existing Dockerfile contains any BuildKit-only syntax, create {component}/Dockerfile.azure with all BuildKit syntax removed.
BuildKit-only syntax (strip all): # syntax= directives, RUN --mount=... (all types: cache, secret, bind, tmpfs), RUN --network=..., RUN --security=..., COPY --link, COPY --chmod=..., heredoc syntax (RUN <<EOF).
⛔ Package manager pinning applies here too. When stripping BuildKit from an existing Dockerfile, also replace npm install -g {pm}@latest with the exact version from the project’s packageManager field in package.json (e.g., pnpm@9.4.0). The upstream Dockerfile’s @latest may pull a version incompatible with the base image’s Node.js version.
⛔ Handle multi-line continuations (\) — remove the BuildKit flag but preserve the actual command across all continuation lines. Never leave a bare RUN with no command.