Phần 1: Thiết lập một pipeline CI/CD đơn giản cho Python và PyPI
Đăng ngày 17 July 2025
Giới thiệu
Tự động hóa các quy trình phát triển đã trở nên thiết yếu trong các dự án hiện đại. Một pipeline CI/CD được thiết kế tốt không chỉ giúp phát hiện sớm các hồi quy trong chu kỳ phát triển mà còn tự động hóa hoàn toàn quy trình triển khai.
Trong bài viết này, chúng ta sẽ khám phá cách thiết lập một pipeline hoàn chỉnh với GitHub Actions cho một ứng dụng Python, từ tích hợp liên tục (CI) đến triển khai liên tục (CD) trên PyPI.
Kiến trúc Pipeline
Quy trình của chúng tôi gồm hai quy trình làm việc riêng biệt:
-
Quy trình CI: Chạy trên mỗi push và pull request
-
Quy trình CD: Chỉ được kích hoạt khi có bản phát hành GitHub
@startuml
!theme plain
package "GitHub Kho lưu trữ" {
[Source Code] as source
[GitHub Actions] as actions
}
package "Quy trình CI" {
[Checkout] as checkout_ci
[Setup Python] as python_ci
[Install Dependencies] as deps_ci
[Linting (Ruff)] as lint
[Unit Tests] as tests
}
package "Quy trình CD" {
[Checkout] as checkout_cd
[Setup Python] as python_cd
[Build Package] as build
[Publish to PyPI] as pypi
}
source --> actions : Đẩy/PR
actions --> checkout_ci
checkout_ci --> python_ci
python_ci --> deps_ci
deps_ci --> lint
lint --> tests
source --> actions : Phát hành
actions --> checkout_cd : Khi phát hành
checkout_cd --> python_cd
python_cd --> build
build --> pypi
@enduml
Cấu hình Pipeline Tích hợp Liên tục (CI)
Cấu trúc Workflow CI
Quy trình CI được thiết kế để xác thực mọi đóng góp mã nguồn. Dưới đây là cấu hình đầy đủ của nó:
name: CI/CD Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install ruff pytest pytest-mock
- name: Run Linting (Ruff)
run: ruff check .
- name: Run Tests (Pytest)
run: pytest
Phân tích các bước CI
1. Trình kích hoạt (on)
----
on:
push:
branches:
- main
pull_request:
branches:
- main
----
Pipeline được kích hoạt trên: - Mỗi lần push lên nhánh`main` - Mỗi pull request đến`main`
Cách tiếp cận này đảm bảo rằng mã chính vẫn ổn định và mọi đóng góp đều được xác thực trước khi tích hợp.
==== 2. Môi trường thực thi
```yaml
----
runs-on: ubuntu-latest
----
Ubuntu Latest mang lại sự cân bằng tốt giữa hiệu năng, chi phí và khả năng tương thích cho hầu hết các dự án Python.
==== 3. Checkout Mã
```yaml
----
- name: Checkout code
uses: actions/checkout@v4
----
Hành động`checkout@v4`Lấy mã nguồn của kho lưu trữ. Phiên bản v4 mang lại những cải tiến về hiệu năng và bảo mật.
==== 4. Cấu hình Python
```yaml
----
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
----
Việc sử dụng`'3.x'`cho phép tự động sử dụng phiên bản ổn định mới nhất của Python 3, đơn giản hóa việc bảo trì.
==== 5. Cài đặt các phụ thuộc
```yaml
----
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install ruff pytest pytest-mock
----
Bước này: - Cập nhật pip lên phiên bản mới nhất Cài đặt các phần phụ thuộc của dự án - Thêm các công cụ phát triển (linting và kiểm thử)
==== 6. Linting với Ruff
```yaml
----
- name: Run Linting (Ruff)
run: ruff check .
----
**Ruff**là một linter Python siêu nhanh được viết bằng Rust. Nó kết hợp các tính năng của nhiều công cụ (Flake8, Black, isort) thành một công cụ duy nhất có hiệu năng cao.
==== 7. Thực hiện kiểm thử
```yaml
----
- name: Run Tests (Pytest)
run: pytest
----
Pytest chạy toàn bộ bộ kiểm thử, đảm bảo rằng các thay đổi không gây ra hồi quy.
== Cấu hình Pipeline Triển khai (CD)
=== Cấu trúc của Quy trình CD
Quy trình CD chỉ được kích hoạt khi có các bản phát hành GitHub và tự động hóa việc xuất bản lên PyPI:
[source,yaml]
----
name: Publish to PyPI
on:
release:
types:
- published
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
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: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
----
=== Phân tích các bước CD
==== 1. Kích hoạt Release
```yaml
----
on:
release:
types:
- published
----
Pipeline CD chỉ được kích hoạt khi xuất bản một bản release GitHub. Cách tiếp cận này đảm bảo kiểm soát chính xác các đợt triển khai.
==== 2. Cài đặt Công cụ Build
```yaml
----
pip install setuptools wheel twine
----
- **setuptools**: Công cụ đóng gói Python - **bánh xe**: Định dạng phân phối Python hiện đại - **twine**: Công cụ an toàn để tải lên PyPI
==== 3. Cấu hình Xác thực
```yaml
----
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
----
Xác thực sử dụng token API PyPI được lưu trữ dưới dạng secret GitHub, an toàn hơn so với thông tin đăng nhập thông thường.
==== 4. Build và Xuất bản
```yaml
----
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
----
- `sdist`: Tạo một bản phân phối nguồn - `bdist_wheel`: Tạo một wheel (bản phân phối nhị phân) - `twine upload`: Xuất bản các bản phân phối lên PyPI
== Cấu hình Gói Python
=== Cấu trúc của setup.py
Để pipeline hoạt động, dự án của bạn phải bao gồm một tệp`setup.py`:
[source,python]
----
from setuptools import setup, find_packages
with open("README.adoc", "r", encoding="utf-8") as fh:
long_description = fh.read()
setup(
name="playlist-downloader",
version="1.0.0",
author="Votre Nom",
author_email="[email protected]",
description="CLI tool for managing YouTube playlists",
long_description=long_description,
long_description_content_type="text/plain",
url="https://github.com/cheroliv/playlist-downloader",
packages=find_packages(),
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
],
python_requires=">=3.8",
install_requires=[
"typer>=0.9.0",
"yt-dlp>=2023.1.6",
"google-api-python-client>=2.70.0",
"google-auth-oauthlib>=0.7.1",
"pymonad>=2.4.0",
"pyyaml>=6.0",
],
entry_points={
"console_scripts": [
"playlist-downloader=cli:app",
],
},
)
----
=== Các điểm chính của setup.py
1. **Siêu dữ liệu**: Tên, phiên bản, tác giả, mô tả
2. **Phụ thuộc**: Danh sách các gói cần thiết
3. **Điểm truy cập**: Các lệnh CLI được hiển thị
4. **Bộ phân loại**: Siêu dữ liệu cho PyPI
== Bảo mật với GitHub Secrets
=== Cấu hình Token PyPI
1. **Tạo một token API trên PyPI** :
- Đăng nhập vào PyPI - Đi đến Cài đặt tài khoản > API token - Tạo một token mới với các quyền phù hợp
1. **Thêm bí mật vào GitHub** :
- Cài đặt kho lưu trữ > Bí mật và biến > Actions - Tạo một bí mật mới có tên`PYPI_API_TOKEN` - Dán token PyPI của bạn
[plantuml, secrets-flow, svg]
----
@startuml
!theme plain
actor Developer as dev
participant "GitHub Kho lưu trữ" as repo
participant "GitHub Hành động" as actions
participant PyPI
dev -> repo : Cấu hình bí mật PYPI_API_TOKEN
repo -> actions : Kích hoạt pipeline CD khi phát hành
actions -> actions : Truy cập bí mật một cách an toàn
actions -> PyPI : Xác thực bằng token
PyPI -> PyPI : Xác thực và xuất bản gói
note over actions, PyPI
Token không bao giờ bị lộ trong nhật ký
Có thể luân chuyển tự động
end note
@enduml
----
== Quy trình triển khai hoàn chỉnh
=== Trình tự Triển khai
[plantuml, deployment-sequence, svg]
----
@startuml
!theme plain
actor Developer as dev
participant "Git cục bộ" as git
participant "GitHub" as github
participant "GitHub Hành động" as actions
participant PyPI
participant "Người dùng cuối" as users
dev -> git : git tag v1.0.0
dev -> git : git push origin v1.0.0
git -> github : Đẩy thẻ
dev -> github : Tạo bản phát hành từ thẻ
github -> actions : Kích hoạt pipeline CD
actions -> actions : Mã thanh toán
actions -> actions : Thiết lập môi trường Python
actions -> actions : Cài đặt công cụ build
actions -> actions : Xây dựng các bản phân phối (sdist + wheel)
actions -> PyPI : Tải lên PyPI bằng token
PyPI -> PyPI : Xác thực và xuất bản
users -> PyPI : pip install playlist-downloader
note over dev, github
Việc tạo bản phát hành có thể được tự động hóa hoặc thực hiện thủ công thông qua giao diện người dùng GitHub
end note
@enduml
----
=== Các trạng thái của Pipeline
[plantuml, pipeline-states, svg]
----
@startuml
!theme plain
[*] --> Idle
Idle --> CI_Running : Push/PR đã được tạo
CI_Running --> CI_Success : Tất cả các kiểm tra đều đạt
CI_Running --> CI_Failed : Linting/Tests thất bại
CI_Success --> Idle : Đã hợp nhất xong
CI_Failed --> Idle : Sửa và thử lại
Idle --> CD_Running : Bản phát hành đã được công bố
CD_Running --> CD_Success : Gói đã được xuất bản
CD_Running --> CD_Failed : Lỗi Build/Upload
CD_Success --> Idle : Gói có sẵn trên PyPI
CD_Failed --> Idle : Sửa và thử lại bản phát hành
note on link #red : Gộp các khối
note on link #green : Cho phép triển khai
@enduml
----
== Thực tiễn tốt nhất và Tối ưu hóa
=== 1. Quản lý phiên bản
Sử dụng các thẻ Git ngữ nghĩa:
```bash
----
git tag -a v1.2.3 -m "Release version 1.2.3"
git push origin v1.2.3
----
=== 2. Kiểm thử Ma trận
Để kiểm tra trên nhiều phiên bản Python:
```yaml
----
strategy:
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
----
=== 3. Bộ nhớ đệm các Phụ thuộc
Tăng tốc các bản build bằng bộ nhớ đệm:
```yaml
----
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
----
=== 4. Môi trường triển khai
Hãy sử dụng môi trường GitHub để triển khai có kiểm soát:
```yaml
----
jobs:
deploy:
environment: production
runs-on: ubuntu-latest
----
== Ca sử dụng và Kiến trúc
=== Biểu đồ ca sử dụng
[plantuml, use-cases, svg]
----
@startuml
!theme plain
left to right direction
actor "Nhà phát triển" as dev
actor "GitHub Hành động" as ga
actor "Người dùng cuối" as user
package "Hệ thống CI/CD" {
usecase "Chạy Linting" as lint
usecase "Thực thi kiểm thử" as test
usecase "Gói bản dựng" as build
usecase "Xuất bản tới PyPI" as publish
usecase "Tạo bản phát hành" as release
}
dev --> lint : Đẩy mã
dev --> test : Đẩy mã
dev --> release : Tạo bản phát hành
ga --> build : Khi kích hoạt phát hành
ga --> publish : Sau khi build thành công
user --> publish : Gói tải xuống
lint .> test : triggers
test .> build : on success
build .> publish : on success
@enduml
----
=== Kiến trúc Triển khai
[plantuml, deployment-architecture, svg]
----
@startuml
!theme plain
cloud "GitHub" {
[Source Repository]
[GitHub Actions]
[Secrets Store]
}
cloud "PyPI" {
[Package Registry]
[Distribution Files]
}
node "CI/CD Pipeline" {
[Linting]
[Testing]
[Building]
[Publishing]
}
[Source Repository] --> [GitHub Actions] : Triggers
[GitHub Actions] --> [Linting]
[Linting] --> [Testing]
[Testing] --> [Building]
[Building] --> [Publishing]
[Publishing] --> [Package Registry] : Uploads
[Secrets Store] --> [Publishing] : Provides token
note as N1
Xác thực bảo mật
dựa trên token
end note
[Secrets Store] .. N1
@enduml
----
== Giám sát và Gỡ lỗi
=== Nhật ký và Giám sát
GitHub Actions cung cấp nhật ký chi tiết cho từng bước. Để gỡ lỗi:
1. **Hãy kiểm tra nhật ký**của mỗi bước
2. **Bật debug**với`ACTIONS_STEP_DEBUG`
3. **Hãy sử dụng các artifacts**để sao lưu các tệp build
```yaml
----
- name: Upload build artifacts
uses: actions/upload-artifact@v3
if: failure()
with:
name: build-logs
path: build/
----
=== Thông báo
Thêm thông báo Slack hoặc email:
```yaml
----
- name: Notify on failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
----
== Kết luận
Việc thiết lập một pipeline CI/CD vững chắc với GitHub Actions thay đổi hoàn toàn trải nghiệm phát triển. Bằng cách tự động hóa linting, kiểm thử và triển khai, bạn:
- **Giảm thiểu lỗi**trong sản xuất - **Tăng tốc các chu kỳ**phát triển - **Nâng cao niềm tin**trong các bản phát hành của bạn - **Hãy tạo điều kiện thuận lợi cho việc hợp tác**theo nhóm
Pipeline này có thể được điều chỉnh cho các loại dự án Python khác nhau bằng cách điều chỉnh các công cụ linting, các framework kiểm thử, hoặc các đích triển khai.
Khoản đầu tư ban đầu vào việc cấu hình các quy trình làm việc này sẽ nhanh chóng được hoàn vốn nhờ tiết kiệm thời gian và giảm thiểu lỗi thủ công trong quá trình triển khai.
== Tài nguyên bổ sung
- https://docs.github.com/en/actions[Tài liệu GitHub Actions] - https://packaging.python.org/[Hướng dẫn đóng gói Python] - https://docs.pytest.org/[Tài liệu Pytest] - https://docs.astral.sh/ruff/[Tài liệu Ruff] - https://twine.readthedocs.io/[Tài liệu Twine]
✅ Đã đạt được pipeline hoạt động! Giờ đây bạn đã có một pipeline CI/CD đơn giản cho phép bạn tự động hóa các bài kiểm tra và xuất bản gói Python của mình lên PyPI trực tiếp từ GitHub Actions.
Tuy nhiên, pipeline này vẫn được chủ ý giữ ở mức tối giản. Nó vẫn chưa bao quát một số khía cạnh thiết yếu trong bối cảnh chuyên nghiệp:
Kiểm thử đa phiên bản Python,
Phân tích bảo mật tự động,
Triển khai dần dần qua Test PyPI,
Giám sát và số liệu đo lường của pipeline,
Tự động hóa việc quản lý phiên bản và tích hợp các thực hành tốt hiện đại (pyproject.toml).
Trong phần tiếp theo, chúng ta sẽ nâng lên một tầm cao mới. Bạn sẽ học cách biến pipeline cơ bản này thành một chuỗi triển khai công nghiệp thực thụ, vững chắc và an toàn, sẵn sàng cho các dự án Python trong môi trường sản xuất.