This document provides a comprehensive overview of the GitLab CI/CD pipeline for the Python Tornado microservice application.
- Python Microservice Tornado - CI/CD Pipeline Documentation
The CI/CD pipeline automates the build, test, and deployment processes for the Python Tornado microservice. The pipeline is defined in .gitlab/gitlab-ci.yml and consists of multiple stages with jobs distributed across modular configuration files.
.gitlab/
├── ci/
│ ├── app-test.yml # API endpoint testing jobs
│ ├── build.yml # Docker image building jobs
│ ├── compliance.yml # Linting and validation jobs
│ ├── coverage.yml # Code coverage jobs
│ ├── deploy.yml # Deployment jobs
│ └── test.yml # Testing jobs
├── ansible/ # Ansible playbooks for Kubernetes deployment
├── docker/ # Dockerfiles for the application
└── scripts/ # Testing scripts
The pipeline consists of the following stages:
stages:
- compliance
- build
- test
- coverage
- deploy
- app-test
- cleanup
- Compliance: Validates Dockerfile and Ansible playbooks
- Build: Builds Docker images using Kaniko
- Test: Runs security scans, static type checking, linting, and unit tests
- Coverage: Generates and displays code coverage reports
- Deploy: Deploys the application to Kubernetes via Ansible
- App-Test: Tests the deployed application's API endpoints
- Cleanup: Cleans up resources when necessary
The pipeline builds three distinct Docker images:
-
Application Image: Contains the Python microservice
${CI_REGISTRY_IMAGE}:${TAG}- Used for running the application
-
Ansible Image: Contains Ansible and Kubernetes tools
${CI_REGISTRY_IMAGE}:ansible-${TAG}- Used for deployment jobs
-
Coverage Image: Hosts the HTML code coverage report
${CI_REGISTRY_IMAGE}:coverage-${TAG}- Deployed alongside the main application
For tagged commits, images are tagged with the Git tag. For branch commits, images use the branch name as the tag.
The pipeline starts with validation checks:
- docker-lint: Uses Hadolint to validate all Dockerfiles
- ansible-lint: Validates Ansible playbooks for best practices
Images are built using Kaniko, which doesn't require Docker-in-Docker privileges:
build-image:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.23.2-debug
entrypoint: [""]
# ...
script:
- /kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/.gitlab/docker/python/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${TAG}"Multiple test jobs run in parallel:
- python-type-check: Static type checking with MyPy
- python-linter: Code style checking with Flake8
- python-unit-test: Runs unit tests
Docker images are scanned for vulnerabilities using Trivy:
docker-security-scan:
stage: test
image:
name: aquasec/trivy:0.60.0
entrypoint: [""]
# ...
script:
- trivy image "${CI_REGISTRY_IMAGE}:${TAG}" --no-progress --severity CRITICAL --exit-code 1
- trivy image "${CI_REGISTRY_IMAGE}:${TAG}" --no-progress --severity HIGH --exit-code 0The pipeline will fail if CRITICAL vulnerabilities are found, but only reports HIGH vulnerabilities without failing.
Code coverage reports are generated and converted to HTML:
python-code-coverage:
stage: coverage
# ...
script:
- cd src
- coverage run --source=addrservice --branch -m unittest discover tests -p '*_test.py'
- coverage html
- coverage reportCoverage reports are deployed to dedicated endpoints:
- Production:
http://coverage.${KUBE_DOMAIN} - Integration/Preproduction:
http://coverage.${CI_ENVIRONMENT_SLUG}.${KUBE_DOMAIN} - Review:
http://coverage.${CI_ENVIRONMENT_SLUG}.${KUBE_DOMAIN}
Deployments are managed using Ansible playbooks that create Kubernetes resources:
-
Production Deployment
- Triggered by Git tags
- URL:
http://${KUBE_DOMAIN} - 3 pod replicas for high availability
-
Integration/Preproduction Deployment
- Triggered by specific branches
- Integration:
developbranch - Preproduction:
masterbranch
- Integration:
- URL:
http://${CI_ENVIRONMENT_SLUG}.${KUBE_DOMAIN} - 1 pod replica
- Triggered by specific branches
-
Review Deployment
- Triggered by feature branches (branches starting with
feat-) - URL:
http://${CI_ENVIRONMENT_SLUG}.${KUBE_DOMAIN} - 1 pod replica
- Includes cleanup job
- Triggered by feature branches (branches starting with
deploy_production:
stage: deploy
image: ${CI_REGISTRY_IMAGE}:ansible-${TAG}
variables:
TAG: $CI_COMMIT_TAG
rules:
- if: '$CI_COMMIT_TAG'
# ...After deployment, the API endpoints are tested using a bash script:
post-get-test:
stage: app-test
image: curlimages/curl:8.12.1
# ...
script:
- sh .gitlab/scripts/api-test.sh $URL src/data/addresses/namo.json
- sh .gitlab/scripts/api-test.sh $URL src/data/addresses/raga.jsonThe script tests the full CRUD cycle:
- Creates an address entry using POST
- Retrieves the entry using GET
- Deletes the entry using DELETE
- Verifies deletion with GET (expects 404)
Each environment gets its own Kubernetes namespace based on CI_ENVIRONMENT_SLUG. Namespaces are automatically created during deployment and can be cleaned up when environments are stopped.
The Ansible playbooks create several Kubernetes resources:
- Deployments: Define pod configurations and replicas
- Services: Expose pods internally
- Ingress: Configure external access with custom hostnames
- Secrets: Store registry credentials and SSL certificates
For production environments:
replicas: 3 # High availability with multiple replicasFor non-production environments:
replicas: 1 # Single replicaFor review environments, the pipeline includes stop jobs to clean up resources:
stop_review:
stage: deploy
# ...
script:
- cd .gitlab/ansible
- ansible-playbook reset.yml --tags review
environment:
name: review/$TAG
action: stop
when: manualThe pipeline dynamically creates environment URLs:
- Production:
http://${KUBE_DOMAIN} - Non-production:
http://${CI_ENVIRONMENT_SLUG}.${KUBE_DOMAIN} - Coverage reports:
http://coverage.${CI_ENVIRONMENT_SLUG}.${KUBE_DOMAIN}
This CI/CD pipeline ensures that code is thoroughly tested and securely deployed, with comprehensive coverage reporting and automated API testing to validate functionality at every stage.