Tomcat
Apache Tomcat chart for Kubernetes using the official docker.io/library/tomcat image. The chart supports immutable application images, mounted WARs, optional writable webapps, JMX, and modern ingress patterns.
Key Features
- Official Tomcat image pinned to
11.0.22-jdk17-temurin-noble - Optional ROOT health webapp for deterministic probes and Helm tests
- Copies image-baked webapps into writable runtime volume when needed
- Writable
webapps,logs,temp, andworkvolumes for non-root runtime - Ingress, Gateway API, dual-stack Service fields, NetworkPolicy, HPA, PDB, persistent webapps/logs, and JMX
Installation
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install tomcat helmforge/tomcat --namespace tomcat --create-namespace
helm install tomcat oci://ghcr.io/helmforgedev/helm/tomcat --namespace tomcat --create-namespace
Examples
Application probes through TCP:
webapps:
defaultRoot:
enabled: false
startupProbe:
mode: tcp
livenessProbe:
mode: tcp
readinessProbe:
mode: tcp
JMX:
jmx:
enabled: true
hostname: tomcat.example.local
Operations
Prefer immutable Tomcat images or init containers that fetch versioned WAR artifacts. Enable JMX only on trusted networks and add authentication or TLS flags through jmx.extraOpts when exposing remote JMX.
Architecture
The chart deploys the official Tomcat image with a writable application layer for webapps, logs, temp, and work.
This keeps the container security posture strict while still allowing Tomcat to unpack WARs and write runtime files.
Application delivery options:
- Bake WAR files or exploded applications into a custom Tomcat image.
- Mount WAR artifacts through an init container and shared volume.
- Use
webapps.persistencefor controlled mutable deployments. - Disable the default ROOT health webapp when your application provides its own health endpoint.
The default ROOT application exists only to make probes and Helm tests deterministic on a fresh install.
Production Values
For production applications, disable the sample ROOT app, switch probes to an application-safe endpoint or TCP mode, and configure routing explicitly:
replicaCount: 2
webapps:
defaultRoot:
enabled: false
copyImageContent:
enabled: true
startupProbe:
mode: tcp
livenessProbe:
mode: tcp
readinessProbe:
mode: tcp
gatewayAPI:
enabled: true
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- tomcat.example.com
networkPolicy:
enabled: true
ingress:
extraFrom:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: gateway-system
Deploying Applications
For immutable images, keep webapps.copyImageContent.enabled=true; the chart copies image-baked contents from
/usr/local/tomcat/webapps into the writable volume only when that volume is empty.
For artifact-driven deployments, add an init container:
extraInitContainers:
- name: fetch-war
image: docker.io/curlimages/curl:8.17.0
command:
- sh
- -ec
- |
curl -fsSL "$WAR_URL" -o /webapps/ROOT.war
env:
- name: WAR_URL
value: https://artifacts.example.com/apps/myapp-1.2.3.war
volumeMounts:
- name: webapps
mountPath: /webapps
Use persistent webapps only when applications are intentionally installed or mutated at runtime:
webapps:
persistence:
enabled: true
size: 20Gi
logs:
persistence:
enabled: true
size: 10Gi
Reverse Proxy Configuration
When Tomcat is behind an ingress controller or Gateway, configure connector proxy attributes so applications generate correct absolute URLs and redirects:
tomcat:
serverXml: |
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
proxyName="tomcat.example.com"
proxyPort="443"
scheme="https"
secure="true" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" />
</Engine>
</Service>
</Server>
Use tomcat.existingServerXmlConfigMap when platform teams manage the full server configuration externally.
JMX
Remote JMX is opt-in and should stay on trusted networks:
jmx:
enabled: true
hostname: tomcat.example.local
extraOpts: '-Dcom.sun.management.jmxremote.local.only=false'
networkPolicy:
enabled: true
ingress:
extraFrom:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
For authenticated or TLS-secured JMX, mount the required files with extraVolumes and append the JVM flags through
jmx.extraOpts.
Validation
After deployment:
helm test tomcat -n tomcat
kubectl get pods -n tomcat -l app.kubernetes.io/name=tomcat
kubectl logs -n tomcat deploy/tomcat --since=10m
kubectl get events -n tomcat --sort-by=.lastTimestamp
If probes use HTTP paths, confirm the deployed application serves those paths before disabling the default ROOT health webapp.
Common Issues
| Symptom | Likely Cause | Fix |
|---|---|---|
| Probe failures after deploying a WAR | /health.jsp no longer exists | Switch probes to TCP or configure app-specific probe paths. |
Redirects use http:// behind TLS | Connector proxy attributes missing | Set proxyName, proxyPort, scheme, and secure. |
| Image-baked apps disappear | Writable webapps volume hides image content | Keep webapps.copyImageContent.enabled=true. |
| JMX cannot connect | RMI hostname or NetworkPolicy is wrong | Set jmx.hostname and allow monitoring namespace traffic. |
Values
| Parameter | Default | Description |
|---|---|---|
replicaCount | 1 | Number of Tomcat pods when HPA is disabled. |
image.repository | docker.io/library/tomcat | Official Tomcat image repository. |
image.tag | 11.0.22-jdk17-temurin-noble | Tomcat image tag. |
webapps.defaultRoot.enabled | true | Render minimal ROOT app for health checks. |
webapps.copyImageContent.enabled | true | Copy image-baked webapps into writable volume. |
webapps.persistence.enabled | false | Persist /usr/local/tomcat/webapps. |
logs.persistence.enabled | false | Persist Tomcat logs. |
jmx.enabled | false | Enable JMX remote settings and Service ports. |
gatewayAPI.enabled | false | Render Gateway API HTTPRoute. |
networkPolicy.enabled | false | Render NetworkPolicy. |