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¶
- validate - Code quality checks (linting, formatting, type checking)
- test - Unit and integration tests
- build - Docker image building
- security - Security scanning (SAST, dependency scanning)
- e2e - End-to-end testing
- deploy:qual - Deployment to qualification environment
- 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:¶
Registration¶
- Get the registration token from GitLab:
- Go to your GitLab project
- Navigate to Settings → CI/CD → Runners
- Expand Expand runners settings
-
Copy the Registration token
-
Register the runner:
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 prefixREGISTRY_USER- Registry username (usually GitLab username)REGISTRY_PASSWORD- Registry password (GitLab personal access token)DEPLOY_QUAL_HOST- Qualification VPS hostnameDEPLOY_USER- SSH user for deploymentSSH_PRIVATE_KEY- SSH private key for VPS accessDEPLOY_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¶
- Create feature branch:
git checkout -b feature/my-feature - Make changes and commit
- Push branch:
git push origin feature/my-feature - Pipeline runs automatically (validate, test, build, security)
- Create merge request
- E2E tests run on merge request
- After review, merge to
main - Qualification deployment runs automatically
Hotfix Deployment¶
- Create hotfix branch:
git checkout -b hotfix/critical-fix - Make fix and commit
- Push and create merge request
- After merge to
main, manually trigger production deployment - Monitor deployment logs
Release Process¶
- Create release branch:
git checkout -b release/v1.2.0 - Finalize changes and testing
- Merge to
main - Tag release:
git tag v1.2.0 && git push origin v1.2.0 - 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¶
- Always test locally first - Run tests and builds locally before pushing
- Use feature branches - Never commit directly to
main - Review before merging - Always review merge requests
- Monitor deployments - Watch deployment logs and service health
- Keep secrets secure - Never commit secrets to repository
- Update documentation - Keep docs in sync with pipeline changes