DevOps & Automation

Advanced Java WebApp CI/CD: Automated Testing & Rollbacks

Building production-ready GitLab pipelines for Java Maven applications on Tomcat 9.

Why the Ubuntu Server & Runner are the "Brains"

Before looking at the .gitlab-ci.yml, you must understand the physical flow of data. Without this "Handshake," your automation will fail.

The Ubuntu Host

This is where the GitLab Runner lives. It’s a clean environment that waits for instructions. In our project, it uses Docker to spin up a Maven container only when needed.

The Runner's Role

The Runner is the "Translator." It takes the instructions from GitLab and executes them on your server. Without a properly configured Runner, your repository is just a dead storage of code.

The CI/CD Handshake Flow

1. Code Push → 2. GitLab Triggers Runner → 3. Runner Builds on Ubuntu → 4. Deployment to Target IP

Preparation Checklist (Target Servers)

Before the YAML can work, your Ubuntu Target servers (Test/Prod) must be prepped:

Requirement Why it's Critical
Port 8080 Open Allows users to see the Java Webapp after deployment.
Tomcat 9 Service The "Runtime" that actually executes your .war file.
SSH Keys The "Fingerprint" that allows the Runner to deploy without asking for a password.
GitLab Runner Console ID: #9942105 - Pipeline Simulator
Build
Test
Deploy
Revert
Runner Status: Idle
● Connected to GitLab.com Shell: /bin/bash
> Waiting for build instruction...

1. Advanced Infrastructure Setup

Success in CI/CD depends 90% on environment preparation. Here is how we configure our Ubuntu ecosystem.

The GitLab Runner: Why it Matters

Unlike Jenkins, which uses a heavy Master-Slave architecture, GitLab uses Runners. A Runner is a lightweight agent installed on your Ubuntu server that "polls" GitLab for jobs.

  • Security: Executes commands locally on your Ubuntu host.
  • Efficiency: Only consumes RAM/CPU when a build is active.
  • Isolation: Can run builds inside Docker containers to prevent library conflicts.

Ubuntu Server Configuration

We use Ubuntu as our host for its native Systemd support and package stability. Before the pipeline runs, execute these on your Runner machine:

sudo apt update
sudo apt install maven tomcat9 openjdk-11-jdk -y

Note: Ensure port 8080 and 22 are whitelisted in your Cloud Security Group.

Runner Installation & Registration

This "Handshake" connects your Ubuntu server to the GitLab UI.

# Download and Register
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
sudo chmod +x /usr/local/bin/gitlab-runner
sudo gitlab-runner register
During registration, use the tag "Common Runner". If the tag doesn't match the .gitlab-ci.yml, the job will stay in 'pending' status forever.

Why we moved from Jenkins to GitLab CI/CD

Feature Jenkins (Legacy) GitLab CI/CD (Modern)
Config Storage UI-based / Fragmented In-Repo (.gitlab-ci.yml)
Dependencies Plugin Management Hell Containerized / Docker Native
Scaling Manual Slave Setup Auto-scaling Runners

2. Advanced .gitlab-ci.yml Design

By leveraging YAML Variables, we keep our configuration DRY. This allows us to change server IPs in one place without editing the script logic.

stages:
  - build
  - test
  - deploy

variables:
  APP_NAME: "webapp.war"
  TEST_SERVER: "ubuntu@172.31.34.244"
  PROD_SERVER: "ubuntu@172.31.44.28"
  DEPLOY_PATH: "/var/lib/tomcat9/webapps"

Continuous Build:
  stage: build
  tags:
    - Common Runner
  script:
    - git clone "https://github.com/cicdclouds/cicdclouds_javawebapp.git"
    - cd MyJavaApp && mvn package
    - cp MyJavaApp/webapp/target/webapp.war $CI_PROJECT_DIR/$APP_NAME
  artifacts:
    paths:
      - $APP_NAME
    expire_in: 1h

Continuous Test:
  stage: test
  tags:
    - Common Runner
  dependencies:
    - Continuous Build
  script:
    - scp $APP_NAME $TEST_SERVER:$DEPLOY_PATH/test.war
    - git clone "https://github.com/cicdclouds/cicdclouds_testingweb.git"
    - java -jar cicdclouds/cicdclouds_testingweb.git
  environment:
    name: testing
    url: http://172.31.34.244:8080/test

Continuous Deploy:
  stage: deploy
  tags:
    - Common Runner
  dependencies:
    - Continuous Build
  script:
    - scp $APP_NAME $PROD_SERVER:$DEPLOY_PATH/prodapp.war
  environment:
    name: production
    url: http://172.31.44.28:8080/prodapp
  when: manual
  

3. Automated Health Check Gates

Success isn't just a 200 OK on the SCP command. It's ensuring the Java Servlet is actually responding to requests.

Critical Logic: If the health check fails, the pipeline halts. Broken code never touches the manual production trigger.

4. Zero-Downtime Rollback

Before any production deployment, our script automatically creates a backup of the current stable WAR file.

ssh $PROD_SERVER "cp $DEPLOY_PATH/prodapp.war $DEPLOY_PATH/prodapp.war.bak"

Troubleshooting & FAQ

Ensure the ubuntu user owns the directory: sudo chown -R ubuntu:ubuntu /var/lib/tomcat9/webapps.

Switch to the Docker executor in your runner config and use the maven:3.8.5-openjdk-11 image in your YAML.