Tools: Building a Complete CI/CD Pipeline for a Python Application (GitLab + Docker + SonarQube) (2026)
Modern software development relies heavily on automation. Continuous Integration and Continuous Deployment (CI/CD) pipelines help ensure that code is tested, analyzed, and deployed reliably with minimal manual intervention. In this article, weβll walk through how to build a simple yet effective CI/CD pipeline for a Python application using: GitLab CI/CDDockerSonarQubePytestπ§ Why CI/CD Matters A well-designed CI/CD pipeline allows you to: Automatically run tests on every code changeEnsure consistent and reproducible deploymentsDetect bugs and code quality issues earlyReduce manual errors during deployment The goal is simple: deliver reliable software faster and safer. Hereβs a typical structure for a Python project with CI/CD: project/βββ app.pyβββ requirements.txtβββ tests/β βββ test_app.pyβββ Dockerfileβββ .gitlab-ci.ymlβββ sonar-project.propertiesπ Step 1 β Python Applicationapp.pyfrom flask import Flask, jsonifyimport os @app.route("/")def home(): return jsonify({"message": "Hello from CI/CD pipeline", "status": "ok"}) @app.route("/health")def health(): return jsonify({"service": "up"}), 200 @app.route("/config")def config(): env = os.getenv("APP_ENV", "dev") return jsonify({"environment": env}) if name == "main": app.run(host="0.0.0.0", port=5000)π§ͺ Step 2 β Automated Teststests/test_app.pyfrom app import app def test_home(): client = app.test_client() response = client.get("/") assert response.status_code == 200 def test_health(): client = app.test_client() response = client.get("/health") assert response.status_code == 200requirements.txtflaskpytestπ³ Step 3 β Dockerizing the ApplicationDockerfileFROM python:3.11-slim COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt ENV APP_ENV=production CMD ["python", "app.py"]Why Docker? Docker ensures that your application runs in a consistent environment, regardless of where it's deployed. βοΈ Step 4 β GitLab CI/CD Pipeline.gitlab-ci.ymlstages: variables: IMAGE_NAME: python-app CONTAINER_NAME: python-app-dev run_tests: stage: test script: - pip install -r requirements.txt - pytest build_image: stage: build script: - docker build --network=host -t $IMAGE_NAME:latest . sonarqube_check: stage: sonarqube image: name: sonarsource/sonar-scanner-cli:latest entrypoint: [""] script: - sonar-scanner allow_failure: true deploy_dev: stage: deploy script: - docker stop $CONTAINER_NAME || true - docker rm $CONTAINER_NAME || true - docker run -d --network host --name $CONTAINER_NAME $IMAGE_NAME:latest needs: ["run_tests", "build_image"]π Step 5 β Code Quality with SonarQubesonar-project.propertiessonar.projectKey=python-appsonar.projectName=python-appsonar.sources=.sonar.tests=testssonar.qualitygate.wait=true SonarQube performs static code analysis, helping detect: BugsCode smellsMaintainability issuesPotential vulnerabilitiesπ Pipeline Workflow The pipeline follows a simple and effective flow: Test β Build β Analyze β Deploy Runs automated tests using pytest. Creates a Docker image of the application. Uses SonarQube to evaluate code quality. Stops the previous container and deploys a new version. π DevSecOps Considerations Security should be integrated early in the development lifecycle. This pipeline introduces basic DevSecOps practices by: Validating code through automated testsPerforming static analysis with SonarQubeStructuring the pipeline to prevent unsafe deployments For production environments, this can be extended with: Dependency vulnerability scanningDocker image scanning (e.g., Trivy)Secret management solutionsβ οΈ Limitations This setup is intentionally simple and may have limitations: No staging environmentNo rollback mechanismBasic security checksSingle-container deploymentπ Possible Improvements To make this pipeline production-ready, you could: Add a linting stage (e.g., flake8)Enforce SonarQube quality gatesIntroduce multiple environments (dev / staging / prod)Use Docker Compose or KubernetesAdd automated security scansImplement CI/CD variables and secret managementπ§Ύ Conclusion This CI/CD pipeline demonstrates how to automate the full lifecycle of a Python application: TestingBuildingQuality analysisDeployment Even with a simple setup, you can significantly improve reliability, consistency, and development speed. CI/CD is not about complexity β it's about automation, confidence, and repeatability. Start simple. Make it work. Then improve it. Thatβs the real DevOps mindset. Templates let you quickly answer FAQs or store snippets for re-use. as well , this person and/or