Skip to content

Docker Compatibility

Biowilko edited this page Aug 19, 2026 · 2 revisions

Docker Compatibility

squarepeg supports the most-used subset of docker run flags — see the CLI Reference for the full flag table — and deliberately rejects, with a specific message, everything that has no sane equivalent on a remote cluster. Nothing is silently ignored: an unrecognised-but-docker-shaped flag either works, or fails immediately with an explanation.

Unsupported flags

Flag Why it can't work the same way What to do instead
--network Container networking is a cluster-level concept, not a per-run one Use kubernetes.spec.dnsPolicy / spec.hostNetwork in config
--privileged kubernetes.spec.containers[].securityContext.privileged
--gpus kubernetes.spec.containers[].resources (e.g. nvidia.com/gpu: 1)
-p, --publish No "host" to publish a port to on a remote cluster Create a Kubernetes Service
-d, --detach squarepeg always attaches to stream output; there's no detached mode
--restart Controlled by --mode and, for Jobs, job.spec.backoffLimit in config
-u, --user kubernetes.spec.containers[].securityContext.runAsUser
--mount -v/--volume, or the volumes config section for anything more complex
--cap-add, --cap-drop kubernetes.spec.containers[].securityContext.capabilities
--add-host kubernetes.spec.hostAliases
--link No equivalent on Kubernetes Use a Service and DNS
--platform kubernetes.spec.nodeSelector
--env-file Pass variables individually with -e, or set defaults.env in config
--hostname kubernetes.spec.hostname
--tmpfs An emptyDir volume (-v /path), or the volumes config section

Each of these fails immediately with a message naming the flag and, where one exists, the config-passthrough equivalent — you never get a bare "no such option" for something docker itself supports.

Behavioural divergences

These flags/behaviours are supported, but work differently from plain docker run in ways worth knowing about up front:

docker behaviour squarepeg behaviour Why
Host bind mounts (-v /host:/container) Rejected by default There is no "host" on a remote cluster — the node running your container isn't your machine. Use a config-defined named volume backed by a PVC, or opt in with allow_host_path_mounts: true if you're genuinely targeting a local cluster.
Named volumes persist between runs Fall back to emptyDir unless declared in config's volumes: section An anonymous or undeclared volume is scratch space only — it doesn't survive past the Pod/Job's lifetime.
stdout/stderr can be split (docker logs separates them) Merged into one interleaved stream by default Splitting is opt-in (split_streams in config) and depends on a Kubernetes apiserver feature gate not universally enabled.
-i forwards your terminal's stdin Accepted, but stdin is never actually forwarded The endpoint squarepeg reads container output from is read-only; real interactive attach (a websocket exec/attach channel) isn't implemented.
-t alone just sets a tty -t without -i also opens stdin on the container, and squarepeg warns Some clusters reject tty: true with stdin: false. Since -i never forwards real input anyway, a process that then blocks reading stdin will hang — pass -i explicitly to acknowledge you understand this.
-m 512m means 512 mebibytes Converted to the equivalent k8s binary quantity (512Mi) A bare m suffix in raw Kubernetes quantities means milli (thousandths), not mebi. Passing docker-style memory strings through unconverted would silently produce a near-zero memory limit that gets admitted and instantly OOM-kills the container. See full conversion table.
Container exits 137 (OOM) with no explanation Exit code reported as-is, but the OOMKilled reason is printed to stderr A bare 137 is opaque; squarepeg tells you why.

ENTRYPOINT vs CMD

docker run IMAGE CMD... overrides the image's CMD while keeping its ENTRYPOINT. On Kubernetes, args overrides CMD and command overrides ENTRYPOINT. squarepeg therefore maps:

You write squarepeg produces
squarepeg run myimage arg1 arg2 args: [arg1, arg2] (entrypoint untouched)
squarepeg run --entrypoint /bin/sh myimage arg1 command: [/bin/sh], args: [arg1]

Getting this backwards would silently break every image with an entrypoint wrapper script — which is most non-trivial containers — so --entrypoint exists specifically to give you a way to express Kubernetes command.

Shell pipes, redirects, and other shell syntax

COMMAND is passed to the container as literal argv tokens (Kubernetes args/command), never through a shell — identical to docker run's own exec-form default. This means |, >, &&, ;, and similar shell operators have no special meaning to the container by themselves:

squarepeg run alpine cat foo | grep bar        # grep runs on YOUR machine, against squarepeg's own stdout --
                                                 # cat foo runs in the container completely unfiltered

To use a pipe or redirect inside the container, invoke a shell explicitly and quote the whole thing so your local shell doesn't interpret it first:

squarepeg run alpine sh -c "cat foo | grep bar > out.txt"

Memory units

docker syntax Meaning k8s quantity squarepeg produces
512m 512 mebibytes 512Mi
1g 1 gibibyte 1Gi
1024k 1024 kibibytes 1Mi (squarepeg picks the largest exact unit)
2gb 2 gibibytes (gb accepted as an alias for g) 2Gi
100 (no suffix) 100 bytes 100

CPU works the same way in spirit: --cpus 0.5500m millicores, --cpus 2"2" whole cores. --request-cpu/--limit-cpu/--request-memory/--limit-memory are not converted — they're passed straight through as Kubernetes-native quantities, since they're explicitly for when you want to write the k8s value yourself.

Clone this wiki locally