GitLab CI/CD: Architecting, Deploying, and Optimizing Pipelines
Continuous Integration with GitLab
Understanding XYZ Team DevOps Pipeline
In this guide, we’ll walk through the GitLab CI/CD workflow for building, testing, and deploying the XYZ team’s Node.js application. Every commit in the GitLab repository triggers a sequence of automated stages—running tests, measuring code coverage, building Docker images, and deploying to Kubernetes clusters—culminating in manual approval and production rollout.
Pipeline Overview
Stage | Description | Failure Behavior |
---|---|---|
1. Unit Testing | Install dependencies and run unit tests | Stops on failure |
2. Code Coverage | Parallel jobs: test-report & coverage-analysis | Coverage errors ignored |
3. Containerization | Build, smoke-test, and push Docker image | Stops on failure |
4. Deploy to Development | Apply Kubernetes manifests to the dev cluster and fetch ingress URL | Stops on failure |
5. Integration Testing | Verify service health via the dev endpoint | Stops on failure |
6. Manual Approval | Human gate before production deployment | Pauses pipeline until approved |
7. Deploy to Production | Apply manifests to the prod cluster and fetch ingress URL | Stops on failure |
8. Post-Deployment Integration Testing | Validate production health via the live endpoint | Stops on failure |
1. Unit Testing
Install dependencies with npm and execute all unit tests. Any failure aborts the pipeline immediately.
# Install dependencies
npm install
# Run unit tests
npm test
# (Optional) Archive or download test reports
Note
Store your test reports (e.g., JUnit XML) as artifacts for later analysis or reporting.
2. Code Coverage
Run two parallel jobs:
- Test Report: Fails on test errors.
- Coverage Analysis: Runs coverage but ignores errors to avoid blocking downstream stages.
# Job A: Test Report
npm install
npm test
# Job B: Coverage Analysis (errors ignored)
npm install
npm run coverage
# Archive coverage-report artifact
Note
Ignoring coverage errors ensures that a slight dip in metrics doesn’t halt deployments.
3. Containerization
Build and push a Docker image tagged with the commit SHA. Optionally, smoke-test the container before pushing.
# Build image
docker build -t myregistry/xyz-app:${CI_COMMIT_SHA} .
# Optional smoke test
docker run --rm myregistry/xyz-app:${CI_COMMIT_SHA} npm test
# Push to registry
docker push myregistry/xyz-app:${CI_COMMIT_SHA}
4. Deploy to Development
Apply Kubernetes manifests to the development cluster and retrieve the ingress hostname.
# Apply manifests to dev context
kubectl apply -f k8s/ --context dev
# Fetch Dev ingress URL
INGRESS_URL=$(kubectl get ingress xyz-app-ingress \
--context dev \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo "Dev URL: https://${INGRESS_URL}"
Note
Ensure your kubeconfig is configured with the dev
context. See Kubernetes docs.
5. Integration Testing
Validate the development deployment by hitting the health endpoint.
curl --fail https://${INGRESS_URL}/live
6. Manual Approval
A developer or reviewer must approve the pipeline before production rollout. If declined, the pipeline stops here.
Warning
Do not skip this step. Manual gates help prevent unintended production changes.
7. Deploy to Production
Once approved, deploy the same manifests to the production cluster.
kubectl apply -f k8s/ --context prod
INGRESS_URL=$(kubectl get ingress xyz-app-ingress \
--context prod \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo "Prod URL: https://${INGRESS_URL}"
8. Post-Deployment Integration Testing
Confirm that the production service is live and healthy.
curl --fail https://${INGRESS_URL}/live
Commands Summary
# 1. Unit Testing
npm install
npm test
# 2. Code Coverage (parallel jobs)
npm install && npm test # Test Report
npm install && npm run coverage # Coverage Analysis (ignored errors)
# 3. Containerization
docker build -t myregistry/xyz-app:${CI_COMMIT_SHA} .
docker run --rm myregistry/xyz-app:${CI_COMMIT_SHA} npm test
docker push myregistry/xyz-app:${CI_COMMIT_SHA}
# 4. Deploy to Dev
kubectl apply -f k8s/ --context dev
INGRESS_URL=$(kubectl get ingress xyz-app-ingress \
--context dev \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
curl --fail https://${INGRESS_URL}/live
# 6. Deploy to Prod
kubectl apply -f k8s/ --context prod
INGRESS_URL=$(kubectl get ingress xyz-app-ingress \
--context prod \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
curl --fail https://${INGRESS_URL}/live
Links and References
Watch Video
Watch video content