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. |
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
.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.
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
ubuntu user owns the directory: sudo chown -R ubuntu:ubuntu /var/lib/tomcat9/webapps.
maven:3.8.5-openjdk-11 image in your YAML.