引言

在当今快速迭代的软件开发环境中,DevOps实践和CI/CD流水线已成为团队提高交付效率、保证软件质量的关键。本文将深入探讨如何构建完整的DevOps体系,从代码提交到生产部署的全流程自动化实践。

一、DevOps核心理念

1.1 DevOps的CALMS模型

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# ========== DevOps CALMS模型 ==========
"""
    C - Culture (文化)
    ├── 协作精神
    ├── 持续改进
    ├── 容错心态
    └── 透明沟通

    A - Automation (自动化)
    ├── 构建自动化
    ├── 测试自动化
    ├── 部署自动化
    └── 监控自动化

    L - Lean (精益)
    ├── 消除浪费
    ├── 持续交付
    ├── 快速反馈
    └── 价值流优化

    M - Measurement (度量)
    ├── 关键指标追踪
    ├── 数据驱动决策
    ├── 持续监控
    └── 效果评估

    S - Sharing (分享)
    ├── 知识共享
    ├── 最佳实践传播
    ├── 工具共享
    └── 经验总结
"""

# DevOps成熟度评估模型
DEVOPS_MATURITY_LEVELS = {
    "Level 1 - 初始级": {
        "characteristics": [
            "手动操作为主",
            "缺乏标准化流程",
            "开发和运维分离"
        ],
        "practices": [],
        "improvements": [
            "建立基础自动化流程",
            "制定标准化规范"
        ]
    },
    "Level 2 - 可重复级": {
        "characteristics": [
            "有基本的CI流程",
            "环境配置初步标准化",
            "文档化流程"
        ],
        "practices": [
            "版本控制",
            "单元测试",
            "基础自动化构建"
        ],
        "improvements": [
            "扩展自动化范围",
            "增加测试覆盖率"
        ]
    },
    "Level 3 - 已定义级": {
        "characteristics": [
            "完整的CI/CD流水线",
            "基础设施即代码",
            "自动化测试体系"
        ],
        "practices": [
            "持续集成",
            "持续部署",
            "自动化测试",
            "配置管理"
        ],
        "improvements": [
            "优化部署流程",
            "增强监控能力"
        ]
    },
    "Level 4 - 可管理级": {
        "characteristics": [
            "全链路自动化",
            "完善的监控体系",
            "快速故障恢复"
        ],
        "practices": [
            "自动化运维",
            "监控告警",
            "故障自愈",
            "性能优化"
        ],
        "improvements": [
            "持续优化",
            "成本控制"
        ]
    },
    "Level 5 - 优化级": {
        "characteristics": [
            "智能运维",
            "预测性维护",
            "持续创新"
        ],
        "practices": [
            "AI辅助决策",
            "混沌工程",
            "自动化优化"
        ],
        "improvements": [
            "持续演进"
        ]
    }
}

1.2 DevOps指标体系

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# ========== DORA指标 ==========

class DORAMetrics:
    """DORA (DevOps Research and Assessment) 核心指标"""

    @staticmethod
    def deployment_frequency(deployments: int, days: int) -> float:
        """
        部署频率
        - 精英级:按需部署 (每天多次)
        - 高绩效:每周1-6个月
        - 中等绩效:每月1-6个月
        - 低绩效:少于每6个月1次
        """
        return deployments / days

    @staticmethod
    def lead_time_for_changes(commit_time: str, deploy_time: str) -> float:
        """
        变更前置时间
        从代码提交到成功部署的时间
        - 精英级:小于1小时
        - 高绩效:小于1天
        - 中等绩效:1周-1个月
        - 低绩效:超过1个月
        """
        from datetime import datetime

        commit = datetime.fromisoformat(commit_time)
        deploy = datetime.fromisoformat(deploy_time)

        return (deploy - commit).total_seconds() / 3600  # 小时

    @staticmethod
    def time_to_restore_service(incident_time: str, restore_time: str) -> float:
        """
        服务恢复时间
        - 精英级:小于1小时
        - 高绩效:小于1天
        - 中等绩效:1天-1周
        - 低绩效:超过1周
        """
        from datetime import datetime

        incident = datetime.fromisoformat(incident_time)
        restore = datetime.fromisoformat(restore_time)

        return (restore - incident).total_seconds() / 3600  # 小时

    @staticmethod
    def change_failure_rate(total_deployments: int, failed_deployments: int) -> float:
        """
        变更失败率
        - 精英级:0-15%
        - 高绩效:15-30%
        - 中等绩效:30-60%
        - 低绩效:超过60%
        """
        return (failed_deployments / total_deployments) * 100

    @classmethod
    def evaluate_performance(cls, metrics: dict) -> str:
        """评估团队DevOps绩效等级"""

        score = 0

        if metrics['deployment_frequency'] >= 1:  # 每天至少1次
            score += 1
        if metrics['lead_time'] <= 1:  # 小于1小时
            score += 1
        if metrics['restore_time'] <= 1:  # 小于1小时
            score += 1
        if metrics['failure_rate'] <= 15:  # 小于15%
            score += 1

        levels = {
            4: "精英级",
            3: "高绩效",
            2: "中等绩效",
            1: "低绩效",
            0: "低绩效"
        }

        return levels[score]

# ========== 自定义DevOps指标 ==========

class DevOpsMetricsCollector:
    """DevOps指标收集器"""

    def __init__(self):
        self.metrics = {
            'builds': [],
            'deployments': [],
            'incidents': [],
            'tests': []
        }

    def record_build(self, build_info: dict):
        """记录构建信息"""
        self.metrics['builds'].append({
            'timestamp': build_info['timestamp'],
            'branch': build_info['branch'],
            'commit': build_info['commit'],
            'status': build_info['status'],
            'duration': build_info['duration'],
            'triggered_by': build_info['triggered_by']
        })

    def record_deployment(self, deployment_info: dict):
        """记录部署信息"""
        self.metrics['deployments'].append({
            'timestamp': deployment_info['timestamp'],
            'environment': deployment_info['environment'],
            'version': deployment_info['version'],
            'status': deployment_info['status'],
            'duration': deployment_info['duration'],
            'deployed_by': deployment_info['deployed_by']
        })

    def record_incident(self, incident_info: dict):
        """记录故障信息"""
        self.metrics['incidents'].append({
            'detected_at': incident_info['detected_at'],
            'resolved_at': incident_info.get('resolved_at'),
            'severity': incident_info['severity'],
            'affected_services': incident_info['affected_services'],
            'root_cause': incident_info.get('root_cause')
        })

    def calculate_metrics(self, days: int = 30) -> dict:
        """计算DevOps指标"""

        from datetime import datetime, timedelta

        cutoff_time = datetime.now() - timedelta(days=days)

        # 筛选时间范围内的数据
        recent_builds = [
            b for b in self.metrics['builds']
            if datetime.fromisoformat(b['timestamp']) > cutoff_time
        ]

        recent_deployments = [
            d for d in self.metrics['deployments']
            if datetime.fromisoformat(d['timestamp']) > cutoff_time
        ]

        recent_incidents = [
            i for i in self.metrics['incidents']
            if datetime.fromisoformat(i['detected_at']) > cutoff_time
        ]

        # 计算指标
        total_builds = len(recent_builds)
        successful_builds = len([b for b in recent_builds if b['status'] == 'success'])
        build_success_rate = (successful_builds / total_builds * 100) if total_builds > 0 else 0

        total_deployments = len(recent_deployments)
        successful_deployments = len([d for d in recent_deployments if d['status'] == 'success'])
        deployment_success_rate = (successful_deployments / total_deployments * 100) if total_deployments > 0 else 0

        deployment_frequency = total_deployments / days

        total_incidents = len(recent_incidents)
        resolved_incidents = len([i for i in recent_incidents if i.get('resolved_at')])
        avg_resolution_time = 0

        if resolved_incidents > 0:
            resolution_times = []
            for incident in recent_incidents:
                if incident.get('resolved_at'):
                    detected = datetime.fromisoformat(incident['detected_at'])
                    resolved = datetime.fromisoformat(incident['resolved_at'])
                    resolution_times.append((resolved - detected).total_seconds() / 3600)

            avg_resolution_time = sum(resolution_times) / len(resolution_times)

        return {
            'build_metrics': {
                'total_builds': total_builds,
                'success_rate': round(build_success_rate, 2),
                'avg_duration': round(
                    sum(b['duration'] for b in recent_builds) / total_builds if total_builds > 0 else 0,
                    2
                )
            },
            'deployment_metrics': {
                'total_deployments': total_deployments,
                'success_rate': round(deployment_success_rate, 2),
                'frequency_per_day': round(deployment_frequency, 2)
            },
            'incident_metrics': {
                'total_incidents': total_incidents,
                'resolved_incidents': resolved_incidents,
                'avg_resolution_time_hours': round(avg_resolution_time, 2)
            }
        }

二、持续集成(CI)实践

2.1 Git工作流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# ========== Git工作流模型 ==========

class GitWorkflow:
    """Git工作流管理"""

    BRANCH_STRATEGIES = {
        "Git Flow": {
            "branches": {
                "main": "生产分支,只接受来自release的合并",
                "develop": "开发主分支",
                "feature": "功能开发分支,从develop创建",
                "release": "发布准备分支,从develop创建",
                "hotfix": "紧急修复分支,从main创建"
            },
            "workflow": """
            1. 从develop创建feature分支
            2. 完成开发后合并回develop
            3. 准备发布时创建release分支
            4. 测试通过后合并到main和develop
            5. 紧急修复从main创建hotfix分支
            6. 修复后合并到main和develop
            """
        },
        "GitHub Flow": {
            "branches": {
                "main": "始终可部署的生产分支",
                "feature": "功能分支,从main创建"
            },
            "workflow": """
            1. 从main创建feature分支
            2. 提交并推送到远程
            3. 创建Pull Request
            4. Code Review和讨论
            5. 合并到main
            6. 立即部署
            """
        },
        "GitLab Flow": {
            "branches": {
                "main": "主分支",
                "feature": "功能分支",
                "environment": "环境分支(staging, production)"
            },
            "workflow": """
            1. 从main创建feature分支
            2. 完成后合并回main
            3. main分支触发CI/CD
            4. 通过测试后部署到staging
            5. 人工验证后部署到production
            """
        },
        "Trunk Based Development": {
            "branches": {
                "trunk/main": "主分支,所有开发在此进行"
            },
            "workflow": """
            1. 开发者直接在主分支提交
            2. 使用Feature Flags控制功能发布
            3. 频繁集成到主分支
            4. 持续部署
            """
        }
    }

class BranchProtectionRules:
    """分支保护规则"""

    def __init__(self):
        self.rules = {}

    def add_protection(self, branch: str, rules: dict):
        """添加分支保护规则"""
        self.rules[branch] = {
            'require_pull_request': rules.get('require_pull_request', True),
            'require_approvals': rules.get('require_approvals', 1),
            'dismiss_stale_reviews': rules.get('dismiss_stale_reviews', True),
            'require_status_checks': rules.get('require_status_checks', True),
            'required_status_checks': rules.get('required_status_checks', []),
            'require_linear_history': rules.get('require_linear_history', True),
            'allow_force_pushes': rules.get('allow_force_pushes', False),
            'allow_deletions': rules.get('allow_deletions', False)
        }

    def check_protection(self, branch: str) -> dict:
        """检查分支保护状态"""
        return self.rules.get(branch, {})

2.2 CI流水线配置

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# ========== Jenkins Pipeline ==========

# Jenkinsfile
pipeline {
    agent any

    tools {
        maven 'Maven 3.8'
        jdk 'JDK 11'
    }

    environment {
        APP_NAME = 'my-application'
        VERSION = "${env.BUILD_ID}"
        REGISTRY = 'registry.example.com'
        IMAGE_NAME = "${REGISTRY}/${APP_NAME}:${VERSION}"
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Setup') {
            steps {
                sh '''
                    echo "Setting up build environment..."
                    python3 -m venv venv
                    . venv/bin/activate
                    pip install -r requirements.txt
                '''
            }
        }

        stage('Code Quality') {
            parallel {
                stage('Lint') {
                    steps {
                        sh '''
                            . venv/bin/activate
                            flake8 src/ --max-line-length=120
                        '''
                    }
                }
                stage('Security Scan') {
                    steps {
                        sh '''
                            . venv/bin/activate
                            bandit -r src/
                        '''
                    }
                }
            }
        }

        stage('Unit Tests') {
            steps {
                sh '''
                    . venv/bin/activate
                    pytest tests/unit/ --cov=src --cov-report=xml --cov-report=html
                '''
            }
            post {
                always {
                    junit 'test-results/*.xml'
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: 'htmlcov',
                        reportFiles: 'index.html',
                        reportName: 'Coverage Report'
                    ])
                }
            }
        }

        stage('Integration Tests') {
            steps {
                sh '''
                    docker-compose -f docker-compose.test.yml up -d
                    sleep 10
                    . venv/bin/activate
                    pytest tests/integration/
                    docker-compose -f docker-compose.test.yml down
                '''
            }
        }

        stage('Build') {
            steps {
                sh '''
                    . venv/bin/activate
                    python setup.py sdist bdist_wheel
                '''
            }
        }

        stage('Docker Build') {
            steps {
                script {
                    docker.build(image: IMAGE_NAME)
                }
            }
        }

        stage('Security Scan Image') {
            steps {
                sh '''
                    trivy image ${IMAGE_NAME} --severity HIGH,CRITICAL
                '''
            }
        }

        stage('Push to Registry') {
            when {
                branch 'main'
            }
            steps {
                script {
                    docker.withRegistry("https://${REGISTRY}", 'docker-registry-credentials') {
                        docker.image(IMAGE_NAME).push()
                        docker.image(IMAGE_NAME).push('latest')
                    }
                }
            }
        }

        stage('Deploy to Staging') {
            when {
                branch 'main'
            }
            steps {
                sh '''
                    kubectl set image deployment/${APP_NAME} \
                        ${APP_NAME}=${IMAGE_NAME} \
                        --namespace=staging
                    kubectl rollout status deployment/${APP_NAME} \
                        --namespace=staging
                '''
            }
        }

        stage('Smoke Tests') {
            when {
                branch 'main'
            }
            steps {
                sh '''
                    . venv/bin/activate
                    pytest tests/smoke/ --base-url=https://staging.example.com
                '''
            }
        }

        stage('Deploy to Production') {
            when {
                branch 'main'
                approval {
                    input 'Deploy to Production?'
                }
            }
            steps {
                sh '''
                    kubectl set image deployment/${APP_NAME} \
                        ${APP_NAME}=${IMAGE_NAME} \
                        --namespace=production
                    kubectl rollout status deployment/${APP_NAME} \
                        --namespace=production
                '''
            }
        }
    }

    post {
        success {
            echo "Pipeline succeeded!"
            cleanWs()
        }
        failure {
            echo "Pipeline failed!"
            mail to: 'team@example.com',
                 subject: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                 body: "Check console output at ${env.BUILD_URL}"
        }
        always {
            sh '''
                docker system prune -f
            '''
        }
    }
}

# ========== GitHub Actions Workflow ==========

# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

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

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.9'
          cache: 'pip'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install flake8 black isort

      - name: Run flake8
        run: |
          flake8 src/ tests/ --count --select=E9,F63,F7,F82 --show-source --statistics

      - name: Check code formatting
        run: |
          black --check src/ tests/

      - name: Check import ordering
        run: |
          isort --check-only src/ tests/

  test:
    name: Test
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11']

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install -r requirements-dev.txt

      - name: Run tests
        run: |
          pytest tests/ --cov=src --cov-report=xml --cov-report=html

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml
          flags: unittests
          name: codecov-umbrella

  security:
    name: Security Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Run Bandit
        run: |
          pip install bandit[toml]
          bandit -r src/

      - name: Run Safety
        run: |
          pip install safety
          safety check --file requirements.txt

      - name: Run Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-results.sarif'

      - name: Upload Trivy results
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

  build:
    name: Build Docker Image
    runs-on: ubuntu-latest
    needs: [lint, test, security]
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'

    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix={{branch}}-

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: build
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'

    environment:
      name: production
      url: https://example.com

    steps:
      - uses: actions/checkout@v3

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: Update kubeconfig
        run: |
          aws eks update-kubeconfig --name production-cluster --region us-east-1

      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/app \
            app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
            --namespace=production

      - name: Verify deployment
        run: |
          kubectl rollout status deployment/app --namespace=production

2.3 测试自动化策略

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# ========== 测试金字塔 ==========

class TestAutomationStrategy:
    """测试自动化策略"""

    TEST_PYRAMID = {
        "Unit Tests (70%)": {
            "scope": "单个函数/类",
            "speed": "毫秒级",
            "cost": "低",
            "isolation": "完全隔离",
            "examples": [
                "函数返回值验证",
                "边界条件测试",
                "异常处理测试"
            ]
        },
        "Integration Tests (20%)": {
            "scope": "多个组件协作",
            "speed": "秒级",
            "cost": "中",
            "isolation": "部分隔离",
            "examples": [
                "API集成测试",
                "数据库集成测试",
                "服务间通信测试"
            ]
        },
        "E2E Tests (10%)": {
            "scope": "完整用户流程",
            "speed": "分钟级",
            "cost": "高",
            "isolation": "无隔离",
            "examples": [
                "用户注册流程",
                "购物车完整流程",
                "支付完整流程"
            ]
        }
    }

class AutomatedTestSuite:
    """自动化测试套件"""

    def __init__(self):
        self.unit_tests = []
        self.integration_tests = []
        self.e2e_tests = []

    def add_unit_test(self, test_func):
        """添加单元测试"""
        self.unit_tests.append(test_func)

    def add_integration_test(self, test_func):
        """添加集成测试"""
        self.integration_tests.append(test_func)

    def add_e2e_test(self, test_func):
        """添加E2E测试"""
        self.e2e_tests.append(test_func)

    def run_all_tests(self):
        """运行所有测试"""
        results = {
            'unit': self._run_tests(self.unit_tests),
            'integration': self._run_tests(self.integration_tests),
            'e2e': self._run_tests(self.e2e_tests)
        }

        return results

    def _run_tests(self, tests):
        """运行测试"""
        passed = 0
        failed = 0

        for test in tests:
            try:
                test()
                passed += 1
            except AssertionError as e:
                failed += 1
                print(f"Test failed: {e}")

        return {
            'total': len(tests),
            'passed': passed,
            'failed': failed
        }

# ========== 测试驱动开发(TDD)工作流 ==========

class TDDWorkflow:
    """TDD工作流"""

    @staticmethod
    def red_green_refactor(feature_name: str):
        """
        Red-Green-Refactor循环

        Red: 编写失败的测试
        Green: 编写最少代码使测试通过
        Refactor: 重构代码
        """

        print(f"\n=== TDD Workflow for {feature_name} ===")

        # Red: 编写测试
        print("\n[RED] Writing failing test...")
        test_code = f"""
def test_{feature_name}():
    result = {feature_name}()
    assert result is not None
"""
        print(test_code)

        # Green: 实现功能
        print("\n[GREEN] Implementing minimum code to pass...")
        impl_code = f"""
def {feature_name}():
    return True
"""
        print(impl_code)

        # Refactor: 重构
        print("\n[REFACTOR] Improving code quality...")
        print("Optimizing implementation...")

        return True

# ========== 行为驱动开发(BDD) ==========

class BDDScenario:
    """BDD场景定义"""

    def __init__(self, name: str):
        self.name = name
        self.given_steps = []
        self.when_steps = []
        self.then_steps = []

    def given(self, description: str, action=None):
        """Given步骤"""
        self.given_steps.append({
            'description': description,
            'action': action
        })
        return self

    def when(self, description: str, action=None):
        """When步骤"""
        self.when_steps.append({
            'description': description,
            'action': action
        })
        return self

    def then(self, description: str, assertion=None):
        """Then步骤"""
        self.then_steps.append({
            'description': description,
            'assertion': assertion
        })
        return self

    def execute(self):
        """执行场景"""
        print(f"\nScenario: {self.name}")

        # 执行Given步骤
        print("\nGiven:")
        context = {}
        for step in self.given_steps:
            print(f"  {step['description']}")
            if step['action']:
                context.update(step['action'](context) or {})

        # 执行When步骤
        print("\nWhen:")
        for step in self.when_steps:
            print(f"  {step['description']}")
            if step['action']:
                context.update(step['action'](context) or {})

        # 执行Then步骤
        print("\nThen:")
        for step in self.then_steps:
            print(f"  {step['description']}")
            if step['assertion']:
                step['assertion'](context)

        return context

# 使用示例
def user_login_scenario():
    """用户登录场景"""

    scenario = BDDScenario("User successfully logs in")

    scenario.given("a registered user with email 'user@example.com' and password 'password123'")
              .when("the user submits valid credentials")
              .then("the user should be authenticated")
              .then("the user should receive an authentication token")

    # 实际执行时会实现具体的action和assertion
    return scenario

三、持续部署(CD)实践

3.1 部署策略

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# ========== 部署策略 ==========

class DeploymentStrategy:
    """部署策略"""

    @staticmethod
    def rolling_update(deployment_config: dict):
        """
        滚动更新

        逐步替换旧实例,确保服务始终可用
        """
        total_replicas = deployment_config['replicas']
        max_unavailable = deployment_config.get('max_unavailable', 1)
        max_surge = deployment_config.get('max_surge', 1)

        print(f"Starting rolling update...")
        print(f"Total replicas: {total_replicas}")
        print(f"Max unavailable: {max_unavailable}")
        print(f"Max surge: {max_surge}")

        for i in range(total_replicas):
            print(f"Updating replica {i+1}/{total_replicas}...")
            # 部署新实例
            # 等待健康检查通过
            # 终止旧实例

        print("Rolling update completed!")

    @staticmethod
    def blue_green_deployment(deployment_config: dict):
        """
        蓝绿部署

        并行维护两套环境,通过切换流量实现零停机部署
        """
        print("Starting blue-green deployment...")

        # 当前环境
        current_env = deployment_config['current_environment']  # 'blue' or 'green'

        # 目标环境
        target_env = 'green' if current_env == 'blue' else 'blue'

        print(f"Current environment: {current_env}")
        print(f"Target environment: {target_env}")

        # 1. 在目标环境部署新版本
        print(f"\n1. Deploying new version to {target_env} environment...")
        # 部署到目标环境

        # 2. 等待目标环境健康检查
        print(f"\n2. Waiting for {target_env} to be healthy...")
        # 健康检查

        # 3. 切换流量
        print(f"\n3. Switching traffic from {current_env} to {target_env}...")
        # 切换负载均衡器

        # 4. 验证新版本
        print(f"\n4. Validating {target_env}...")
        # 运行烟雾测试

        # 5. 保留旧环境(可选回滚)
        print(f"\n5. Keeping {current_env} as rollback option...")

        print("Blue-green deployment completed!")

    @staticmethod
    def canary_deployment(deployment_config: dict):
        """
        金丝雀部署

        逐步将流量引导到新版本,监控问题并快速回滚
        """
        print("Starting canary deployment...")

        canary_steps = deployment_config.get('canary_steps', [
            {'percentage': 5, 'duration': 300},    # 5% 流量,5分钟
            {'percentage': 25, 'duration': 600},   # 25% 流量,10分钟
            {'percentage': 50, 'duration': 600},   # 50% 流量,10分钟
            {'percentage': 100, 'duration': 0}     # 100% 流量
        ])

        for step in canary_steps:
            percentage = step['percentage']
            duration = step['duration']

            print(f"\nRouting {percentage}% of traffic to canary...")

            # 调整流量分配
            # 监控关键指标
            # 如果检测到问题,立即回滚

            if duration > 0:
                print(f"Monitoring for {duration} seconds...")
                # 等待并监控

        print("\nAll traffic routed to new version!")
        print("Canary deployment completed!")

    @staticmethod
    def a_b_testing_deployment(deployment_config: dict):
        """
        A/B测试部署

        同时运行多个版本,按特定规则分配流量
        """
        print("Starting A/B testing deployment...")

        variants = deployment_config['variants']  # [{'name': 'A', 'percentage': 50}, ...]

        total_percentage = sum(v['percentage'] for v in variants)

        if total_percentage != 100:
            raise ValueError(f"Total percentage must be 100%, got {total_percentage}%")

        print("Traffic allocation:")
        for variant in variants:
            print(f"  {variant['name']}: {variant['percentage']}%")

        # 配置流量分配规则
        # 设置指标收集
        # 配置自动回滚规则

        print("A/B testing deployment completed!")

# ========== 部署回滚 ==========

class DeploymentRollback:
    """部署回滚"""

    def __init__(self, deployment_manager):
        self.deployment_manager = deployment_manager
        self.rollback_history = []

    def execute_rollback(self, target_version: str, reason: str):
        """执行回滚"""

        print(f"\nInitiating rollback to version {target_version}")
        print(f"Reason: {reason}")

        # 1. 记录回滚
        rollback_record = {
            'timestamp': datetime.now().isoformat(),
            'from_version': self.deployment_manager.get_current_version(),
            'to_version': target_version,
            'reason': reason
        }
        self.rollback_history.append(rollback_record)

        # 2. 执行回滚
        try:
            # 停止当前版本
            print("Stopping current version...")

            # 部署目标版本
            print(f"Deploying version {target_version}...")

            # 验证回滚
            print("Verifying rollback...")

            print(f"Rollback to version {target_version} completed successfully!")

        except Exception as e:
            print(f"Rollback failed: {e}")
            raise

    def get_rollback_history(self):
        """获取回滚历史"""
        return self.rollback_history

3.2 GitOps实践

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# ========== GitOps with ArgoCD ==========

# 应用部署清单
# apps/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-application
  namespace: argocd
spec:
  project: default

  source:
    repoURL: https://github.com/org/infrastructure.git
    targetRevision: main
    path: apps/my-application
    helm:
      valueFiles:
        - values-prod.yaml

  destination:
    server: https://kubernetes.default.svc
    namespace: production

  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

# Kubernetes部署清单
# apps/my-application/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-application
  labels:
    app: my-application
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-application
  template:
    metadata:
      labels:
        app: my-application
    spec:
      containers:
      - name: app
        image: registry.example.com/my-application:{{ .Values.image.tag }}
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: my-application
spec:
  selector:
    app: my-application
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-application
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: my-application-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-application
            port:
              number: 80

# Helm Values
# apps/my-application/values-prod.yaml
image:
  tag: "1.2.3"

replicas: 3

resources:
  requests:
    memory: "256Mi"
    cpu: "200m"
  limits:
    memory: "512Mi"
    cpu: "500m"

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80

database:
  host: postgres-production.example.com
  port: 5432
  name: app_production
  sslMode: require

四、基础设施即代码(IaC)

4.1 Terraform配置

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# ========== Terraform配置示例 ==========

# 主配置文件
# main.tf
terraform {
  required_version = ">= 1.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  backend "s3" {
    bucket         = "terraform-state-prod"
    key            = "production/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = {
      Environment = var.environment
      Project     = var.project_name
      ManagedBy   = "Terraform"
    }
  }
}

# VPC配置
# modules/vpc/main.tf
resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "${var.project_name}-vpc"
  }
}

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-igw"
  }
}

resource "aws_subnet" "public" {
  count                   = length(var.availability_zones)
  vpc_id                  = aws_vpc.main.id
  cidr_block              = cidrsubnet(var.vpc_cidr, 8, count.index)
  availability_zone       = var.availability_zones[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.project_name}-public-${count.index}"
    Type = "Public"
  }
}

resource "aws_subnet" "private" {
  count             = length(var.availability_zones)
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 8, count.index + length(var.availability_zones))
  availability_zone = var.availability_zones[count.index]

  tags = {
    Name = "${var.project_name}-private-${count.index}"
    Type = "Private"
  }
}

resource "aws_eip" "nat" {
  count  = length(var.availability_zones)
  domain = "vpc"

  tags = {
    Name = "${var.project_name}-nat-${count.index}"
  }

  depends_on = [aws_internet_gateway.main]
}

resource "aws_nat_gateway" "main" {
  count         = length(var.availability_zones)
  allocation_id = aws_eip.nat[count.index].id
  subnet_id     = aws_subnet.public[count.index].id

  tags = {
    Name = "${var.project_name}-nat-${count.index}"
  }

  depends_on = [aws_internet_gateway.main]
}

# EKS集群配置
# modules/eks/main.tf
resource "aws_eks_cluster" "main" {
  name     = "${var.project_name}-cluster"
  role_arn = aws_iam_role.cluster.arn
  version  = var.kubernetes_version

  vpc_config {
    subnet_ids = concat(
      aws_subnet.private[*].id,
      aws_subnet.public[*].id
    )

    endpoint_private_access = true
    endpoint_public_access  = true

    public_access_cidrs = var.allowed_public_access_cidrs
  }

  enabled_cluster_log_types = var.cluster_log_types

  depends_on = [
    aws_iam_role_policy_attachment.cluster_amazon_eks_cluster_policy,
    aws_iam_role_policy_attachment.cluster_amazon_eks_vpc_resource_controller,
  ]

  tags = {
    Name = "${var.project_name}-eks"
  }
}

resource "aws_eks_node_group" "main" {
  cluster_name    = aws_eks_cluster.main.name
  node_group_name = "${var.project_name}-node-group"
  node_role_arn   = aws_iam_role.node.arn
  subnet_ids      = aws_subnet.private[*].id

  scaling_config {
    desired_size = var.node_group_desired_size
    max_size     = var.node_group_max_size
    min_size     = var.node_group_min_size
  }

  instance_types = var.node_instance_types

  remote_access {
    ec2_ssh_key               = var.ssh_key_name
    source_security_group_ids = [aws_security_group.node.id]
  }

  labels = {
    Environment = var.environment
    Project     = var.project_name
  }

  tags = {
    Name = "${var.project_name}-node"
  }

  depends_on = [
    aws_iam_role_policy_attachment.node_amazon_eks_worker_node_policy,
    aws_iam_role_policy_attachment.node_amazon_eks_cni_policy,
    aws_iam_role_policy_attachment.node_amazon_ec2_container_registry_read_only,
  ]
}

# 变量定义
# variables.tf
variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-east-1"
}

variable "environment" {
  description = "Environment name"
  type        = string
  validation {
    condition     = contains(["development", "staging", "production"], var.environment)
    error_message = "Environment must be development, staging, or production."
  }
}

variable "project_name" {
  description = "Project name"
  type        = string
}

variable "vpc_cidr" {
  description = "CIDR block for VPC"
  type        = string
  default     = "10.0.0.0/16"
}

variable "availability_zones" {
  description = "List of availability zones"
  type        = list(string)
  default     = ["us-east-1a", "us-east-1b", "us-east-1c"]
}

# 输出定义
# outputs.tf
output "cluster_id" {
  description = "EKS cluster ID"
  value       = aws_eks_cluster.main.id
}

output "cluster_endpoint" {
  description = "EKS cluster endpoint"
  value       = aws_eks_cluster.main.endpoint
}

output "cluster_security_group_id" {
  description = "Security group ID attached to the EKS cluster"
  value       = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
}

output "cluster_certificate_authority_data" {
  description = "Base64 encoded certificate data required to communicate with the cluster"
  value       = aws_eks_cluster.main.certificate_authority[0].data
}

4.2 Docker与Kubernetes配置

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# ========== Docker配置 ==========

# Dockerfile
FROM python:3.11-slim

# 设置工作目录
WORKDIR /app

# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

# 安装系统依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        gcc \
        libc6-dev \
        && rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY src/ ./src/
COPY config/ ./config/

# 创建非root用户
RUN useradd -m -u 1000 appuser && \
    chown -R appuser:appuser /app
USER appuser

# 暴露端口
EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

# 启动应用
CMD ["gunicorn", "src.app:app", "--bind", "0.0.0.0:8080", "--workers", "4"]

# docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: my-application:latest
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/app
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=app
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d app"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on:
      - app
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:

# ========== Kubernetes配置 ==========

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-application
  labels:
    app: my-application
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: my-application
  template:
    metadata:
      labels:
        app: my-application
    spec:
      serviceAccountName: my-application

      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        fsGroup: 1000

      containers:
      - name: app
        image: registry.example.com/my-application:1.0.0
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP

        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: database-url
        - name: REDIS_URL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: redis-url

        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"

        livenessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3

        readinessProbe:
          httpGet:
            path: /ready
            port: http
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3

        lifecycle:
          preStop:
            exec:
              command:
              - sh
              - -c
              - sleep 15

      terminationGracePeriodSeconds: 30

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-application
spec:
  type: ClusterIP
  selector:
    app: my-application
  ports:
  - name: http
    port: 80
    targetPort: http
    protocol: TCP

# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-application
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-application
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
      - type: Percent
        value: 100
        periodSeconds: 30
      - type: Pods
        value: 2
        periodSeconds: 60
      selectPolicy: Max

总结

构建高效的DevOps和CI/CD流水线需要:

  1. 文化先行:建立协作、持续改进的DevOps文化
  2. 自动化优先:实现从构建到部署的全流程自动化
  3. 度量驱动:通过关键指标持续优化流程
  4. 基础设施即代码:用代码管理基础设施
  5. 持续监控:建立完善的监控和告警体系

相关工具推荐