Cannot start Tomcat from outside container

[Edit: I’m running Docker Desktop 4.34.3 (170107)
on Windows 11 Pro 23H2 (10.0.22631.4317)
using WSL2
version 2.3.24.0
kernel 5.15.153.1-2]

[Edit2: I stuck a read -pdone at the end of the start-tomcat.sh script. The app runs if I exec the script from outside. When I press Enter, the script exits normally, and Tomcat instantly dies. It does not shut down cleanly, the process simply ceases to exist as if someone did a kill -9 on it. I even tried ./startup.sh & in the script. The parent PID becomes 1 as you’d expect, but when the parent script exits, something hunts Tomcat down and kills it.

It’s looking like you are not allowed to create a process and expect it to live beyond the docker compose exec command. If you try, docker will hunt it down and nuke it from orbit.]

[Last edit, I think: I duct-taped it. My entrypoint.sh is a simple while true loop with a long sleep in there. It traps SIGTERM and cleanly shuts down Tomcat and exits.

I added a trap for SIGUSR1 which starts Tomcat up, and replaced the start-tomcat.sh contents with a simple kill -SIGUSR1 1

That starts Tomcat and it survives. So, now I can make my little powershell gui with buttons for starting and stopping Tomcat, pulling in war files, running db change scripts, etc.]

I have a weird issue. I created a Tomcat image for dev work on a web app.

(Before you say “you didn’t use the official Tomcat image…” – The app is running on Tomcat 8.5.100, and Java 8. I haven’t found an official image for that version. Yes, I am aware that 8.5 is EOL’d. Yes, we have set of projects on the books to upgrade the app to Java 11 and Tomcat 9 initially, and beyond, to Java 21+ and Spring Boot and Tomcat 10+. As Gowron liked to say, “But not today.”)

I put a very simple script in /usr/local/bin/start-tomcat.sh:

#!/bash/bin
cd /opt/tomcat/tomcat/bin
./catalina.sh start

(I do have chmod +x /usr/local/bin/* in the Dockerfile)

If I go into bash with docker compose exec blah-tomcat bash and run the script, Tomcat starts up fine, and the app runs.

If I try to run the script from outside with docker compose exec blah-tomcat start-tomcat.sh the script runs, catalina.sh fires off its regular output of env variables, says “Tomcat started”.

Tomcat does not start. The catalina.out file is created but never written to. The length is 0. ps -ef shows that the server is not running.

I have also tried docker compose exec blah-tomcat bash -c "start-tomcat.sh" with the same non-results.

I have also tried docker compose exec blah-tomcat bash -c "cd /opt/tomcat/tomcat/bin && ./catalina.sh start" with the same non-results.

If I change the start-tomcat.sh script to say ./catalina.sh run it fires up the server and the app runs. But that means it is on stdout, no output to catalina.out. Not useful for debugging, as I cannot search for stuff in a file that doesn’t exist.

This is a dev environment. I want to be able to shut Tomcat down, pull in fresh war files, start Tomcat up, shut Tomcat down, mess with the db, start Tomcat up, etc.

Right now, that requires I open up a bash terminal and run the commands from within bash in the container. Sure, a minor inconvenience, but a big mystery. If this doesn’t work, what else will fail?

Does anyone have any hints on how to debug this?

A container is mainly for a single process that starts when you start the container. So if the container is running and you can use docker exec to run a second process in the container, something already keeps the container alive. What is that?

The tomcat process should start in the foreground defined in the Dockerfile as CMD or ENTRYPOINT. Then you can stop and start the container not the process in the container. That would be a virtual machine approach and containers are not virtual machines.

When you use docker exec, the process you start will live until the exec process runs. When you run a bash with docker exec, you have an interactive terminal and processes can run until that bash process runs. That bash will be the parent of every process you run from it.

When you run bash with another command as its argument, if the argument runs a process in the background, bash will stop immediately as the processes under the bash process.

If you want to learn about CMD and ENTRYPOINT: Constructing commands to run in Docker containers - DEV Community

What I have right now in my entrypoint.sh is a while true loop (there’s a sleep 1000 in there so it doesn’t suck resources) to keep the container alive. It traps SIGTERM, and shuts Tomcat down if it is running, then exits, terminating the container.

I want to do dev work, which means stopping Tomcat, putting new war files in the webapps directory, starting Tomcat back up. I also wanted to be able to bring Tomcat down and do things with the db in the mysql container.

What you’re saying is that the correct Docker way is for me to:

  1. Bring the stack down (ie with docker compose down from a powershell script) – or maybe just the container if I want to muck around with the DB without interfering with Tomcat.
  2. put the new war files in the proper place
  3. Bring the stack back up
  4. In the entrypoint.sh, copy the war files from the mount point into the webapps directory and start Tomcat
  5. Never stop Tomcat while the container is running, always bring the stack down instead.

In that case, the only things I’d ever exec from outside would be:

  1. Grab log files out to the mount point for later inspection
  2. Do a tail -f of catalina.out so I can watch it.

Thanks for the info – I am very used to sitting inside a Linux VM, and dynamically messing with stuff without terminating the VM. Docker is a new thing for me, and there are some definite differences in philosophy.

Whether you use docker compsoe down or docker compose stop is up to you “down” also deletes everything and stop just stops the container. In order for it to work, you need a a command in the container that handles the stop sognal correctly. If we use your script as a command, this should work

#!/bash/bin
cd /opt/tomcat/tomcat/bin
exec ./catalina.sh start

“exec” is fo replacing the bash process with the tomcat process as bash would not forward stop signals.

Maybe this one?

https://hub.docker.com/layers/library/tomcat/8.5.100-jdk8-corretto/images/sha256-583a29bddf2fc58b2e8567453cbb83870e065a6ca43f135bde0d4e9e18456bc8?context=explore

I never heard of corretto, so this could be something you already found and didn’t want to use.

I’m not sure what that would mean, but normally you would run a separate container for the database. Otherwise you wold need to instal a process manager in the container and let that process manager handle everything else.

Using docker exec is good for debugging like checking the files, trying to access an external URL to see if there is a network issue or learning about containers or the app running in containers by runnign commands interactively in a shell.Othrwise, whenever you can, you should define the one process you want to run in the container and use docker commands (or SDKs implemented in multiple languages) to start and stop containers.

The documentation has a getting started guide, but here is a template I usually share for learning about Docker basics:

Recommended links to learn the basics and concepts:

The only problem with “My tutorials” is that I tested it on macOS and Linux and some commands could fail on Windows. Using WSL2 integration and running docker commands from a WSL distro should help though.

It is the openjdk distribution from AWS. It works regardless whether it is used inside a container or on a local machine, or in a datacenter or a cloud provider.

1 Like

Thanks. I continue to learn stuff.

I was a little unclear on the structure of my app – I have a compose stack with three services: mysql, tomcat, and apache httpd.

I’ll be revamping the tomcat container, so that it simply starts Tomcat during the ENTRYPOINT script. For my dev environment, it’ll pull in war files from a bind mount before starting Tomcat. For prod, I’ll bake the war files directly into the image. That’ll be my one process for that container.

My comment about mucking around with the DB means going into the mysql container and doing things like running update sql files. The app can sometimes freak out if the database changes while it is running. So there, I’d stop the Tomcat container, do what I need to do to the database, and start the Tomcat container again.

I’ll look at corretto. Right now, all three images are built the way I currently build the Linux server.

Thank you for the help. It has clarified things for me.