GitLab CI/CD: Standalone Deployment Pipeline | Trigger Deployments for Environment Automation
1. Why Do We Need a Standalone Deployment Pipeline?
In a robust CI/CD architecture, building code and deploying code are distinct responsibilities. While your application project (such as a Spring Boot application) handles compilation, unit testing, and artifact generation, the actual deployment infrastructure requires specific target configurations, environment secrets, and execution scripts.
- Decoupling Concerns: Keeping deployment logic inside the application repository creates tight coupling and code duplication across microservices.
- Centralized Control: A standalone deployment repository centralizes deployment scripts (
.shfiles), SSH keys, environment variables, and release workflows. - Flexible Triggering: It allows teams to trigger deployments independently via Web UI, REST API, or as a child pipeline triggered by a parent application pipeline.
2. Core Mental Model & Real-Life Analogy
Real-Life Analogy: The Central Dispatch and Regional Warehouses
Imagine a central manufacturing plant (your Spring Boot code repository) that produces goods and packages them into shipping boxes (JAR artifacts). Instead of every factory truck driving blindly across the country, there is a Central Logistics Hub (the Standalone Deployment Pipeline).
- You call the hub and provide an order slip: "Take Box version 1.0.0, drive to the QA warehouse, safely shut down the old machinery, replace the box, restart the machines, and verify the door sensors (Health Check)."
- The logistics hub executes the precise operational checklist (
deploy.sh), completely independent of how the factory built the box.
3. Architecture of the Standalone Deployment Project
The standalone pipeline is engineered to accept dynamic runtime inputs (parameters) through GitLab CI/CD pipeline variables, making it universally reusable across different environments (dev, qa, stage, prod).
4. Operational Script Design: deploy.sh
The core driver on the target EC2 instance is a modular shell script that handles four distinct operational modes: start, stop, restart, and deploy.
Script Parameter Handling
#!/bin/bash
OPTION=$1
TARGET_DIR=$2
JOB_ID=$3
case $OPTION in
"start")
start_application
;;
"stop")
stop_application
;;
"restart")
stop_application
sleep 5
start_application
;;
"deploy")
environment_upgrade
;;
*)
echo "Invalid option provided: $OPTION"
exit 1
;;
esac
The environment_upgrade Function Flow
When a deployment is triggered, the script executes a tightly controlled lifecycle sequence:
- Stop Application: Calls the application's maintenance script (
maintenance.sh stop) residing inside the target directory. - Replace JAR: Deletes the existing JAR file in the
bin/directory and moves the newly transferredapp.jarfrom the temporary staging folder into position. - Start Application: Invokes the maintenance script (
maintenance.sh start) to spin up the new artifact.
5. GitLab CI/CD Pipeline Configuration (.gitlab-ci.yml)
The pipeline is structured with clear rule restrictions and dynamic environment variable mapping.
Pipeline Rules and Input Parameters
stages:
- deploy
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_PIPELINE_SOURCE == "pipeline"' # Allows triggering as a Child Pipeline
variables:
OPTIONS:
description: "Select deployment action"
value: "deploy"
options:
- "deploy"
- "start"
- "stop"
- "restart"
- "health-check"
DEPLOY_ENV:
description: "Target deployment environment"
value: "dev"
options:
- "dev"
- "qa"
- "stage"
- "prod"
ARTIFACT_VERSION:
description: "Version of the artifact to deploy (e.g., 1.0.0 or 1.0.0-SNAPSHOT)"
value: "1.0.0"
6. Environment-Specific Variable Resolution & Artifact Downloader
Depending on whether the user selects dev, qa, stage, or prod, the pipeline dynamically binds the correct target EC2 host, directory paths, and health check endpoints.
Handling Releases vs. Snapshots
The artifact downloader logic distinguishes between stable releases and dynamic snapshots:
- Release Version: Directly constructs the download URL using the static version tag (
1.0.0). - Snapshot Version: Queries the artifact repository endpoint to scan all revisions, parses the manifest to locate the newest timestamped revision, and downloads the absolute latest snapshot JAR.
# Conceptual artifact resolution workflow
if [[ "$ARTIFACT_VERSION" == *-SNAPSHOT ]]; then
echo "Resolving latest Snapshot revision..."
# Fetches metadata XML, parses latest revision ID, builds target download URL
else
echo "Downloading Release artifact for version: $ARTIFACT_VERSION"
fi
7. Transfer & Execution Workflow (SCP + Remote Execution)
Once the artifact is downloaded to the GitLab runner, it must be pushed securely to the backend EC2 instance.
deploy_job:
stage: deploy
script:
- echo "Setting environment details for $DEPLOY_ENV..."
- ./scripts/download_artifact.sh
- ssh -i $SSH_PRIVATE_KEY $EC2_USER@$HOST_NAME "mkdir -p /tmp/deploy_$CI_JOB_ID"
- scp -i $SSH_PRIVATE_KEY ./scripts/deploy.sh $EC2_USER@$HOST_NAME:/tmp/deploy_$CI_JOB_ID/
- scp -i $SSH_PRIVATE_KEY ./app.jar $EC2_USER@$HOST_NAME:/tmp/deploy_$CI_JOB_ID/
- ssh -i $SSH_PRIVATE_KEY $EC2_USER@$HOST_NAME "/tmp/deploy_$CI_JOB_ID/deploy.sh deploy $TARGET_DIR $CI_JOB_ID"
- rm -rf /tmp/deploy_$CI_JOB_ID
rules:
- if: '$OPTIONS == "deploy"'
8. Post-Deployment Health Check & Verification
Because Spring Boot applications take several seconds to initialize embedded servers (Tomcat/Netty), rushing the verification leads to false negatives.
Health Check Execution Block
- Wait Buffer: The pipeline pauses for
15 secondsto allow the Spring IoC container to finish wiring beans and start the embedded web server. - HTTP Status Check (
curl): Evaluates the health endpoint URL.
echo "Performing post-deployment health check..."
sleep 15
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_CHECK_URL)
if [ "$HTTP_STATUS" -eq 200 ]; then
echo "Success: Application is healthy! HTTP Status: $HTTP_STATUS"
exit 0
else
echo "Failure: Health check failed with status: $HTTP_STATUS"
exit 1
fi
9. Step-by-Step Execution Walkthrough
- Triggering via GitLab Web UI:
- Navigate to Build > Pipelines > Run Pipeline.
- Select the target branch (
main). - Choose
OPTIONSasdeploy,DEPLOY_ENVasqa, and provideARTIFACT_VERSIONas1.0.0.
- Execution Phase:
- The runner resolves environment variables corresponding to
qa. - The artifact is fetched from the artifact repository.
- A temporary staging directory (
/tmp/deploy_<job_id>) is initialized on the backend EC2. - Files (
deploy.shandapp.jar) are transferred viascp.
- The runner resolves environment variables corresponding to
- Application Lifecycle Management:
deploy.shstops the running service, replaces the old JAR with the new JAR, and starts the application.
- Verification:
- The pipeline sleeps for 15 seconds, executes a
curlhealth check, receives a200 OKstatus, and reports a successful green pipeline.
- The pipeline sleeps for 15 seconds, executes a
10. Summary and Key Takeaways
- Decoupled Architecture: Standalone deployment pipelines isolate infrastructure deployment logic from application build logic, enabling clean microservice maintenance.
- Dynamic Parameterization: GitLab pipeline parameters (
variableswith options) empower users to select specific actions (start,stop,restart,deploy) and target environments (dev,qa,stage,prod) dynamically. - Robust Snapshot Handling: Automated snapshot resolution ensures that deployment jobs always fetch and deploy the absolute latest revision of a SNAPSHOT artifact.
- Secure Remote Operations: Using temporary directories (
/tmp/...),scpfile transfers, and remote SSH execution maintains clean EC2 environments without leaving stray files behind. - Automated Health Checks: Incorporating a buffer delay followed by an HTTP
curlstatus check guarantees that deployments are automatically validated before declaring success.