Versioning, Changelog và Dependency Management – Những thứ quyết định một phần mềm có "sống sót" được trong Production hay không
Rất nhiều dự án kỹ thuật thất bại không phải vì code tệ, mà vì quản lý phiên bản (Versioning), Dependency và Release Process kém. Một ứng dụng có thể chạy hoàn hảo trong môi trường Development nhưng lại lỗi ngay khi triển khai Production chỉ vì khác phiên bản thư viện, khác Python Interpreter hoặc API của dependency đã thay đổi.
Trong thực tế, một dự án Python không chỉ bao gồm source code. Nó còn bao gồm:
Mỗi khi chúng ta import một thư viện, chúng ta đang tạo thêm một dependency mà hệ thống phải kiểm soát trong suốt vòng đời phát triển phần mềm. Dependency có thể phá hỏng ứng dụng như thế nào?
Giả sử ứng dụng của bạn được phát triển với:
Python 3.11
requests 2.22.0
Nhưng Production đang sử dụng:
Python 3.13
requests 2.32.0
Ứng dụng có thể:
Nguyên nhân là API của thư viện có thể đã thay đổi và không còn tương thích ngược hoàn toàn. Ngay cả khi thư viện mới hơn, không có gì đảm bảo ứng dụng của bạn vẫn hoạt động chính xác nếu chưa kiểm thử đầy đủ.
Đây là lý do các hệ thống DevOps hiện đại luôn sử dụng:
để kiểm soát môi trường thực thi.
Semantic Versioning – Ngôn ngữ chung của phần mềm hiện đại
Tài liệu khuyến nghị sử dụng Semantic Versioning (SemVer).
Một phiên bản thường có dạng:
MAJOR.MINOR.PATCH
Ví dụ:
2.3.1
Ý nghĩa: MAJOR
Khi tăng Major Version:
2.x.x → 3.x.x
Có thể xuất hiện:
Không nên nâng cấp Production một cách vội vàng. MINOR
Ví dụ:
2.2.0 → 2.3.0
Thường bao gồm:
PATCH
Ví dụ:
2.3.0 → 2.3.1
Chỉ bao gồm:
Các mô hình Versioning khác
Ngoài Semantic Versioning, tài liệu còn đề cập: Serial Versioning
Version 1
Version 2
Version 3
Đơn giản nhưng không thể hiện rõ mức độ thay đổi của phần mềm. Date-based Versioning
Ví dụ:
20.04
24.04
26.04
Ubuntu sử dụng phương pháp này.
Người dùng chỉ cần nhìn vào số phiên bản là biết ngay:
20.04 = April 2020
24.04 = April 2024
Date-based Versioning ngày càng phổ biến trong các sản phẩm Cloud Native hiện đại.
Alpha, Beta, RC và GA – Đừng triển khai nhầm phiên bản
Rất nhiều kỹ sư chỉ nhìn số phiên bản mà quên mất trạng thái Release.
Ví dụ:
2.3.0dev1
Là phiên bản Development rất sớm.
2.3.0a1
Là Alpha.
Chức năng chưa hoàn thiện.
2.3.0rc1
Là Release Candidate.
Thông thường đây là phiên bản gần như hoàn chỉnh, phù hợp để:
Là General Availability (GA).
Đây mới là phiên bản đa số doanh nghiệp bắt đầu triển khai Production.
Changelog – Tài liệu mà DevOps nên đọc đầu tiên trước khi Upgrade
Mỗi package nên có một tài liệu cực kỳ quan trọng:
CHANGELOG
Tài liệu này ghi lại:
Tác giả tài liệu cũng chia sẻ một thói quen rất thực tế:
Sau đó mới kiểm tra:
Đây cũng chính là quy trình mà rất nhiều đội SecDevOps đang áp dụng.
Deprecated – Từ khóa mà DevOps không nên bỏ qua
Nếu Changelog ghi:
Deprecated
điều đó không có nghĩa tính năng đã bị xóa.
Nó có nghĩa:
Thông thường tính năng Deprecated sẽ bị xóa sau một hoặc vài phiên bản tiếp theo. Nếu tiếp tục sử dụng, một ngày nào đó ứng dụng của bạn sẽ bị phá vỡ khi nâng cấp hệ thống.
Packaging trong Python
Python sử dụng:
pip
làm Package Manager chính.
Nguồn package phổ biến nhất:
PyPI (Python Package Index)
Ưu điểm của PyPI:
Setup.py – Trái tim của quá trình đóng gói
Python sử dụng:
from setuptools import setup
để xây dựng package.
Một file tối thiểu:
setup(
name='my_package',
version='1.0.0',
packages=find_packages()
)
Ngoài ra còn có thể khai báo:
để kiểm soát toàn bộ quá trình build và cài đặt.
Source Distribution và Wheel
Sau khi build:
python3 setup.py sdist bdist_wheel
kết quả:
dist/
my_package-0.1.0.tar.gz
my_package-0.1.0-py3-none-any.whl
Trong đó: tar.gz
Source Distribution.
Cần build trên máy đích. .whl
Wheel.
Là Binary Distribution đã được build sẵn.
Triển khai:
Kết luận
Release Packaging và Dependency Management không phải là công việc "phụ" của Developer. Đây là một phần cốt lõi của DevOps và SecDevOps.
Một quy trình phát hành chuyên nghiệp cần:
Nếu bỏ qua những thành phần này, hệ thống rất dễ rơi vào tình trạng:
Đó cũng là lý do tại sao trong các hệ thống Cloud Native hiện đại, việc quản lý Version, Dependency và Release Process được xem là một năng lực cốt lõi của Platform Engineering và Software Supply Chain Security.
devops #SecDevOps python #Packaging #DependencyManagement #SemanticVersioning #SoftwareSupplyChain #PlatformEngineering #CloudNative automation
Rất nhiều dự án kỹ thuật thất bại không phải vì code tệ, mà vì quản lý phiên bản (Versioning), Dependency và Release Process kém. Một ứng dụng có thể chạy hoàn hảo trong môi trường Development nhưng lại lỗi ngay khi triển khai Production chỉ vì khác phiên bản thư viện, khác Python Interpreter hoặc API của dependency đã thay đổi.
Trong thực tế, một dự án Python không chỉ bao gồm source code. Nó còn bao gồm:
- Modules và Libraries
- Resource Files
- Runtime Environment
- Python Interpreter
- Dependency Versions
- Packaging và Release Metadata
Mỗi khi chúng ta import một thư viện, chúng ta đang tạo thêm một dependency mà hệ thống phải kiểm soát trong suốt vòng đời phát triển phần mềm. Dependency có thể phá hỏng ứng dụng như thế nào?
Giả sử ứng dụng của bạn được phát triển với:
Python 3.11
requests 2.22.0
Nhưng Production đang sử dụng:
Python 3.13
requests 2.32.0
Ứng dụng có thể:
- Không cài đặt được
- Phát sinh Exception
- Gặp lỗi Runtime
- Hoạt động không ổn định
- Bị Crash
- Giảm hiệu năng
Nguyên nhân là API của thư viện có thể đã thay đổi và không còn tương thích ngược hoàn toàn. Ngay cả khi thư viện mới hơn, không có gì đảm bảo ứng dụng của bạn vẫn hoạt động chính xác nếu chưa kiểm thử đầy đủ.
Đây là lý do các hệ thống DevOps hiện đại luôn sử dụng:
- Dependency Requirement Lists
- Virtual Environment
- Containerization
- Automated Testing
- Continuous Integration
để kiểm soát môi trường thực thi.
Semantic Versioning – Ngôn ngữ chung của phần mềm hiện đại
Tài liệu khuyến nghị sử dụng Semantic Versioning (SemVer).
Một phiên bản thường có dạng:
MAJOR.MINOR.PATCH
Ví dụ:
2.3.1
Ý nghĩa: MAJOR
Khi tăng Major Version:
2.x.x → 3.x.x
Có thể xuất hiện:
- Breaking Changes
- API không tương thích
- Yêu cầu chỉnh sửa code
Không nên nâng cấp Production một cách vội vàng. MINOR
Ví dụ:
2.2.0 → 2.3.0
Thường bao gồm:
- Tính năng mới
- Backward Compatible
- Không phá vỡ API cũ
PATCH
Ví dụ:
2.3.0 → 2.3.1
Chỉ bao gồm:
- Bug Fix
- Security Fix
- Không bổ sung tính năng mới
- Tương thích ngược
Các mô hình Versioning khác
Ngoài Semantic Versioning, tài liệu còn đề cập: Serial Versioning
Version 1
Version 2
Version 3
Đơn giản nhưng không thể hiện rõ mức độ thay đổi của phần mềm. Date-based Versioning
Ví dụ:
20.04
24.04
26.04
Ubuntu sử dụng phương pháp này.
Người dùng chỉ cần nhìn vào số phiên bản là biết ngay:
20.04 = April 2020
24.04 = April 2024
Date-based Versioning ngày càng phổ biến trong các sản phẩm Cloud Native hiện đại.
Alpha, Beta, RC và GA – Đừng triển khai nhầm phiên bản
Rất nhiều kỹ sư chỉ nhìn số phiên bản mà quên mất trạng thái Release.
Ví dụ:
2.3.0dev1
Là phiên bản Development rất sớm.
2.3.0a1
Là Alpha.
Chức năng chưa hoàn thiện.
2.3.0rc1
Là Release Candidate.
Thông thường đây là phiên bản gần như hoàn chỉnh, phù hợp để:
- Proof of Concept
- Lab Testing
- UAT
Là General Availability (GA).
Đây mới là phiên bản đa số doanh nghiệp bắt đầu triển khai Production.
Changelog – Tài liệu mà DevOps nên đọc đầu tiên trước khi Upgrade
Mỗi package nên có một tài liệu cực kỳ quan trọng:
CHANGELOG
Tài liệu này ghi lại:
- Phiên bản phát hành
- Ngày phát hành
- Tính năng mới
- Tính năng thay đổi
- Tính năng bị loại bỏ
- Bug Fix
- Security Fix
Tác giả tài liệu cũng chia sẻ một thói quen rất thực tế:
Khi có phiên bản mới, việc đầu tiên là kiểm tra Security Fixes.
Sau đó mới kiểm tra:
- Added Features
- Deprecated Features
- Removed Features
Đây cũng chính là quy trình mà rất nhiều đội SecDevOps đang áp dụng.
Deprecated – Từ khóa mà DevOps không nên bỏ qua
Nếu Changelog ghi:
Deprecated
điều đó không có nghĩa tính năng đã bị xóa.
Nó có nghĩa:
Hãy ngừng phát triển mới dựa trên tính năng này.
Thông thường tính năng Deprecated sẽ bị xóa sau một hoặc vài phiên bản tiếp theo. Nếu tiếp tục sử dụng, một ngày nào đó ứng dụng của bạn sẽ bị phá vỡ khi nâng cấp hệ thống.
Packaging trong Python
Python sử dụng:
pip
làm Package Manager chính.
Nguồn package phổ biến nhất:
PyPI (Python Package Index)
Ưu điểm của PyPI:
- Hàng nghìn thư viện
- Lưu trữ nhiều phiên bản lịch sử
- Giải quyết Dependency Conflict tốt hơn Repository của Linux Distribution
- Hỗ trợ đa nền tảng
Setup.py – Trái tim của quá trình đóng gói
Python sử dụng:
from setuptools import setup
để xây dựng package.
Một file tối thiểu:
setup(
name='my_package',
version='1.0.0',
packages=find_packages()
)
Ngoài ra còn có thể khai báo:
- install_requires
- python_requires
- dependency_links
- include_package_data
- exclude_package_data
để kiểm soát toàn bộ quá trình build và cài đặt.
Source Distribution và Wheel
Sau khi build:
python3 setup.py sdist bdist_wheel
kết quả:
dist/
my_package-0.1.0.tar.gz
my_package-0.1.0-py3-none-any.whl
Trong đó: tar.gz
Source Distribution.
Cần build trên máy đích. .whl
Wheel.
Là Binary Distribution đã được build sẵn.
Triển khai:
- Nhanh hơn
- Ít lỗi hơn
- Phù hợp Production hơn
Kết luận
Release Packaging và Dependency Management không phải là công việc "phụ" của Developer. Đây là một phần cốt lõi của DevOps và SecDevOps.
Một quy trình phát hành chuyên nghiệp cần:
- Semantic Versioning
- Changelog đầy đủ
- Dependency Control
- Virtual Environment hoặc Container
- requirements.txt
- Package Distribution chuẩn hóa
Nếu bỏ qua những thành phần này, hệ thống rất dễ rơi vào tình trạng:
"Works on my machine, fails in Production."
Đó cũng là lý do tại sao trong các hệ thống Cloud Native hiện đại, việc quản lý Version, Dependency và Release Process được xem là một năng lực cốt lõi của Platform Engineering và Software Supply Chain Security.
devops #SecDevOps python #Packaging #DependencyManagement #SemanticVersioning #SoftwareSupplyChain #PlatformEngineering #CloudNative automation