4

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 use ENTRYPOINT

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 with ENTRYPOINT 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?

James
  • 4,599
  • 2
  • 19
  • 27
  • The `heroku.yml` `run` is overwriting your entrypoint. – Tin Nguyen May 11 '20 at 07:21
  • @TinNguyen I'm pretty sure that's not the case because the error message from my program (which I didn't include in my post) complains about `-c` (from the problematic `/bin/sh -c`) being an unrecognized flag. Which is actually a correct behavior. Can you point to any part of Heroku's documentation that says `run` is overwriting `ENTRYPOINT`? – James May 11 '20 at 14:13
  • I'm also running into this issue, did you find a solution? – ileitch May 16 '20 at 20:32
  • @ileitch Unfortunately, I haven't found a solution yet. I've gone back to deploying to a tried-and-true k8s cluster with Helm where trivial things like this are just not a problem. – James May 19 '20 at 18:16
  • I would try two separate things. First, add the `--myflag1` and `--myflag2` parameters to the ENTRYPOINT in your Dockerfile. If that won't work, it seems to me that Heroku is compelled to add the `/bin/sh` as a CMD instruction for some reason. Maybe if you specify a CMD yourself, it won't do it? – MrMister May 23 '20 at 19:01
  • 1
    @James did you ever find a solution to this? – Matthias Nov 16 '21 at 20:11

0 Answers0