Docker/Podman Composer — Manual

Vollständige Funktionsbeschreibung: beide Richtungen, alle run-Flags und Compose-Keys, Netze, Volumes, $-Quoting, Startskript und podman-Besonderheiten.

Zurück zur Übersicht: Docker/Podman Composer · Tool live öffnen: www.jpkc.com/tools/docker/

Dieses Manual beschreibt den Docker/Podman Composer vollständig: was in jeder der beiden Konvertierungsrichtungen passiert, welche run-Flags und Compose-Keys unterstützt werden, wie Netze, Volumes und Dollarzeichen behandelt werden, wie das erzeugte Startskript aufgebaut ist und wo die Grenzen liegen. Die Oberfläche des Tools ist auf Englisch — die Tab-, Feld- und Button-Namen werden hier deshalb in ihrer englischen Original-Schreibweise genannt (mit deutscher Erläuterung), damit du dich im echten Interface zurechtfindest.

Aufbau: drei Tabs, eine clientseitige Engine

Das Tool hat drei Reiter: Run → Compose, Compose → Run und Reference (Referenz). Die ersten beiden sind die Konverter, der dritte ist ein eingebautes Nachschlagewerk. Beide Konverter laufen vollständig im Browser — Shell-Tokenizer, Flag-Parser, YAML-Emitter und der js-yaml-Parser sind JavaScript. Es gibt keinen Server-Abruf und keine API; deine Eingaben verlassen den Browser nicht. Alle vier Editorfelder basieren auf dem ACE-Editor mit Syntax-Hervorhebung für Shell (sh) bzw. YAML.

Die Umwandlung läuft live: Sobald du tippst oder etwas einfügst, rechnet das Tool nach einer kurzen Pause (300 ms) neu. Einen Konvertieren-Knopf gibt es nicht. Zu jedem Eingabefeld gehören ein Example-Knopf, der ein fertiges Beispiel lädt, und ein Clear-Knopf, der das Feld leert.

Compose project name

Über den Tabs liegt das optionale Feld Compose project name (Compose-Projektname, Platzhalter myapp). Es gilt für beide Richtungen, denn Compose benennt Netze, Volumes und Container nach dem Projekt — ohne Angabe nach dem Ordnernamen:

  • Run → Compose: Der Name landet als name: ganz oben in der Datei (kleingeschrieben, ungültige Zeichen werden zu _).
  • Compose → Run: Das Tool braucht den Namen, um die Bezeichner nachzubilden, die Compose selbst vergeben würde — myapp_default für das Standardnetz, myapp_daten für ein Volume daten, myapp-web-1 für den Container des Services web. Reihenfolge: Feld vor name: in der Datei; fehlt beides, nimmt das Tool myapp und weist darauf hin.

Projektname und die gewählte Runtime (docker/podman) speichert das Tool im localStorage deines Browsers, damit sie beim nächsten Besuch wieder eingestellt sind. Deine Befehle und Compose-Dateien werden nicht gespeichert.

Hinweise unter der Ausgabe

Unter beiden Ausgabefeldern erscheint bei Bedarf eine Liste: rot für Fehler (etwa „No image found in: …“ oder ein YAML-Syntaxfehler mit Zeile und Spalte), gelb für Warnungen — fast alles, was das Tool nicht oder nur mit Einschränkung übersetzen konnte. Die Liste wird Screenreadern angesagt. Lies sie nach jeder Umwandlung: Sie sagt dir, was im Ergebnis fehlt und warum. Ein paar Angaben fallen allerdings ohne Hinweis weg; welche das sind, steht in den Abschnitten zu beiden Richtungen weiter unten.

Richtung 1: Run → Compose

Im Tab Run → Compose fügst du oben einen oder mehrere Befehle in das Feld Docker / Podman Run Command ein. Darunter erscheint im Feld Docker Compose YAML sofort das Ergebnis.

Wie der Befehl gelesen wird

Bevor die Flags ausgewertet werden, zerlegt ein Tokenizer den Text nach den Regeln der POSIX-Shell. Er beherrscht:

  • Zeilenfortsetzungen mit Backslash (\ am Zeilenende, auch mit Windows-Zeilenenden) — lange, mehrzeilige Befehle werden zu einem Befehl zusammengezogen.
  • Einfache Anführungszeichen ('…') als literalen Text, doppelte Anführungszeichen ("…"), in denen nur \$, \`, \", \\ und der Zeilenumbruch maskiert werden, sowie ANSI-C-Quoting $'…' mit \n, \t, \r und Co.
  • Quotes mitten im Wort: -e MSG="a b" ergibt das eine Argument MSG=a b.
  • Kommentare (# am Wortanfang bis Zeilenende) und Befehlstrenner: Zeilenumbruch, ;, && und || beenden einen Befehl.
  • Pipes und Umleitungen (|, &, <, >): Der Rest der Zeile wird ignoriert, mit Hinweis.
  • Kommandosubstitution ($(…), Backticks) bleibt als Text stehen, mit Hinweis — sie läuft nur in einer echten Shell.

Unterstützt werden beide Schreibweisen --flag value und --flag=value. Kombinierte Kurz-Flags werden zerlegt, auch wenn das letzte einen Wert erwartet: -it, -dp 80:80 oder -p8080:80 funktionieren. -- beendet die Flags; das nächste Wort ist das Image. Boolesche Flags mit =false (etwa --init=false) werden nicht gesetzt. Das erste Argument, das kein Flag ist, gilt als Image; alles danach wird zum command.

Unbekannte Flags fallen weg, aber nicht stillschweigend: Das Tool meldet „Unknown flag … — dropped“ und warnt, falls das folgende Wort dadurch womöglich als Image gelesen wurde.

Welche Befehle erkannt werden

Das Eingabefeld darf mehrere Befehle enthalten — jeder run wird zu einem eigenen Service in einer Compose-Datei. Erkannt werden:

  • Programme docker, podman und nerdctl (auch mit Pfad); ein vorangestelltes sudo und Variablenzuweisungen wie FOO=1 docker run … werden übersprungen. Globale Optionen vor dem Unterkommando (--context, -H …) ignoriert das Tool mit Hinweis.
  • run, create sowie container run und container create — je ein Service.
  • network create und volume create — sie werden zu Top-Level-Definitionen (siehe Netzwerke und Volumes).
  • Alle anderen Unterkommandos (docker ps, docker compose …) und Nicht-Docker-Befehle werden mit Hinweis übergangen.

Der Service-Name entsteht aus --name, falls gesetzt (kleingeschrieben, ungültige Zeichen werden zu _); ohne --name wird er aus dem Image abgeleitet (letztes Pfadsegment ohne Tag und Digest, z. B. nginx:1.27-alpine → nginx). Kommt ein Name doppelt vor, hängt das Tool _2, _3 … an.

Unterstützte Wert-Flags (Flag → Compose-Key)

Diese Flags erwarten einen Wert und werden auf einen Compose-Key abgebildet. Mehrfach angegebene Flags (Ports, Volumes, Env …) landen als YAML-Liste bzw. Map.

  • Identität: --name → container_name; --hostname/-h → hostname; --domainname → domainname; --platform → platform; --mac-address → mac_address
  • Image & Pull: --pull → pull_policy; --entrypoint → entrypoint (als einelementige Liste); --runtime → runtime; --isolation → isolation
  • Ports & Expose: -p/--publish → ports; --expose → expose
  • Volumes: -v/--volume → volumes (kurze Syntax); --mount → volumes in der langen Syntax (type, source, target, read_only, bind.propagation, volume.nocopy, volume.subpath, tmpfs.size/mode …; bei type=bind zusätzlich bind.create_host_path: false, weil --mount fehlende Host-Ordner nicht anlegt); --tmpfs → tmpfs; --volumes-from → volumes_from
  • Umgebung: -e/--env → environment; --env-file → env_file
  • Netzwerk: --network/--net → networks bzw. network_mode; --network-alias/--net-alias → aliases; --ip/--ip6 → ipv4_address/ipv6_address; --link-local-ip → link_local_ips; --dns → dns; --dns-search → dns_search; --dns-opt/--dns-option → dns_opt; --add-host → extra_hosts; --link → links
  • Lebenszyklus & Signale: --restart → restart; --stop-signal → stop_signal; --stop-timeout → stop_grace_period (30 wird zu 30s)
  • Laufzeit: -u/--user → user; -w/--workdir → working_dir; --ipc → ipc; --pid → pid; --uts → uts; --userns → userns_mode; --cgroupns → cgroup; --cgroup-parent → cgroup_parent
  • Labels & Annotationen: -l/--label → labels; --label-file → label_file; --annotation → annotations
  • Arbeitsspeicher: -m/--memory → mem_limit; --memory-swap → memswap_limit; --memory-reservation → mem_reservation; --memory-swappiness → mem_swappiness; --shm-size → shm_size
  • CPU: --cpus → cpus; -c/--cpu-shares → cpu_shares; --cpuset-cpus → cpuset; --cpu-period, --cpu-quota, --cpu-rt-period, --cpu-rt-runtime, --cpu-count, --cpu-percent → gleichnamige Keys mit Unterstrich
  • Weitere Limits: --pids-limit → pids_limit; --oom-score-adj → oom_score_adj; --ulimit → ulimits (nofile=1024:2048 wird zu soft/hard); --sysctl → sysctls; --storage-opt → storage_opt
  • Block-I/O: --blkio-weight, --blkio-weight-device, --device-read-bps, --device-read-iops, --device-write-bps, --device-write-iops → blkio_config
  • Geräte & Sicherheit: --device → devices; --device-cgroup-rule → device_cgroup_rules; --gpus → deploy.resources.reservations.devices (Treiber nvidia, Capability gpu, count bzw. device_ids; in der Form --gpus "device=…,capabilities=…" liest das Tool nur device, count, capabilities und driver, andere Schlüssel fallen ohne Hinweis weg); --cap-add → cap_add; --cap-drop → cap_drop; --security-opt → security_opt; --group-add → group_add
  • Logging: --log-driver → logging.driver; --log-opt → logging.options (als key: value)
  • Healthcheck: --health-cmd → healthcheck.test (als [CMD-SHELL, …]); --health-interval, --health-timeout, --health-retries, --health-start-period, --health-start-interval → die entsprechenden healthcheck.*-Felder

Unterstützte Boolean-Flags (ohne Wert)

  • -t/--tty → tty: true
  • -i/--interactive → stdin_open: true
  • --privileged → privileged: true
  • --read-only → read_only: true
  • --init → init: true
  • --oom-kill-disable → oom_kill_disable: true
  • --no-healthcheck → healthcheck.disable: true
  • -d/--detach → entfällt (in Compose implizit)

Flags ohne Compose-Entsprechung

Manche run-Optionen haben in Compose keinen Platz. Das Tool verwirft sie und sagt dir in der Hinweisliste, welche es waren:

  • --rm — Compose behält gestoppte Container; für Einmal-Läufe verweist der Hinweis auf docker compose run --rm.
  • -P/--publish-all — Compose kennt das nicht; trag die Ports unter ports ein.
  • Ohne Compose-Key („has no Compose equivalent — dropped“): --cidfile, --cpuset-mems, --io-maxbandwidth, --io-maxiops, --kernel-memory, --use-api-socket, --volume-driver sowie die Podman-Optionen --pod, --systemd, --secret und --tz.
  • Still übergangen, weil sie nur das Starten im Terminal betreffen: -d, -a/--attach, --detach-keys, --sig-proxy, -q/--quiet, --disable-content-trust, --help und die Podman-Optionen --replace und --http-proxy.

Netzwerke und Volumes

Ein docker run greift auf Netze und benannte Volumes zu, die außerhalb von Compose existieren. Damit die erzeugte Datei gültig ist und Compose nicht stattdessen neue Objekte mit Projektpräfix anlegt, deklariert das Tool sie auf oberster Ebene:

  • --network NAME → networks: [NAME] am Service und NAME: {external: true} unter networks: ganz oben.
  • -v NAME:/pfad und --mount type=volume,src=NAME,… → NAME: {external: true} unter volumes: ganz oben. Bind-Mounts (Pfade mit /, ./, ~, $ oder Windows-Laufwerk) bleiben unberührt.
  • Steht im Eingabefeld zusätzlich docker network create NAME bzw. docker volume create NAME, wird statt external: true eine echte Definition mit name: NAME (exakter Name, wie Docker ihn angelegt hat) erzeugt. Übernommen werden bei Netzen --driver, --opt, --label, --subnet, --gateway, --ip-range, --ipam-driver, --internal, --attachable und --ipv6, bei Volumes --driver, --opt, --label und --name. --scope, --aux-address und --ipv4 liest das Tool samt Wert ein, übernimmt sie aber nicht und meldet das auch nicht; andere unbekannte Optionen quittiert es mit „network create: … is not mapped.“ Ein angelegtes Netz oder Volume, das kein run benutzt, landet ebenfalls als Definition in der Datei.
  • --network host, none, bridge, default und container:NAME werden zu network_mode.
  • Netzoptionen (--network-alias, --ip, --ip6, --link-local-ip) gehören zum ersten benannten Netz; dann schreibt das Tool networks: in der Map-Form mit aliases, ipv4_address usw. Die ausführliche Form --network name=backend,alias=jobs,ip=… wird ebenfalls gelesen; unbekannte Schlüssel darin übergeht das Tool ohne Hinweis. Ohne benanntes Netz verwirft das Tool solche Optionen mit Hinweis.

Ein Unterschied bleibt bewusst bestehen: docker run ohne --network landet im Default-Bridge-Netz, Compose legt dagegen ein eigenes Netz <projekt>_default an.

Das YAML-Ausgabeformat

Die Ausgabe beginnt — falls ein Projektname gesetzt ist — mit name:, dann folgt der services:-Block, danach die Top-Level-Blöcke networks: und volumes:. Innerhalb eines Services gilt eine feste Reihenfolge der häufigen Keys: image, container_name, restart, entrypoint, command, ports, expose, volumes, tmpfs, environment, env_file, networks, network_mode, hostname, user, working_dir, healthcheck, logging; alle übrigen Keys folgen in der Reihenfolge der Flags. command steht als Liste da, ein Wort pro Eintrag. Eine version:-Zeile wird nicht erzeugt (moderne Compose-Spezifikation, das Feld gilt als veraltet).

Werte setzt das Tool nur dann in doppelte Anführungszeichen, wenn ein YAML-Leser sie sonst anders verstehen würde. Geprüft wird per Round-Trip durch js-yaml, zusätzlich gegen die Fallen von YAML 1.1: Port-Angaben wie "8080:80" (ältere Leser lesen 22:22 als Zahl zur Basis 60), reine Zahlen als String wie "3600" und die alten Booleans yes, no, on, off, y, n.

Das Ergebnisfeld trägt das Badge „editable" und ist tatsächlich editierbar: Du kannst direkt im Tool ergänzen, was sich aus einem Run-Befehl nicht ableiten lässt — etwa depends_on oder einen build:-Block. Mit Copy kopierst du die YAML, mit compose.yaml lädst du sie als Datei compose.yaml herunter (lokal erzeugter Blob). Bearbeitest du danach die Eingabe, überschreibt die Live-Umwandlung deine Änderungen im Ausgabefeld.

Richtung 2: Compose → Run

Im Tab Compose → Run fügst du eine Compose-Datei in das Feld Docker Compose YAML ein. Darunter erscheint im Feld Generated Run Commands ein fertiges Shell-Skript. Dieses Ausgabefeld ist schreibgeschützt; über Copy kopierst du den Inhalt, über run.sh lädst du ihn als Datei run.sh herunter — mit vorangestelltem #!/bin/sh und set -e, damit das Skript beim ersten Fehler abbricht.

docker oder podman wählen

Im Fuß des Eingabefelds gibt es einen Radio-Schalter Runtime mit den Optionen docker (Standard) und podman. Er bestimmt das Befehlswort aller erzeugten Zeilen — run, build, network create, network connect und volume create. Die Flags selbst sind identisch, weil Podman die docker run-Optionen weitgehend kompatibel nachbildet. Eine Ausnahme sind GPUs: Für Docker entsteht --gpus all bzw. --gpus '"device=0,1"', für Podman --device nvidia.com/gpu=all (CDI-Schreibweise).

Aufbau des erzeugten Skripts

Das Skript ist so geordnet, dass es von oben nach unten lauffähig ist:

  1. # Networks and volumes — zuerst die Netze, denn docker run legt keine an. Jede Zeile ist idempotent: docker network inspect NAME >/dev/null 2>&1 || docker network create … NAME. Übernommen werden driver, driver_opts, internal, attachable, enable_ipv6, ipam (driver, subnet, gateway, ip_range) und labels. Externe Netze erscheinen nur als Kommentar („must already exist“). Volumes mit driver, driver_opts oder labels werden per docker volume create angelegt; einfache Volumes legt docker run selbst an.
  2. Je Service ein Block mit der Kommentarzeile # <service>, bei build: davor ein docker build, dann docker run -d mit einem Flag pro Zeile (Backslash-Fortsetzung) und in der letzten Zeile Image plus Command.
  3. docker network connect für jedes weitere Netz eines Services, direkt nach seinem run.

Die Services stehen in depends_on-Reihenfolge: Abhängigkeiten zuerst. Bei einem Zyklus warnt das Tool.

Was eingelesen und erzeugt wird

Der YAML-Parser (js-yaml) akzeptiert eine vollständige Compose-Datei mit services: und auch eine blanke Services-Map, sofern jeder Eintrag image oder build hat. Service-, Netz- und Volume-Namen müssen den Compose-Regeln folgen (Buchstaben, Ziffern, _, ., -, beginnend mit Buchstabe oder Ziffer) — sonst meldet das Tool einen Fehler; einen Service mit ungültigem Namen lässt es aus.

Jeder Befehl beginnt mit <runtime> run -d und --name: aus container_name, sonst wie bei Compose <projekt>-<service>-1. Danach werden die Compose-Keys in run-Flags zurückübersetzt:

  • Image & Build: image; build (String oder Objekt) → docker build -t <image> [-f dockerfile] [--target …] [--build-arg …] <context> vor dem run — ohne image heißt das Image <projekt>-<service>. Fehlen image und build, meldet das Tool einen Fehler.
  • Neustart: restart, ersatzweise deploy.restart_policy (none → no, on-failure mit max_attempts → on-failure:N, sonst always).
  • Einfache Werte: hostname, domainname, platform, user (→ --user), working_dir (→ --workdir), mac_address, ipc, pid, uts, userns_mode (→ --userns), cgroup (→ --cgroupns), cgroup_parent, isolation, runtime, shm_size, stop_signal, pull_policy (→ --pull, if_not_present → missing, build entfällt)
  • Ressourcen: mem_limit (→ --memory), mem_reservation, memswap_limit (→ --memory-swap), mem_swappiness, cpus, cpu_shares, cpu_period, cpu_quota, cpu_rt_period, cpu_rt_runtime, cpuset (→ --cpuset-cpus), cpu_count, cpu_percent, oom_score_adj, pids_limit, oom_kill_disable, blkio_config, sysctls, storage_opt, ulimits; außerdem deploy.resources.limits (memory, cpus, pids) und deploy.resources.reservations.memory, falls die Service-Keys fehlen; GPU-Reservierungen und gpus → --gpus bzw. Podman-CDI
  • Netzwerk: network_mode (service:NAME → container:<containername>); sonst networks (Liste oder Map) — das erste Netz per --network mit --network-alias <service> plus eigenen aliases, --ip, --ip6, --link-local-ip, jedes weitere per network connect --alias …. Ohne networks kommt der Container wie bei Compose ins Netz <projekt>_default. Dazu links/external_links (→ --link mit Containernamen), extra_hosts (Liste, auch host=ip, oder Map → --add-host), dns, dns_search, dns_opt (→ --dns-option)
  • Ports: ports als Kurz-String oder Lang-Objekt mit host_ip (IPv6 in eckigen Klammern), published, target, protocol; expose
  • Volumes: kurze Syntax (benannte Volumes bekommen den Projektpräfix, <projekt>_<name>); lange Syntax → --mount type=…,source=…,target=… mit readonly, bind-propagation, volume-nocopy, volume-subpath, consistency — ein Bind-Mount mit absolutem oder relativem Pfad, den Compose anlegen dürfte, wird zu -v, weil nur -v fehlende Host-Ordner anlegt (mit gesetztem bind.propagation bleibt er --mount); type: tmpfs → --tmpfs ziel:size=…,mode=…; tmpfs; volumes_from (Service → Containername). Host-Pfade mit ~/ schreibt das Tool als "$HOME"/…, weil die Shell ~ nur ungequotet am Wortanfang auflöst. Bei Secrets/Configs klappt das, in der langen Syntax nur, wenn daraus -v wird: Bleibt ein Bind-Mount bei --mount (mit bind.create_host_path: false oder bind.propagation), steht ~ unaufgelöst im Skript. In der kurzen Syntax setzt das Tool den Pfad derzeit doppelt zusammen (~/data:/data → -v "$HOME"/data/data:/data). Schreib in beiden Fällen $HOME/… oder einen absoluten Pfad.
  • Secrets & Configs: mit file: → schreibgeschützter Bind-Mount (-v datei:ziel:ro), Secrets nach /run/secrets/<ziel>, Configs nach /<ziel> (ein absolutes target gilt unverändert); ohne target ist das Ziel der Name des Secrets bzw. Configs
  • Umgebung: env_file (String, Liste oder Objekt mit path/required), environment (Liste oder Map → -e KEY=VALUE)
  • Labels & Sicherheit: labels, label_file, annotations, cap_add, cap_drop, security_opt, group_add, device_cgroup_rules, devices (String oder Objekt), privileged, read_only, init, stdin_open (→ -i), tty (→ -t)
  • Logging: logging.driver → --log-driver, logging.options → je ein --log-opt key=value
  • Healthcheck: test als [CMD-SHELL, …] oder String → --health-cmd; [CMD, …] → die Wörter einzeln shell-gequotet, mit Hinweis, dass docker run nur die Shell-Form kennt und das Image /bin/sh braucht; disable: true oder NONE → --no-healthcheck; dazu interval, timeout, start_period, start_interval, retries
  • Stoppen: stop_grace_period → --stop-timeout in ganzen Sekunden, aufgerundet (1m30s → 90)
  • Entrypoint & Command: --entrypoint nimmt nur ein Programm. Aus entrypoint: [sh, -c] wird daher --entrypoint sh, das -c rückt vor das Command. Strings werden wie in Compose nach Shell-Regeln in Wörter zerlegt.

Für den Service app aus dem Example-Knopf (Projekt shop, build: ./app, deploy.resources.limits, Netz back mit Alias api, stop_grace_period: 1m30s) entsteht dieser Block:

Terminal
# app
docker build -t shop-app ./app
docker run -d \
  --name shop-app-1 \
  --workdir /app \
  --memory 512M \
  --cpus 0.5 \
  --network shop_back \
  --network-alias app \
  --network-alias api \
  -e NODE_ENV=production \
  -e 'PRICE_TAG=costs $5' \
  --stop-timeout 90 \
  shop-app node server.js

Was beim Compose-Import NICHT übersetzt wird

Was keine docker run-Entsprechung hat, fehlt im Skript. Das meiste davon meldet das Tool in der Hinweisliste:

  • depends_on-Bedingungen wie service_healthy — das Skript hält nur die Reihenfolge ein, es wartet nicht auf einen gesunden Container.
  • profiles — der Befehl läuft immer.
  • deploy.replicas und scale größer 1 — docker run startet genau einen Container.
  • deploy.resources.reservations.cpus und Geräte-Reservierungen ohne gpu-Capability.
  • Secrets/Configs aus environment:, mit content: oder extern (Swarm) — sie lassen sich nicht als Datei einhängen.
  • env_file mit required: false wird trotzdem als --env-file gesetzt; docker run bricht ab, wenn die Datei fehlt.
  • Relative Pfade (./html) — sie gelten relativ zum aktuellen Verzeichnis; führ das Skript neben der Compose-Datei aus.
  • Alle übrigen Service-Keys melden sich mit "<key>" is not converted. — Erweiterungsfelder x-… übergeht das Tool still.

Ohne Hinweis fallen dagegen Unterschlüssel weg, die das Tool unter einem bekannten Key nicht liest. Die Prüfung auf unbekannte Keys läuft nur über die oberste Ebene eines Services. Von build liest das Tool nur context, dockerfile, target und args — build.cache_from oder build.ssh verschwinden also wortlos. Von deploy wertet es nur restart_policy, replicas und resources aus, deploy.placement etwa fehlt ohne Meldung. Bei den Netzen eines Services übernimmt es nur aliases, ipv4_address, ipv6_address und link_local_ips (Letzteres nur beim ersten Netz, bei weiteren Netzen fällt es weg); priority, mac_address oder driver_opts eines Netzes gehen verloren. Vergleich bei solchen Dateien Ein- und Ausgabe selbst.

Dollarzeichen und Variablen

Shell und Compose behandeln $ unterschiedlich: In der Shell expandiert $VAR, '$VAR' nicht. In Compose werden $VAR und ${VAR} aus der Umgebung bzw. der .env-Datei interpoliert, $$ steht für ein wörtliches $. Das Tool übersetzt in beiden Richtungen so, dass eine Variable eine Variable bleibt und ein Literal ein Literal:

  • Run → Compose: -e "HOME_DIR=$HOME" wird zu HOME_DIR=$HOME — Compose setzt den Wert beim Start ein. Ein wörtliches Dollarzeichen wie in -e 'PRICE=$5' wird zu PRICE=$$5.
  • Compose → Run: Wörtliche Teile kommen in einfache Anführungszeichen, $$ wird wieder zu $. ${NAME}, $NAME und die Formen mit Vorgabewert (${NAME:-wert}, ${NAME-wert}, ${NAME:?…}, ${NAME:+…}) werden zu einer Shell-Expansion in doppelten Anführungszeichen, etwa -e NGINX_HOST="${HOST:-example.com}".

Aus Sicherheitsgründen lässt das Tool nur einfache Vorgabewerte zur Expansion durch (Buchstaben, Ziffern und _ . , : / @ % + = - sowie Leerzeichen). Alles andere — Anführungszeichen, $(…), Backticks, Backslashes — bleibt wörtlicher Text in einfachen Anführungszeichen. So kann eine präparierte Compose-Datei im erzeugten Skript keinen Code ausführen. Bedenke: Compose liest Variablen auch aus .env, das Skript nicht — exportiere sie vorher in deiner Shell.

Der Reference-Tab

Der dritte Tab ist ein eingebautes Nachschlagewerk und braucht keine Eingabe:

  • Flag Reference: docker run → Compose — eine nach Themen gruppierte Tabelle (Container Identity, Image & Command, Ports & Volumes, Environment, Network, Lifecycle, Runtime Flags, Security, Resources, Logging, Healthcheck, Labels) mit run-Flag, Compose-Key und Notizen, etwa zu --mount, --network host, --gpus und deploy.resources.
  • Compose-only Features — depends_on (Reihenfolge ja, Bedingungen nein), build (wird zu docker build), profiles/replicas/scale (mit Hinweis ignoriert), secrets/configs (Datei-Varianten als Mount) und Interpolation (${VAR:-default} bleibt Shell-Variable).
  • Restart Policies — no (Standard, nie neu starten), always, unless-stopped, on-failure und on-failure:3 (max. 3 Versuche).
  • Tips — Zeilenfortsetzung mit \, kombinierte Flags, mehrere run-Befehle als mehrere Services, Prüfen mit docker compose config und Ports in Anführungszeichen.

Grenzen — kompakt

  • Ein run = ein Service. Mehrere Befehle ergeben mehrere Services in einer Datei; Optionen ohne Compose-Entsprechung (z. B. --rm, -P, --cidfile) und unbekannte Flags fallen weg, meist mit Hinweis — welche Angaben ohne Hinweis wegfallen, steht unter „Richtung 1: Run → Compose“.
  • Compose-only-Konstrukte gehen teilweise verloren, wenn du von Compose nach run konvertierst: depends_on-Bedingungen, profiles, replicas/scale, Secrets ohne Datei und nicht unterstützte Keys.
  • Kein docker/podman im Hintergrund. Das Tool startet nichts und prüft nichts gegen eine echte Engine — es ist ein reiner Text-zu-Text-Übersetzer. Prüf die erzeugte Datei mit docker compose config, bevor du sie einsetzt.

Für den Einstieg und die Zielgruppen siehe die Übersichtsseite, für konkrete Durchläufe die Beispiele. Ausprobieren kannst du alles direkt im Tool.