← Portfolio

Full-Stack CI/CD Pipeline with GitLab, Ansible, and DigitalOcean

A production-grade monorepo CI/CD pipeline for a full-stack application featuring independent frontend and backend pipelines, SonarCloud quality gates, Docker image packaging, and Ansible-driven deployments to staging and production environments on DigitalOcean.

gitlab-cidevopsdockeransibledigitaloceansonarclouddevsecopspythonmonorepo

A production-oriented GitLab CI/CD pipeline for a full-stack web application deployed on DigitalOcean. The project demonstrates how a monorepo can support independent, change-driven pipelines per application tier, combining automated testing, static analysis, security scanning, and infrastructure automation to deliver secure and repeatable deployments across staging and production environments.

What it does

The repository is structured as a monorepo containing a frontend and a backend application, each with its own Dockerfile and pipeline definition. A root pipeline acts as an orchestrator: it detects which part of the codebase has changed and triggers only the corresponding child pipeline. A commit touching only the frontend never redeploys the backend, and vice versa.

Each child pipeline runs four stages: test, security, package, and deploy.

The test stage validates the application before any artifact is produced. The backend runs Ruff for linting and Pytest for unit testing, generating a coverage report as output. On the default branch, results are submitted to SonarCloud, which performs static analysis and enforces a quality gate — the pipeline blocks if the gate does not pass. Feature branch pushes skip the SonarCloud upload, as the free tier supports only the default branch, keeping branch pipelines fast without sacrificing quality on the main line.

The security stage integrates GitLab’s managed SAST and Secret Detection templates for both tiers, identifying insecure coding patterns and accidentally committed credentials before any image is built.

The package stage builds the Docker image from the tier’s Dockerfile using the commit SHA or Git tag as the image tag, producing an immutable artifact that is pushed to the GitLab Container Registry. The same image that passed all quality and security gates is the exact image that gets deployed — it is never rebuilt at deploy time.

The deploy stage uses Ansible to automate application delivery over SSH. Ansible connects to the target DigitalOcean droplet, renders environment files and Docker Compose configurations from Jinja2 templates, pulls the validated image from the registry, and restarts only the updated service. After deployment, GitLab performs an automated health check against the environment URL — the backend additionally verifies the /api/healthcheck endpoint — and marks the pipeline as failed if the application is not reachable.

Staging deployments occur automatically when changes land on the default branch. Production deployments are triggered by Git tags.

Tech Stack

  • CI platform: GitLab CI/CD (parent-child pipelines)
  • Frontend: (React / Vue / your framework)
  • Backend: Python (uv, Ruff, Pytest)
  • Containerization: Docker
  • Container registry: GitLab Container Registry
  • Configuration management: Ansible (roles, Jinja2 templates)
  • Infrastructure: DigitalOcean Droplets
  • Code quality: SonarCloud (static analysis, coverage, quality gates)
  • Static security analysis: GitLab SAST
  • Secret detection: GitLab Secret Detection
  • Deployment: SSH-based Ansible automation with Docker Compose
  • Environment management: Jinja2-rendered Compose and env files, host-specific variables

Impact

  • Independent deployability: change-driven pipelines ensure that frontend and backend deployments are fully decoupled, reducing risk and eliminating unnecessary pipeline runs
  • Shift-left quality: linting, unit testing, coverage analysis, and SonarCloud quality gates validate the backend before any artifact is produced, preventing regressions from reaching any environment
  • Shift-left security: SAST and Secret Detection run on every pipeline execution for both tiers, catching vulnerabilities and credential leaks before packaging
  • Immutable artifacts: images are tagged with the commit SHA and never rebuilt at deploy time, providing a clear and traceable link from source code to the running container
  • Infrastructure as code: Ansible roles and Jinja2 templates eliminate manually maintained Compose files on the server, making deployments repeatable, auditable, and environment-agnostic
  • Automated verification: post-deployment health checks confirm that the application is actually serving traffic before the pipeline is marked successful, catching silent startup failures
  • Controlled releases: automatic staging deployments provide rapid feedback after every merge, while tag-based production deployments maintain deliberate control over releases

Results

  • Fully automated CI/CD workflow from commit to deployment across two independent application tiers
  • Separate staging and production environments driven by branch and tag strategy
  • Security and quality validation integrated into every pipeline execution
  • Immutable, registry-backed container deployments with full commit traceability
  • Server configuration managed entirely through Ansible — no manual intervention required after initial setup
  • Production-ready DevSecOps monorepo implementation using GitLab CI/CD, Docker, Ansible, and DigitalOcean