简体   繁体   中英

Overriding inherited CMD in Dockerfile does not always work?

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 , ie 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

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

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 "

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM