3、Python持续集成与部署

Python持续集成与部署

1. 持续集成(CI)基础

持续集成是一种软件开发实践,团队成员频繁地将代码集成到共享仓库中,每次集成都通过自动化构建和测试进行验证,从而尽早发现集成错误。

1.1 持续集成的核心原则

mindmap root((持续集成
原则)) 频繁提交 每天至少提交一次 小批量提交 自动化构建 一键构建 构建服务器 自动化测试 单元测试 集成测试 快速反馈 构建状态可视化 失败通知 主干开发 避免长期分支 特性开关

1.2 持续集成工作流

sequenceDiagram participant D as 开发者 participant R as 代码仓库 participant CI as CI服务器 D->>D: 本地开发 D->>D: 本地测试 D->>R: 提交代码 R->>CI: 触发CI流程 CI->>CI: 代码检出 CI->>CI: 安装依赖 CI->>CI: 静态代码分析 CI->>CI: 运行测试 CI->>CI: 构建应用 CI->>D: 反馈结果

1.3 常见CI工具

  1. GitHub Actions: GitHub集成的CI/CD服务
  2. GitLab CI/CD: GitLab集成的CI/CD服务
  3. Jenkins: 开源自动化服务器
  4. CircleCI: 云端CI/CD服务
  5. Travis CI: 开源项目流行的CI服务

2. GitHub Actions详解

GitHub Actions是GitHub提供的CI/CD服务,它允许您自动化软件开发工作流程。

2.1 基本概念

  • 工作流(Workflow): 由一个或多个作业组成的可配置自动化过程
  • 事件(Event): 触发工作流的特定活动,如push、pull request等
  • 作业(Job): 在同一运行器上执行的一组步骤
  • 步骤(Step): 可以运行命令或操作的单个任务
  • 操作(Action): 可重用的工作流组件
  • 运行器(Runner): 运行工作流的服务器

2.2 工作流配置文件

GitHub Actions工作流使用YAML文件定义,存储在仓库的.github/workflows目录中。

yaml 复制代码
# .github/workflows/python-ci.yml
name: Python CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main, develop ]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.8, 3.9, 3.10]

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install flake8 pytest
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    - name: Lint with flake8
      run: |
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
    - name: Test with pytest
      run: |
        pytest

2.3 高级功能

矩阵构建

矩阵构建允许您在不同环境中测试代码:

yaml 复制代码
strategy:
  matrix:
    python-version: [3.8, 3.9, 3.10]
    os: [ubuntu-latest, windows-latest, macos-latest]
缓存依赖

缓存依赖可以加速工作流:

yaml 复制代码
- name: Cache pip dependencies
  uses: actions/cache@v2
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-pip-
工作流之间的数据共享

使用工件(Artifacts)在作业之间共享数据:

yaml 复制代码
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Build package
        run: python setup.py sdist bdist_wheel
      - name: Upload artifacts
        uses: actions/upload-artifact@v2
        with:
          name: dist
          path: dist/
          
  publish:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v2
        with:
          name: dist
          path: dist/
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          password: ${{ secrets.PYPI_API_TOKEN }}
flowchart TD A[构建作业] -->|上传工件| B[工件存储] B -->|下载工件| C[发布作业] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px

3. 持续部署(CD)基础

持续部署是持续集成的扩展,它自动将通过测试的代码部署到生产环境或类生产环境中。

3.1 持续部署流程

graph LR A[代码提交] --> B[持续集成] B --> C{测试通过?} C -->|是| D[自动部署到测试环境] C -->|否| E[通知开发者] D --> F[自动化测试] F --> G{测试通过?} G -->|是| H[自动部署到生产环境] G -->|否| E style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#ffd0e0,stroke:#333,stroke-width:2px style D fill:#d0ffe0,stroke:#333,stroke-width:2px style E fill:#e0d0ff,stroke:#333,stroke-width:2px style F fill:#ffffd0,stroke:#333,stroke-width:2px style G fill:#d0ffff,stroke:#333,stroke-width:2px style H fill:#ffd0ff,stroke:#333,stroke-width:2px

3.2 部署策略

蓝绿部署

蓝绿部署维护两个相同的生产环境,一个活跃(蓝),一个待命(绿)。新版本部署到待命环境,测试通过后,将流量切换到待命环境。

sequenceDiagram participant U as 用户 participant LB as 负载均衡器 participant B as 蓝环境(当前活跃) participant G as 绿环境(待命) U->>LB: 请求 LB->>B: 转发请求 Note over G: 部署新版本 Note over G: 测试新版本 Note over LB: 切换流量 U->>LB: 请求 LB->>G: 转发请求 Note over B: 现在是待命环境
金丝雀部署

金丝雀部署将新版本逐步推送给一小部分用户,然后逐渐增加比例,直到所有用户都使用新版本。

pie title "金丝雀部署流量分配" "新版本" : 10 "旧版本" : 90
pie title "金丝雀部署流量分配(50%)" "新版本" : 50 "旧版本" : 50
pie title "金丝雀部署流量分配(100%)" "新版本" : 100 "旧版本" : 0
滚动部署

滚动部署逐步更新服务实例,一次更新一小部分实例,直到所有实例都更新完成。

graph TD subgraph "步骤1" A1[实例1: 旧版本] A2[实例2: 旧版本] A3[实例3: 旧版本] A4[实例4: 旧版本] end subgraph "步骤2" B1[实例1: 新版本] B2[实例2: 旧版本] B3[实例3: 旧版本] B4[实例4: 旧版本] end subgraph "步骤3" C1[实例1: 新版本] C2[实例2: 新版本] C3[实例3: 旧版本] C4[实例4: 旧版本] end subgraph "步骤4" D1[实例1: 新版本] D2[实例2: 新版本] D3[实例3: 新版本] D4[实例4: 旧版本] end subgraph "步骤5" E1[实例1: 新版本] E2[实例2: 新版本] E3[实例3: 新版本] E4[实例4: 新版本] end A1 --> B1 A2 --> B2 A3 --> B3 A4 --> B4 B1 --> C1 B2 --> C2 B3 --> C3 B4 --> C4 C1 --> D1 C2 --> D2 C3 --> D3 C4 --> D4 D1 --> E1 D2 --> E2 D3 --> E3 D4 --> E4 style A1 fill:#ffe0d0,stroke:#333,stroke-width:2px style A2 fill:#ffe0d0,stroke:#333,stroke-width:2px style A3 fill:#ffe0d0,stroke:#333,stroke-width:2px style A4 fill:#ffe0d0,stroke:#333,stroke-width:2px style B1 fill:#d0ffe0,stroke:#333,stroke-width:2px style B2 fill:#ffe0d0,stroke:#333,stroke-width:2px style B3 fill:#ffe0d0,stroke:#333,stroke-width:2px style B4 fill:#ffe0d0,stroke:#333,stroke-width:2px style C1 fill:#d0ffe0,stroke:#333,stroke-width:2px style C2 fill:#d0ffe0,stroke:#333,stroke-width:2px style C3 fill:#ffe0d0,stroke:#333,stroke-width:2px style C4 fill:#ffe0d0,stroke:#333,stroke-width:2px style D1 fill:#d0ffe0,stroke:#333,stroke-width:2px style D2 fill:#d0ffe0,stroke:#333,stroke-width:2px style D3 fill:#d0ffe0,stroke:#333,stroke-width:2px style D4 fill:#ffe0d0,stroke:#333,stroke-width:2px style E1 fill:#d0ffe0,stroke:#333,stroke-width:2px style E2 fill:#d0ffe0,stroke:#333,stroke-width:2px style E3 fill:#d0ffe0,stroke:#333,stroke-width:2px style E4 fill:#d0ffe0,stroke:#333,stroke-width:2px

4. Python应用部署方案

4.1 Web应用部署

使用Gunicorn和Nginx部署Flask/Django应用
graph LR A[客户端] --> B[Nginx] B --> C[Gunicorn] C --> D[Flask/Django应用] D --> E[数据库] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px style D fill:#ffd0e0,stroke:#333,stroke-width:2px style E fill:#e0d0ff,stroke:#333,stroke-width:2px

部署步骤:

  1. 安装Gunicorn和应用依赖
  2. 配置Gunicorn服务
  3. 配置Nginx作为反向代理
  4. 设置防火墙
  5. 配置SSL证书

Gunicorn服务配置示例(gunicorn.service):

ini 复制代码
[Unit]
Description=Gunicorn instance to serve myapp
After=network.target

[Service]
User=myuser
Group=myuser
WorkingDirectory=/home/myuser/myapp
Environment="PATH=/home/myuser/myapp/venv/bin"
ExecStart=/home/myuser/myapp/venv/bin/gunicorn --workers 3 --bind unix:myapp.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

Nginx配置示例:

nginx 复制代码
server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/myuser/myapp/myapp.sock;
    }
}
使用Docker容器化部署
graph LR A[客户端] --> B[Nginx容器] B --> C[应用容器] C --> D[数据库容器] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px style D fill:#ffd0e0,stroke:#333,stroke-width:2px

Dockerfile示例:

dockerfile 复制代码
FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["gunicorn", "--bind", "0.0.0.0:5000", "wsgi:app"]

docker-compose.yml示例:

yaml 复制代码
version: '3'

services:
  web:
    build: .
    restart: always
    ports:
      - "5000:5000"
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
      
  db:
    image: postgres:13
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
      
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
    depends_on:
      - web

volumes:
  postgres_data:

4.2 Python包发布

发布到PyPI
sequenceDiagram participant D as 开发者 participant B as 构建工具 participant T as TestPyPI participant P as PyPI participant U as 用户 D->>B: 准备包 B->>D: 生成分发包 D->>T: 上传到TestPyPI D->>D: 测试安装 D->>P: 上传到PyPI U->>P: pip install package

准备包的步骤:

  1. 创建setup.py或pyproject.toml
  2. 创建README.md和LICENSE
  3. 创建MANIFEST.in(如果需要)
  4. 构建分发包
  5. 上传到PyPI

setup.py示例:

python 复制代码
from setuptools import setup, find_packages

setup(
    name="mypackage",
    version="0.1.0",
    packages=find_packages(),
    install_requires=[
        "requests>=2.25.0",
        "numpy>=1.20.0",
    ],
    author="Your Name",
    author_email="your.email@example.com",
    description="A short description of your package",
    long_description=open("README.md").read(),
    long_description_content_type="text/markdown",
    url="https://github.com/yourusername/mypackage",
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires=">=3.6",
)

pyproject.toml示例(使用Poetry):

toml 复制代码
[tool.poetry]
name = "mypackage"
version = "0.1.0"
description = "A short description of your package"
authors = ["Your Name <your.email@example.com>"]
readme = "README.md"
repository = "https://github.com/yourusername/mypackage"
license = "MIT"

[tool.poetry.dependencies]
python = "^3.6"
requests = "^2.25.0"
numpy = "^1.20.0"

[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
black = "^21.9b0"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

构建和上传命令:

bash 复制代码
# 使用setuptools
python -m pip install --upgrade pip
pip install setuptools wheel twine
python setup.py sdist bdist_wheel
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
twine upload dist/*

# 使用Poetry
poetry build
poetry publish --repository testpypi
poetry publish
使用GitHub Actions自动发布
yaml 复制代码
# .github/workflows/publish.yml
name: Publish Python Package

on:
  release:
    types: [created]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install setuptools wheel twine
    - name: Build and publish
      env:
        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*

4.3 Serverless部署

AWS Lambda部署
graph LR A[客户端] --> B[API Gateway] B --> C[Lambda函数] C --> D[DynamoDB] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px style D fill:#ffd0e0,stroke:#333,stroke-width:2px

Lambda函数示例:

python 复制代码
import json

def lambda_handler(event, context):
    """
    AWS Lambda函数处理程序
    """
    # 解析请求
    body = json.loads(event.get('body', '{}'))
    name = body.get('name', 'World')
    
    # 处理业务逻辑
    message = f"Hello, {name}!"
    
    # 返回响应
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json'
        },
        'body': json.dumps({
            'message': message
        })
    }

使用Serverless Framework部署:

yaml 复制代码
# serverless.yml
service: my-python-service

provider:
  name: aws
  runtime: python3.9
  region: us-east-1
  
functions:
  hello:
    handler: handler.lambda_handler
    events:
      - http:
          path: hello
          method: post
          cors: true

部署命令:

bash 复制代码
# 安装Serverless Framework
npm install -g serverless

# 部署
serverless deploy

5. 监控与日志

5.1 应用监控

使用Prometheus和Grafana监控Python应用
graph LR A[Python应用] --> B[Prometheus] B --> C[Grafana] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px

Flask应用集成Prometheus示例:

python 复制代码
from flask import Flask
from prometheus_flask_exporter import PrometheusMetrics

app = Flask(__name__)
metrics = PrometheusMetrics(app)

# 静态信息
metrics.info('app_info', 'Application info', version='1.0.0')

@app.route('/')
def main():
    return 'Hello World!'

@app.route('/user/<name>')
@metrics.counter('user_counter', 'Number of user visits', labels={'name': lambda: request.view_args['name']})
def user(name):
    return f'Hello {name}!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')
使用APM(应用性能监控)工具
graph LR A[Python应用] --> B[APM代理] B --> C[APM服务器] C --> D[可视化界面] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px style D fill:#ffd0e0,stroke:#333,stroke-width:2px

使用Elastic APM监控Flask应用示例:

python 复制代码
from flask import Flask
from elasticapm.contrib.flask import ElasticAPM

app = Flask(__name__)

app.config['ELASTIC_APM'] = {
    'SERVICE_NAME': 'my-flask-app',
    'SERVER_URL': 'http://apm-server:8200',
    'ENVIRONMENT': 'production',
}

apm = ElasticAPM(app)

@app.route('/')
def main():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

5.2 日志管理

使用ELK Stack管理日志
graph LR A[Python应用] --> B[Logstash] B --> C[Elasticsearch] C --> D[Kibana] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px style D fill:#ffd0e0,stroke:#333,stroke-width:2px

Python日志配置示例:

python 复制代码
import logging
import logstash

# 创建logger
logger = logging.getLogger('python-logger')
logger.setLevel(logging.INFO)

# 创建logstash处理器
logstash_handler = logstash.TCPLogstashHandler(
    'logstash-host', 5000, version=1)

# 添加处理器到logger
logger.addHandler(logstash_handler)

# 使用logger
logger.info('Python应用启动')
try:
    # 一些可能出错的代码
    result = 1 / 0
except Exception as e:
    logger.error('发生错误', exc_info=True)
使用结构化日志
python 复制代码
import structlog

# 配置结构化日志
structlog.configure(
    processors=[
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer()
    ],
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
)

# 创建logger
logger = structlog.get_logger()

# 使用logger
logger.info("用户登录", user_id="123", ip_address="192.168.1.1")
logger.error("数据库连接失败", db_host="db.example.com", error_code=500)

6. 基础设施即代码(IaC)

6.1 使用Terraform管理云资源

graph LR A[Terraform配置] --> B[Terraform计划] B --> C[Terraform应用] C --> D[云资源] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px style D fill:#ffd0e0,stroke:#333,stroke-width:2px

Terraform配置示例(AWS):

hcl 复制代码
provider "aws" {
  region = "us-east-1"
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  
  tags = {
    Name = "WebServer"
  }
}

resource "aws_s3_bucket" "app_data" {
  bucket = "my-app-data-bucket"
  acl    = "private"
  
  versioning {
    enabled = true
  }
  
  tags = {
    Name = "AppData"
  }
}

6.2 使用Ansible配置服务器

graph LR A[Ansible Playbook] --> B[Ansible控制节点] B --> C[目标服务器1] B --> D[目标服务器2] B --> E[目标服务器3] style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#d0ffe0,stroke:#333,stroke-width:2px style D fill:#d0ffe0,stroke:#333,stroke-width:2px style E fill:#d0ffe0,stroke:#333,stroke-width:2px

Ansible Playbook示例:

yaml 复制代码
---
- name: 配置Web服务器
  hosts: webservers
  become: yes
  
  tasks:
    - name: 安装Python和依赖
      apt:
        name:
          - python3
          - python3-pip
          - nginx
        state: present
        update_cache: yes
        
    - name: 复制应用代码
      copy:
        src: /local/path/to/app
        dest: /var/www/app
        
    - name: 安装Python依赖
      pip:
        requirements: /var/www/app/requirements.txt
        
    - name: 配置Nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/sites-available/default
      notify: 重启Nginx
        
    - name: 启动应用
      systemd:
        name: myapp
        state: started
        enabled: yes
        
  handlers:
    - name: 重启Nginx
      systemd:
        name: nginx
        state: restarted

6.3 使用Docker Compose管理容器

graph TD A[Docker Compose配置] --> B[容器1] A --> C[容器2] A --> D[容器3] B --> E[共享网络] C --> E D --> E style A fill:#d0e0ff,stroke:#333,stroke-width:2px style B fill:#ffe0d0,stroke:#333,stroke-width:2px style C fill:#ffe0d0,stroke:#333,stroke-width:2px style D fill:#ffe0d0,stroke:#333,stroke-width:2px style E fill:#d0ffe0,stroke:#333,stroke-width:2px

Docker Compose配置示例:

yaml 复制代码
version: '3'

services:
  web:
    build: ./web
    ports:
      - "5000:5000"
    depends_on:
      - db
    environment:
      - FLASK_APP=app.py
      - FLASK_ENV=production
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
    volumes:
      - ./web:/app
      
  db:
    image: postgres:13
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
      
  redis:
    image: redis:6
    ports:
      - "6379:6379"

volumes:
  postgres_data:

7. 练习:设置CI/CD流水线

7.1 为Python项目设置GitHub Actions

创建一个简单的Python项目,并为其设置GitHub Actions CI/CD流水线。

项目结构:

markdown 复制代码
my_project/
├── my_package/
│   ├── __init__.py
│   └── main.py
├── tests/
│   ├── __init__.py
│   └── test_main.py
├── .github/
│   └── workflows/
│       └── ci.yml
├── requirements.txt
├── setup.py
└── README.md

main.py:

python 复制代码
def add(a, b):
    """Add two numbers and return the result."""
    return a + b

def subtract(a, b):
    """Subtract b from a and return the result."""
    return a - b

def multiply(a, b):
    """Multiply two numbers and return the result."""
    return a * b

def divide(a, b):
    """Divide a by b and return the result."""
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

test_main.py:

python 复制代码
import unittest
from my_package.main import add, subtract, multiply, divide

class TestMathFunctions(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(1, 2), 3)
        self.assertEqual(add(-1, 1), 0)
        self.assertEqual(add(-1, -1), -2)
        
    def test_subtract(self):
        self.assertEqual(subtract(3, 2), 1)
        self.assertEqual(subtract(2, 3), -1)
        self.assertEqual(subtract(-1, -1), 0)
        
    def test_multiply(self):
        self.assertEqual(multiply(2, 3), 6)
        self.assertEqual(multiply(-2, 3), -6)
        self.assertEqual(multiply(-2, -3), 6)
        
    def test_divide(self):
        self.assertEqual(divide(6, 3), 2)
        self.assertEqual(divide(-6, 3), -2)
        self.assertEqual(divide(-6, -3), 2)
        
        with self.assertRaises(ValueError):
            divide(6, 0)

if __name__ == "__main__":
    unittest.main()

ci.yml:

yaml 复制代码
name: Python CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.8, 3.9, 3.10]

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install flake8 pytest pytest-cov
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        pip install -e .
    - name: Lint with flake8
      run: |
        flake8 my_package tests
    - name: Test with pytest
      run: |
        pytest --cov=my_package tests/
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v1

setup.py:

python 复制代码
from setuptools import setup, find_packages

setup(
    name="my_package",
    version="0.1.0",
    packages=find_packages(),
    install_requires=[],
    author="Your Name",
    author_email="your.email@example.com",
    description="A simple math package",
)

7.2 设置自动部署到PyPI

在上面的CI/CD流水线基础上,添加自动部署到PyPI的功能。

创建一个新的工作流文件.github/workflows/publish.yml:

yaml 复制代码
name: Publish Python Package

on:
  release:
    types: [created]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install setuptools wheel twine
    - name: Build and publish
      env:
        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*

8. 总结

本章介绍了Python持续集成与部署的最佳实践,包括:

  1. 持续集成(CI)基础,包括核心原则、工作流和常见工具
  2. GitHub Actions详解,包括基本概念、工作流配置和高级功能
  3. 持续部署(CD)基础,包括部署流程和不同的部署策略
  4. Python应用部署方案,包括Web应用部署、Python包发布和Serverless部署
  5. 监控与日志,包括应用监控和日志管理
  6. 基础设施即代码(IaC),包括使用Terraform、Ansible和Docker Compose
  7. 通过实践练习设置CI/CD流水线

通过遵循这些最佳实践,您可以建立高效、可靠的软件交付流程,提高开发效率和产品质量。

相关推荐
肩塔didi18 分钟前
用 Pixi 管理 Python 项目:打通Conda 和 PyPI 的边界
后端·python·github
dylan_QAQ33 分钟前
【附录】相对于BeanFactory ,ApplicationContext 做了哪些企业化的增强?
后端·spring
唐诗1 小时前
VMware Mac m系列安装 Windws 11,保姆级教程
前端·后端·github
Lx3521 小时前
Hadoop新手必知的10个高效操作技巧
hadoop·后端
写bug写bug1 小时前
搞懂Spring任务执行器和调度器模型
java·后端·spring
二闹1 小时前
TCP三次握手的智慧:为什么不是两次或四次?
后端·tcp/ip
熊猫片沃子2 小时前
Maven在使用过程中的核心知识点总结
java·后端·maven
集成显卡2 小时前
Rust 实战四 | Traui2+Vue3+Rspack 开发桌面应用:通配符掩码计算器
后端·程序员·rust
苏三说技术2 小时前
糟糕,生产环境频繁Full GC,怎么办?
后端
炸薯人2 小时前
每天一个知识点——Java之CAS操作
后端