Skip to main content

generate-dockerfile

Generate or enhance a Dockerfile for a containerized application using curated base-image recommendations and security best practices. Use AFTER analyze-repo (or after the user has told you the language/framework). Triggers include "generate a Dockerfile", "containerize this", "write Dockerfile for X", or when running aks-loop and no Dockerfile yet exists. If a Dockerfile already exists, this skill enhances it in place.

소스 정보

저장소
Azure/containerization-assist
최근 소스 활동
2026년 7월 16일 16:37
감지된 SKILL.md 언어
영어
스타
43
포크
20

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
generate-dockerfile
description
Generate or enhance a Dockerfile for a containerized application using curated base-image recommendations and security best practices. Use AFTER analyze-repo (or after the user has told you the language/framework). Triggers include "generate a Dockerfile", "containerize this", "write Dockerfile for X", or when running aks-loop and no Dockerfile yet exists. If a Dockerfile already exists, this skill enhances it in place.
argument-hint
<modulePath> <language> [framework] [environment=production|development]
# Generate Dockerfile Produce a production-quality, secure Dockerfile (or enhancement plan for an existing one) for a single module. The output is a complete Dockerfile that the user can write to disk — not a description of one. ## Inputs | Field | Required | Description | |---|---|---| | `modulePath` | yes | Absolute path of the module to containerize (one of the modules from `analyze-repo`). | | `language` | yes | `java` \| `dotnet` \| `javascript` \| `typescript` \| `python` \| `go` \| `rust` \| `php` \| `ruby`. | | `languageVersion` | recommended | E.g. `21`, `8.0`, `20`, `3.11`. Substituted into the base image tag. | | `framework` | optional | E.g. `spring-boot`, `express`, `next`, `django`, `flask`, `asp.net-core`, `gin`. | | `environment` | optional | `production` (default) or `development`. | | `targetPlatform` | optional | `linux/amd64` (default) or `linux/arm64`. | | `detectedDependencies` | optional | Used to choose extra apt/apk packages (e.g. native modules). | | `detectedEnvVars` | optional | List from `analyze-repo`. Used to add `ENV` instructions for `config`/`database` vars and to WARN about `secret`-classified ones (never bake secrets in). | | `existingDockerfile` | optional | If a Dockerfile is already at `<modulePath>/Dockerfile`, read its content and follow the **Enhancement path** instead of the **Generation path**. | ## Prerequisite: analyze-repo This skill needs `language`, `framework`, `detectedDependencies`, and `detectedEnvVars` from the `analyze-repo` skill. If you don't already have that output for `<modulePath>` from earlier in this conversation, follow the `analyze-repo` skill against `<modulePath>` first, then come back. ## Decision: generate or enhance? 1. Check if `<modulePath>/Dockerfile` exists. 2. If **no** → Generation path (Step G1–G4 below). 3. If **yes** → read the file, run **Dockerfile analysis** (Step E1), then Enhancement path (Step E2–E4). --- ## Generation path ### G1 — Choose build strategy Use **multi-stage** if any of these: - `language` ∈ {`java`, `go`, `rust`, `dotnet`} - `language` is `typescript` AND build output is required (`tsc`, `next build`, `vite build`, etc.) - `buildSystem.type` ∈ {`maven`, `gradle`} Otherwise use **single-stage**. The reason this matters: multi-stage drops compilers, SDKs, and source code from the final image — typically 70–90% smaller and a smaller attack surface. ### G2 — Choose the base image(s) **Hard rule: every `FROM` line MUST start with `mcr.microsoft.com/` unless the stack appears in the explicit non-MCR list (G2.3) below.** The Dockerfile is the contract for an Azure-hosted image. Public-registry images (`eclipse-temurin`, `tomcat`, `node`, `python`, `golang`, `rust`) are **not** "alternatives" — they are fallbacks for the few stacks where MCR genuinely does not publish a base. Pick from the catalog in G2.1 first; only if no row matches, drop to G2.3. #### G2.1 — MCR catalog (use these tags, do not invent others) Use only the tags listed here. If your `<LV>` is not in the list, see G2.2 (modernize) or G2.3 (documented fallback) — do NOT guess a tag. **Java — `mcr.microsoft.com/openjdk/jdk`** | `<LV>` | Build tag | Runtime tag | |---|---|---| | 8 | `8-azurelinux` | `8-distroless` | | 11 | `11-azurelinux` | `11-distroless` | | 17 | `17-azurelinux` | `17-distroless` | | 21 | `21-azurelinux` | `21-distroless` | | 25 | `25-azurelinux` | `25-distroless` | These are the only Java major versions on MCR (verified against `https://mcr.microsoft.com/v2/openjdk/jdk/tags/list`). The published tag format is a **single digit major** — `8-azurelinux`, never `1.8-azurelinux` or `8u292-jdk-slim` (those do not exist and fail with `image not found`). MCR does **not** publish a separate `openjdk/jre` repository — for the runtime stage of a JRE-only image, use the `-distroless` variant of the same major (`8-distroless`, `17-distroless`, …) which ships only the JRE. **.NET — `mcr.microsoft.com/dotnet/{sdk,aspnet,runtime}`** | `<LV>` | SDK | ASP.NET runtime | Generic runtime | |---|---|---|---| | 8.0 | `sdk:8.0-azurelinux3.0` | `aspnet:8.0-azurelinux3.0` | `runtime:8.0-azurelinux3.0` | | 9.0 | `sdk:9.0-azurelinux3.0` | `aspnet:9.0-azurelinux3.0` | `runtime:9.0-azurelinux3.0` | **Node.js — `mcr.microsoft.com/azurelinux/{base,distroless}/nodejs`** | `<LV>` | Build tag | Runtime tag | |---|---|---| | 18 | `base/nodejs:18` | `distroless/nodejs:18` | | 20 | `base/nodejs:20` | `distroless/nodejs:20` | | 22 | `base/nodejs:22` | `distroless/nodejs:22` | **Python — `mcr.microsoft.com/azurelinux/{base,distroless}/python`** | `<LV>` | Build tag | Runtime tag | |---|---|---| | 3.11 | `base/python:3.11` | `distroless/python:3.11` | | 3.12 | `base/python:3.12` | `distroless/python:3.12` | Defaults if `languageVersion` is missing: `java=21`, `dotnet=8.0`, `node=20`, `python=3.12`. #### G2.2 — Modernize before falling back If the project targets a version not in G2.1 (typically Python 3.9/3.10, Node 16, Java 7): 1. **Preferred:** bump the build target to the nearest LTS in G2.1 (Python → 3.11, Node → 18). Update package metadata, keep MCR images. 2. Only if modernization is genuinely impossible, drop to G2.3 and document the reason in a `# WHY-NOT-MCR:` comment above the offending `FROM` line. #### G2.3 — Allowed non-MCR fallbacks (closed list) The following bases may appear when, and only when, no MCR row in G2.1 applies. Anything not in this list MUST NOT appear in a `FROM` line. **Hard rule — build images are build-only.** The images in the **Build stage** column below (`maven:*`, `gradle:*`, `golang:*`, `rust:*`, `composer:*`) are builders. They MUST NOT be the final / runtime stage. Using a non-MCR build image obligates a **multi-stage** Dockerfile whose final `FROM` is the matching **Runtime stage** image (an MCR `*-distroless` row from G2.1 wherever one exists). A single-stage Dockerfile that ships a `maven` / `gradle` / `golang` / `rust` builder as the runtime image is a policy violation: it defeats the MCR-runtime goal and ships the full build toolchain plus source in the running image — even though a lone `maven`/`gradle` `FROM` looks "allowed" here. | Stack / Reason | Build stage | Runtime stage | |---|---|---| | Maven builder (MCR ships no Maven-with-JDK image) | `maven:3.9-eclipse-temurin-<LV>` (where `<LV>` ∈ {8, 11, 17, 21}) | use the matching MCR `openjdk/jdk:<LV>-distroless` for runtime | | Gradle builder (MCR ships no Gradle image) | `gradle:<ver>-jdk<LV>` | use the matching MCR `openjdk/jdk:<LV>-distroless` for runtime | | Java EE / Jakarta EE app server (EJB, JSF, full profile — MCR ships no app server) | `maven:3.9-eclipse-temurin-<LV>` or MCR `openjdk/jdk:<LV>-azurelinux` | `jboss/wildfly:<ver>` (WildFly), `payara/server-full:<ver>` (Payara), `tomee:<ver>` (TomEE), or `tomcat:<ver>-jdk<LV>` (servlet-only WAR) | | Servlet/JSP WAR with no EJB | MCR `openjdk/jdk:<LV>-azurelinux` | `tomcat:<ver>-jdk<LV>` | | Go (no MCR base) | `golang:<LV>-alpine` | `gcr.io/distroless/static-debian12:nonroot` (CGO off) or `gcr.io/distroless/base-debian12:nonroot` (CGO on) | | Rust (no MCR base) | `rust:<LV>-slim` | `gcr.io/distroless/cc-debian12:nonroot` | | PHP (no MCR base) | `composer:2` | `php:<LV>-fpm-alpine` or `php:<LV>-apache` | | Ruby (no MCR base) | `ruby:<LV>-slim` | `ruby:<LV>-slim` | **Bare JDK/JRE images (`eclipse-temurin`, `openjdk`, `adoptopenjdk`, `amazoncorretto`, `ibmjava`) are NOT on this list.** For Java versions 8, 11, 17, 21, or 25, the MCR `openjdk/jdk:<LV>-{azurelinux,distroless}` row in G2.1 is mandatory — falling back to `eclipse-temurin:8-jre-alpine` or `adoptopenjdk:8-jre-hotspot` when MCR has the same major is a policy violation, even with a `# WHY-NOT-MCR:` comment. **Tag-name precision for Docker Hub `maven` images:** the only published `maven:3.9-eclipse-temurin-*` tags are `8`, `11`, `17`, `21` — there is **no** `…-jdk` suffix on these. Tags such as `maven:3.9-eclipse-temurin-8-jdk` or `maven:3.9-eclipse-temurin-17-jdk` do **not** exist and fail with `not found`. Use `maven:3.9-eclipse-temurin-17`, not `maven:3.9-eclipse-temurin-17-jdk`. When you use any row from G2.3, prepend a `# WHY-NOT-MCR:` comment above the `FROM` line explaining which condition triggered the fallback (e.g. `# WHY-NOT-MCR: Java EE app server, no MCR equivalent`). **Never invent a tag.** If you are tempted to write `mcr.microsoft.com/<anything>:<LV>-<suffix>` and the exact tag is not in G2.1, stop — either modernize per G2.2 or fall back per G2.3. ### G3 — Construct the Dockerfile **Hard rule: every Dockerfile MUST contain `LABEL com.azure.containerizationassist.createdby="containerization-assist"`, emitted on the line immediately after the `FROM` of the runtime / final stage. No exceptions. A Dockerfile without this label is rejected.** Apply every rule in this checklist: **Layer/structure** - One `WORKDIR` early (use `/app`); never use `cd` in `RUN`. - Copy **dependency manifests first**, install deps, then copy source — to preserve layer cache. - **Source MUST be copied before any build/compile command.** Every build stage that runs `mvn` / `./mvnw` / `gradle` / `./gradlew` / `npm run build` / `tsc` / `dotnet publish` / `go build` / `cargo build` MUST be preceded by a `COPY src ./src` (or equivalent — `COPY . .` for languages without a conventional `src/` layout). Skipping the source copy produces an empty build that fails with errors like "Unable to find main class" or "no main module" at runtime. - Use `RUN` chaining with `&&` to keep layers small. Aim for ≤ 6 `RUN` instructions. - For multi-stage, give each stage a name (`AS build`, `AS runtime`). **Build output & dependencies (derive, never assume)** Where a build writes its artifact, and which dependencies it needs to run, are determined by the project's own config — not by framework convention. Two recurring build failures come from guessing instead of reading: - **Derive the build-output directory; never hardcode it.** Before you `COPY` build output into the runtime stage, find where the build tool actually writes it: 1. Read the build tool's config for a configured output path — e.g. `build.outDir` in `vite.config.*`, `compilerOptions.outDir` in `tsconfig.json`, `outputPath` in `angular.json`, `distDir` in `next.config.*`, `output.path` in `webpack.config.*`, `buildDir` in `nuxt.config.*`. 2. If none is set, use that tool's documented default. 3. If still unsure, run the build in the build stage and `COPY` the directory it actually produced. `build/` is only Create React App's default. Vite, Vue CLI, Angular and most bundlers emit to `dist/`; Next.js to `.next/`. Hardcoding `COPY build/ ...` fails with `"/app/build": not found` on any of them. - **Install full dependencies in the build stage; prune only for runtime.** Compilers and bundlers (`tsc`, `vite`, `webpack`, `rollup`, `esbuild`) almost always live in `devDependencies`. In the build stage run a full install (`npm ci` / `npm install` with **no** `--omit=dev` / `--production`). Running `npm ci --omit=dev` before `npm run build` removes the compiler and fails with `tsc: not found` / exit 127. Only the **runtime** stage may drop dev deps — or, better, copy just the built artifact into a clean runtime image and install nothing there. These two rules hold for any compiled or bundled stack — present or future — so they replace per-framework "copy from X" recipes rather than adding to them. **Security baseline (mandatory)** - Final stage MUST end with a `USER` instruction set to a non-root user. - If the base image already provides one (e.g. `nonroot`, `appuser`), use it; otherwise create one with **two separate instructions** (`USER` is a Dockerfile instruction, not a shell command — it cannot be chained after `RUN ... &&`): - Alpine: ``` RUN adduser -D -u 10001 appuser USER appuser ``` - Debian / Azure Linux: ```
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기