Adapt local container workflows bidirectionally between Docker and Podman. Detect engine availability, preserve build context, and verify differences in BuildKit/Buildah features, caches, Compose providers, rootless permissions, networking, and API sockets. Optimize image size and build time using live official Docker AND Podman documentation via MCP/fetch. Project-agnostic: discover paths, images, registries, labels, and platforms from the repository. Include Azure ACR/azd remote builds and IaC quality/what-if checks only when relevant. USE WHEN: "podman", "docker", "local build", "compose", "rootless", "container volume/permission", "image too large", "build cache", "switch docker podman", "container perf", "container engine".
Preserve the intended behavior when switching Docker to Podman or Podman to Docker.
Use a shared command only where semantics match; otherwise provide explicit variants
and explain limitations. Do not promise universal parity or assume a Docker daemon.
Read repository instructions and discover paths, image names, labels, resource IDs,
platforms, and approved workflows. Never reuse another project's identifiers.
Scope (NON-negotiable)
Local dev/test → target dual-engine (Docker OR Podman). This is where we act.
Cloud/remote build: identify where the builder actually runs. ACR Tasks needs
no local engine; docker buildx --push alone does not select a remote builder.
Preserve an approved remote release path without adding a duplicate local build.
CI → hosted runners typically use Docker + docker/*-action@*. Do NOT rewrite the
CI, the remote build command, or the Dockerfiles to Podman unless explicitly asked.
Rule 0 - Detect the execution environment
For local work, check CLI presence (Get-Command in PowerShell or command -v in
POSIX shells), then the selected engine's version and info commands. An installed
CLI does not prove that its daemon, VM, or remote connection is reachable.
Honor the user's explicit preference. If both engines work and none is specified,
use the repository's convention; ask when switching would affect existing state.
Report connection failures rather than silently changing engines.
Record OS, client/server versions, rootless mode, target architecture, selected
Docker context/Buildx driver or Podman connection, and Compose provider as applicable.
On Windows/macOS, inspect the configured Podman machine and its state before proposing
startup; do not create a replacement machine or change resources without approval.
For shared syntax in PowerShell invoke the selected executable as & $engine ...;
in a POSIX shell use "$engine" .... Use argument arrays and check native exit codes.
An alias does not translate engine-specific options.
For Docker-API consumers such as Testcontainers, verify Podman's compatibility with
the particular client and use the platform's documented local socket or named pipe.
Discover the endpoint; a Unix socket inside a VM is not automatically accessible to
a Windows client. Set DOCKER_HOST only when needed, scoped to the process/session,
and restore it afterwards. Do not expose an unauthenticated TCP API or mount the
engine socket into arbitrary containers. Native Podman commands do not need this shim.
Equivalence table (dual-engine)
Intent
Docker
Podman
Portability note
Build
docker build / docker buildx build
podman build
Common flags overlap; BuildKit and Buildah are different builders
Run
docker run
podman run
Verify networking, mounts, user mapping, and health behavior
Compose
docker compose up
podman compose up
Podman delegates to an external Compose provider
Images/PS
docker images / ps
podman images / ps
same
Registry login
docker login
podman login
Verify registry auth; use secure input, not secrets in command arguments
Multi-arch build
docker buildx build --platform
podman build --platform --manifest
Check execution support and manifest publication separately
Cache mount
RUN --mount=type=cache
Supported by recent Buildah versions
Check exact mount options; caches are not shared across engines
Writing rule: when the syntax is identical, write the detected engine but note the
other "(or docker/podman)"; never hardcode a Docker socket path.
When switching an engine or rewriting a command, these are the parity traps that silently
break a build or change the context. Check each one before emitting.
Dockerfile / BuildKit features
Different implementations: Docker BuildKit can select a frontend with
# syntax=docker/dockerfile:1; without it, BuildKit uses its bundled frontend.
Podman uses Buildah, not that Docker frontend. Keeping the directive is useful
for Docker but does not enable features in Buildah. Verify each feature against
the installed versions, including remote-client restrictions.
RUN --mount=type=cache: supported on both, but the cache is engine-local and NOT
shared between Docker and Podman. Never assume a warm cache after switching engines.
Secrets and SSH: both support secret/SSH build mounts in supported versions;
verify source types and options. Never replace these with ARG/ENV or copy
credentials into the context, layers, logs, or cache.
Heredocs and COPY extensions: verify support for heredocs, COPY --link,
named contexts, and other extensions individually. If unsupported, retain the
approved builder or propose a tested equivalent; never silently remove semantics.
Build context & ignore files
Ignore file precedence: Podman uses .containerignore instead of .dockerignore
when both exist; they are not merged. Podman also has --ignorefile. Docker supports
.dockerignore and Dockerfile-specific ignore files, which take precedence over
the context-root file. Prefer one shared .dockerignore where possible; explicitly
reconcile exclusions if engine-specific files are needed. Do not rely on Git ignore
rules for a local container build.
Preserve the context explicitly: keep the working directory, Dockerfile path,
final context argument, named contexts, target, build arguments, and platform.
-f does not make Docker's context the Dockerfile directory; Podman can default to
that directory when the context is omitted. Always supply the intended context.
Verify included files: inspect packaging/build logs or a disposable context probe
for required files and excluded non-sensitive sentinels. Do not copy actual secrets
into a probe. Upload packers may use different rules from the builder; measure both
uploaded bytes and effective build context. Keep regenerated dependencies and
outputs out without excluding lockfiles or required source files.
Absolute vs relative COPY: COPY ./x /y is relative to the context root on both.
Do not translate to host-absolute paths.
Registry names & tags (a top breakage when switching)
Qualify external images with their registry and namespace to avoid Podman's
short-name resolution differences. Do not rewrite Dockerfile stage aliases as
registry references. Discover actual names; use placeholders in generic examples.
Pin reproducible inputs by digest where appropriate. Explicit version tags are
readable but still mutable; a tag is not an immutable pin. Preserve existing pins.
Cache export/import & multi-arch (buildx vs buildah differ)
Cache flags are not interchangeable: Buildx supports backends such as registry,
local, gha, and inline, subject to driver/version restrictions. Inline is an export
format; import it through the image registry. Podman/Buildah documents repository
arguments such as --layers --cache-to registry.example.com/team/build-cache --cache-from registry.example.com/team/build-cache, not Buildx's
type=registry,ref=... syntax. Do not assume cache-format interoperability or a
warm cache after migration. Explain any replacement of a gha/local/inline backend.
Local image availability: the default Buildx docker driver loads automatically.
Other drivers generally need --load for local testing unless configured otherwise;
--push publishes to a registry and does not imply local loading. Podman normally
stores build output in its selected engine's store, which may be in a VM or remote.
Preserve the requested output and confirm the image is available to the runtime.
Multi-arch: Buildx can build and push a multi-platform index. Podman supports
multiple --platform values with --manifest, followed by manifest publication
including all platform images (verify podman manifest push --all for the version).
Both need native builders, emulation, or cross-compilation for foreign-architecture
execution. Verify the published platform list; do not equate multi-arch with --load.
Runtime translation traps
Host networking: Podman's --network host uses the engine host's network
namespace, including in rootless operation. On a VM-backed engine that host is not
necessarily the desktop OS. Docker Desktop support also depends on configuration.
Prefer explicit port publication where suitable; test host access and DNS.
Bind mounts: resolve paths in the correct client/engine filesystem and check
UID/GID mapping. SELinux :Z/:z relabeling can apply to both engines; it changes
host labels and is not a harmless no-op. Use it only when required and approved.
GPU access: verify engine version, vendor runtime/CDI setup, host OS, and VM
passthrough. Podman supports CDI device names and some versions support --gpus;
do not assume a universal flag translation or add privileged mode as a shortcut.
Podman rootless pitfalls (the real friction)
SELinux: when enforced, distinguish private :Z from shared :z labels.
Never recursively relabel system directories or disable isolation just to pass a test.
UID/GID: default rootless mapping maps the caller to container root.
--userns=keep-id can help with bind mounts, but may change the process user and
conflict with the image's expectations. Test the actual runtime user and writes;
avoid recursive ownership changes to host data as a default fix.
Ports: low-port restrictions depend on the engine host's
net.ipv4.ip_unprivileged_port_start. Prefer a high host port instead of changing
host security settings. Bind local-only services to loopback where appropriate.
Compose: podman compose wraps an external provider such as docker-compose
or podman-compose; it is not a separate native Compose implementation. Discover
the selected provider and version; test dependencies, health conditions, volumes,
and build behavior. Protect resolved configuration because it may contain secrets.
Healthchecks: verify that the chosen image format preserves health metadata,
then inspect actual scheduling and health transitions. Podman supports automatic
intervals, subject to host/version support; podman auto-update is not the scheduler.
Ground on official docs LIVE via MCP (MANDATORY for perf)
Before recommending or applying a performance/build optimization, verify the official
Docker AND Podman docs live — never from memory (BuildKit flags,
--mount=type=cache, --cache-to/from, buildah/podman build evolve fast).
Fetch BOTH engines to stay dual-compatible, compare, then apply.
Tool order:
mcp_microsoft_lea_microsoft_docs_search / microsoft_docs_fetch → for any Azure/ACR
side (e.g. az acr build, ACR Tasks, ACR cache), when relevant.
vscode-websearchforcopilot_webSearchorfetch_webpage → for Docker and Podman
(docs outside Microsoft Learn). Always query the canonical URLs below.
Only conclude on a perf flag after reading the matching official page;
if Docker and Podman diverge, surface both and pick the portable one.
Canonical URLs to consult (fetch with a targeted query):
Docker — build best practices: https://docs.docker.com/build/building/best-practices/
Azure (when targeting Azure, via microsoft_docs_*): search "az acr build", "ACR Tasks cache",
"azd package", "azd provision preview", "az deployment group what-if", "bicep build lint".
Rule: cite consulted URLs and match the guidance to installed versions. Tool-generated
commands are suggestions, not evidence; check official references and CLI help.
If either engine's relevant documentation is unavailable, disclose that specific gap
and mark the affected recommendation [to verify]; do not claim dual-engine validation.
Image / container perf (engine-agnostic)
These rules apply to any local build AND to a remote/registry build. Do not change a
project's Dockerfiles without an explicit request. Confirm each flag via the live docs
above before applying it:
Layer order: stable deps BEFORE application code (COPY the dependency manifest/
lockfile then install, COPY the source afterward) to maximize the cache.
Build cache mount: RUN --mount=type=cache,target=<pkg-cache-dir> <install cmd>
only with verified builder/version support. This is independent of reproducibility:
keep lockfiles and hashes where supported whether or not caching is enabled.
Strict multi-stage: disposable builder stage; copy into the runtime only the
artifacts actually needed (built venv/binaries), never the toolchain.
Minimal supported base: select for runtime compatibility, not size alone; pin
by digest for immutability and keep a deliberate security-update policy.
Lean ignore file: exclude .venv, node_modules, build outputs, .git, temp dirs
in .dockerignore (and .containerignore if you target Podman only).
Reduce RUN layers: chain package-manager steps and clean caches in a single RUN
(e.g. apt-get update && … && rm -rf /var/lib/apt/lists/*).
Reproducibility: pinned versions, no unbounded upgrades.
Measure before claiming gains: compare context/upload bytes, cold and warm build
times, cache hits, final image size, and startup under the same platform/resources.
Tune stage concurrency and VM CPU/RAM only against measured bottlenecks. Avoid broad
cache pruning or deleting user images/volumes; clean only artifacts created for testing.
For a migration, run a focused build and runtime smoke test on each available target
engine, checking context inclusion, image metadata, startup, health, and relevant mounts
or ports. Record any engine unavailable locally and the remaining CI validation needed.
Azure remote build & IaC verification (ONLY when the project targets Azure)
Applies only when Azure is requested or confirmed by the project configuration;
Terraform alone does not imply Azure. Skip otherwise. Verify flags using live Microsoft
Learn docs and installed CLI help. Use available Azure best-practice/CLI tools, but
cross-check generated commands. Follow repository release gates and approved scripts.
Faster/cleaner remote image build
Server-side build (no local engine): az acr build runs on ACR Tasks. Prefer an
existing approved remote release workflow when available; do not replace CI implicitly.
Verify subscription, resource group, registry, RBAC, network access, and target platform
before submission. Builds/pushes incur cost and change registry state: require authorization.
Measure context upload: the ACR Tasks packer may include files a local
.dockerignore would drop. Verify which ignore rules the packer honors for your setup and
keep large regenerable folders out of the uploaded context (VCS-ignore them if needed).
Cache capabilities: do not pass Buildx --cache-from/--cache-to flags to
az acr build; the current quick-build CLI does not expose them. A BuildKit builder
using ACR as a registry cache is a separate workflow. Inspect the actual ACR task
definition/backend before recommending cache changes. Artifact pull-through cache
is not the same as build-layer cache.
azd path: inspect azure.yaml, hooks, host support, and the installed azd version.
A supported docker.remoteBuild: true configuration uses ACR; otherwise packaging
can require a local engine. Check fallback behavior in logs rather than assuming all
azd builds are remote. Separate package/build, provisioning, and deployment; review
hooks before even a preview. Do not add a second build or change these settings implicitly.
Verify the artifact: after an authorized build, check terminal task status, image
digest and architecture, vulnerability policy, and the intended destination. A queued
task is not a successful build; do not deploy as part of a documentation or build-only task.
Infra verification & code quality (run BEFORE apply)
Preview the delta — never blind-apply:
Bicep/ARM: use az deployment group what-if or the matching subscription/other
scope, with the actual template, parameters, subscription, and location as required.
azd: use azd provision --preview only when supported by the installed version and
IaC provider. Otherwise use that provider's native preview; never substitute apply.
Terraform: initialize using the project's provider lockfile, run terraform plan
with -out to a protected, ignored temporary path, and review with terraform show.
Treat plans/JSON as sensitive. Apply that saved plan only after separate authorization.
Static quality gates:
Bicep: compile and lint the actual template with the installed Bicep CLI and
bicepconfig.json; include parameter validation and the project's PSRule checks.
Terraform: terraform fmt -check, terraform validate, and tflint; optionally
checkov/tfsec for security posture.
Guardrails on the plan: reject a saved plan if it deletes or replaces resources you did
not intend to change; diff the what-if output and call out every destroy/replace explicitly
before proceeding. Do not run apply when the preview shows unexpected changes.
Review beyond syntax: check identity/RBAC, secret handling, public access, private
DNS/network paths, policy, capacity, and costs. Preview can contain unknown values and
does not prove runtime readiness. Report unavailable checks and verify deployed state
only after an authorized deployment.
Preserve CI, Dockerfiles, and the configured remote build path unless their change
was explicitly requested. A passing quality gate is not deployment authorization.
Exit checklist
Mark conditional items not applicable with a reason; do not invent tests or infrastructure.
Current project paths, image names, labels, IDs, and approved workflows were discovered.
For local work: engine reachability, preference, versions, OS, connection, and platform are known.
Shared commands preserve semantics; engine-specific variants and unsupported features are explicit.
If an API client is used: endpoint compatibility is checked, exposure is restricted, and overrides are scoped.
External images are qualified and pins preserved; stage aliases are unchanged.
BuildKit versus Buildah capabilities are verified; a Docker syntax directive is not treated as a Buildah upgrade.
Context, Dockerfile, target, arguments, platform, named contexts, and ignore precedence are preserved and checked.
If caching/multi-arch is used: backend syntax, output/loading, execution support, and published platforms are verified.
If runtime is affected: mounts, user mapping, SELinux, ports, host/VM networking, and health behavior are tested as relevant.
If Compose/GPU is used: provider or device/runtime support is verified for the selected versions.
Every performance recommendation is grounded in live official Docker AND Podman docs with cited URLs; unavailable evidence is marked [to verify].
Gains are measured, not assumed; focused build/smoke tests cover available target engines and remaining gaps are disclosed.
If Azure applies: actual builder/azd configuration, context upload, auth/network prerequisites, task outcome, and artifact are checked as relevant.
If Azure IaC changes: compile/lint/validate and supported what-if or saved-plan review pass; unexpected deletes/replacements block apply.
No unrequested Dockerfile/CI/remote-path changes, unauthorized build/push/deployment, leaked secrets, or broad cleanup; test artifacts are cleaned.
1---2name: container-engine-compat3description: Adapt local container workflows bidirectionally between Docker and Podman. Detect engine availability, preserve build context, and verify differences in BuildKit/Buildah features, caches, Compose providers, rootless permissions, networking, and API sockets. Optimize image size and build time using live official Docker AND Podman documentation via MCP/fetch. Project-agnostic: discover paths, images, registries, labels, and platforms from the repository. Include Azure ACR/azd remote builds and IaC quality/what-if checks only when relevant. USE WHEN: "podman", "docker", "local build", "compose", "rootless", "container volume/permission", "image too large", "build cache", "switch docker podman", "container perf", "container engine".4---56# Docker and Podman Compatibility and Performance78## Goal9Preserve the intended behavior when switching **Docker to Podman or Podman to Docker**.10Use a shared command only where semantics match; otherwise provide explicit variants11and explain limitations. Do not promise universal parity or assume a Docker daemon.12Read repository instructions and discover paths, image names, labels, resource IDs,13platforms, and approved workflows. Never reuse another project's identifiers.1415## Scope (NON-negotiable)16- **Local dev/test** → target dual-engine (Docker OR Podman). This is where we act.17- **Cloud/remote build**: identify where the builder actually runs. ACR Tasks needs18 no local engine; `docker buildx --push` alone does not select a remote builder.19 Preserve an approved remote release path without adding a duplicate local build.20- **CI** → hosted runners typically use Docker + `docker/*-action@*`. Do NOT rewrite the21 CI, the remote build command, or the Dockerfiles to Podman unless explicitly asked.2223## Rule 0 - Detect the execution environment24For local work, check CLI presence (`Get-Command` in PowerShell or `command -v` in25POSIX shells), then the selected engine's `version` and `info` commands. An installed26CLI does not prove that its daemon, VM, or remote connection is reachable.27Honor the user's explicit preference. If both engines work and none is specified,28use the repository's convention; ask when switching would affect existing state.29Report connection failures rather than silently changing engines.3031Record OS, client/server versions, rootless mode, target architecture, selected32Docker context/Buildx driver or Podman connection, and Compose provider as applicable.33On Windows/macOS, inspect the configured Podman machine and its state before proposing34startup; do not create a replacement machine or change resources without approval.3536For shared syntax in PowerShell invoke the selected executable as `& $engine ...`;37in a POSIX shell use `"$engine" ...`. Use argument arrays and check native exit codes.38An alias does not translate engine-specific options.3940For Docker-API consumers such as Testcontainers, verify Podman's compatibility with41the particular client and use the platform's documented local socket or named pipe.42Discover the endpoint; a Unix socket inside a VM is not automatically accessible to43a Windows client. Set `DOCKER_HOST` only when needed, scoped to the process/session,44and restore it afterwards. Do not expose an unauthenticated TCP API or mount the45engine socket into arbitrary containers. Native Podman commands do not need this shim.4647## Equivalence table (dual-engine)48| Intent | Docker | Podman | Portability note |49|---|---|---|---|50| Build | `docker build` / `docker buildx build` | `podman build` | Common flags overlap; BuildKit and Buildah are different builders |51| Run | `docker run` | `podman run` | Verify networking, mounts, user mapping, and health behavior |52| Compose | `docker compose up` | `podman compose up` | Podman delegates to an external Compose provider |53| Images/PS | `docker images` / `ps` | `podman images` / `ps` | same |54| Registry login | `docker login` | `podman login` | Verify registry auth; use secure input, not secrets in command arguments |55| Multi-arch build | `docker buildx build --platform` | `podman build --platform --manifest` | Check execution support and manifest publication separately |56| Cache mount | `RUN --mount=type=cache` | Supported by recent Buildah versions | Check exact mount options; caches are not shared across engines |5758Writing rule: when the syntax is identical, **write the detected engine** but note the59other "(or `docker`/`podman`)"; never hardcode a Docker socket path.6061## Translation correctness — build & context (avoid broken builds)62When switching an engine or rewriting a command, these are the parity traps that silently63break a build or change the context. Check each one before emitting.6465### Dockerfile / BuildKit features66- **Different implementations**: Docker BuildKit can select a frontend with67 `# syntax=docker/dockerfile:1`; without it, BuildKit uses its bundled frontend.68 Podman uses **Buildah**, not that Docker frontend. Keeping the directive is useful69 for Docker but does not enable features in Buildah. Verify each feature against70 the installed versions, including remote-client restrictions.71- **`RUN --mount=type=cache`**: supported on both, but the cache is engine-local and NOT72 shared between Docker and Podman. Never assume a warm cache after switching engines.73- **Secrets and SSH**: both support secret/SSH build mounts in supported versions;74 verify source types and options. Never replace these with `ARG`/`ENV` or copy75 credentials into the context, layers, logs, or cache.76- **Heredocs and COPY extensions**: verify support for heredocs, `COPY --link`,77 named contexts, and other extensions individually. If unsupported, retain the78 approved builder or propose a tested equivalent; never silently remove semantics.7980### Build context & ignore files81- **Ignore file precedence**: Podman uses `.containerignore` instead of `.dockerignore`82 when both exist; they are not merged. Podman also has `--ignorefile`. Docker supports83 `.dockerignore` and Dockerfile-specific ignore files, which take precedence over84 the context-root file. Prefer one shared `.dockerignore` where possible; explicitly85 reconcile exclusions if engine-specific files are needed. Do not rely on Git ignore86 rules for a local container build.87- **Preserve the context explicitly**: keep the working directory, Dockerfile path,88 final context argument, named contexts, target, build arguments, and platform.89 `-f` does not make Docker's context the Dockerfile directory; Podman can default to90 that directory when the context is omitted. Always supply the intended context.91- **Verify included files**: inspect packaging/build logs or a disposable context probe92 for required files and excluded non-sensitive sentinels. Do not copy actual secrets93 into a probe. Upload packers may use different rules from the builder; measure both94 uploaded bytes and effective build context. Keep regenerated dependencies and95 outputs out without excluding lockfiles or required source files.96- **Absolute vs relative COPY**: `COPY ./x /y` is relative to the context root on both.97 Do not translate to host-absolute paths.9899### Registry names & tags (a top breakage when switching)100- **Qualify external images** with their registry and namespace to avoid Podman's101 short-name resolution differences. Do not rewrite Dockerfile stage aliases as102 registry references. Discover actual names; use placeholders in generic examples.103- **Pin reproducible inputs** by digest where appropriate. Explicit version tags are104 readable but still mutable; a tag is not an immutable pin. Preserve existing pins.105106### Cache export/import & multi-arch (buildx vs buildah differ)107- **Cache flags are not interchangeable**: Buildx supports backends such as registry,108 local, gha, and inline, subject to driver/version restrictions. Inline is an export109 format; import it through the image registry. Podman/Buildah documents repository110 arguments such as `--layers --cache-to registry.example.com/team/build-cache111 --cache-from registry.example.com/team/build-cache`, not Buildx's112 `type=registry,ref=...` syntax. Do not assume cache-format interoperability or a113 warm cache after migration. Explain any replacement of a gha/local/inline backend.114- **Local image availability**: the default Buildx `docker` driver loads automatically.115 Other drivers generally need `--load` for local testing unless configured otherwise;116 `--push` publishes to a registry and does not imply local loading. Podman normally117 stores build output in its selected engine's store, which may be in a VM or remote.118 Preserve the requested output and confirm the image is available to the runtime.119- **Multi-arch**: Buildx can build and push a multi-platform index. Podman supports120 multiple `--platform` values with `--manifest`, followed by manifest publication121 including all platform images (verify `podman manifest push --all` for the version).122 Both need native builders, emulation, or cross-compilation for foreign-architecture123 execution. Verify the published platform list; do not equate multi-arch with `--load`.124125### Runtime translation traps126- **Host networking**: Podman's `--network host` uses the engine host's network127 namespace, including in rootless operation. On a VM-backed engine that host is not128 necessarily the desktop OS. Docker Desktop support also depends on configuration.129 Prefer explicit port publication where suitable; test host access and DNS.130- **Bind mounts**: resolve paths in the correct client/engine filesystem and check131 UID/GID mapping. SELinux `:Z`/`:z` relabeling can apply to both engines; it changes132 host labels and is not a harmless no-op. Use it only when required and approved.133- **GPU access**: verify engine version, vendor runtime/CDI setup, host OS, and VM134 passthrough. Podman supports CDI device names and some versions support `--gpus`;135 do not assume a universal flag translation or add privileged mode as a shortcut.136137## Podman rootless pitfalls (the real friction)1381. **SELinux**: when enforced, distinguish private `:Z` from shared `:z` labels.139 Never recursively relabel system directories or disable isolation just to pass a test.1402. **UID/GID**: default rootless mapping maps the caller to container root.141 `--userns=keep-id` can help with bind mounts, but may change the process user and142 conflict with the image's expectations. Test the actual runtime user and writes;143 avoid recursive ownership changes to host data as a default fix.1443. **Ports**: low-port restrictions depend on the engine host's145 `net.ipv4.ip_unprivileged_port_start`. Prefer a high host port instead of changing146 host security settings. Bind local-only services to loopback where appropriate.1474. **Compose**: `podman compose` wraps an external provider such as `docker-compose`148 or `podman-compose`; it is not a separate native Compose implementation. Discover149 the selected provider and version; test dependencies, health conditions, volumes,150 and build behavior. Protect resolved configuration because it may contain secrets.1515. **Healthchecks**: verify that the chosen image format preserves health metadata,152 then inspect actual scheduling and health transitions. Podman supports automatic153 intervals, subject to host/version support; `podman auto-update` is not the scheduler.154155## Ground on official docs LIVE via MCP (MANDATORY for perf)156Before recommending or applying a performance/build optimization, **verify the official157Docker AND Podman docs live** — never from memory (BuildKit flags,158`--mount=type=cache`, `--cache-to/from`, buildah/`podman build` evolve fast).159Fetch BOTH engines to stay dual-compatible, compare, then apply.160161Tool order:1621. `mcp_microsoft_lea_microsoft_docs_search` / `microsoft_docs_fetch` → for any Azure/ACR163 side (e.g. `az acr build`, ACR Tasks, ACR cache), when relevant.1642. `vscode-websearchforcopilot_webSearch` **or** `fetch_webpage` → for Docker and Podman165 (docs outside Microsoft Learn). Always query the canonical URLs below.1663. Only conclude on a perf flag after reading the matching official page;167 if Docker and Podman diverge, surface both and pick the portable one.168169Canonical URLs to consult (fetch with a targeted `query`):170- Docker — build best practices: `https://docs.docker.com/build/building/best-practices/`171- Docker — BuildKit cache mounts: `https://docs.docker.com/build/cache/optimize/`172- Docker — cache backends (`--cache-to/from`): `https://docs.docker.com/build/cache/backends/`173- Docker — multi-stage: `https://docs.docker.com/build/building/multi-stage/`174- Docker — `.dockerignore`: `https://docs.docker.com/build/concepts/context/#dockerignore-files`175- Podman — `podman build`: `https://docs.podman.io/en/latest/markdown/podman-build.1.html`176- Podman — rootless: `https://docs.podman.io/en/latest/markdown/podman.1.html` + `https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md`177- Podman runtime: `https://docs.podman.io/en/latest/markdown/podman-run.1.html`178- Podman Compose: `https://docs.podman.io/en/latest/markdown/podman-compose.1.html`179- Docker frontend: `https://docs.docker.com/reference/dockerfile/`180- Docker drivers: `https://docs.docker.com/build/builders/drivers/`181- Azure remote builds: `https://learn.microsoft.com/azure/developer/azure-developer-cli/remote-builds`182- ACR CLI: `https://learn.microsoft.com/cli/azure/acr#az-acr-build`183- Azure (when targeting Azure, via `microsoft_docs_*`): search "az acr build", "ACR Tasks cache",184 "azd package", "azd provision preview", "az deployment group what-if", "bicep build lint".185186Rule: cite consulted URLs and match the guidance to installed versions. Tool-generated187commands are suggestions, not evidence; check official references and CLI help.188If either engine's relevant documentation is unavailable, disclose that specific gap189and mark the affected recommendation `[to verify]`; do not claim dual-engine validation.190191## Image / container perf (engine-agnostic)192These rules apply to any local build AND to a remote/registry build. Do not change a193project's Dockerfiles without an explicit request. **Confirm each flag via the live docs194above before applying it**:195- **Layer order**: stable deps BEFORE application code (COPY the dependency manifest/196 lockfile then install, COPY the source afterward) to maximize the cache.197- **Build cache mount**: `RUN --mount=type=cache,target=<pkg-cache-dir> <install cmd>`198 only with verified builder/version support. This is independent of reproducibility:199 keep lockfiles and hashes where supported whether or not caching is enabled.200- **Strict multi-stage**: disposable builder stage; copy into the runtime only the201 artifacts actually needed (built venv/binaries), never the toolchain.202- **Minimal supported base**: select for runtime compatibility, not size alone; pin203 by digest for immutability and keep a deliberate security-update policy.204- **Lean ignore file**: exclude `.venv`, `node_modules`, build outputs, `.git`, temp dirs205 in `.dockerignore` (and `.containerignore` if you target Podman only).206- **Reduce RUN layers**: chain package-manager steps and clean caches in a single RUN207 (e.g. `apt-get update && … && rm -rf /var/lib/apt/lists/*`).208- **Reproducibility**: pinned versions, no unbounded upgrades.209- **Measure before claiming gains**: compare context/upload bytes, cold and warm build210 times, cache hits, final image size, and startup under the same platform/resources.211 Tune stage concurrency and VM CPU/RAM only against measured bottlenecks. Avoid broad212 cache pruning or deleting user images/volumes; clean only artifacts created for testing.213214For a migration, run a focused build and runtime smoke test on each available target215engine, checking context inclusion, image metadata, startup, health, and relevant mounts216or ports. Record any engine unavailable locally and the remaining CI validation needed.217218## Azure remote build & IaC verification (ONLY when the project targets Azure)219Applies only when Azure is requested or confirmed by the project configuration;220Terraform alone does not imply Azure. Skip otherwise. Verify flags using live Microsoft221Learn docs and installed CLI help. Use available Azure best-practice/CLI tools, but222cross-check generated commands. Follow repository release gates and approved scripts.223224### Faster/cleaner remote image build225- **Server-side build (no local engine)**: `az acr build` runs on ACR Tasks. Prefer an226 existing approved remote release workflow when available; do not replace CI implicitly.227 Verify subscription, resource group, registry, RBAC, network access, and target platform228 before submission. Builds/pushes incur cost and change registry state: require authorization.229- **Measure context upload**: the ACR Tasks packer may include files a local230 `.dockerignore` would drop. Verify which ignore rules the packer honors for your setup and231 keep large regenerable folders out of the uploaded context (VCS-ignore them if needed).232- **Cache capabilities**: do not pass Buildx `--cache-from/--cache-to` flags to233 `az acr build`; the current quick-build CLI does not expose them. A BuildKit builder234 using ACR as a registry cache is a separate workflow. Inspect the actual ACR task235 definition/backend before recommending cache changes. Artifact pull-through cache236 is not the same as build-layer cache.237- **azd path**: inspect `azure.yaml`, hooks, host support, and the installed azd version.238 A supported `docker.remoteBuild: true` configuration uses ACR; otherwise packaging239 can require a local engine. Check fallback behavior in logs rather than assuming all240 azd builds are remote. Separate package/build, provisioning, and deployment; review241 hooks before even a preview. Do not add a second build or change these settings implicitly.242- **Verify the artifact**: after an authorized build, check terminal task status, image243 digest and architecture, vulnerability policy, and the intended destination. A queued244 task is not a successful build; do not deploy as part of a documentation or build-only task.245246### Infra verification & code quality (run BEFORE apply)247- **Preview the delta — never blind-apply**:248 - Bicep/ARM: use `az deployment group what-if` or the matching subscription/other249 scope, with the actual template, parameters, subscription, and location as required.250 - azd: use `azd provision --preview` only when supported by the installed version and251 IaC provider. Otherwise use that provider's native preview; never substitute apply.252 - Terraform: initialize using the project's provider lockfile, run `terraform plan`253 with `-out` to a protected, ignored temporary path, and review with `terraform show`.254 Treat plans/JSON as sensitive. Apply that saved plan only after separate authorization.255- **Static quality gates**:256 - Bicep: compile and lint the actual template with the installed Bicep CLI and257 `bicepconfig.json`; include parameter validation and the project's PSRule checks.258 - Terraform: `terraform fmt -check`, `terraform validate`, and `tflint`; optionally259 `checkov`/`tfsec` for security posture.260- **Guardrails on the plan**: reject a saved plan if it deletes or replaces resources you did261 not intend to change; diff the what-if output and call out every destroy/replace explicitly262 before proceeding. Do not run `apply` when the preview shows unexpected changes.263- **Review beyond syntax**: check identity/RBAC, secret handling, public access, private264 DNS/network paths, policy, capacity, and costs. Preview can contain unknown values and265 does not prove runtime readiness. Report unavailable checks and verify deployed state266 only after an authorized deployment.267- Preserve CI, Dockerfiles, and the configured remote build path unless their change268 was explicitly requested. A passing quality gate is not deployment authorization.269270## Exit checklist271Mark conditional items not applicable with a reason; do not invent tests or infrastructure.272273- [ ] Current project paths, image names, labels, IDs, and approved workflows were discovered.274- [ ] For local work: engine reachability, preference, versions, OS, connection, and platform are known.275- [ ] Shared commands preserve semantics; engine-specific variants and unsupported features are explicit.276- [ ] If an API client is used: endpoint compatibility is checked, exposure is restricted, and overrides are scoped.277- [ ] External images are qualified and pins preserved; stage aliases are unchanged.278- [ ] BuildKit versus Buildah capabilities are verified; a Docker syntax directive is not treated as a Buildah upgrade.279- [ ] Context, Dockerfile, target, arguments, platform, named contexts, and ignore precedence are preserved and checked.280- [ ] If caching/multi-arch is used: backend syntax, output/loading, execution support, and published platforms are verified.281- [ ] If runtime is affected: mounts, user mapping, SELinux, ports, host/VM networking, and health behavior are tested as relevant.282- [ ] If Compose/GPU is used: provider or device/runtime support is verified for the selected versions.283- [ ] Every performance recommendation is grounded in live official Docker AND Podman docs with cited URLs; unavailable evidence is marked `[to verify]`.284- [ ] Gains are measured, not assumed; focused build/smoke tests cover available target engines and remaining gaps are disclosed.285- [ ] If Azure applies: actual builder/azd configuration, context upload, auth/network prerequisites, task outcome, and artifact are checked as relevant.286- [ ] If Azure IaC changes: compile/lint/validate and supported what-if or saved-plan review pass; unexpected deletes/replacements block apply.287- [ ] No unrequested Dockerfile/CI/remote-path changes, unauthorized build/push/deployment, leaked secrets, or broad cleanup; test artifacts are cleaned.
Run npx skillmds@latest add olivmertens/container-engine-compat in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Adapt local container workflows bidirectionally between Docker and Podman. Detect engine availability, preserve build context, and verify differences in BuildKit/Buildah features, caches, Compose providers, rootless permissions, networking, and API sockets. Optimize image size and build time using live official Docker AND Podman documentation via MCP/fetch. Project-agnostic: discover paths, images, registries, labels, and platforms from the repository. Include Azure ACR/azd remote builds and IaC quality/what-if checks only when relevant. USE WHEN: "podman", "docker", "local build", "compose", "rootless", "container volume/permission", "image too large", "build cache", "switch docker podman", "container perf", "container engine". It is listed under DevOps & Infra on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
olivMertens (@olivmertens) published this skill. Their other Agent Skills are listed on their SkillMD profile.