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

StageDescriptionFailure Behavior
1. Unit TestingInstall dependencies and run unit testsStops on failure
2. Code CoverageParallel jobs: test-report & coverage-analysisCoverage errors ignored
3. ContainerizationBuild, smoke-test, and push Docker imageStops on failure
4. Deploy to DevelopmentApply Kubernetes manifests to the dev cluster and fetch ingress URLStops on failure
5. Integration TestingVerify service health via the dev endpointStops on failure
6. Manual ApprovalHuman gate before production deploymentPauses pipeline until approved
7. Deploy to ProductionApply manifests to the prod cluster and fetch ingress URLStops on failure
8. Post-Deployment Integration TestingValidate production health via the live endpointStops 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

Watch Video

Watch video content

Previous
Run and Test NodeJS App on Local Machine