Issue
I have a Dockerfile
, which looks like this:
FROM centos/httpd
COPY ./aquarium-javascript/html/ /var/www/html/
RUN yum install -y java-11-openjdk
COPY ./aquarium_fish-0.0.1-SNAPSHOT.jar ./
COPY ./aquarium_species-0.0.1-SNAPSHOT.jar ./
COPY ./aquarium_gateway-0.0.1-SNAPSHOT.jar ./
COPY ./wrapper.sh ./
EXPOSE 8080
EXPOSE 80
RUN bash wrapper.sh
The wrapper.sh
looks like this:
java -jar aquarium_fish-0.0.1-SNAPSHOT.jar &
sleep 7;
java -jar aquarium_species-0.0.1-SNAPSHOT.jar &
sleep 7;
java -jar aquarium_gateway-0.0.1-SNAPSHOT.jar &
sleep 7;
When I run the java files manually using the sudo docker exec -it <container> /bin/bash
it works, but when I do it in the wrapper.sh
it doesn't. I figured that it must be like this because the intermediate container is removed after executing the java files. Is there any way to stop this from happening? Or am I interpreting this situation wrong?
Solution
The short answer is: You don't. RUN
commands are executed during image build and in ephemeral containers with the purpose of modifying some part of the image. They're supposed to finish quickly so you can eventually obtain the finished container image. If you want things to be long-running, you use docker run
for that. The command to be run by docker run
can be set in the Dockerfile
, with either CMD
or ENTRYPOINT
.
As Wojtek Wencel suggests, you can obtain a long running container by changing RUN bash wrapper.sh
into CMD ["bash", "wrapper.sh"]
, (adding a wait
at the end of wrapper.sh
), and running the image with docker run --rm aquarium
after building it with docker build -t aquarium
. The problem with this approach is that there won't be any neat handling when one of the processes fails, and the log output will be intermingled, sometimes with no easy way to tell the lines apart.
As David Maze suggested, it would be more appropriate to give each process its own container, and run them together with docker-compose. There are various ways of doing that, I tend to:
- Change
RUN bash wrapper.sh
toENTRYPOINT ["java", "-jar"]
- Use a
docker-compose.yaml
like
version: "2.4"
services:
fish:
command: aquarium_fish-0.0.1-SNAPSHOT.jar
build:
context: .
species:
command: aquarium_species-0.0.1-SNAPSHOT.jar
build:
context: .
gateway:
command: aquarium_gateway-0.0.1-SNAPSHOT.jar
build:
context: .
ports:
- 80:80 # Guessing here.
That would also make wrapper.sh
unnecessary.
This is a fairly standard usecase, so there's a myriad ways to do this. You could also keep wrapper.sh
and pass the service name into the container as an environment variable or argument to it.
Answered By - Caesar Answer Checked By - Terry (WPSolving Volunteer)