Khóa học

Hãy tưởng tượng bạn đã giải một bài toán máy học end-to-end và tìm ra lời giải tối ưu với các mô hình tốt nhất. Tuy nhiên, khi bạn chuyển giao mã cho đội kỹ thuật, đoạn mã vốn chạy mượt trên máy của bạn lại không hoạt động trên máy chủ của họ, có thể vì hệ điều hành khác hoặc phiên bản thư viện khác.
Dù bạn đã làm việc cẩn thận và chăm chỉ, sự cố bực bội này đôi khi vẫn xảy ra. Hầu hết nhà phát triển đều trải qua ít nhất một lần. Vậy giải pháp là gì? Đó là lúc Docker xuất hiện. Với Docker, bạn có thể định nghĩa một môi trường chính xác và nhất quán cho dự án, đảm bảo mã của bạn chạy trơn tru bất kể môi trường hay thiết lập bên dưới.
Hướng dẫn này sẽ giới thiệu Docker và các khái niệm liên quan, đồng thời giải thích tầm quan trọng của nó đối với nhà khoa học dữ liệu. Ngoài ra, bài viết sẽ giúp bạn cài đặt công cụ và sử dụng cho dự án tiếp theo thông qua ví dụ. Cuối cùng — bạn sẽ học các thực tiễn tốt nhất trong ngành khi sử dụng Docker và có lời giải cho mọi thắc mắc liên quan đến Docker.
Docker, Container và Image là gì?
Docker là một nền tảng để xây dựng, chạy và phân phối ứng dụng.
Container là các gói độc lập, nhẹ, có thể thực thi, chứa mọi thứ cần để chạy một ứng dụng, bao gồm mã, runtime, thư viện, biến môi trường và tệp cấu hình.
Docker Image là một tệp chỉ đọc chứa toàn bộ hướng dẫn cần thiết để tạo ra một container. Chúng được dùng để tạo và khởi chạy các container mới lúc runtime.
Docker giúp nhà phát triển đóng gói ứng dụng cùng với các phụ thuộc vào một container, sau đó có thể chạy trên bất kỳ máy nào đã cài Docker.
Ở một nghĩa nào đó, giống như bạn được cấp một chiếc máy mới cho một dự án mới. Bạn sẽ cài các gói cần thiết, sao chép các tệp cần thiết vào máy và chạy script. Bạn cũng có thể chuyển giao “chiếc máy” mới này đi nơi khác. Ví dụ này có phần giản lược, nhưng bạn hiểu ý rồi đấy.
Docker container khác gì so với Máy ảo (Virtual Machine)?
Ngay khi chúng ta định nghĩa container, bạn sẽ tự hỏi nó khác gì máy ảo, vì cả hai đều cho phép nhiều môi trường cô lập chạy trên cùng một máy vật lý.
Hãy xem khác biệt kiến trúc trong hình dưới và thử xem bạn nhận ra điểm khác nhau nào.

Hình do tác giả cung cấp
Mỗi máy ảo là một môi trường cô lập có thể chạy các hệ điều hành và cấu hình khác nhau. Điều này cũng có nghĩa là mỗi VM cần một bản sao đầy đủ của hệ điều hành, tiêu tốn nhiều tài nguyên. Ứng dụng dạng container thì chạy trong môi trường cô lập nhưng không cần bản sao đầy đủ của hệ điều hành, nhờ đó nhẹ và hiệu quả hơn.
Dù máy ảo hữu ích, container thường là đủ và lý tưởng để phân phối ứng dụng.
Vì sao Docker quan trọng với nhà khoa học dữ liệu?
Có lẽ bạn đang thắc mắc tại sao mình, với vai trò nhà khoa học dữ liệu, cần học Docker. Chẳng phải đã có đội DevOps lo phần hạ tầng sao?
Câu hỏi hợp lý — nhưng Docker cực kỳ quan trọng với nhà khoa học dữ liệu, ngay cả khi có đội DevOps. Hãy cùng hiểu vì sao Docker hữu ích.
Tích hợp với đội DevOps
Có đội DevOps không làm mất đi lợi ích của Docker; ngược lại, nó giúp thu hẹp khoảng cách giữa đội phát triển và vận hành. Nhà khoa học dữ liệu có thể dùng Docker để đóng gói mã và chuyển cho đội DevOps triển khai và mở rộng. Bạn rất có thể sẽ gặp quy trình này trong các đội khoa học dữ liệu có cấu trúc.
Môi trường nhất quán & khả năng tái lập
Nhà khoa học dữ liệu thường làm việc với các phụ thuộc và cấu hình phức tạp cần được thiết lập và duy trì. Môi trường phải giữ nguyên để có kết quả tương tự. Docker cho phép tạo và chia sẻ một môi trường nhất quán với toàn bộ phụ thuộc và cấu hình đã cài sẵn, để người khác dễ dàng tái lập.
Tính di động
Các container Docker có thể chạy trên bất kỳ môi trường nào có Docker, gồm laptop, máy chủ và nền tảng đám mây. Điều này giúp nhà khoa học dữ liệu dễ dàng chuyển công việc giữa các môi trường khác nhau.
Phân tách tài nguyên
Docker cho phép nhiều container chạy trên cùng một máy, mỗi container có tài nguyên cô lập. Điều này giúp quản lý tài nguyên hiệu quả hơn và tránh xung đột với ứng dụng khác. Khi bạn có nhiều dự án ML, tính năng này đúng là cứu cánh.
Thúc đẩy cộng tác
Docker cho phép nhà khoa học dữ liệu chia sẻ công việc với bất kỳ ai, kể cả đội từ xa, trong các container. Cộng tác là phần thiết yếu của làm việc nhóm, và Docker giảm ma sát cho việc này.
Phần lớn nhà khoa học dữ liệu giàu kinh nghiệm sẽ đồng ý rằng với Docker, họ có thể tập trung vào công việc chuyên môn mà không bận tâm đến hạ tầng bên dưới.
Hướng dẫn Docker: Dùng Docker cho Dự án Tiếp theo
Vì đã thống nhất về sự cần thiết của Docker với nhà khoa học dữ liệu, hãy bắt tay làm quen ngay. Trước hết, chúng ta phải cài Docker trên máy và làm quen với các lệnh thường dùng.
Cài đặt Docker trên máy của bạn hoặc máy chủ nội bộ
Docker có sẵn cho mọi hệ điều hành phổ biến như Linux, Windows và Mac. Việc cài đặt khá đơn giản và tốt nhất là làm theo tài liệu chính thức.
Nếu bạn muốn tạo image của riêng mình và đẩy lên Docker Hub (như trong một số lệnh bên dưới), bạn cần tạo tài khoản trên Docker Hub. Hãy coi Docker Hub là nơi trung tâm để nhà phát triển lưu trữ và chia sẻ Docker image.
Làm quen với các lệnh Docker phổ biến
Sau khi thiết lập Docker trên máy (hoặc máy chủ), bước tiếp theo là làm quen với một số lệnh Docker. Dưới đây là danh sách lệnh bạn nên tham khảo từ tài liệu chính thức của Docker.
Để giúp bạn khởi đầu, chúng tôi liệt kê mười lệnh Docker thường dùng mà bạn chắc chắn sẽ gặp.
- docker run: Dùng để chạy một container từ image. Cờ -p ánh xạ một cổng trên máy chủ sang một cổng trên container. Ví dụ, lệnh sau sẽ chạy một container từ image "nginx" và ánh xạ cổng 80 trên máy chủ sang cổng 80 trên container.
docker run -p 80:80 nginx- docker ps: Dùng để liệt kê tất cả container đang chạy. Hữu ích khi chúng ta có nhiều container cô lập chạy trên cùng một máy.
docker ps- docker stop: Dùng để dừng một container đang chạy.
docker stop <container_id>- docker rmLệnh này dùng để xóa một container đã dừng.
docker rm <container_id>- docker images: Dùng để liệt kê tất cả image trên máy chủ. Lệnh hữu ích để xem các image cục bộ sẵn có trước khi chạy chúng để tạo container.
docker images- docker rmi: Dùng để xóa một image.
docker rmi <image_id>- docker build: Dùng để xây dựng image từ Dockerfile. Cờ -t chỉ định tên image và dấu . ở cuối chỉ định ngữ cảnh build là thư mục hiện tại.
docker build -t my_image .- docker exec: Dùng để chạy một lệnh bên trong container đang chạy.
docker exec -it <container_id> /bin/bash- docker pull: Dùng để kéo một image từ registry, chẳng hạn như Docker Hub.
docker pull <image_name>- docker push: Dùng để đẩy một image lên registry.
docker push <image_name>
Bây giờ chúng ta đã biết cách thiết lập Docker và các lệnh thường dùng, mục tiêu tiếp theo là đóng gói (dockerize) một ứng dụng máy học.
Bạn muốn được chứng nhận Docker? Hãy xem hướng dẫn về chứng chỉ Docker!
Đóng gói một Ứng dụng Máy học Đơn giản với Docker
Nếu làm theo quy trình ba bước đơn giản, việc đóng gói bất kỳ ứng dụng máy học nào bằng Docker còn dễ hơn bạn nghĩ.

Hình do tác giả cung cấp.
Hãy chọn một script máy học mức cơ bản để mọi thứ đơn giản, vì mục tiêu của chúng ta là minh họa cách đóng gói một script. Ví dụ sau xây dựng mô hình hồi quy logistic đơn giản trên tập dữ liệu iris.
# Load the libraries
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# Load the iris dataset
iris = load_iris()
X = iris.data
y = iris.target
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Train a logistic regression model
clf = LogisticRegression()
clf.fit(X_train, y_train)
# Make predictions
y_pred = clf.predict(X_test)
# Print the accuracy of the model
accuracy_score = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy_score}')
1. Xác định môi trường
Bạn cần biết chính xác môi trường hiện tại để có thể tái tạo nó ở nơi khác. Cách dễ nhất (và phổ biến nhất) là tạo tệp requirements.txt liệt kê tất cả thư viện dự án đang dùng, kèm phiên bản.
Nội dung tệp có dạng như sau:
scikit-learn==1.2.0
Lưu ý: Một ứng dụng máy học phức tạp hơn sẽ dùng thêm nhiều thư viện như NumPy, pandas, matplotlib và các thư viện khác. Do đó tạo tệp requirements.txt sẽ hợp lý hơn thay vì chỉ cài trực tiếp thư viện (sẽ nói thêm trong phần thực tiễn tốt nhất bên dưới.)
2. Viết Dockerfile
Bước tiếp theo là tạo tệp tên Dockerfile để có thể tạo môi trường và thực thi ứng dụng của chúng ta trong đó. Nói đơn giản, đây là “sổ tay hướng dẫn” cho Docker, nêu môi trường cần có, nội dung và các bước thực thi.
FROM python:3.9
WORKDIR /src
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python","iris_classification.py"]
Dockerfile này dùng image Python chính thức làm base image, đặt thư mục làm việc, sao chép tệp requirements.txt và cài đặt phụ thuộc, sao chép mã ứng dụng và chạy lệnh python iris_classification.py để khởi động ứng dụng.
3. Build Image
Bước cuối để tạo môi trường có thể tái lập là tạo một image (cũng có thể coi là khuôn mẫu) có thể chạy để tạo ra bất kỳ số lượng container nào với cùng cấu hình.
Bạn có thể build image bằng cách chạy lệnh docker build -t <image-name> . trong cùng thư mục chứa Dockerfile.
Giờ bạn đã đóng gói ứng dụng máy học đơn giản ở trên bằng Docker, bạn có thể dùng lệnh docker run, tạo container, rồi dừng chúng khi cần. Chúng ta đã đề cập một số lệnh phổ biến trước đó.
Giờ hãy chuyển từ kiến thức cơ bản sang các kỳ vọng trong môi trường doanh nghiệp.
Các Thực tiễn Tốt nhất Khi Dùng Docker trong Ngành
Hiểu cơ bản là đủ để bắt đầu, nhưng khi làm việc trong ngành, việc tuân theo các thực tiễn tốt nhất là điều tối quan trọng.
Giữ số lượng lớp (layer) ở mức thấp
Mỗi chỉ thị trong Dockerfile tạo ra một layer mới. Quá nhiều layer sẽ làm image lớn và chậm truyền tải.
Xem đoạn mã ví dụ dưới đây:
# Use the official Python image as the build image
FROM python:3.9
# Install the dependencies
RUN pip install pandas
RUN pip install matplotlib
RUN pip install seaborn
# Copy neccesary files
COPY my_script.py .
COPY data/ .
# Run the script
CMD ["python","my_script.py"]
Bạn thấy vấn đề gì? Việc dùng nhiều lệnh run và copy là không cần thiết. Đây là cách khắc phục:
# Use the official Python image as the build image
FROM python:3.9
# Install the dependencies using requirements.txt
COPY my_script.py requirements.txt data/ .
RUN pip install --no-cache-dir -r requirements.txt
# Run the script
CMD ["python","my_script.py"]
Dù điều này rõ ràng trong một tệp nhỏ như thế này, bạn sẽ ngạc nhiên vì chúng ta thường viết Dockerfile cồng kềnh hơn mức cần thiết. Gom các lệnh có chức năng tương tự hoặc thay đổi cùng một tệp là cách dễ để giảm số layer trong Dockerfile.
Sử dụng image chính thức
Image chính thức là các image do nhà phát hành duy trì và hỗ trợ. Chúng thường ổn định và an toàn hơn.
Đôi khi vì vội, chúng ta dùng image không chính thức một cách thiếu thận trọng. Khi có thể, hãy dùng image chính thức làm base cho image của bạn.
Build nhiều giai đoạn (multi-stage) để tối ưu hiệu năng
Multi-stage build trong Docker cho phép bạn dùng nhiều chỉ thị FROM trong cùng một Dockerfile.
Chúng ta có thể dùng một image lớn hơn làm build image để build ứng dụng, rồi sao chép các tệp cần thiết sang một image runtime nhỏ hơn. Bằng cách không đưa các tệp không cần thiết vào, ta giảm kích thước image cuối, không chỉ tối ưu hiệu năng mà còn giúp ứng dụng an toàn hơn.
Hãy xem ví dụ để hiểu rõ hơn, vì cách này được dùng rất nhiều trong ngành:
# Use the official Python image as the build image
FROM python:3.9 AS build
# Set the working directory
WORKDIR /app
# Copy the requirements.txt file
COPY requirements.txt ./
# Install the dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the application files
COPY . .
# Train the model
RUN python train.py
# Use the official Alpine Linux image as the runtime image
FROM alpine:3
# Set the working directory
WORKDIR /app
# Copy the model files from the build image
COPY --from=build /app/models /app/models
# Copy the requirements.txt file
COPY --from=build /app/requirements.txt /app
# Install the dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Run the application
CMD ["python","predict.py"]
Phân tích ví dụ này, image Python chính thức ban đầu được dùng làm build image và cài mọi phụ thuộc ở giai đoạn đó.
Sau khi chạy tệp train.py, chúng ta sao chép các tệp mô hình sinh ra và tệp requirements.txt sang image Alpine Linux nhỏ hơn cho runtime, dùng để chạy ứng dụng. Nhờ dùng multi-stage build và không đưa phụ thuộc build cùng trình thông dịch Python vào image cuối, chúng ta đã làm kích thước image cuối nhỏ đi đáng kể.
Dùng volume để lưu dữ liệu bền vững
Dữ liệu bên trong container sẽ không còn khi container dừng và bị xóa, nhưng đôi khi bạn cần giữ lại kết quả thí nghiệm để tham chiếu sau. Cũng có thể bạn muốn chia sẻ dữ liệu giữa nhiều container.
Bằng cách dùng lệnh volume, bạn đảm bảo dữ liệu được lưu bên ngoài container. Đây là ví dụ cách thực hiện:
# Use the official Python image as the base image
FROM python:3.9
# Set the working directory
WORKDIR /app
# Copy the requirements.txt file
COPY requirements.txt ./
# Install the dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application files
COPY . .
# Create a directory for storing data
RUN mkdir /app/data
# Define a volume for the data directory
VOLUME /app/data
# Run the application
CMD ["python","main.py"]
Tổ chức và quản lý phiên bản Docker image
Khi bạn bắt đầu làm việc với nhiều Docker image, mọi thứ sẽ rối và nhu cầu tổ chức nảy sinh. Dù thực tiễn có thể khác nhau giữa các tổ chức, ta có thể nêu vài cách thường gặp để tổ chức Docker image:
- Tuân theo quy ước đặt tên nhất quán cho mỗi image. Ví dụ, theo định dạng <registry>/<organization>/<image>:<version>. Điều này giúp nhận diện image và phiên bản trong registry.
- Tuân theo thực tiễn quản lý phiên bản image là thiết yếu, phòng khi cần quay lại phiên bản trước. Bạn đã thấy phiên bản là một phần của quy ước đặt tên, và phiên bản có thể ở dạng major>.<minor>.<patch>.
- Gắn thẻ (tag) image bằng các nhãn có ý nghĩa như latest, staging, production cũng giúp tổ chức và quản lý. Cách này cho phép bạn nhanh chóng nhận biết image dành cho các môi trường và giai đoạn khác nhau trong pipeline triển khai.
Nên thống nhất với tổ chức của bạn; cả đội được kỳ vọng tuân cùng một quy ước.
Kết luận
Bài viết này đề cập tầm quan trọng của việc tạo mã và ứng dụng có thể tái lập bằng các công cụ như Docker cho nhà khoa học dữ liệu. Từ việc nêu tầm quan trọng của Docker đối với nhà khoa học dữ liệu đến hướng dẫn cài đặt và các lệnh Docker thường dùng. Sau đó, bài viết trình bày cách chúng ta có thể đóng gói ứng dụng máy học bằng mã mẫu và các thực tiễn tốt nhất trong ngành khi dùng Docker.
Để học thêm, bạn có thể tham gia khóa Introduction to Docker, khóa này bao quát nhiều nội dung thiết yếu. Bạn cũng có thể cân nhắc theo đuổi chứng chỉ Docker nếu bạn đang làm trong lĩnh vực này.
Phần lớn nhà khoa học dữ liệu tập trung vào các kỹ năng cốt lõi như thống kê, toán học, máy học, học sâu và lập trình mà quên học các thực tiễn kỹ nghệ phần mềm được kỳ vọng trong ngành.
Nếu bạn muốn củng cố kiến thức cốt lõi về khoa học dữ liệu, hãy xem lộ trình Data Scientist with Python giúp học có định hướng qua các dự án. Hoặc, nếu bạn cần ôn lại kỹ năng kỹ nghệ phần mềm, hãy xem khóa software engineering for data scientists with Python, bao gồm các khái niệm thiết yếu như tính mô đun, tài liệu và kiểm thử tự động.
Docker cho Nhà khoa học Dữ liệu: Câu hỏi thường gặp
Nhà khoa học dữ liệu có nên học Docker không?
Học Docker hữu ích với nhà khoa học dữ liệu vì cho phép họ dễ dàng quản lý phụ thuộc và môi trường, đảm bảo mã chạy nhất quán trên các hệ thống khác nhau. Điều đó cũng có nghĩa là họ không phải phụ thuộc hoàn toàn vào đội DevOps.
Làm thế nào để dùng Jupyter Notebook trong container Docker?
Để dùng Jupyter Notebook trong container Docker, tương tự hướng dẫn ở trên, bạn có thể tạo một Dockerfile mới rồi dùng lệnh RUN để cài Jupyter. Sau đó dùng lệnh CMD để khởi động máy chủ Jupyter Notebook. Ngoài ra, bạn có thể dùng image dựng sẵn từ Docker Hub có sẵn Jupyter. Đây là hướng dẫn chi tiết về việc dùng Jupyter Notebook, bao gồm cả qua Docker.
Làm sao tôi có thể chia sẻ dự án khoa học dữ liệu bằng Docker?
Bạn có thể chia sẻ dự án khoa học dữ liệu bằng Docker bằng cách đẩy image của bạn lên một container registry như Docker Hub. Sau đó, người khác có thể kéo image về và chạy dự án trong môi trường của họ.