Definition
- CI/CD pipeline – an automated sequence of stages that takes a code change from a developer's commit all the way to a running environment.
- Source – fetch the exact commit that triggered the pipeline.
- Build – compile and assemble the primary artifact (JAR, binary, image).
- Test – run unit and integration tests to validate correctness.
- Package – produce an immutable deployable artifact such as a container image tagged with the commit.
- Scan – run static analysis and vulnerability scanning with quality gates.
- Deploy – push the artifact to an environment (dev, QA, production).
- Verify – run smoke tests and health checks to confirm the deployment is healthy.
Think of the National Bank of India's cheque clearing line. A cheque arrives at the counter (source), is read and stamped (build), verified against the signature and balance (test), sealed into a clearing envelope (package), checked for forgery (scan), sent to the destination branch (deploy), and the destination confirms it landed correctly (verify). Continuous Integration is Rajesh and Priya dropping cheques into the clearing line many times a day with the machine checking each one immediately. Continuous Delivery means every verified cheque is packed and ready at the vault door, but a manager must press the button to release it. Continuous Deployment means the machine releases it automatically.
Understanding the Concepts
What is a CI/CD pipeline?
A CI/CD pipeline is an automated sequence of stages that carries a code change from a developer's commit to a running environment. Each stage gates the next: if a stage fails, the pipeline stops and nothing broken moves forward. The goal is to detect problems as early as possible and to produce a proven, immutable artifact.
# GitHub Actions: a simple CI/CD pipeline for a banking service
name: transfer-service-pipeline
on:
push:
branches: [main]
jobs:
build-test-scan-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # Source
- uses: actions/setup-java@v4 # Build
with: { java-version: '21', distribution: 'temurin' }
- run: mvn clean package # Build + Test
- run: mvn sonar:sonar # Scan (quality gate)
- run: trivy image --severity HIGH,CRITICAL $IMAGE # Scan (CVE)
- run: kubectl set image deployment/transfer-service # Deploy
- run: curl -f https://transfer.bank.local/actuator/health # Verify
What happens at each stage?
The source stage checks out the exact commit. A trigger such as a Git push or a merged pull request causes the CI server to fetch the code at a known SHA so every later stage works on identical code.
The build stage compiles the source and assembles the primary artifact. For a Spring Boot banking service this is usually mvn clean package -DskipTests, which produces a runnable JAR. Separating build from test lets you fail fast on compilation errors.
# Build the banking transfer service
mvn clean package -DskipTests
# Output: target/transfer-service-1.4.2.jar
The test stage runs automated tests. Unit tests run first because they are fast, then integration tests run against a throwaway database spun up with Testcontainers.
# Run unit tests
mvn test
# Run integration tests with Testcontainers Postgres
mvn verify -Pintegration
The package stage produces a deployable unit. In a container world this is building and tagging an image.
# Package as a container image tagged with the commit SHA
docker build -t registry.bank.local/transfer-service:abc1234 .
The scan stage enforces quality and security. SonarQube checks code quality and coverage; Trivy checks for known CVEs.
# Quality gate
mvn sonar:sonar -Dsonar.qualitygate.wait=true
# Vulnerability scan
trivy image --exit-code 1 --severity HIGH,CRITICAL \
registry.bank.local/transfer-service:abc1234
The deploy stage pushes the artifact to an environment.
# Deploy to Kubernetes
kubectl set image deployment/transfer-service \
transfer-service=registry.bank.local/transfer-service:abc1234 \
-n production
The verify stage confirms the deployment is healthy with smoke tests and health checks.
# Health check
curl -f https://transfer.bank.local/actuator/health
# Business smoke test: a test transfer
curl -X POST https://transfer.bank.local/api/transfers \
-d '{"from":"SAV2001","to":"SAV2002","amount":"1.00"}'
What is Continuous Integration?
Continuous Integration is the practice of merging every developer's change frequently and automatically building and testing each merge. The goal is to catch integration problems within minutes, not days.
// Jenkinsfile: CI pipeline triggered on every push
pipeline {
agent any
triggers { githubPush() }
stages {
stage('Build') { steps { sh 'mvn clean compile' } }
stage('Test') { steps { sh 'mvn test' } }
stage('Scan') { steps { sh 'mvn sonar:sonar' } }
}
}
CI stops at a green build and test. It does not deploy to any environment.
What is Continuous Delivery?
Continuous Delivery extends CI so that every passing build is automatically prepared as a release-ready artifact. The final push to production is behind a manual approval gate.
// Jenkinsfile: Continuous Delivery with manual approval before Prod
pipeline {
agent any
stages {
stage('Build & Test') { steps { sh 'mvn clean verify' } }
stage('Package') { steps { sh 'docker build -t $IMAGE .' } }
stage('Deploy QA') { steps { sh 'kubectl apply -f qa/' } }
stage('Approval') {
steps {
input message: 'Deploy to production?',
submitter: 'release-managers'
}
}
stage('Deploy Prod') { steps { sh 'kubectl apply -f prod/' } }
}
}
This is the standard for banking because a human must sign off before touching the live ledger.
What is Continuous Deployment?
Continuous Deployment removes the manual gate entirely. Every green build reaches production automatically with no human approval.
# GitHub Actions: full Continuous Deployment
jobs:
deploy-prod:
needs: [build, test, scan]
runs-on: ubuntu-latest
steps:
- run: kubectl set image deployment/transfer-service $IMAGE
- run: curl -f https://transfer.bank.local/actuator/health
# No manual approval step. Every green build goes to Prod.
How do CI, CD (Delivery), and CD (Deployment) compare?
| Aspect | Continuous Integration | Continuous Delivery | Continuous Deployment |
|---|---|---|---|
| Trigger | Every commit | Every commit | Every commit |
| Build and test | Automated | Automated | Automated |
| Artifact produced | Yes | Yes, release-ready | Yes, release-ready |
| Deploy to staging | Not included | Automated | Automated |
| Deploy to production | Not included | Manual approval | Fully automated |
| Rollback | Not applicable | Manual or automated | Automated |
| Banking suitability | Always | Production (regulated) | Dev and QA environments |
What are common mistakes?
# WRONG: deploying without scanning.
# A vulnerable dependency reaches production.
steps:
- run: mvn clean package
- run: docker build -t $IMAGE .
- run: kubectl apply -f prod/ # No scan, no quality gate!
# CORRECT: scan and gate before deploy.
steps:
- run: mvn clean verify
- run: mvn sonar:sonar -Dsonar.qualitygate.wait=true
- run: docker build -t $IMAGE .
- run: trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE
- run: kubectl apply -f prod/
# WRONG: rebuilding the artifact for each environment.
# What runs in Prod is not what was tested in QA.
steps:
- run: mvn clean package # Build #1 for QA
- run: mvn clean package # Build #2 for Prod -- different!
# CORRECT: build once, promote the same image.
steps:
- run: mvn clean package
- run: docker build -t $IMAGE:$SHA .
# Promote the exact same image to QA, then to Prod.
What should a senior engineer know?
A senior engineer keeps the artifact immutable and traceable. The image is tagged with the commit SHA and promoted unchanged across every environment. This eliminates the classic problem of deploying the wrong version.
Regulated banking systems almost always use Continuous Delivery to production with an approval gate, while using full Continuous Deployment for lower environments like dev and QA.
# Tag with commit SHA for traceability
IMAGE=registry.bank.local/transfer-service:$(git rev-parse --short HEAD)
docker build -t $IMAGE .
docker push $IMAGE
# The same $IMAGE is deployed to dev, QA, and Prod.
The verify stage is not optional. A deploy that is not confirmed healthy is treated as a failure and rolled back automatically.
Visual Overview
Developer pushes code
│
▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ SOURCE │──▶│ BUILD │──▶│ TEST │
│ checkout │ │ compile │ │ unit+int │
└──────────┘ └──────────┘ └──────────┘
│
┌──────────────────────────────┘
▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ PACKAGE │──▶│ SCAN │──▶│ DEPLOY │──▶│ VERIFY │
│ image tag│ │ SonarQube│ │ kubectl │ │ smoke │
│ :abc1234 │ │ Trivy │ │ apply │ │ health │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
CI vs Delivery vs Deployment:
├── CI ──────────────────────┤
│ Build + Test │
│ │
├── Continuous Delivery ─────┼──── Manual Gate ──── Prod
│ Build + Test + Package + │ (approval)
│ Scan + Deploy to staging │
│ │
├── Continuous Deployment ───┼──── Auto ──── Prod
│ Everything automated, │ (no gate)
│ including production │
Key Takeaway
A CI/CD pipeline is an automated sequence that carries a code change from commit to a running environment through well-defined stages. Each stage gates the next, so a failure stops promotion immediately and nothing broken moves forward. The stages are source, build, test, package, scan, deploy, and verify, and the key design principle is fail fast and promote only what is proven.
The three terms are often confused. Continuous Integration is the discipline of merging every change frequently and automatically building and testing it, catching integration problems within minutes. Continuous Delivery extends that so every passing build is release-ready, but production stays behind a manual approval. Continuous Deployment removes even that gate and releases every green build straight to production. In banking, production uses Continuous Delivery with a human gate while lower environments use full Continuous Deployment.
The most important practice is that the artifact must be immutable and traceable. The image is tagged with the commit SHA, built once, and promoted unchanged through every environment. This eliminates the classic problem of deploying something different from what was tested.
Remember one sentence: CI proves the code works, Delivery keeps it ready behind a button, and Deployment presses that button automatically.
---