Continuous Deployment Explained | GitLab CI/CD CD Overview for Spring Boot App 🚀
This chapter marks the critical transition from Continuous Integration (CI) to Continuous Deployment (CD) in our GitLab CI/CD pipeline series. Having successfully established our CI workflow (build, test, and artifact publishing), we now turn our focus to automating the deployment of our Spring Boot application artifacts to target environments, while refining our artifact decoupling strategy for multi-environment flexibility.
1. Where We Stand: The Completed CI Phase
Up to this point in the playlist, we have fully engineered and validated the Continuous Integration (CI) components of our GitLab CI/CD pipeline.
Core CI Stages Already Implemented:
- Build Stage: Compiles the Spring Boot project and packages code.
- Test Stage: Executes unit and integration test suites against designated test databases.
- Maven Deploy Phase: Publishes snapshot artifacts to the artifact repository.
- Maven Release Phase: Creates a final release artifact, publishing it as a tagged release with a deployable artifact (such as a
.jarfile).
Note: While auxiliary components like code linting and static analysis exist, our primary focus has been locked on the core CI pipeline backbone—taking raw source code and turning it into a pristine, versioned, release-ready artifact stored securely in an artifact repository.
2. The Deployment Problem: Manual vs. Automated Environments
With our release artifact (e.g., app.jar) sitting in the artifact repository, the next logical question arises: How does this artifact reach our target servers?
In enterprise application development, you rarely deal with just one production server. A typical architecture includes multiple non-production environments (Development, Testing, Stage/UAT) followed by Production.
The Pain of Manual Deployment (The Naive Way)
If you attempt to deploy these environments manually without a CD pipeline, the operational overhead becomes immense:
- Connect via SSH from your local machine to an intermediary Jump Server.
- From the Jump Server, SSH into the internal Backend EC2 instance.
- Use
curlorwgetto pull the.jarfile from the artifact repository. - Locate the specific directory on the backend server where the application runs.
- Stop the existing Java process, replace the
.jarfile, and restart the service.
Repeating this cumbersome workflow across multiple environments, releases, and hotfixes is error-prone, slow, and unsustainable. This exact bottleneck is what Continuous Deployment (CD) eliminates.
3. Core Mental Model: Bridging CI to CD
The ultimate objective of our upcoming pipeline expansion is to automate the handoff between the artifact registry and our target servers.
Real-Life Analogy: The Automated Factory Bottleneck
Think of Continuous Integration (CI) as an automated automobile assembly line. Raw metal and parts go in, and a fully functional car rolls off the belt and is parked in a holding lot (the Artifact Repository).
However, leaving cars parked in the lot doesn't put them in customer driveways. Continuous Deployment (CD) is the automated delivery truck system that picks up the car from the holding lot, drives it across the country, and unloads it directly at the correct dealership (Target Environment), ready for keys to be turned—all without a human needing to manually drive every single car.
4. Architectural Refinement: Loose Coupling via Runtime Injection
Before writing our deployment jobs, our architecture required a crucial code refactoring: Decoupling the .jar file from environment-specific configurations.
The Problem with Build-Time Profiles
In earlier iterations, our Spring Boot application relied heavily on Maven profiles (dev, test, prod).
- A build targeted for
devwas hardcoded with development database credentials. - A build targeted for
prodwas tightly coupled to production database configurations at build time.
This meant we had to maintain separate builds for separate environments, violating the core tenet of immutable artifacts: Build once, deploy anywhere.
The Solution: Runtime Configuration Injection
To make our pipeline truly enterprise-grade, we modified our project structure so that database connection details are injected at runtime, not build time.
Updated pom.xml Profile Strategy
In our updated pom.xml, we streamlined profiles specifically to separate local developer testing from automated CI/CD execution:
Note: By shifting database and environment configurations to runtime parameters, our generated
.jarfile becomes completely environment-agnostic. We can take the exact same.jarbinary and safely deploy it across Dev, Test, Staging, and Production without rebuilding.
5. Summary and Key Takeaways
- Transitioning from CI to CD: Phase 1 (CI) successfully compiles, tests, and publishes versioned release artifacts; Phase 2 (CD) automates the delivery and execution of those artifacts onto target infrastructure.
- Eliminating Manual Bottlenecks: Manual SSH hops, jump servers, and manual file downloads are replaced by automated pipeline jobs that push and restart applications seamlessly.
- The Power of Immutable Artifacts: Decoupling the application binary from environment configurations ensures that the exact same
.jarbuilt in CI can be promoted across multiple environments. - Runtime Environment Injection: Shifting database and infrastructure properties from build-time Maven profiles to runtime execution parameters guarantees flexibility and prevents environment-specific build pollution.
- Multi-Environment Scalability: Managing multiple non-production (Dev, Test, Stage) and Production environments becomes maintainable only through automated CD pipelines.
- Production-Ready Workflow: A complete GitLab CI/CD pipeline combines automated building, rigorous testing, secure artifact storage, automated deployment, and post-deployment health validation.