A Compose command: is a Kubernetes args:, and command: replaces the entrypoint
Translating a Compose file to a Deployment, command: in Kubernetes silently drops the image ENTRYPOINT. Gotenberg lost its init wrapper and Paperless' exporter lost its environment. Check what the old container actually ran.
Moving a document-management stack from a Docker host into the cluster, I translated each Compose service by hand. Two of them broke for the same reason, and neither complained clearly.
The names don’t line up between the two systems. Compose’s entrypoint:
replaces the image’s ENTRYPOINT and its command: replaces the image’s CMD.
Kubernetes calls them command: and args:. So a Compose command: becomes
args:. If you write it as command: in a pod spec instead, you also throw
away the image’s entrypoint, which is usually doing something.
Check what the old container really ran
Don’t trust the Compose file; it only shows what was overridden. Ask Docker:
docker inspect --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}' <container>Gotenberg’s image starts through tini --, which reaps child processes. Using
command: for its Compose arguments dropped tini and ran the binary directly.
args: kept the entrypoint and passed the flags to it.
When you do bypass the entrypoint
Paperless-ngx’s image uses s6-overlay as its entrypoint. Its management commands,
such as document_exporter, are scripts that start with
#!/command/with-contenv, which reads the container’s environment from a
directory that s6 populates at startup. A CronJob that runs the exporter through
command: ["sh", "-c", ...] skips /init, so that directory doesn’t exist:
s6-envdir: fatal: unable to envdir /run/s6/container_environmentSetting S6_KEEP_ENV=1 makes with-contenv fall back to the environment the
container was started with. I proved it with a throwaway container on the old
host, running the same exporter with and without the variable, before putting it
in a manifest.
A third one belongs here, though it isn’t about arguments. A shell pipeline
under plain sh has no pipefail, so pg_dump | gzip reports success when the
dump was cut off halfway and the size check still passes. Dump to a temporary
file in custom format, list it back with pg_restore -l, and rename it into
place only if that works.