How to Spin Up an Apache Tomcat Container with Podman on Windows
Running a Java web app is easier when you let a container do the heavy lifting.
With Podman you get a Docker‑compatible workflow, no daemon lurking in the background and, best of all, rootless mode that won’t scare your admin friend.
Steps to get Tomcat up and running
Install Podman
- Windows: Grab the latest installer from the official site or use Chocolatey:
choco install podman.
The installer configures WSL‑2, which is where Podman lives on Windows.
- Linux: sudo apt-get install podman (Debian/Ubuntu) or the equivalent for your distro.
Why this matters? Without a proper backend you’ll see “cannot connect to socket” errors before your container even starts.
Pull the official Tomcat image
podman pull tomcat:9-jdk11-openjdk-slim
I once pulled tomcat:latest and got a 404 because the registry moved it to tomcat:10. Explicit tags avoid that headache.
Map ports and volumes
podman run -d \ --name tomcat-demo \ -p 8080:8080 \ -v C:\myapps\war:/usr/local/tomcat/webapps:Z \ tomcat:9-jdk11-openjdk-slim
- -p exposes the container’s 8080 to your host, so you can hit http://localhost:8080.
- The volume mapping lets you drop WAR files into a local folder and have them auto‑deployed.
The :Z flag is WSL‑2’s way of setting SELinux context; without it the container will complain about “permission denied” when trying to read your WAR.
Check the logs
podman logs -f tomcat-demo
Watch for the “Server startup in X ms” line. If you see java.lang.NoClassDefFoundError, you’re probably missing a library or the image doesn’t include JDK 8, which some older WARs expect.
Shut down when done
podman stop tomcat-demo podman rm tomcat-demo
You can keep the container alive as long as you need; Podman won’t eat up resources in the background like Docker’s daemon does.
Common pitfalls & how to fix them
- Port collision
Scenario: “I get an error that port 8080 is already in use after a quick restart.”
Fix: Run netstat -ano | findstr :8080 on Windows or ss -ltnp | grep :8080 on Linux, kill the process, or choose another host port (e.g., -p 9090:8080).
- Missing Java version
Scenario: “My WAR boots but throws a ‘java.lang.UnsupportedClassVersionError’.”
Fix: Pick an image that matches your app’s JDK target, like tomcat:9-jdk8-openjdk-slim.
- SELinux/AppArmor hiccups on WSL‑2
Scenario: “Podman refuses to mount my volume and says ‘permission denied’.”
Fix: Add the :Z suffix or adjust your distro’s AppArmor profile. On Windows, also ensure the folder isn’t flagged as read‑only.
Tweaking Tomcat inside a container
If you need to bump memory limits or tweak JVM flags, create a tiny wrapper script:
# start-tomcat.sh #!/bin/bash export CATALINA_OPTS="-Xms512m -Xmx1024m" exec "$@"
Then build your own image:
FROM tomcat:9-jdk11-openjdk-slim COPY start-tomcat.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/start-tomcat.sh ENTRYPOINT ["start-tomcat.sh", "catalina.sh"]
Build with podman build -t mytomcat . and run as usual. This keeps the container lean while giving you control over JVM tuning.
Final thoughts
Using Podman for Tomcat is a no‑frills way to spin up a Java web server on any machine that supports containers. It eliminates the daemon overhead, works great with WSL‑2 on Windows, and keeps your system clean from root privileges. Give it a try; if you hit a snag or have a neat trick to share, drop me a line.