I'll first preface with relevant sections in Heroku's documentation on their container registry and runtime for Docker deploys.
The Docker commands and runtime section states:
ENTRYPOINT
is optional. If not set,/bin/sh -c
will be used
CMD
will always be executed by a shell so that config vars are made available to your process; to execute single binaries or use images without a shell please useENTRYPOINT
I want to highlight that last sentence (emphasis added):
to execute single binaries or use images without a shell please use
ENTRYPOINT
Furthermore, in the Unsupported Dockerfile commands section.
SHELL
- The default shell for Docker images is/bin/sh
, you can override withENTRYPOINT
if necessary.
My understanding from this is that if the ENTRYPOINT
instruction exists in my Dockerfile, then Heroku's container stack will not execute the command with /bin/sh
. But apparently my understanding is wrong, because that seems to be still happening.
Here is an illustration of what my Dockerfile looks like:
FROM golang:1.14 as build
# ... builds the binary
FROM scratch
# ... other irrelevant stuff
COPY --from=build /myprogram /myprogram
ENTRYPOINT ["/myprogram"]
The final image contains the binary at /myprogram
in a scratch
base image. Since scratch
doesn't have /bin/sh
, it is necessary to override this. According to their documentation, this is done with ENTRYPOINT
.
However, when I deploy it to Heroku, it appears to still execute with a shell. To illustrate:
% heroku ps -a my-app-name
== web (Free): /bin/sh -c --myflag1 --myflag2 (1)
Which means it's ultimately executing:
/myprogram /bin/sh -c --myflag1 --myflag2
Which is obviously not what I want. But what happened to this part of the documentation (which I highlighted earlier)?:
to execute single binaries or use images without a shell please use
ENTRYPOINT
...
The heroku.yml file looks like the following:
---
build:
docker:
web: Dockerfile
run:
web:
command:
- --myflag1
- --myflag2
I still have the same problem with the shell form and the exec form. Meaning, I also tried with the heroku.yml file looking like this:
---
build:
docker:
web: Dockerfile
run:
web: --myflag1 --myflag2
Now, I know that I can get everything to "just work" by basing the final image on an image that has /bin/sh
and remove the ENTRYPOINT
instruction, specifying the command with /myprogram
. I don't need to use scratch, but I want to, and should be able to use scratch
, right? It's what I've been using for many years to run my statically linked binaries in containers and I have never come across problems like this when deploying on other platforms.
So am I misunderstanding their documentation? What do I need to do to get rid of this /bin/sh
shenanigan?