持续集成(CI)和持续部署(CD)是现代软件开发中不可或缺的实践,能够显著提升开发效率、减少错误并加速交付流程。本文将探讨如何利用 GitHub Actions 和 Jenkins 构建高效的 CI/CD 流水线,并通过实战案例展示如何自动化构建、测试和部署 Python 应用程序。无论你是个人开发者还是团队成员,本文都将帮助你掌握 CI/CD 的核心技能,并优化开发工作流。
GitHub Actions 是一个内置于 GitHub 的 CI/CD 工具,使用 .github/workflows
目录下的 YAML 文件定义流水线。其主要特点包括:
push
、pull_request
)。Jenkins 是一个开源的 CI/CD 工具,支持高度自定义的流水线构建。其主要特性包括:
以下是一个使用 GitHub Actions 自动运行 pytest 单元测试的示例。
my_project/
├── src/
│ ├── math_operations.py
├── tests/
│ ├── test_math_operations.py
├── .github/
│ └── workflows/
│ └── ci.yml
# src/math_operations.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
# tests/test_math_operations.py
import pytest
from src.math_operations import add, subtract
@pytest.mark.parametrize("a, b, expected", [
(2, 3, 5),
(-1, 1, 0),
(0, 0, 0)
])
def test_add(a, b, expected):
assert add(a, b) == expected
@pytest.mark.parametrize("a, b, expected", [
(5, 3, 2),
(0, 0, 0),
(10, 5, 5)
])
def test_subtract(a, b, expected):
assert subtract(a, b) == expected
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
- name: Run tests
run: pytest tests/
当代码推送到 main
分支时,GitHub Actions 将自动运行测试并生成报告:
============================= test session starts =============================
collected 6 items
tests/test_math_operations.py ...... [100%]
============================== 6 passed in 0.03s ==============================
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello, CI/CD!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git 'https://github.com/your-repo/flask-app.git'
}
}
stage('Build') {
steps {
sh 'docker build -t flask-app .'
}
}
stage('Test') {
steps {
sh 'docker run --rm flask-app pytest'
}
}
stage('Deploy') {
steps {
sh '''
docker stop flask-app || true
docker rm flask-app || true
docker run -d --name flask-app -p 5000:5000 flask-app
'''
}
}
}
}
http://:5000
可看到 “Hello, CI/CD!”。FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
# 更新包列表
sudo apt update
# 安装 Java 运行时环境(Jenkins 依赖)
sudo apt install openjdk-11-jdk -y
# 添加 Jenkins 官方仓库
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo tee \
/usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null
# 安装 Jenkins
sudo apt update
sudo apt install jenkins -y
# 启动 Jenkins 服务
sudo systemctl start jenkins
# 设置 Jenkins 开机自启
sudo systemctl enable jenkins
访问 http://<云服务器IP>:8080
,按照提示完成初始化配置(需从服务器日志获取初始管理员密码)。
在 Jenkins 控制台依次安装以下插件:
# 安装 Docker
sudo apt install docker.io -y
# 启动 Docker 服务
sudo systemctl start docker
# 设置 Docker 开机自启
sudo systemctl enable docker
# 将当前用户加入 Docker 组(避免每次使用 sudo)
sudo usermod -aG docker $USER
newgrp docker # 立即生效
在 Jenkins 服务器与目标云服务器之间配置 SSH 免密登录:
# 在 Jenkins 服务器生成 SSH 密钥(如已有可跳过)
ssh-keygen -t rsa -b 4096
# 将公钥复制到云服务器
ssh-copy-id user@<云服务器IP>
在 Jenkins 控制台添加以下凭据:
pipeline {
agent any
environment {
SERVER_IP = 'your-server-ip'
DOCKER_HUB_REPO = 'your-dockerhub-username/flask-app'
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/your-repo/flask-app.git'
}
}
stage('Build Docker Image') {
steps {
script {
docker.build("${DOCKER_HUB_REPO}:${env.BUILD_ID}")
}
}
}
stage('Push Docker Image') {
steps {
script {
docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials-id') {
docker.image("${DOCKER_HUB_REPO}:${env.BUILD_ID}").push()
}
}
}
}
stage('Deploy to Server') {
steps {
sshagent(['ssh-credentials-id']) {
sh """
ssh -o StrictHostKeyChecking=no user@${SERVER_IP} '
docker pull ${DOCKER_HUB_REPO}:${env.BUILD_ID} && \
docker stop flask-app || true && \
docker rm flask-app || true && \
docker run -d --name flask-app -p 5000:5000 ${DOCKER_HUB_REPO}:${env.BUILD_ID}
'
"""
}
}
}
}
}
访问应用
在浏览器输入 http://<云服务器IP>:5000
,应显示 “Hello, CI/CD!”。
查看容器日志
docker logs flask-app
docker
组:sudo usermod -aG docker jenkins
sudo systemctl restart jenkins
trivy
)。通过以上步骤,您可以实现从代码提交到部署的全自动化流程。如果需要更高级的配置(如蓝绿部署、回滚机制),可进一步探索 Jenkins 的高级特性!
本文通过实战案例展示了如何使用 GitHub Actions 和 Jenkins 构建 CI/CD 流水线。GitHub Actions 适合轻量级的自动化任务,而 Jenkins 提供了更高的灵活性和可扩展性。结合 Docker 容器化技术,可以进一步简化部署流程并提高应用的一致性。
cache
功能)避免重复安装依赖。附录:相关资源