dockersbtsbt-native-packager

What is the difference between Cmd and ExecCmd in Docker/SBT?


In the sbt-native-packager Docker plugin, what is the difference between these directives? And how do we combine Cmd/ExecCmd with RUN/ENTRYPOINT/CMD?

For example, I am trying to add git to my docker image. The following errored out:

ExecCmd("RUN", "yum install git")

but Cmd("RUN", "yum install git") worked.


Solution

  • RUN, CMD, and ENTRYPOINT have two syntaxes in a standard Dockerfile,

    RUN echo shell format automatically wrapped in /bin/sh -c
    RUN ["echo", "exec", "format", "with", "JSON", "syntax"]
    

    These roughly correspond to Cmd() and ExecCmd(), respectively. Looking at how these commands are translated in dockerfile.scala, Cmd() is anything where the words are just separated by spaces, and ExecCmd() is specifically the JSON-array syntax.

    dockerCommands := Seq(
      Cmd("FROM", "centos"),
      Cmd("RUN", "yum install git"),
      Cmd("RUN", "yum", "install", "git"),
      ExecCmd("RUN", "yum", "install", "git")
    )
    

    The first two Cmd("RUN", ...) lines will actually generate the same thing, because Cmd() just joins its arguments with spaces, but comparing the second with ExecCmd("RUN", ...) is informative. As with other cases using Dockerfile exec (JSON-array) syntax, you need to make sure you split out the command into separate words.

    In terms of CMD and ENTRYPOINT, you'd use the same rules you'd normally use in a Dockerfile. ENTRYPOINT all but must use ExecCmd() or else it will lose the command part when the container runs, CMD can use either syntax and must use Cmd() if it has shell syntax.

    dockerCommands ++= Seq(
      ExecCmd("ENTRYPOINT", "/app/entrypoint.sh")
      Cmd("CMD", "java $JVM_ARGS -jar app.jar")
    )
    

    A couple of other Dockerfile options also accept JSON-array syntax and you could use ExecCmd() here if you wanted to force that.

    ExecCmd("COPY", "filename with a space.txt", "./")