π― Goal
To set up a local CI/CD pipeline using Jenkins, deploying a Spring Boot WAR to two separate Tomcat 11 instances (DEV and QA) on a Windows system.
π Initial Issues Faced
- Tomcat auto-shutdown after Jenkins build
- Jenkins would invoke
startup.bat
, but as soon as the job finished, Tomcat shut down. - This was due to
startup.bat
running inside the Jenkins process and getting killed after.
- Port Conflicts
- Both Tomcat instances used the same default ports (
8080
,8005
,8009
), which prevented them from running simultaneously.
- Environment variables not picked up by Spring Boot
- I needed a way to inject environment-specific values (like
env=DEV/QA
) into Spring's@Value
annotations.
π§ Key Learnings & Fixes
β 1. Use Tomcat as a Windows Service
Instead of relying on startup.bat
, I:
- Installed TomcatDev and TomcatQA as Windows services:
cd "C:\apache-tomcat-11.0.8-DEV\bin"
service.bat install TomcatDev
cd "C:\apache-tomcat-11.0.8-QA\bin"
service.bat install TomcatQA
- Used
sc
to control services from Jenkins:
bat 'sc stop TomcatDev && timeout /t 5 >nul && sc start TomcatDev'
This prevents Jenkins from terminating the server.
β 2. Customize server.xml for Each Instance
Modified these ports in conf/server.xml
for both instances:
Port Type | DEV | QA |
---|---|---|
HTTP | 8081 | 8082 |
Shutdown Port | 8006 | 8007 |
AJP | 8009 | 8010 |
Ensure they don't overlap, or services will fail silently or crash.
β 3. Set Environment-Specific Flags
- Created a
setenv.bat
inside eachbin/
folder:
set JAVA_OPTS=-Denv=DEV
Spring Boot picks this up with:
@Value("${env}")
private String environment;
π§ Jenkinsfile: Deploy to Tomcat Services
Hereβs a simplified Jenkins pipeline excerpt:
stage('Deploy to DEV') {
steps {
bat """
sc stop TomcatDev
timeout /t 5 >nul
copy target\\app.war "C:\\apache-tomcat-11.0.8-DEV\\webapps\\app.war"
sc start TomcatDev
"""
}
}
Same pattern for QA.
π¬ Final Thoughts
This debugging session taught me a lot about how Jenkins, Windows, and Tomcat interact.
If you're running Tomcat on Windows and see it die after Jenkins runs, it's probably due to how you're starting it. Using services + sc
is the safest and most robust way.
π LinkedIn Recap Post
If you're short on time, I shared a quick summary of this battle on LinkedIn:
π https://www.linkedin.com/in/rajarshig007/post
Top comments (0)