Skip to content

CI/CD Pipeline Guide

Complete guide to the GitLab CI/CD pipeline for the Portugal Odyssey platform.

Overview

The GitLab CI/CD pipeline automates the entire software delivery process, from code validation to production deployment. It ensures code quality, security, and reliable deployments.

Key Features

  • Automated Code Quality Checks - Linting and type checking for all code
  • Comprehensive Testing - Unit, integration, and E2E tests
  • Security Scanning - SAST, dependency scanning, container scanning, secret detection
  • Docker Image Management - Build, tag, and push to GitLab Container Registry
  • Automated Deployments - SSH-based deployment to qualification and production
  • Parallel Execution - Fast pipeline with parallel job execution

Pipeline Duration

  • Fast path (no changes): ~5-10 minutes
  • Full pipeline: ~20-30 minutes
  • With deployments: ~35-45 minutes

Pipeline Structure

Stages

  1. validate - Code quality checks (linting, formatting, type checking)
  2. test - Unit and integration tests
  3. build - Docker image building
  4. security - Security scanning (SAST, dependency scanning)
  5. e2e - End-to-end testing
  6. deploy:qual - Deployment to qualification environment
  7. deploy:prod - Deployment to production environment (protected)

Branch Strategy (GitHub Flow)

  • main - Production-ready code, triggers production deployment
  • feature/* - Feature branches, run full pipeline except production deployment
  • hotfix/* - Emergency fixes, can deploy directly to production
  • release/* - Release preparation branches

Pipeline Triggers

  • Push to any branch: Runs validate, test, build, security stages
  • Merge Request: Full pipeline including e2e tests
  • Push to main: Full pipeline + deploy to qualification
  • Manual production deployment: Requires maintainer approval

Testing Strategy

Project-Level Testing

Location: tests/integration/

Test Types: - API Integration Tests: Test API Gateway routing to all services - Cross-Service Tests: Verify service interactions - End-to-End Workflows: Complete user journeys

Service-Level Testing

Each service includes: - Unit Tests: Located in services/[service]/test/ or services/[service]/src/**/*.spec.ts - Integration Tests: Service-specific integration tests - E2E Tests: Located in tests/e2e/

Docker Image Management

Image Building

Images are built using multi-stage Dockerfiles: - infrastructure/dockerfiles/nodejs.dev.Dockerfile - Development - infrastructure/dockerfiles/nodejs.qual.Dockerfile - Qualification - infrastructure/dockerfiles/nodejs.prod.Dockerfile - Production

Image Tagging

  • Latest: registry.gitlab.com/group/project/[service]:latest
  • Commit SHA: registry.gitlab.com/group/project/[service]:[sha]
  • Branch: registry.gitlab.com/group/project/[service]:[branch-name]

Container Registry

All images are pushed to GitLab Container Registry: - Registry URL: registry.gitlab.com/portugalodissey/po-platform - Authentication: Via GitLab CI/CD variables

Deployment

Qualification Environment

Trigger: Automatic on push to main branch

Process: 1. Build Docker images 2. Push to registry 3. SSH to VPS 4. Pull images 5. Restart services via Docker Compose

VPS Details: - Host: qual.portugalodyssey.pt - User: root - Path: /opt/po-platform

Production Environment

Trigger: Manual (requires maintainer approval)

Process: Same as qualification, but to production VPS

VPS Details: - Host: prod.portugalodyssey.pt (or same VPS with different network) - User: root - Path: /opt/po-platform

Self-Hosted GitLab Runner Setup

To reduce shared runner compute minutes, you can set up a self-hosted runner on the VPS.

Prerequisites

  • VPS access
  • Root or sudo access
  • GitLab project registration token

Installation

On Ubuntu/Debian:

# Download the GitLab Runner repository
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# Install GitLab Runner
sudo apt-get install gitlab-runner

Verify Installation:

gitlab-runner --version

Registration

  1. Get the registration token from GitLab:
  2. Go to your GitLab project
  3. Navigate to SettingsCI/CDRunners
  4. Expand Expand runners settings
  5. Copy the Registration token

  6. Register the runner:

sudo gitlab-runner register

When prompted, provide: - GitLab URL: https://gitlab.com/ - Registration token: (paste from GitLab UI) - Description: VPS Self-Hosted Runner - Tags: self-hosted,vps,docker (comma-separated) - Executor: docker - Default Docker image: docker:24 - Privileged mode: true (required for Docker-in-Docker)

Configuration

The runner configuration is stored in /etc/gitlab-runner/config.toml.

Key Settings:

concurrent = 4
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "VPS Self-Hosted Runner"
  url = "https://gitlab.com/"
  token = "..."
  executor = "docker"
  [runners.docker]
    image = "docker:24"
    privileged = true
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]

Managing the Runner

# Start runner
sudo gitlab-runner start

# Stop runner
sudo gitlab-runner stop

# Restart runner
sudo gitlab-runner restart

# Check status
sudo gitlab-runner status

# View logs
sudo gitlab-runner --debug run

Troubleshooting

Runner not picking up jobs: - Check runner is online in GitLab UI - Verify tags match job requirements - Check runner logs: sudo gitlab-runner --debug run

Docker-in-Docker issues: - Ensure privileged mode is enabled - Check Docker socket is mounted: /var/run/docker.sock:/var/run/docker.sock

Network issues: - Verify VPS can reach GitLab.com - Check firewall rules - Test connectivity: curl https://gitlab.com

Environment Variables

Required CI/CD Variables

Set these in GitLab project settings → CI/CD → Variables:

  • REGISTRY_IMAGE - Container registry image prefix
  • REGISTRY_USER - Registry username (usually GitLab username)
  • REGISTRY_PASSWORD - Registry password (GitLab personal access token)
  • DEPLOY_QUAL_HOST - Qualification VPS hostname
  • DEPLOY_USER - SSH user for deployment
  • SSH_PRIVATE_KEY - SSH private key for VPS access
  • DEPLOY_PROD_HOST - Production VPS hostname (if different)

Service-Specific Variables

Some services may require additional variables: - Database URLs - API keys - Service-specific secrets

See Environment Variables Reference for complete list.

Common Workflows

Feature Development

  1. Create feature branch: git checkout -b feature/my-feature
  2. Make changes and commit
  3. Push branch: git push origin feature/my-feature
  4. Pipeline runs automatically (validate, test, build, security)
  5. Create merge request
  6. E2E tests run on merge request
  7. After review, merge to main
  8. Qualification deployment runs automatically

Hotfix Deployment

  1. Create hotfix branch: git checkout -b hotfix/critical-fix
  2. Make fix and commit
  3. Push and create merge request
  4. After merge to main, manually trigger production deployment
  5. Monitor deployment logs

Release Process

  1. Create release branch: git checkout -b release/v1.2.0
  2. Finalize changes and testing
  3. Merge to main
  4. Tag release: git tag v1.2.0 && git push origin v1.2.0
  5. Deploy to production

Troubleshooting

Pipeline Failures

Build failures: - Check Dockerfile syntax - Verify base images are available - Review build logs for specific errors

Test failures: - Run tests locally first - Check test environment setup - Review test logs for details

Deployment failures: - Verify SSH access to VPS - Check VPS has required resources - Review deployment logs on VPS

Common Issues

"Image not found" errors: - Verify image was built successfully - Check registry authentication - Ensure image tag matches

"Connection refused" errors: - Check service health on VPS - Verify network configuration - Review Traefik routing

"Permission denied" errors: - Check SSH key permissions - Verify user has required permissions on VPS - Review Docker socket permissions

Best Practices

  1. Always test locally first - Run tests and builds locally before pushing
  2. Use feature branches - Never commit directly to main
  3. Review before merging - Always review merge requests
  4. Monitor deployments - Watch deployment logs and service health
  5. Keep secrets secure - Never commit secrets to repository
  6. Update documentation - Keep docs in sync with pipeline changes

See Also