Python CI/CD Pipelines Best Practices¶
Objective: Master senior-level Python CI/CD pipeline patterns for production systems. When you need to build automated testing and deployment pipelines, when you want to implement comprehensive quality gates, when you need enterprise-grade CI/CD strategiesโthese best practices become your weapon of choice.
Core Principles¶
- Automation: Automate all repetitive tasks
- Quality: Implement comprehensive quality gates
- Speed: Optimize for fast feedback loops
- Reliability: Ensure consistent and reliable deployments
- Security: Integrate security scanning and compliance
GitHub Actions Workflows¶
Comprehensive CI Pipeline¶
# python/01-github-actions-ci.py
"""
GitHub Actions CI/CD pipeline patterns and automation
"""
from typing import List, Dict, Any, Optional, Union, Tuple
from dataclasses import dataclass, asdict
from enum import Enum
import yaml
import json
from datetime import datetime, timedelta
import logging
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class PipelineStage(Enum):
"""Pipeline stage enumeration"""
LINT = "lint"
TEST = "test"
BUILD = "build"
SECURITY = "security"
DEPLOY = "deploy"
class GitHubActionsBuilder:
"""GitHub Actions workflow builder"""
def __init__(self, project_name: str):
self.project_name = project_name
self.workflow_config = {}
self.pipeline_metrics = {}
def create_ci_workflow(self, python_version: str = "3.11") -> str:
"""Create comprehensive CI workflow"""
workflow = {
"name": "CI Pipeline",
"on": {
"push": {"branches": ["main", "develop"]},
"pull_request": {"branches": ["main", "develop"]}
},
"env": {
"PYTHON_VERSION": python_version,
"POETRY_VERSION": "1.6.1"
},
"jobs": {
"lint": {
"runs-on": "ubuntu-latest",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Python", "uses": "actions/setup-python@v4", "with": {"python-version": "${{ env.PYTHON_VERSION }}"}},
{"name": "Install Poetry", "uses": "snok/install-poetry@v1", "with": {"version": "${{ env.POETRY_VERSION }}"}},
{"name": "Configure Poetry", "run": "poetry config virtualenvs.create false"},
{"name": "Install dependencies", "run": "poetry install --no-interaction --no-ansi"},
{"name": "Run Black", "run": "poetry run black --check --diff ."},
{"name": "Run isort", "run": "poetry run isort --check-only --diff ."},
{"name": "Run Flake8", "run": "poetry run flake8 ."},
{"name": "Run MyPy", "run": "poetry run mypy ."}
]
},
"test": {
"runs-on": "ubuntu-latest",
"strategy": {"matrix": {"python-version": ["3.9", "3.10", "3.11"]}},
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Python", "uses": "actions/setup-python@v4", "with": {"python-version": "${{ matrix.python-version }}"}},
{"name": "Install Poetry", "uses": "snok/install-poetry@v1", "with": {"version": "${{ env.POETRY_VERSION }}"}},
{"name": "Configure Poetry", "run": "poetry config virtualenvs.create false"},
{"name": "Install dependencies", "run": "poetry install --no-interaction --no-ansi"},
{"name": "Run tests", "run": "poetry run pytest --cov=app --cov-report=xml --cov-report=html"},
{"name": "Upload coverage", "uses": "codecov/codecov-action@v3", "with": {"file": "./coverage.xml"}}
]
},
"security": {
"runs-on": "ubuntu-latest",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Python", "uses": "actions/setup-python@v4", "with": {"python-version": "${{ env.PYTHON_VERSION }}"}},
{"name": "Install dependencies", "run": "pip install safety bandit"},
{"name": "Run Safety", "run": "safety check"},
{"name": "Run Bandit", "run": "bandit -r . -f json -o bandit-report.json"},
{"name": "Upload security report", "uses": "actions/upload-artifact@v3", "with": {"name": "security-report", "path": "bandit-report.json"}}
]
},
"build": {
"runs-on": "ubuntu-latest",
"needs": ["lint", "test", "security"],
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Docker Buildx", "uses": "docker/setup-buildx-action@v3"},
{"name": "Login to Docker Hub", "uses": "docker/login-action@v3", "with": {"username": "${{ secrets.DOCKER_USERNAME }}", "password": "${{ secrets.DOCKER_PASSWORD }}"}},
{"name": "Build and push", "uses": "docker/build-push-action@v5", "with": {
"context": ".",
"push": True,
"tags": "${{ github.repository }}:${{ github.sha }},${{ github.repository }}:latest",
"cache-from": "type=gha",
"cache-to": "type=gha,mode=max"
}}
]
}
}
}
return yaml.dump(workflow, default_flow_style=False, sort_keys=False)
def create_cd_workflow(self, environment: str = "production") -> str:
"""Create CD workflow for deployment"""
workflow = {
"name": f"CD Pipeline - {environment.title()}",
"on": {
"push": {"branches": ["main"]},
"workflow_dispatch": {"inputs": {"environment": {"description": "Environment to deploy to", "required": True, "default": environment}}}
},
"env": {
"ENVIRONMENT": environment,
"REGISTRY": "ghcr.io"
},
"jobs": {
"deploy": {
"runs-on": "ubuntu-latest",
"environment": environment,
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up kubectl", "uses": "azure/setup-kubectl@v3", "with": {"version": "latest"}},
{"name": "Configure AWS credentials", "uses": "aws-actions/configure-aws-credentials@v4", "with": {
"aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}",
"aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}",
"aws-region": "us-west-2"
}},
{"name": "Update kubeconfig", "run": "aws eks update-kubeconfig --region us-west-2 --name ${{ secrets.EKS_CLUSTER_NAME }}"},
{"name": "Deploy to Kubernetes", "run": f"kubectl apply -f k8s/{environment}/"},
{"name": "Wait for deployment", "run": "kubectl rollout status deployment/${{ github.event.repository.name }} -n ${{ env.ENVIRONMENT }}"},
{"name": "Run smoke tests", "run": "python scripts/smoke_tests.py --environment ${{ env.ENVIRONMENT }}"}
]
}
}
}
return yaml.dump(workflow, default_flow_style=False, sort_keys=False)
def create_release_workflow(self) -> str:
"""Create release workflow"""
workflow = {
"name": "Release Pipeline",
"on": {
"push": {"tags": ["v*"]},
"workflow_dispatch": {"inputs": {"version": {"description": "Version to release", "required": True, "type": "string"}}}
},
"jobs": {
"release": {
"runs-on": "ubuntu-latest",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Python", "uses": "actions/setup-python@v4", "with": {"python-version": "3.11"}},
{"name": "Install Poetry", "uses": "snok/install-poetry@v1"},
{"name": "Configure Poetry", "run": "poetry config virtualenvs.create false"},
{"name": "Install dependencies", "run": "poetry install --no-interaction --no-ansi"},
{"name": "Build package", "run": "poetry build"},
{"name": "Publish to PyPI", "run": "poetry publish", "env": {"POETRY_PYPI_TOKEN_PYPI": "${{ secrets.PYPI_TOKEN }}"}},
{"name": "Create GitHub Release", "uses": "actions/create-release@v1", "env": {"GITHUB_TOKEN": "${{ secrets.GITHUB_TOKEN }}"}, "with": {
"tag_name": "${{ github.ref }}",
"release_name": "Release ${{ github.ref }}",
"draft": False,
"prerelease": False
}}
]
}
}
}
return yaml.dump(workflow, default_flow_style=False, sort_keys=False)
def create_quality_gates(self) -> str:
"""Create quality gates workflow"""
workflow = {
"name": "Quality Gates",
"on": {"pull_request": {"branches": ["main"]}},
"jobs": {
"quality-gates": {
"runs-on": "ubuntu-latest",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Python", "uses": "actions/setup-python@v4", "with": {"python-version": "3.11"}},
{"name": "Install dependencies", "run": "pip install -r requirements.txt"},
{"name": "Run tests", "run": "pytest --cov=app --cov-fail-under=80"},
{"name": "Run security scan", "run": "bandit -r . -f json -o bandit-report.json"},
{"name": "Check dependencies", "run": "safety check"},
{"name": "Run performance tests", "run": "pytest tests/performance/ -v"},
{"name": "Upload quality report", "uses": "actions/upload-artifact@v3", "with": {"name": "quality-report", "path": "bandit-report.json"}}
]
}
}
}
return yaml.dump(workflow, default_flow_style=False, sort_keys=False)
class GitLabCIPipeline:
"""GitLab CI/CD pipeline builder"""
def __init__(self, project_name: str):
self.project_name = project_name
self.pipeline_config = {}
def create_gitlab_ci(self) -> str:
"""Create GitLab CI configuration"""
gitlab_ci = {
"stages": ["lint", "test", "security", "build", "deploy"],
"variables": {
"PYTHON_VERSION": "3.11",
"PIP_CACHE_DIR": "$CI_PROJECT_DIR/.cache/pip"
},
"cache": {
"paths": [".cache/pip", "venv/"]
},
"before_script": [
"python -m venv venv",
"source venv/bin/activate",
"pip install --upgrade pip"
],
"lint": {
"stage": "lint",
"script": [
"pip install black isort flake8 mypy",
"black --check --diff .",
"isort --check-only --diff .",
"flake8 .",
"mypy ."
],
"artifacts": {"reports": {"junit": "junit.xml"}}
},
"test": {
"stage": "test",
"script": [
"pip install -r requirements.txt",
"pytest --cov=app --cov-report=xml --cov-report=html --junitxml=junit.xml"
],
"coverage": "/TOTAL.*\\s+(\\d+%)$/",
"artifacts": {
"reports": {
"junit": "junit.xml",
"cobertura": "coverage.xml"
},
"paths": ["htmlcov/"]
}
},
"security": {
"stage": "security",
"script": [
"pip install safety bandit",
"safety check",
"bandit -r . -f json -o bandit-report.json"
],
"artifacts": {"reports": {"sast": "bandit-report.json"}}
},
"build": {
"stage": "build",
"script": [
"docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .",
"docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
],
"only": ["main", "develop"]
},
"deploy:staging": {
"stage": "deploy",
"script": [
"kubectl apply -f k8s/staging/",
"kubectl rollout status deployment/$CI_PROJECT_NAME -n staging"
],
"environment": {"name": "staging", "url": "https://staging.example.com"},
"only": ["develop"]
},
"deploy:production": {
"stage": "deploy",
"script": [
"kubectl apply -f k8s/production/",
"kubectl rollout status deployment/$CI_PROJECT_NAME -n production"
],
"environment": {"name": "production", "url": "https://example.com"},
"only": ["main"],
"when": "manual"
}
}
return yaml.dump(gitlab_ci, default_flow_style=False, sort_keys=False)
class JenkinsPipeline:
"""Jenkins pipeline builder"""
def __init__(self, project_name: str):
self.project_name = project_name
self.jenkins_config = {}
def create_jenkinsfile(self) -> str:
"""Create Jenkinsfile for pipeline"""
jenkinsfile = """pipeline {
agent any
environment {
PYTHON_VERSION = '3.11'
DOCKER_REGISTRY = 'your-registry.com'
KUBECONFIG = credentials('kubeconfig')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Lint') {
steps {
sh 'python -m venv venv'
sh 'source venv/bin/activate && pip install black isort flake8 mypy'
sh 'source venv/bin/activate && black --check --diff .'
sh 'source venv/bin/activate && isort --check-only --diff .'
sh 'source venv/bin/activate && flake8 .'
sh 'source venv/bin/activate && mypy .'
}
}
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'source venv/bin/activate && pytest tests/unit/ --cov=app --cov-report=xml'
}
}
stage('Integration Tests') {
steps {
sh 'source venv/bin/activate && pytest tests/integration/ --cov=app --cov-report=xml'
}
}
}
post {
always {
publishCoverage adapters: [coberturaAdapter('coverage.xml')], sourceFileResolver: sourceFiles('STORE_LAST_BUILD')
}
}
}
stage('Security') {
steps {
sh 'source venv/bin/activate && pip install safety bandit'
sh 'source venv/bin/activate && safety check'
sh 'source venv/bin/activate && bandit -r . -f json -o bandit-report.json'
}
post {
always {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: '.',
reportFiles: 'bandit-report.json',
reportName: 'Security Report'
])
}
}
}
stage('Build') {
steps {
script {
def image = docker.build("${DOCKER_REGISTRY}/${env.JOB_NAME}:${env.BUILD_NUMBER}")
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry-credentials') {
image.push()
image.push('latest')
}
}
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh 'kubectl apply -f k8s/production/'
sh 'kubectl rollout status deployment/${JOB_NAME} -n production'
}
}
}
post {
always {
cleanWs()
}
success {
emailext (
subject: "Build Successful: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "Build ${env.BUILD_NUMBER} completed successfully.",
to: "${env.CHANGE_AUTHOR_EMAIL}"
)
}
failure {
emailext (
subject: "Build Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "Build ${env.BUILD_NUMBER} failed. Please check the logs.",
to: "${env.CHANGE_AUTHOR_EMAIL}"
)
}
}
}
"""
return jenkinsfile
class PipelineOptimizer:
"""Pipeline optimization utilities"""
def __init__(self):
self.optimization_metrics = {}
def analyze_pipeline_performance(self, pipeline_data: Dict[str, Any]) -> Dict[str, Any]:
"""Analyze pipeline performance metrics"""
total_duration = 0
stage_durations = {}
for stage, data in pipeline_data.items():
if isinstance(data, dict) and 'duration' in data:
duration = data['duration']
stage_durations[stage] = duration
total_duration += duration
# Calculate optimization opportunities
optimization_suggestions = []
if total_duration > 1800: # 30 minutes
optimization_suggestions.append("Consider parallelizing stages to reduce total duration")
if any(duration > 600 for duration in stage_durations.values()): # 10 minutes
optimization_suggestions.append("Optimize slow stages with caching or better tooling")
return {
"total_duration": total_duration,
"stage_durations": stage_durations,
"optimization_suggestions": optimization_suggestions,
"performance_score": self._calculate_performance_score(total_duration, stage_durations)
}
def _calculate_performance_score(self, total_duration: int, stage_durations: Dict[str, int]) -> float:
"""Calculate pipeline performance score (0-100)"""
# Ideal total duration is under 10 minutes
duration_score = max(0, 100 - (total_duration / 60) * 2)
# Check for balanced stage durations
if stage_durations:
avg_duration = sum(stage_durations.values()) / len(stage_durations)
variance = sum((duration - avg_duration) ** 2 for duration in stage_durations.values()) / len(stage_durations)
balance_score = max(0, 100 - (variance / avg_duration) * 10)
else:
balance_score = 100
return (duration_score + balance_score) / 2
def optimize_pipeline_caching(self, pipeline_config: Dict[str, Any]) -> Dict[str, Any]:
"""Optimize pipeline with caching strategies"""
optimized_config = pipeline_config.copy()
# Add caching for dependencies
if "jobs" in optimized_config:
for job_name, job_config in optimized_config["jobs"].items():
if "steps" in job_config:
# Add cache step for Python dependencies
cache_step = {
"name": "Cache dependencies",
"uses": "actions/cache@v3",
"with": {
"path": "~/.cache/pip",
"key": "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}",
"restore-keys": "${{ runner.os }}-pip-"
}
}
# Insert cache step after checkout
steps = job_config["steps"]
for i, step in enumerate(steps):
if step.get("uses") == "actions/checkout@v4":
steps.insert(i + 1, cache_step)
break
return optimized_config
def create_parallel_jobs(self, jobs: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Create parallel job configuration"""
parallel_jobs = {}
for job in jobs:
job_name = job["name"]
job_config = job["config"]
# Add parallel execution
if "strategy" not in job_config:
job_config["strategy"] = {"matrix": {"python-version": ["3.9", "3.10", "3.11"]}}
parallel_jobs[job_name] = job_config
return parallel_jobs
# Usage examples
def example_cicd_pipelines():
"""Example CI/CD pipeline usage"""
# GitHub Actions
github_builder = GitHubActionsBuilder("my-python-app")
# Create CI workflow
ci_workflow = github_builder.create_ci_workflow()
print("GitHub Actions CI workflow created")
# Create CD workflow
cd_workflow = github_builder.create_cd_workflow("production")
print("GitHub Actions CD workflow created")
# Create release workflow
release_workflow = github_builder.create_release_workflow()
print("GitHub Actions release workflow created")
# GitLab CI
gitlab_builder = GitLabCIPipeline("my-python-app")
gitlab_ci = gitlab_builder.create_gitlab_ci()
print("GitLab CI configuration created")
# Jenkins
jenkins_builder = JenkinsPipeline("my-python-app")
jenkinsfile = jenkins_builder.create_jenkinsfile()
print("Jenkins pipeline created")
# Pipeline optimization
optimizer = PipelineOptimizer()
# Analyze performance
pipeline_data = {
"lint": {"duration": 120},
"test": {"duration": 300},
"build": {"duration": 180},
"deploy": {"duration": 240}
}
performance_analysis = optimizer.analyze_pipeline_performance(pipeline_data)
print(f"Pipeline performance analysis: {performance_analysis}")
# Optimize caching
optimized_config = optimizer.optimize_pipeline_caching({"jobs": {}})
print("Pipeline caching optimized")
Advanced Pipeline Patterns¶
# python/02-advanced-pipeline-patterns.py
"""
Advanced CI/CD pipeline patterns and automation strategies
"""
from typing import List, Dict, Any, Optional, Union, Tuple
import yaml
import json
from datetime import datetime, timedelta
import logging
logger = logging.getLogger(__name__)
class AdvancedPipelineBuilder:
"""Advanced pipeline builder with enterprise patterns"""
def __init__(self, project_name: str):
self.project_name = project_name
self.pipeline_templates = {}
def create_multi_environment_pipeline(self) -> str:
"""Create multi-environment deployment pipeline"""
pipeline = {
"name": "Multi-Environment Pipeline",
"on": {
"push": {"branches": ["main", "develop", "feature/*"]},
"pull_request": {"branches": ["main", "develop"]}
},
"jobs": {
"determine-environment": {
"runs-on": "ubuntu-latest",
"outputs": {
"environment": "${{ steps.env.outputs.environment }}",
"deploy": "${{ steps.env.outputs.deploy }}"
},
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Determine Environment", "id": "env", "run": """
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "environment=production" >> $GITHUB_OUTPUT
echo "deploy=true" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then
echo "environment=staging" >> $GITHUB_OUTPUT
echo "deploy=true" >> $GITHUB_OUTPUT
else
echo "environment=development" >> $GITHUB_OUTPUT
echo "deploy=false" >> $GITHUB_OUTPUT
fi
"""}
]
},
"quality-gates": {
"runs-on": "ubuntu-latest",
"needs": "determine-environment",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Python", "uses": "actions/setup-python@v4", "with": {"python-version": "3.11"}},
{"name": "Install dependencies", "run": "pip install -r requirements.txt"},
{"name": "Run tests", "run": "pytest --cov=app --cov-fail-under=80"},
{"name": "Run security scan", "run": "bandit -r . -f json -o bandit-report.json"},
{"name": "Run performance tests", "run": "pytest tests/performance/ -v"}
]
},
"build-and-push": {
"runs-on": "ubuntu-latest",
"needs": ["determine-environment", "quality-gates"],
"if": "needs.determine-environment.outputs.deploy == 'true'",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up Docker Buildx", "uses": "docker/setup-buildx-action@v3"},
{"name": "Login to Registry", "uses": "docker/login-action@v3", "with": {
"registry": "ghcr.io",
"username": "${{ github.actor }}",
"password": "${{ secrets.GITHUB_TOKEN }}"
}},
{"name": "Build and push", "uses": "docker/build-push-action@v5", "with": {
"context": ".",
"push": True,
"tags": f"ghcr.io/${{{{ github.repository }}}}:${{{{ needs.determine-environment.outputs.environment }}}}-${{{{ github.sha }}}}}",
"cache-from": "type=gha",
"cache-to": "type=gha,mode=max"
}}
]
},
"deploy": {
"runs-on": "ubuntu-latest",
"needs": ["build-and-push"],
"if": "needs.determine-environment.outputs.deploy == 'true'",
"environment": "${{ needs.determine-environment.outputs.environment }}",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up kubectl", "uses": "azure/setup-kubectl@v3"},
{"name": "Configure AWS credentials", "uses": "aws-actions/configure-aws-credentials@v4", "with": {
"aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}",
"aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}",
"aws-region": "us-west-2"
}},
{"name": "Update kubeconfig", "run": "aws eks update-kubeconfig --region us-west-2 --name ${{ secrets.EKS_CLUSTER_NAME }}"},
{"name": "Deploy", "run": f"kubectl apply -f k8s/${{{{ needs.determine-environment.outputs.environment }}}}/"},
{"name": "Wait for rollout", "run": "kubectl rollout status deployment/${{ github.event.repository.name }} -n ${{ needs.determine-environment.outputs.environment }}"},
{"name": "Run smoke tests", "run": "python scripts/smoke_tests.py --environment ${{ needs.determine-environment.outputs.environment }}"}
]
}
}
}
return yaml.dump(pipeline, default_flow_style=False, sort_keys=False)
def create_blue_green_deployment(self) -> str:
"""Create blue-green deployment pipeline"""
pipeline = {
"name": "Blue-Green Deployment",
"on": {"workflow_dispatch": {"inputs": {"environment": {"description": "Environment", "required": True, "default": "production"}}}},
"jobs": {
"blue-green-deploy": {
"runs-on": "ubuntu-latest",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up kubectl", "uses": "azure/setup-kubectl@v3"},
{"name": "Configure AWS credentials", "uses": "aws-actions/configure-aws-credentials@v4", "with": {
"aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}",
"aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}",
"aws-region": "us-west-2"
}},
{"name": "Update kubeconfig", "run": "aws eks update-kubeconfig --region us-west-2 --name ${{ secrets.EKS_CLUSTER_NAME }}"},
{"name": "Determine current color", "id": "current-color", "run": """
CURRENT_COLOR=$(kubectl get service ${{ github.event.repository.name }}-service -o jsonpath='{.spec.selector.color}' || echo "blue")
echo "color=$CURRENT_COLOR" >> $GITHUB_OUTPUT
if [[ "$CURRENT_COLOR" == "blue" ]]; then
echo "new-color=green" >> $GITHUB_OUTPUT
else
echo "new-color=blue" >> $GITHUB_OUTPUT
fi
"""},
{"name": "Deploy new version", "run": """
NEW_COLOR=${{ steps.current-color.outputs.new-color }}
kubectl apply -f k8s/${{ inputs.environment }}/deployment-$NEW_COLOR.yaml
kubectl rollout status deployment/${{ github.event.repository.name }}-$NEW_COLOR -n ${{ inputs.environment }}
"""},
{"name": "Switch traffic", "run": """
NEW_COLOR=${{ steps.current-color.outputs.new-color }}
kubectl patch service ${{ github.event.repository.name }}-service -p '{"spec":{"selector":{"color":"'$NEW_COLOR'"}}}'
"""},
{"name": "Run health checks", "run": "python scripts/health_checks.py --environment ${{ inputs.environment }}"},
{"name": "Cleanup old version", "run": """
OLD_COLOR=${{ steps.current-color.outputs.color }}
kubectl delete deployment ${{ github.event.repository.name }}-$OLD_COLOR -n ${{ inputs.environment }}
"""}
]
}
}
}
return yaml.dump(pipeline, default_flow_style=False, sort_keys=False)
def create_canary_deployment(self) -> str:
"""Create canary deployment pipeline"""
pipeline = {
"name": "Canary Deployment",
"on": {"workflow_dispatch": {"inputs": {"environment": {"description": "Environment", "required": True, "default": "production"}}}},
"jobs": {
"canary-deploy": {
"runs-on": "ubuntu-latest",
"steps": [
{"uses": "actions/checkout@v4"},
{"name": "Set up kubectl", "uses": "azure/setup-kubectl@v3"},
{"name": "Configure AWS credentials", "uses": "aws-actions/configure-aws-credentials@v4", "with": {
"aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}",
"aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}",
"aws-region": "us-west-2"
}},
{"name": "Update kubeconfig", "run": "aws eks update-kubeconfig --region us-west-2 --name ${{ secrets.EKS_CLUSTER_NAME }}"},
{"name": "Deploy canary", "run": """
kubectl apply -f k8s/${{ inputs.environment }}/canary-deployment.yaml
kubectl rollout status deployment/${{ github.event.repository.name }}-canary -n ${{ inputs.environment }}
"""},
{"name": "Run canary tests", "run": "python scripts/canary_tests.py --environment ${{ inputs.environment }}"},
{"name": "Monitor canary metrics", "run": "python scripts/monitor_canary.py --environment ${{ inputs.environment }} --duration 300"},
{"name": "Promote canary", "run": """
kubectl apply -f k8s/${{ inputs.environment }}/production-deployment.yaml
kubectl rollout status deployment/${{ github.event.repository.name }} -n ${{ inputs.environment }}
"""},
{"name": "Cleanup canary", "run": "kubectl delete deployment ${{ github.event.repository.name }}-canary -n ${{ inputs.environment }}"}
]
}
}
}
return yaml.dump(pipeline, default_flow_style=False, sort_keys=False)
class PipelineMonitoring:
"""Pipeline monitoring and alerting"""
def __init__(self):
self.monitoring_config = {}
def create_monitoring_dashboard(self) -> str:
"""Create monitoring dashboard configuration"""
dashboard = {
"dashboard": {
"title": "CI/CD Pipeline Monitoring",
"panels": [
{
"title": "Pipeline Success Rate",
"type": "stat",
"targets": [
{"expr": "sum(rate(pipeline_runs_total{status=\"success\"}[5m])) / sum(rate(pipeline_runs_total[5m])) * 100"}
]
},
{
"title": "Average Build Duration",
"type": "graph",
"targets": [
{"expr": "avg(pipeline_duration_seconds)"}
]
},
{
"title": "Failed Pipelines",
"type": "table",
"targets": [
{"expr": "pipeline_runs_total{status=\"failure\"}"}
]
}
]
}
}
return json.dumps(dashboard, indent=2)
def create_alerting_rules(self) -> str:
"""Create alerting rules for pipeline monitoring"""
rules = {
"groups": [
{
"name": "pipeline_alerts",
"rules": [
{
"alert": "PipelineFailureRate",
"expr": "sum(rate(pipeline_runs_total{status=\"failure\"}[5m])) / sum(rate(pipeline_runs_total[5m])) > 0.1",
"for": "5m",
"labels": {"severity": "warning"},
"annotations": {"summary": "High pipeline failure rate detected"}
},
{
"alert": "PipelineDurationHigh",
"expr": "avg(pipeline_duration_seconds) > 1800",
"for": "10m",
"labels": {"severity": "warning"},
"annotations": {"summary": "Pipeline duration is unusually high"}
}
]
}
]
}
return yaml.dump(rules, default_flow_style=False, sort_keys=False)
# Usage examples
def example_advanced_pipelines():
"""Example advanced pipeline usage"""
# Advanced pipeline builder
advanced_builder = AdvancedPipelineBuilder("my-python-app")
# Multi-environment pipeline
multi_env_pipeline = advanced_builder.create_multi_environment_pipeline()
print("Multi-environment pipeline created")
# Blue-green deployment
blue_green_pipeline = advanced_builder.create_blue_green_deployment()
print("Blue-green deployment pipeline created")
# Canary deployment
canary_pipeline = advanced_builder.create_canary_deployment()
print("Canary deployment pipeline created")
# Pipeline monitoring
monitoring = PipelineMonitoring()
# Monitoring dashboard
dashboard = monitoring.create_monitoring_dashboard()
print("Monitoring dashboard created")
# Alerting rules
alerting_rules = monitoring.create_alerting_rules()
print("Alerting rules created")
TL;DR Runbook¶
Quick Start¶
# 1. GitHub Actions CI
github_builder = GitHubActionsBuilder("my-app")
ci_workflow = github_builder.create_ci_workflow()
cd_workflow = github_builder.create_cd_workflow("production")
# 2. GitLab CI
gitlab_builder = GitLabCIPipeline("my-app")
gitlab_ci = gitlab_builder.create_gitlab_ci()
# 3. Jenkins Pipeline
jenkins_builder = JenkinsPipeline("my-app")
jenkinsfile = jenkins_builder.create_jenkinsfile()
# 4. Advanced patterns
advanced_builder = AdvancedPipelineBuilder("my-app")
multi_env_pipeline = advanced_builder.create_multi_environment_pipeline()
blue_green_pipeline = advanced_builder.create_blue_green_deployment()
# 5. Pipeline optimization
optimizer = PipelineOptimizer()
performance_analysis = optimizer.analyze_pipeline_performance(pipeline_data)
optimized_config = optimizer.optimize_pipeline_caching(pipeline_config)
Essential Patterns¶
# Complete CI/CD setup
def setup_cicd_pipelines():
"""Setup complete CI/CD pipeline environment"""
# GitHub Actions builder
github_builder = GitHubActionsBuilder("my-app")
# GitLab CI builder
gitlab_builder = GitLabCIPipeline("my-app")
# Jenkins builder
jenkins_builder = JenkinsPipeline("my-app")
# Advanced pipeline builder
advanced_builder = AdvancedPipelineBuilder("my-app")
# Pipeline optimizer
optimizer = PipelineOptimizer()
# Pipeline monitoring
monitoring = PipelineMonitoring()
print("CI/CD pipeline setup complete!")
This guide provides the complete machinery for Python CI/CD pipelines. Each pattern includes implementation examples, automation strategies, and real-world usage patterns for enterprise pipeline management.