GitLab CI/CD: Architecting, Deploying, and Optimizing Pipelines

Continuous Integration with GitLab

Project Status Meeting 2

Welcome to the second project status meeting! In this session, we’ll investigate how our CI/CD pipeline inadvertently hit the production database and refactor it to use a dedicated test instance.


The Issue: Tests Pointing at Production

After wrapping up the first three tasks, Alice was pulled into an urgent meeting. Monitoring alerts revealed that the production MongoDB cluster had become sluggish and occasionally unresponsive—right after the team enabled GitLab CI/CD pipelines.

Reviewing the pipeline, Alice saw two test jobs both connecting directly to the production database via environment variables:

variables:
  MONGO_URI: 'mongodb+srv://supercluster.d3jj.mongodb.net/superData'
  MONGO_USERNAME: superuser
  MONGO_PASSWORD: $M_DB_PASSWORD

unit_testing:
  stage: test
  image: node:17-alpine3.14
  cache:
    key:
      files:
        - package-lock.json
      prefix: node_modules
  before_script:
    - npm install
  script:
    - npm test
  artifacts:
    when: always
    expire_in: 3 days
    name: Moca-Test-Result
    paths:
      - test-results.xml
    reports:
      junit: test-results.xml

code_coverage:
  stage: test
  image: node:17-alpine3.14
  cache:
    key:
      files:
        - package-lock.json
      prefix: node_modules
  before_script:
    - npm install
  script:
    - npm run coverage
  artifacts:
    when: always
    expire_in: 3 days
    name: Coverage-Report
    paths:
      - coverage/

Warning

Never run CI tests against your production database. This can lead to performance degradation, data corruption, and security risks.


Why Use a Dedicated Test Database?

Running tests against production can:

  • Introduce load and latency for real users.
  • Accidentally modify or delete critical data.
  • Complicate debugging because of shared state.

Instead, spin up an isolated MongoDB instance or use a mock service.


Using GitLab CI Services

GitLab CI/CD supports services—auxiliary containers that start alongside your job. You can:

  • Launch a database container (e.g., mongo:4.4)
  • Seed it with test data in before_script
  • Point your application to localhost or the service alias

Read more in the GitLab Services documentation.

Note

Services are defined per-job. Each service runs in its own Docker container, linked to the job container.


Refactored Pipeline Configuration

Below is a revised .gitlab-ci.yml that replaces the production connection with a local MongoDB service:

variables:
  MONGO_INITDB_DATABASE: testdb
  MONGO_INITDB_ROOT_USERNAME: testuser
  MONGO_INITDB_ROOT_PASSWORD: testpass

.default_test_template: &test_template
  stage: test
  image: node:17-alpine3.14
  services:
    - name: mongo:4.4
      alias: mongo
  before_script:
    - npm install
    - |
      # Wait for MongoDB to be ready
      until mongo --host mongo -u $MONGO_INITDB_ROOT_USERNAME \
        -p $MONGO_INITDB_ROOT_PASSWORD \
        --eval "db.adminCommand('ping')" &>/dev/null; do
        echo "Waiting for MongoDB..."
        sleep 2
      done
    - npm run seed-test-data   # seed-test-data script should populate 'testdb'
  variables:
    MONGO_URI: "mongodb://$MONGO_INITDB_ROOT_USERNAME:$MONGO_INITDB_ROOT_PASSWORD@mongo:27017/$MONGO_INITDB_DATABASE"

unit_testing:
  <<: *test_template
  script:
    - npm test
  artifacts:
    when: always
    expire_in: 3 days
    name: moca-test-result
    paths:
      - test-results.xml
    reports:
      junit: test-results.xml

code_coverage:
  <<: *test_template
  script:
    - npm run coverage
  artifacts:
    when: always
    expire_in: 3 days
    name: coverage-report
    paths:
      - coverage/

Job Configuration Comparison

JobOriginal DBRefactored with Services
unit_testingProduction MongoDB clusterLocal mongo:4.4 service
code_coverageProduction MongoDB clusterLocal mongo:4.4 service

Further Reading and References

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Invalidate Cache