3

I am getting some inconsistent behavior in connection with overriding CMD in a derived Dockerfile.

The base Dockerfile looks something like this:

FROM myVeryBaseImage

ENV WEBAPP_CONTEXT=my-app
WORKDIR /opt/${WEBAPP_CONTEXT}

COPY app/*.jar ./${WEBAPP_CONTEXT}.jar
COPY baseconfig/* ./config/${WEBAPP_CONTEXT}/

CMD java -jar ${WEBAPP_CONTEXT}.jar --Dspring.profiles.active=docker

This base image is provided by another team and it would be difficult to change it. I am now composing a bunch of containers where I want to run the same app multiple times, but with different configurations.

So I figured I'd extend the image copying some more configuration into it and running it with a different spring profile:

FROM baseImage
COPY config/application-*.properties ./config/${WEBAPP_CONTEXT}/
CMD java -jar ${WEBAPP_CONTEXT}.jar -Dspring.profiles.active=${PROFILE}

And in the docker-compose.yml:

myapp-foo:
 build: ./myapp-custom
 image: myapp-custom
 environment:
  PROFILE: foo
 volumes:
  - /opt/my-app/foo:/opt/my-app

myapp-bar:
 image: myapp-custom
 environment:
  PROFILE: bar
 volumes:
  - /opt/my-app/bar:/opt/my-app

I would have expected to have 2 containers running, using the application-foo.properties and application-bar.properties respectively.

It seems, though, that both use the appplication-docker.properties , i.e. the docker profile defined in the base Dockerfile.

If I change the CMD in the derived Dockerfile completely, it works:

CMD echo "${PROFILE}"

Output is "foo" and "bar", respectively. Any hints what might be going on?

My versions are:

docker-compose version 1.8.1, build 878cff1
Docker version 1.12.3, build 6b644ec

Update:
After @blackibiza's suggestions, I changed the derived Dockerfile to

FROM baseImage
COPY config/application-*.properties ./config/${WEBAPP_CONTEXT}/
ENTRYPOINT /opt/jdk1.8.0_102/bin/java
CMD ["-jar", "${WEBAPP_CONTEXT}.jar", "-Dspring.profiles.active=foo"]

Without the docker-compose stuff, just to see how the derived image would look like. I get error messages from java, trying to run the container. Inspecting the image gives the following:

$ docker inspect --format='{{.Config.Cmd}} {{.Config.Entrypoint}}' testapp
[-jar ${WEBAPP_CONTEXT}.jar -Dspring.profiles.active=french] [/bin/sh -c /opt/jdk1.8.0_102/bin/java]

So it still tries to execute /bin/sh and not java. That doesn't look like what I would have expected from the documentation.

Update2: Using the JSON-array syntax for CMD triggers another problem:

FROM baseImage
COPY config/application-*.properties ./config/${WEBAPP_CONTEXT}/
CMD ["java", "-jar", "${WEBAPP_CONTEXT}.jar", "-Dspring.profiles.active=foo"]

Will not expand the use of ${WEBAPP_CONTEXT} and therefore result in an error

Error: Unable to access jarfile ${WEBAPP_CONTEXT}.jar
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90

2 Answers2

3

What you are looking for is the override of the entrypoint. As described in the Docker reference,

If you want to run your without a shell then you must express the command as a JSON array and give the full path to the executable. This array form is the preferred format of CMD. Any additional parameters must be individually expressed as strings in the array:

FROM ubuntu

CMD ["/usr/bin/wc","--help"]

If you would like your container to run the same executable every time, then you should consider using ENTRYPOINT in combination with CMD. See ENTRYPOINT.

While with Composer you can override the CMD arguments like explained here:

db:
  command: '-d'
  ports:
    - 5432:5432

you should define an ENTRYPOINT, which is in your case:

ENTRYPOINT java
CMD ["-jar", "${WEBAPP_CONTEXT}.jar"]

In your specific case, I will argue to expose the shell as entry point and override the CMD with a script, like:

ENTRYPOINT /bin/sh
CMD ["./script.sh"]

and in your compose YML:

command: './script2.sh'

UPDATE (based on changed question):

What it's missing is the definition of the variable. In this case, I suggest to use ARG instead of ENV to build the container with the permanent value passed in:

docker build -t your_image:your_version --build-arg WEBAPP_CONTEXT=your_context .

to get a substitution of the value at build time. The ARG has the advantage of being inherited in your child images

madduci
  • 2,635
  • 1
  • 32
  • 51
  • Hi Michele, I am running the same program in the derived and the base image, it's only the one parameter that should change. I wanted to avoid having to repeat the whole litany in a command in the compose file. Shouldn't a CMD in the derived Dockerfile do the same? – Arne Mertz Nov 11 '16 at 14:27
  • @ArneMertz yes but you are not using the JSON form specified in the Docker reference, as long as you don't use a shell to launch it. Try to define as default ENTRYPOINT java and let CMD configure only the parameter, like: CMD ["${PROFILE}"] – madduci Nov 11 '16 at 14:41
  • @ArneMertz IÄve added the suggestion to use ARG instead of ENV for your case, using the JSON approach – madduci Nov 14 '16 at 09:03
  • Thanks for your patience :-) The ARG approach will work for `WEBAPP_CONTEXT`, since it's the same for all containers I want to create via the compose file. Using ARG for the spring profile will, however, result in a different image for each container which wanted to avoid. – Arne Mertz Nov 14 '16 at 09:13
  • then leave only the ENTRYPOINT, delete CMD and when you run your container with command, append the arguments you need @ArneMertz – madduci Nov 14 '16 at 09:27
  • **1** setting the entrypoint and providing the arguments via command line gave me the same Java errors as described above in the first Update - `ENTRYPOINT` did not override but _append_ java to the default `/bin/sh -c`. **2** I tried using no command and no entry point in the Dockerfile at all, starting the container via `docker run testimage java -jar -my-app.jar -Dspring.profiles.active=foo`, and the container started, but STILL with the `docker` profile active instead of the `foo` profile -.- – Arne Mertz Nov 14 '16 at 10:27
  • forget the whole thing. The java argument `-Dspring.profile.active` doesn't have any effect, the profile is set in another .profile - not a Docker problem at all. – Arne Mertz Nov 14 '16 at 10:35
3

Don't just copy & paste faulty Java commands. The -Dspring.profile.active argument will not be recognized if it comes after the .jar file.

Fix the CMD line to be

CMD java -jar -Dspring.profiles.active=${PROFILE} ${WEBAPP_CONTEXT}.jar

and all is well.

See also "Setting active profile and config location from command line in spring boot"

Community
  • 1
  • 1
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90