Triển khai công cụ khoa học dữ liệu: Từ mã nguồn đến Docker container
Bài viết đầu tiên trong chuỗi hướng dẫn triển khai công cụ khoa học dữ liệu, giải quyết bài toán kinh điển "chạy được trên máy tôi nhưng không chạy được trên máy bạn". Chúng ta sẽ đi từ việc chia sẻ mã nguồn qua GitHub, sử dụng môi trường ảo Python, cho đến đóng gói ứng dụng bằng Docker container.

Nếu một cái cây đổ trong rừng mà không ai nghe thấy, liệu nó có phát ra âm thanh? Nếu bạn xây dựng một công cụ khoa học dữ liệu tuyệt vời mà không ai có thể sử dụng, liệu nó có tạo ra giá trị?
Một mô hình hay công cụ tối ưu hóa nằm trên laptop cá nhân có thể mang lại chút giá trị, nhưng đòn bẩy của nó sẽ bị giới hạn bởi thời gian của bạn và khả năng truyền đạt kết quả cho người khác. Một công cụ đã được triển khai có thể cho phép nhiều người truy cập vào các dự đoán và khuyến nghị giá trị mà nó tạo ra — loại bỏ bạn khỏi vị trí trung gian và trao quyền cho đối tác kinh doanh, khách hàng và đồng nghiệp sử dụng công cụ trực tiếp.
Đây là chuỗi bài viết nhiều phần, đi từ mã nguồn trên laptop của tôi đến triển khai CI/CD hoàn chỉnh cho một công cụ tối ưu hóa. Bài viết đầu tiên này sẽ đề cập đến các giải pháp cho thách thức kinh điển "chạy được trên máy tôi, nhưng không chạy được trên máy bạn".
Các chủ đề cụ thể chúng ta sẽ tìm hiểu bao gồm:
- Sao chép mã từ GitHub
- Môi trường ảo Python (virtual environment)
- Docker và container hóa
- Giới thiệu công cụ ví dụ mà chúng ta sẽ triển khai
Giới thiệu công cụ ví dụ
Công cụ chúng ta triển khai giải quyết một bài toán được gọi là bài toán cắt vật liệu (stock cutting problem). Vài năm trước, tôi đã viết một bài về bài toán này và cách giải — bạn có thể tham khảo nếu muốn tìm hiểu sâu.
Công cụ — mà tôi gọi là Cutting Stock Planner — sử dụng quy hoạch tuyến tính (linear programming) và giao diện đơn giản dựa trên FastAPI để đưa ra phương án cắt tối ưu, giúp giảm thiểu số lượng thanh vật liệu cần mua.
Hãy chạy thử một ví dụ để minh họa. Giả sử bạn muốn làm một chiếc ghế và cần thực hiện nhiều đường cắt. Bạn có thể mua thanh vật liệu dài 8 feet, và chiếc ghế yêu cầu nhiều đoạn cắt với độ dài khác nhau. Bạn nhập chiều dài thanh vật liệu và danh sách các đoạn cắt vào giao diện đơn giản, nhấn nút Create Cut Plan, và ngay lập tức bạn nhận được phương án cắt tối ưu hiển thị trên màn hình. Không có gì cầu kỳ — chỉ là một use case đơn giản, phù hợp để chúng ta triển khai.
Giao diện công cụ Cutting Stock Planner
Chia sẻ mã nguồn trên GitHub
Cách đơn giản nhất để "triển khai" (dùng từ này khá lỏng lẻo) công cụ là chia sẻ mã nguồn với người dùng dự kiến. Cách tốt nhất để chia sẻ trực tiếp mã nguồn là thông qua các công cụ quản lý phiên bản và lưu trữ đám mây như Git/GitHub. GitHub cho phép người dùng dễ dàng sao chép các tệp và cấu trúc thư mục từ dự án.
Đây không phải là hướng dẫn về Git/GitHub, nhưng hãy điểm qua nhanh cách người dùng có thể truy cập công cụ tối ưu hóa. Sau đó chúng ta sẽ nói về tất cả những hạn chế của cách tiếp cận này.
Khi đã vào repo, bạn nhấn vào nút Code màu xanh, sao chép liên kết được cung cấp. Chúng ta sẽ dùng liên kết này để báo cho Git biết cần clone repo nào.
Mở terminal, điều hướng đến thư mục bạn muốn chứa repo và chạy lệnh dưới đây (dùng URL vừa sao chép sau git clone):
git clone https://github.com/jaromhulet/cutting-stock-planner.git
Bây giờ bạn đã có một bản sao hoàn chỉnh mã của tôi trên máy. Với mã đã được clone, hãy điều hướng đến thư mục gốc của repo và chạy lệnh uvicorn bên dưới — lệnh này sẽ chạy giao diện người dùng ngay trên máy cục bộ.
Sau đó bạn có thể truy cập giao diện trong trình duyệt tại địa chỉ: http://localhost:8000/
Chia sẻ mã nguồn qua GitHub không hẳn là tồi — thực tế nó rất tốt cho việc viết mã, đặc biệt khi nhiều người cùng làm việc. Nhưng với vai trò công cụ triển khai, nó có nhiều hạn chế. Vấn đề chính là nó đặt gần như toàn bộ trách nhiệm (và thách thức) triển khai lên vai người dùng.
Dưới đây là bảng tóm tắt các hạn chế và ngữ cảnh bổ sung:
- Người dùng cần cài Git và clone repo: Việc cài Git và clone không khó, nhưng đòi hỏi một mức kiến thức kỹ thuật nhất định và có thể gây e ngại với nhiều người. Nó cũng bất tiện, làm giảm khả năng chấp nhận công cụ — ngay cả với người dùng kỹ thuật.
- Người dùng cần đúng phiên bản Python: Không chỉ cần Python được cài (thêm một tác vụ tải và cài đặt), mà còn phải đúng phiên bản.
- Người dùng cần phiên bản gói Python tương thích: Nếu phiên bản gói không khớp, ứng dụng có thể crash hoặc hoạt động bất thường. Người dùng phải hiểu yêu cầu phiên bản gói và đảm bảo đáp ứng trên máy mình. Việc khớp phiên bản cho ứng dụng này có thể gây xung đột với các ứng dụng khác trên máy.
- Người dùng cần đủ tài nguyên tính toán: Người dùng phải chạy ứng dụng cục bộ, nghĩa là tài nguyên tính toán phải đến từ họ. Với ứng dụng nhỏ này thì không sao, nhưng nhiều công cụ production có thể khó hoặc không thể chạy cục bộ.
Sử dụng môi trường ảo Python
Sau khi hiểu rằng chia sẻ mã đơn thuần có những hạn chế đáng kể, hãy nói về một công nghệ trong Python gọi là môi trường ảo (virtual environment), giúp giải quyết một số vấn đề khi chỉ clone repo. Môi trường ảo là một bước đi đúng hướng, nhưng chúng ta cũng sẽ thấy chúng có giới hạn.
Lưu ý: Các ngôn ngữ lập trình khác cũng có giải pháp cô lập môi trường, nhưng vì Python được dùng rộng rãi trong khoa học dữ liệu, chúng ta sẽ tập trung vào môi trường ảo Python.
Vậy môi trường ảo Python là gì? Đó là một thư mục được cô lập chứa một trình thông dịch Python (interpreter) và một bộ gói Python riêng. Nó được tạo từ một bản cài Python cụ thể trên máy bạn, nên bản thân môi trường ảo thường không giải quyết vấn đề cần đúng phiên bản Python. Tuy nhiên, tính cô lập cho phép người dùng thay đổi bên trong môi trường ảo mà không ảnh hưởng đến thiết lập hay thực thi của các dự án, ứng dụng khác.
Hãy minh họa lợi ích của môi trường ảo bằng một ví dụ đơn giản. Giả sử ta có code A xây dựng tháng trước, dùng FastAPI phiên bản 0.141.1 — giống ứng dụng của chúng ta. Ta cũng có code B xây dựng hai năm trước, dùng FastAPI phiên bản 0.120.0. Hiện tại máy đang cài FastAPI 0.141.0, nhưng hôm nay ta muốn chạy code B. Ta phải gỡ FastAPI 0.141.0 và cài FastAPI 0.120.0 — hơi khó chịu. Rồi mai cần chạy code A, lại phải quay về FastAPI 0.141.0! Hãy tưởng tượng ta có nhiều hơn hai code base và nhiều hơn một gói. Vấn đề này nhanh chóng trở thành cơn đau đầu. Môi trường ảo tạo ra các vùng cô lập, nơi các cấu hình khác nhau tồn tại mà không xung đột với nhau.
Môi trường ảo giúp quản lý xung đột phiên bản
Giờ ta đã hiểu môi trường ảo là gì và cách dùng để giúp code chạy trên máy khác, hãy tóm tắt so sánh chúng với việc chỉ sao chép mã từ GitHub:
- Chỉ dùng GitHub: Cần cài Git và clone repo? Có. Cần cài Python? Có. Cần phiên bản Python khớp yêu cầu? Có. Cần tài nguyên của người dùng? Có. Cần cài dependencies vào môi trường Python gốc? Có.
- GitHub + Môi trường ảo: Cần cài Git và clone repo? Có. Cần cài Python? Có. Cần phiên bản Python khớp? Có. Cần tài nguyên người dùng? Có. Cần cài dependencies vào môi trường Python gốc? Không!
Môi trường ảo giúp người dùng tổ chức quản lý dependencies tốt hơn, nhưng trách nhiệm thiết lập môi trường cần thiết trên máy vẫn thuộc về người dùng. Trong phần tiếp theo, chúng ta sẽ xem container hóa với Docker chuyển phần lớn trách nhiệm thiết lập và cấu hình môi trường ra khỏi người dùng như thế nào.
Container hóa với Docker
Cho đến giờ, chúng ta đã nói về các cách chạy ứng dụng trên máy khác yêu cầu người dùng tự thiết lập môi trường phù hợp. Docker tiếp cận theo hướng khác. Nó cho phép đóng gói mã và dependencies vào một container image. Sau đó ta có thể chia sẻ image này với người dùng, họ dùng Docker để tạo và chạy container từ image đó. Thay vì yêu cầu người dùng cài Python, cấu hình môi trường ảo và cài các gói cần thiết, chúng ta cung cấp một môi trường sẵn sàng để chạy.
Docker thực sự mạnh mẽ và giải quyết nhiều vấn đề chúng ta gặp khi cố làm code chạy trên máy tính khác. Vì vậy, hãy dành chút thời gian tìm hiểu Docker. Chúng ta bắt đầu bằng việc định nghĩa và thảo luận về Dockerfile, image và container.
Dockerfile
Dockerfile là một tập hợp các chỉ dẫn dùng để tạo Docker image. Các chỉ dẫn này bao gồm những thứ như phiên bản Python sử dụng, nơi tìm mã nguồn, và nơi lấy yêu cầu phiên bản gói. Hãy đi qua Dockerfile đơn giản cho ứng dụng cắt vật liệu của chúng ta để có trải nghiệm thực tế.
Đây là Dockerfile cho ứng dụng:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Hãy đi từng dòng:
FROM python:3.12-slim: Dòng đầu tiên thực chất bảo Docker bắt đầu từ một image có sẵn khác đã chứa Python 3.12 làm nền tảng. Đây là image Python chính thức. Bạn có thể hình dung nó như việc chỉnh sửa một công thức có sẵn. Thay vì tự sáng tạo công thức bánh pancake có chuối, bạn lấy công thức người khác đã làm và thêm nguyên liệu riêng. Trong trường hợp này,python:3.12-slimlà công thức khởi đầu, phần còn lại của Dockerfile thêm những thứ ứng dụng cần.WORKDIR /app: Bảo Docker tạo và dùng/applàm thư mục làm việc bên trong image.COPY requirements.txt .: Bảo Docker sao chép tệprequirements.txtvào image. Dấu.nghĩa là sao chép vào thư mục làm việc hiện tại, đã được đặt là/appở dòng trước.RUN pip install --no-cache-dir -r requirements.txt: Hướng dẫn Docker cài các gói định nghĩa trongrequirements.txtvào image khi image được build. Đây là nơi Docker tự động tái tạo môi trường gói mà trước đó ta phải quản lý thủ công khi clone repo và dùng môi trường ảo.COPY app.py .: Bảo Docker sao chép tệpapp.pyvào thư mục làm việc.EXPOSE 8000: Báo Docker rằng ứng dụng dự kiến lắng nghe trên cổng 8000. Điều này không thực sự làm cổng truy cập được từ máy chủ; việc ánh xạ cổng được thiết lập khi ta chạy container.CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]: Bảo Docker chạy dòng lệnh này trong terminal khi khởi động container từ image. Lệnh này khởi động giao diện cho công cụ tối ưu cắt vật liệu.
Image
Docker image là các bộ sưu tập được đóng gói chứa mã, dependencies và các gói khác cần thiết để chạy ứng dụng. Chúng được tạo dựa trên chỉ dẫn trong Dockerfile. Docker image là thứ có thể chia sẻ để làm ứng dụng chạy trên máy tính khác.
Image có thể được tạo dễ dàng bằng lệnh docker build.
Container
Container đơn giản là các phiên bản đang chạy của image. Chúng là ứng dụng sống. Ta không thể giải bài toán cắt vật liệu bằng Dockerfile hay image, vì cả hai đều không phải ứng dụng đang chạy. Container được tạo từ image và cung cấp môi trường chạy nơi ứng dụng thực thi, sử dụng tài nguyên tính toán của máy chủ.
Để có container cho ứng dụng chạy trên máy khác, yêu cầu là máy đó đã cài Docker và có đủ tài nguyên tính toán để chạy ứng dụng. Docker xử lý phần còn lại của cấu hình môi trường.
Hãy xem cách chạy ứng dụng với Docker. Nếu bạn tự tạo image (nó đã nằm trong kho image của Docker), bạn chỉ cần chạy lệnh bên dưới. Nếu image được chia sẻ với bạn, hãy điều hướng đến nơi lưu image và chạy dòng này trước để thêm vào kho image:
docker load -i cutting-stock.tar
Sau đó, bạn có thể truy cập liên kết này trong trình duyệt: http://localhost:8000/
Qua liên kết, bạn có quyền truy cập công cụ cắt vật liệu đang chạy qua Docker container. Nó vẫn chạy cục bộ và trông giống như khi chạy bằng các cách khác. Khác biệt nằm ở cách ta đến đó. Ta không cần cài Python hay phiên bản gói cụ thể. Tất cả những gì cần là Docker được cài trên máy, image, và một dòng lệnh trong terminal. Đó chính là sức mạnh của Docker!
So sánh cuối cùng
Chúng ta đã so sánh ba kỹ thuật để làm code chạy trên máy khác: chỉ clone code từ GitHub, clone code và chạy trong môi trường ảo, và chạy code với Docker container. Mỗi giải pháp cải thiện so với giải pháp trước. Docker container là người thắng cuộc; chỉ yêu cầu người dùng cung cấp tài nguyên tính toán, cài Docker, nhận image và chạy một hai dòng lệnh trong terminal.
Bảng tóm tắt so sánh:
- Cần cài Git và clone repo? GitHub only: Có — Môi trường ảo: Có — Docker: Không
- Cần cài Python trên máy? Có — Có — Không
- Cần phiên bản Python khớp yêu cầu? Có — Có — Không
- Cần cài dependencies vào môi trường Python gốc? Có — Không — Không
- Cần tài nguyên người dùng để chạy? Có — Có — Có
- Cần cài Docker trên máy người dùng? Không — Không — Có
So sánh các phương pháp triển khai
Làm thế nào để tốt hơn nữa?
Chạy Docker container cục bộ là giải pháp tốt nhất cho tính di động của mã mà chúng ta đã khám phá trong bài này. Nhưng nó vẫn có một số yêu cầu cụ thể từ người dùng: phải cài Docker. Trong bài tiếp theo, chúng ta sẽ khám phá cách làm cho ứng dụng truy cập được qua đám mây, chỉ cần kết nối internet và một trình duyệt web — thứ mà hầu như ai cũng có.
Hãy đón chờ!
Bài viết liên quan

Công nghệ
Mô hình AI hàng đầu giỏi Vật lý đến đâu? Nghiên cứu mới chỉ ra các bài kiểm tra hiện hành đang đánh giá sai
16 tháng 9, 2026

Công nghệ
Nộp đơn xin việc lẽ ra nên khó hơn. Thật đấy
25 tháng 8, 2026

Công nghệ
Tôi xây dựng công cụ kiểm tra tuyên bố bằng Codex — và nó đã bỏ sót một tuyên bố sai
16 tháng 10, 2026