欢迎来到"Python教程从零基础到实战"系列的第十八期!
学了这么多期,你掌握了 FastAPI 写后端、学了异步编程、也了解了微服务架构。但还有一个关键环节我们一直没有深入:**你怎么把自己的代码从本地优雅地发布到服务器上?**
这就是 CI/CD(持续集成 / 持续交付)和 DevOps 要解决的问题。在这一期里,我们会从零开始搭建一套自动化流程——代码一提交,就自动跑测试、检查质量、构建镜像,最后部署到云端。
准备好了吗?让我们从"写代码的人"变成"交付价值的人"。
---
## 一、什么是 CI/CD 和 DevOps?
### 先搞清楚三个缩写
**CI(Continuous Integration,持续集成)**:每次你往代码仓库推送修改时,自动触发一系列操作——拉取最新代码、安装依赖、运行测试、生成报告。如果任何一步失败,你就立刻知道,而不是等到上线那天才出丑。
**CD(Continuous Delivery / Deployment,持续交付 / 持续部署)**:测试通过了怎么办?自动把构建产物推送到某个环境——先是预发环境,确认没问题后再推到生产环境。整个流程不用你手动点按钮。
**DevOps(Development + Operations,研发运维一体化)**:这不是一个工具,而是一种文化。核心思想是让开发人员对自己写的代码负全责——从开发、测试、部署到上线后的监控,全流程打通。
### 为什么这些对你重要?
你可能觉得:"我只是个学 Python 的初学者,搞什么 DevOps?"
说实话,**越早接触 CI/CD,你的代码水平提升越快**。因为你需要思考的可不仅是"这个功能能不能跑",而是"这个功能怎么可靠地交付"。这正是初级工程师和中级工程师的分水岭。
---
## 二、GitHub Actions:你的第一个 CI/CD 流水线
### 2.1 什么是 GitHub Actions?
GitHub Actions 是 GitHub 提供的自动化平台。当你在仓库里发生某些事件(比如 push 代码、创建 PR)时,它可以自动运行你定义的脚本。
关键概念:
-**Workflow(工作流)**:整个自动化流程的配置文件,放在 `.github/workflows/` 目录下。
-**Job(任务)**:工作流中的一组步骤,所有步骤并行执行。
-**Step(步骤)**:Job 中的每一步操作,可以是一条命令或者一个 Action。
-**Runner(运行器)**:执行 workflow 的环境,GitHub 提供 Ubuntu/macOS/Windows 虚拟机。
### 2.2 第一个 Workflow:运行测试
假设你有一个 FastAPI 项目,目录结构如下:
```
my-fastapi-app/
├── main.py
├── requirements.txt
├── tests/
│ ├── test_main.py
│ └── conftest.py
├── .github/
│ └── workflows/
│ └── ci.yml # ← 我们的 workflow 文件
└── pyproject.toml
```
创建 `.github/workflows/ci.yml`:
```yaml
# 定义触发条件:每次 push 和 pull_request 到 main 分支时触发
name: Python CI
on:
push:
branches: [main]
pull_request:
branches: [main]
# 定义一个 job
jobs:
test:
# 在最新的 Ubuntu 虚拟机上运行
runs-on: ubuntu-latest
# 定义不同 Python 版本(同时测多个版本)
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
# Step 1: 检出代码
- name: Checkout code
uses: actions/checkout@v4
# Step 2: 设置 Python 环境
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
# Step 3: 安装依赖
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov httpx
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
# Step 4: 运行 Lint 检查
- name: Lint with ruff
run: |
pip install ruff
ruff check .
ruff format --check .
# Step 5: 运行测试
- name: Run tests
run: |
pytest tests/ -v --cov=. --cov-report=term-missing
# Step 6: 上传覆盖率报告(需要 Codecov 等第三方服务)
- name: Upload coverage
uses: codecov/codecov-action@v4
if: matrix.python-version == '3.13'# 只上传一次
```
这就是完整的 CI 流水线!每次你 push 代码到 GitHub,GitHub 会自动:
1. 在 3 个 Python 版本上并行运行
2. 拉取代码 → 装依赖 → 跑 linter → 跑测试
3. 如果任何一步报错,你的 PR 就会被标记为失败
### 2.3 实际项目示例
以一个真实的 FastAPI 项目为例,完整展示 workflow:
```yaml
name: FastAPI Deploy Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# ===== Job 1: 测试 =====
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-cov ruff mypy httpx
- name: Lint check
run: |
ruff check . || exit 1
ruff format --check . || exit 1
- name: Type check with mypy
run: mypy . --ignore-missing-imports || true
- name: Run tests
run: pytest tests/ -v --cov=myapp --cov-report=xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
fail_ci_if_error: false
# ===== Job 2: 构建 Docker 镜像 =====
build-and-push:
needs: test# 依赖 test 通过
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }}
labels: ${{ steps.meta.outputs.labels }}
# ===== Job 3: 部署到服务器 =====
deploy:
needs: build-and-push
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/my-fastapi-app
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
```
关键点解读:
-`needs: test`:build job 只在 test job 成功后才运行,这是 CI/CD 的核心——**不允许有问题的代码进入构建阶段**。
-`if: github.ref == 'refs/heads/main'`:只有推送到 main 分支才触发构建和部署,feature 分支的 PR 只会跑测试不会部署。
-`secrets.*`:敏感信息(SSH 密钥、服务器地址)通过 GitHub Secrets 注入,绝不硬编码在 workflow 文件中。
---
## 三、Dockerfile 实战:构建生产级镜像
workflow 里的 `docker/build-push-action` 怎么知道你该构建什么?需要一个 `Dockerfile`。
### 3.1 基础版 Dockerfile
```dockerfile
# ===== 构建阶段 =====
FROM python:3.12-slim AS builder
WORKDIR /build
# 复制依赖描述文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir -r requirements.txt \
&& pip install --no-cache-dir gunicorn uvicorn[standard]
# 复制源代码
COPY . .
# ===== 运行阶段 =====
FROM python:3.12-slim AS runner
# 创建非 root 用户(安全最佳实践)
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
# 从 builder 阶段复制安装的包和应用代码
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder --chown=appuser:appuser /build /app
# 切换到非 root 用户
USER appuser
# 暴露端口
EXPOSE 8000
# 健康检查(Kubernetes / Docker 编排系统会用到)
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
# 启动应用(使用 gunicorn + uvicorn workers)
CMD ["gunicorn", "main:app", "--workers", "4", "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000", "--timeout", "120"]
```
### 3.2 Docker Compose 编排本地开发环境
光有一个 Dockerfile 还不够,你的 FastAPI 应用通常需要数据库、Redis 等依赖。Docker Compose 让你一条命令拉起整套环境:
```yaml
# docker-compose.yml
version: "3.9"
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
- REDIS_URL=redis://cache:6379/0
- SECRET_KEY=${SECRET_KEY:-dev-secret-change-me}
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
cache:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
pgdata:
redis_data:
```
启动整套环境:
```bash
dockercomposeup-d
# 等待健康检查通过后访问 http://localhost:8000/docs
```
---
## 四、部署策略:从简单到高级
### 4.1 方案一:最简单 — SSH 直连部署
不需要任何额外工具,直接用 SSH 登录服务器执行脚本:
```yaml
# .github/workflows/deploy.yml 中的部署步骤
- name: Deploy to production
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_HOST }}
username: deployer
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/myapp
git pull origin main
docker compose down
docker compose up -d --build
docker system prune -af
```
优点:零成本、上手快。
缺点:没有回滚机制、容易出问题。
### 4.2 方案二:蓝绿部署(Blue-Green Deployment)
准备两套完全一样的环境,一套在线(蓝色),一套备用(绿色)。部署新版本时先在绿色环境跑,验证通过后把流量切过去。
```yaml
# docker-compose.bluegreen.yml
version: "3.9"
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
# 根据 ACTIVATE 变量切换配置
- ./nginx.active.conf:/etc/nginx/conf.d/default.conf:ro
blue:
extends: web
container_name: myapp-blue
green:
extends: web
container_name: myapp-green
environment:
- APP_VERSION=canary# 标识 Canary 版本
```
Nginx 配置中用环境变量切换:
```nginx
# nginx.active.conf
upstream backend {
server blue:8000; # 改成 green:8000 即可秒级切换
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
```
切换流程:
```bash
#!/bin/bash
# switch-deployment.sh — 部署新版本并切换流量
# Step 1: 构建新版本的绿色环境
dockercomposeup-dgreen--build
# Step 2: 等待启动并做健康检查
foriin {1..30}; do
ifcurl-sfhttp://localhost:8081/health > /dev/null; then
echo"Green environment is healthy!"
break
fi
sleep2
done
# Step 3: 切换 Nginx 配置指向绿色环境
echo"upstream backend { server green:8000; }" > nginx.conf
dockercomposerestartnginx
# Step 4: 观察一段时间,如果没问题再切换回蓝色
echo"Traffic switched to green. Monitoring for 5 minutes..."
sleep300
# Step 5: 确认正常后将蓝色环境更新为新版本,实现轮换
dockercomposestopgreen
dockerrenamemyapp-greenmyapp-blue
dockercomposeup-dblue--build
```
### 4.3 方案三:金丝雀发布(Canary Release)
不是把所有流量一刀切到新环境,而是先让一小部分用户(比如 5%)访问新版本,观察一段时间确认没问题再全部推出去。
```python
# Canary 路由逻辑 — 在 FastAPI 中实现
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import random
app = FastAPI()
classCanaryMiddleware(BaseHTTPMiddleware):
"""金丝雀发布中间件:按比例分发流量"""
def__init__(self, app, canary_percentage: float = 5.0):
super().__init__(app)
self.canary_percentage = canary_percentage
# 可以从配置中心/环境变量动态读取
self.canary_version = "v2.0"
asyncdefdispatch(self, request: Request, call_next):
if random.uniform(0, 100) < self.canary_percentage:
# 5% 流量走新版本
request.state.route = "canary"
# 这里可以修改请求头标记版本
request.headers.append(("X-Canary-Version", self.canary_version))
else:
request.state.route = "stable"
response = await call_next(request)
response.headers["X-Routing"] = request.state.route
return response
app.add_middleware(CanaryMiddleware, canary_percentage=5.0)
@app.get("/health")
asyncdefhealth():
return {
"status": "ok",
"version": "v2.0",
"routing": "canary",
}
```
配合监控,可以逐步提高金丝雀比例:5% → 20% → 50% → 100%。每步都看错误率、响应时间等指标。
---
## 五、基础设施即代码(IaC)与 Pulumi
Docker 解决了"应用怎么打包"的问题,但服务器本身呢?Pulumi 是用编程语言(包括 Python)来定义云资源。
### 5.1 用 Pulumi Python 部署云资源
```python
"""
deploy.py — 用 Pulumi + Python 定义云上基础设施
"""
import pulumi
import pulumi_docker as docker
import pulumi_cloudinit as cloudinit
# ===== 1. 构建 Docker 镜像 =====
project_name = "my-fastapi-app"
docker_image = docker.Image(
project_name,
build=docker.DockerBuild(
context=f"./{project_name}",
dockerfile="./{project_name}/Dockerfile",
),
image_name=f"{project_name}:latest",
registry=docker.ImageRegistryArgs(
server="ghcr.io",
username=pulumi.Config().get("gh_username"),
password=pulumi.Config().get_secret("gh_token"),
),
)
# ===== 2. 创建云服务器 =====
cloud_init_config = cloudinit.InitConfig(
gzip=False,
base64_encode_secondary=False,
part_multPart=MultipartMimePart(
parts=[
PartMimePart(
content="""#cloud-config
package_update: true
packages:
- docker.io
- python3-pip
write_files:
- path: /opt/myapp/.env
content: |
DATABASE_URL=postgresql://user:pass@db:5432/myapp
SECRET_KEY=super-secret-key
- path: /opt/myapp/docker-compose.yml
content: |
version: '3.9'
services:
web:
image: ghcr.io/myorg/my-fastapi-app:latest
ports:
- '8000:8000'
env_file: .env
""",
)
]
),
)
cloud_init_user_data = cloud_init_config.render_data()
vm = Instance(
f"{project_name}-server",
instance_type="t3.small",
ami="ami-0c55b159cbfafe1f0", # Ubuntu 22.04
user_data=cloud_init_user_data,
key_name=pulumi.Config().get("ssh_key_name"),
)
# ===== 3. 输出公网 IP =====
pulumi.export("server_public_ip", vm.public_ip)
pulumi.export("image_name", docker_image.image_name)
```
运行部署:
```bash
pulumistackinitproduction
pulumiup
```
这比手动在控制台点点点可靠多了——所有的云资源都在代码版本控制里,谁改了什么、什么时候改的一清二楚。
### 5.2 Terraform(传统备选方案)
如果不喜欢 Python 方式,Terraform 用 HCL 语言做同样的事情:
```hcl
# main.tf — 用 Terraform 定义云资源
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-west-2"
}
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.small"
user_data = <<-EOF
#!/bin/bash
apt-get update && apt-get install -y docker.io
systemctl start docker
EOF
tags = {
Name = "my-fastapi-server"
}
}
resource "aws_security_group" "web_sg" {
name = "allow-web-traffic"
ingress {
from_port = 8000
to_port = 8000
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
```
---
## 六、实战演练:完整的 CI/CD 流水线
现在我们把前面学到的所有内容串在一起,打造一个从开发到部署的完整流水线。
### 6.1 项目结构
```
my-fastapi-app/
├── main.py # FastAPI 应用入口
├── models.py # 数据模型
├── schemas.py # Pydantic schema
├── services/
│ ├── __init__.py
│ └── data_service.py # 业务逻辑层
├── tests/
│ ├── __init__.py
│ ├── conftest.py # pytest fixture
│ └── test_main.py # API 测试
├── .github/workflows/
│ ├── ci.yml # 测试流水线
│ └── deploy.yml # 部署流水线
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── pyproject.toml # 项目元数据
```
### 6.2 CI/CD 流水线流程图
```
开发者推送代码
│
▼
触发 GitHub Actions (ci.yml)
│
├─→ 安装 Python 依赖
│
├─→ Ruff Lint 检查(格式 + 代码质量)
│ └─→ 失败?发送通知给开发者,停止流程
│ └─→ 成功?继续
│
├─→ 运行单元测试 + 覆盖率检查
│ └─→ 失败?通知开发者
│ └─→ 成功?继续
│
├─→ 构建 Docker 镜像
│ └─→ 推送到 GHCR(GitHub Container Registry)
│
└─→ 部署到预发环境(staging)
└─→ 运行冒烟测试
└─→ 全部通过?手动确认后 → 部署到生产
```
### 6.3 完整的 workflow 文件
这是我们在前面已经看到过的 `ci.yml` 和 `deploy.yml` 的精简完整版,这里再整理一遍让你更清晰:
```yaml
# .github/workflows/ci-deploy.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_TAG: ${{ github.sha }}
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-cov ruff mypy
- name: Ruff lint & format check
run: |
ruff check .
ruff format --check .
- name: MyPy type check
run: mypy . --ignore-missing-imports || true
- name: Run unit tests
run: pytest tests/ -v --cov=. --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v4
build-and-push:
needs: lint-and-test
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to GHCR
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: ghcr.io/${{ github.repository }}:${{ env.IMAGE_TAG }}
deploy-staging:
needs: build-and-push
runs-on: ubuntu-latest
environment: staging
steps:
- name: Deploy to staging
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.STAGING_HOST }}
username: deployer
key: ${{ secrets.STAGING_SSH_KEY }}
script: |
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
smoke-test-staging:
needs: deploy-staging
runs-on: ubuntu-latest
steps:
- name: Smoke test
run: |
# 等待容器启动
sleep 10
# 检查健康端点
RESPONSE=$(curl -sf http://${{ secrets.STAGING_HOST }}:8000/health)
echo "Response: $RESPONSE"
echo "$RESPONSE" | jq -e '.status == "ok"'
```
---
## 七、实操练习
### 练习题
**第 1 题:为你的现有项目添加 CI**
选一个你已经写过的 Python 项目,在 GitHub 上创建一个仓库,然后:
1. 创建 `.github/workflows/ci.yml`
2. 让它能在 push 时自动运行 pytest 测试
3. 提交代码并观察 GitHub Actions 面板的运行结果
```python
# 参考答案思路
# 在 workflow 中添加 steps:
# 1. checkout@v4
# 2. setup-python@v5 with python-version: "3.12"
# 3. pip install pytest
# 4. pytest tests/ -v
```
**第 2 题:编写 Dockerfile 并本地测试**
为你之前的 FastAPI 应用写一个 Dockerfile,然后本地构建并运行:
```bash
dockerbuild-tmy-fastapi-app:test.
dockerrun-p8000:8000--rmmy-fastapi-app:test
# 访问 http://localhost:8000/docs 验证
```
```python
# Dockerfile 关键内容参考
# FROM python:3.12-slim
# WORKDIR /app
# COPY requirements.txt .
# RUN pip install --no-cache-dir -r requirements.txt
# COPY . .
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
**第 3 题:实现蓝绿部署脚本**
编写一个 shell 或 Python 脚本,实现蓝绿部署:
1. 启动新版本容器
2. 等待健康检查通过
3. 切换到新版本
4. 保留旧版本作为回滚选项
```python
# 参考答案思路
import subprocess
import time
import urllib.request
defblue_green_deploy(version: str) -> None:
# 1. 构建并启动绿色环境
subprocess.run(["docker", "compose", "up", "-d", "--build", "green"])
# 2. 健康检查
for _ inrange(30):
try:
resp = urllib.request.urlopen("http://localhost:8081/health")
if resp.status == 200:
break
exceptException:
pass
time.sleep(2)
else:
raiseRuntimeError("Green environment failed health check!")
# 3. 切换流量
subprocess.run([
"docker", "exec", "nginx", "sh", "-c",
"echo 'upstream backend { server green:8000; }' > /etc/nginx/conf.d/default.conf"
])
subprocess.run(["docker", "compose", "restart", "nginx"])
print(f"Successfully deployed v{version}")
blue_green_deploy("2.0.0")
```
**第 4 题:添加 Pulumi 基础设施代码**
在一个已有的 AWS 账户上,用 Pulumi Python 编写部署 FastAPI 应用的 IaC 脚本:
1. 创建 EC2 实例
2. 配置安全组(开放 8000 端口)
3. 输出公网 IP 以便访问
```python
# 参考答案思路
# import pulumi
# import pulumi_aws as aws
# vm = aws.ec2.Instance("web-server", ...)
# pulumi.export("ip", vm.public_ip)
```
**第 5 题:设计一个多级流水线**
为一个电商微服务项目设计 CI/CD 流水线。该项目包含:
- user-service(用户服务,REST API)
- order-service(订单服务,REST API)
- notification-service(通知服务,接收消息队列事件)
要求:
- 每个服务有独立的测试和构建
- 所有服务测试通过后才部署
- 部署顺序:user → order → notification(注意依赖关系)
---
## 八、总结
这一期我们聊了很多内容,我尽量把它拆解成你能一步步跟上的节奏:
1.**CI/CD 的本质**:让别人不能把 bug 合并进来,让代码从本地到服务器的每一步都是可重复、可追溯的。
2.**GitHub Actions 是起步最快的工具**:不需要额外装软件,直接在 GitHub 里定义 YAML 就行了。
3.**Docker 是现代部署的标准**:不管你的代码跑在本地还是云上,打包进容器就能保证一致的环境。
4.**蓝绿部署和金丝雀发布是进阶话题**:它们解决了"上线万一出问题怎么办"的恐惧。
5.**基础设施即代码**:服务器也是代码的一部分,应该被审查、被测试、被版本化。
最重要的一句话:**不要追求一步到位完美。先从最简单的 CI 开始——每次 push 自动跑测试,这就已经是 80% 的进步了。**
---
## 九、课后练习参考答案
### 第 3 题完整实现(蓝绿部署脚本)
```python
#!/usr/bin/env python3
"""blue_green_deploy.py — 蓝绿部署自动化脚本"""
import subprocess
import time
import urllib.request
import sys
defwait_for_health(url: str, timeout: int = 60, interval: int = 2) -> bool:
"""等待服务健康检查通过"""
elapsed = 0
while elapsed < timeout:
try:
resp = urllib.request.urlopen(url, timeout=5)
if resp.status == 200:
print(f" ✅ 服务健康检查通过")
returnTrue
exceptException:
pass
time.sleep(interval)
elapsed += interval
print(f" ❌ 超时:{timeout}秒内未通过健康检查")
returnFalse
defswap_traffic(blue_port: int, green_port: int, nginx_container: str = "nginx") -> None:
"""切换 Nginx 流量方向"""
current = "blue"if blue_port == 8000else"green"
target = "green"if current == "blue"else"blue"
target_port = green_port if target == "green"else blue_port
cmd = [
"docker", "exec", nginx_container, "sh", "-c",
f"echo 'upstream backend {{ server localhost:{target_port}; }}' > "
"/etc/nginx/conf.d/upstream.conf"
]
subprocess.run(cmd, check=True)
subprocess.run(["docker", "compose", "restart", nginx_container], check=True)
print(f" 🔄 流量已切换: {current} → {target}")
defrollback(current_port: int, nginx_container: str = "nginx") -> None:
"""回滚到上一个版本"""
target_port = current_port - 8000 + 8000# blue=8000, green=8001
# 简化版:回滚就是切回去
print(" ⚠️ 执行回滚...")
defmain():
iflen(sys.argv) < 2:
print("用法: python blue_green_deploy.py <version>")
sys.exit(1)
version = sys.argv[1]
print(f"🚀 开始部署 v{version}...")
# Step 1: 构建新镜像
print(" 📦 构建 Docker 镜像...")
subprocess.run([
"docker", "build", "-t", f"myapp:{version}", "-f", "Dockerfile", "."
], check=True)
# Step 2: 启动绿色环境
print(" 🟢 启动绿色环境...")
env_vars = {
"APP_VERSION": version,
"BLUE_PORT": "8000",
"GREEN_PORT": "8001",
}
subprocess.run([
"docker", "compose", "run", "--rm", "--no-deps",
"green", "docker", "swarm", "init"
])
# Step 3: 健康检查
print(" 🔍 等待健康检查...")
ifnot wait_for_health("http://localhost:8001/health"):
print(" ❌ 健康检查失败,回滚!")
# rollback(8001)
sys.exit(1)
# Step 4: 切换流量
print(" 🌊 切换流量...")
swap_traffic(8000, 8001)
# Step 5: 停止旧蓝色容器(可选)
print(" ✅ 部署完成 v{version}")
if__name__ == "__main__":
main()
```
### 第 5 题架构图参考
```
┌─────────────────────────────────────────────────┐
│ GitHub Push Event │
└────────────────────────┬────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ User Svc │ │ Order Svc │ │ Notif Svc │
│ CI Build │ │ CI Build │ │ CI Build │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└────────────────────────┼───────────────────────┘
│
All tests passed? → Build Docker images
│
┌──────────────▼──────────────┐
│ Deploy Order: │
│ 1. User Service (base) │
│ 2. Order Service (depends) │
│ 3. Notification Service │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ Smoke Tests on Staging │
└──────────────┬──────────────┘
│
Manual Approval → Deploy to Production
```
---
## 十、下期预告
**Episode 19:Python 并发与多线程深度实践**
我们已经学了 asyncio(协程),接下来要补上并发编程的另一半:**多线程和多进程**。
- threading 和 multiprocessing 的区别和使用场景
- GIL 是什么?为什么它会影响你的性能?
- 用 concurrent.futures 简化并发编程
- 生产者-消费者模式的多种实现
- GIL 绕过技巧:多进程池 + 协程混合架构
敬请期待!
---
**📚 系列回顾**
到目前为止我们学过的内容:
| Episode | 主题 |
|---------|------|
| 01 | 环境搭建与基础语法 |
| 02 | 数据结构与字符串处理 |
| 03 | 面向对象编程 |
| 04 | 装饰器、生成器与文件 IO |
| 05 | 爬虫入门 |
| 06 | 数据分析入门 |
| 07 | Web 后端开发 |
| 08 | AI 实战入门 |
| 09 | 前端入门 |
| 10 | 项目实战——Dashboard |
| 11 | Docker 容器化部署 |
| 12 | 数据库进阶 |
| 13 | 异步编程与并发 |
| 14 | 日志系统与调试技巧 |
| 15 | 自动化运维与脚本实战 |
| 16 | 单元测试与代码质量 |
| 17 | 微服务入门 |
| 18 | CI/CD 与 DevOps 实战 ← **本期** |
加油!你已经从零基础走到了"能用 Python 写完整的后端并部署上线"的水平。🎉