1. Giới thiệu
Trong ba phần trước của series “Bắt đầu với Docker”, chúng ta đã lần lượt khám phá những khái niệm nền tảng: Docker là gì và các ứng dụng thực tiễn (Phần 1), cách cài đặt Docker trên Windows, Linux và macOS (Phần 2), tiếp theo là làm quen với container cũng như các lệnh cơ bản (Phần 3).
Sang Phần 4, trọng tâm chuyển sang một thành phần quan trọng hơn trong Docker: Docker Image và Dockerfile. Docker Image có thể xem như một “snapshot” của môi trường chạy ứng dụng, chứa mọi thứ cần thiết để khởi tạo container. Dockerfile lại là tập hợp hướng dẫn giúp tự động tạo ra image đó một cách nhất quán.
Việc sử dụng Dockerfile thay vì tạo image thủ công mang lại nhiều lợi ích như dễ quản lý phiên bản, đảm bảo tính đồng nhất và tối ưu hóa quy trình build. Đây là nền tảng không thể thiếu khi triển khai ứng dụng trong môi trường thực tế.
2. Docker Image là gì?
Docker Image là một template chỉ đọc dùng để tạo container. Mỗi container được sinh ra từ image giống như cách một đối tượng được khởi tạo từ một khuôn mẫu đã có sẵn. Image chứa đầy đủ hệ điều hành tối giản, thư viện, cấu hình và mã nguồn, nhờ vậy ứng dụng có thể chạy đồng nhất trên bất kỳ máy nào.
Một Docker Image thường bao gồm ba thành phần chính. Base Image là lớp nền tảng như Alpine, Debian hoặc một runtime như Node hay Python. Filesystem snapshot chứa mã nguồn, thư viện, file cấu hình và mọi tài nguyên ứng dụng cần. Cuối cùng là hệ thống layer cache, nơi mỗi lệnh trong Dockerfile tạo ra một lớp mới và có thể được tái sử dụng trong các lần build sau.
Có ba loại image phổ biến. Official Images được duy trì bởi Docker hoặc các tổ chức lớn và là lựa chọn an toàn cho production. Community Images được chia sẻ bởi cộng đồng và cần cân nhắc khi sử dụng. Loại cuối cùng là custom images – những image bạn tự xây dựng cho dự án của mình, thường là phần bạn sẽ làm việc nhiều nhất khi triển khai ứng dụng.
3. Cấu trúc layer trong Docker Image
Docker Image không phải là một file đơn lẻ mà được tạo thành từ nhiều layer xếp chồng lên nhau. Cơ chế layer giúp Docker tái sử dụng các phần không thay đổi của image, từ đó tăng tốc độ build, giảm dung lượng lưu trữ và tối ưu quá trình phân phối image trong CI/CD.
Khi Dockerfile được xử lý, mỗi instruction như FROM, RUN, COPY hay ADD sẽ tạo ra một layer mới. Nếu ở lần build tiếp theo lệnh đó không đổi, Docker sẽ dùng lại layer đã cache thay vì tạo mới. Điều này giúp quy trình phát triển trở nên nhanh và tiết kiệm tài nguyên hơn.
Cấu trúc layer được hợp nhất bằng Union File System. Các layer bên dưới là read-only và chỉ layer trên cùng – container layer – mới cho phép ghi trong quá trình container chạy. Vì vậy khi container bị xóa, mọi thay đổi trong container layer cũng biến mất.
Sử dụng layers hiệu quả đòi hỏi hiểu rõ thứ tự lệnh trong Dockerfile. Những lệnh ít thay đổi nên được đặt trước để tận dụng tối đa cache, còn những lệnh thường thay đổi như COPY mã nguồn nên đặt sau. Khi kết hợp với .dockerignore và base image nhẹ như Alpine, bạn có thể tạo ra các image tối ưu, nhỏ gọn và build rất nhanh.
4. Dockerfile là gì?
Dockerfile là một tệp văn bản mô tả từng bước để Docker tạo ra Docker Image. Có thể xem Dockerfile như “công thức” giúp quá trình xây dựng image được tự động hóa, nhất quán và dễ kiểm soát hơn. Thay vì thao tác thủ công trong container rồi commit, Dockerfile cho phép bạn định nghĩa mọi thứ bằng mã và đưa vào Git để quản lý version.
Một Dockerfile được tạo bằng cú pháp rõ ràng, mỗi dòng là một instruction như FROM, RUN, COPY… Mỗi lệnh được thực thi theo thứ tự từ trên xuống và hình thành thành các layer trong image. Dockerfile thường được đặt ở thư mục gốc của project để Docker có thể sử dụng toàn bộ context khi build.
5. Các chỉ thị cơ bản trong Dockerfile
Dockerfile có nhiều chỉ thị, nhưng chỉ cần nắm những chỉ thị nền tảng dưới đây, bạn đã đủ khả năng tự xây dựng một image hoàn chỉnh.
FROM: Chỉ định base image. Đây luôn là dòng đầu tiên, ví dụ FROM node:18-alpine.
WORKDIR: Thiết lập thư mục làm việc bên trong container, ví dụ WORKDIR /app.
COPY: Sao chép file hoặc thư mục từ máy host vào image. Ví dụ COPY package.json ..
RUN: Thực thi các lệnh trong quá trình build, ví dụ RUN npm install.
CMD và ENTRYPOINT: Định nghĩa lệnh mặc định container chạy khi khởi động. CMD có thể bị override, còn ENTRYPOINT mang tính cố định.
EXPOSE: Khai báo cổng mà container lắng nghe (ví dụ EXPOSE 3000). Đây chỉ là metadata, không tự mở cổng.
ENV: Khai báo biến môi trường, ví dụ ENV NODE_ENV=production.
ADD: Tương tự COPY nhưng hỗ trợ giải nén và tải từ URL. Nên ưu tiên COPY để đảm bảo tính minh bạch.
6. Ví dụ: Tạo Dockerfile cho ứng dụng Node.js
Ví dụ một Dockerfile phổ biến cho ứng dụng Node.js:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]Dockerfile này thể hiện đầy đủ quá trình: chọn base image, copy file phụ thuộc, cài đặt package, đưa mã nguồn vào image và thiết lập lệnh chạy mặc định.
7. Build và chạy Docker Image
Sau khi có Dockerfile, bạn có thể tiến hành build và chạy container.
Build image:
docker build -t my-node-app .
Chạy container:
docker run -p 3000:3000 my-node-app
Liệt kê image đã có:
docker images
docker images
Xóa image không dùng:
docker rmi my-node-app
8. Tối ưu Dockerfile
Tối ưu Dockerfile giúp image nhẹ hơn và tăng tốc độ build.
Giảm số layer bằng cách gộp các lệnh RUN.
Sử dụng file .dockerignore để loại bỏ file không cần thiết trong quá trình build.
Ưu tiên sử dụng base image nhẹ như Alpine.
Áp dụng multi-stage build cho các ứng dụng cần build code trước khi chạy (như React, Go, Java).
Chỉ copy những file thực sự cần thiết vào image.
9. Kiểm tra và phân tích image
Docker hỗ trợ nhiều công cụ để kiểm tra image.
Lệnh docker history giúp xem chi tiết từng layer.
Lệnh docker inspect hiển thị metadata của image.
Các công cụ quét bảo mật như Docker Scan hoặc Trivy giúp kiểm tra lỗ hổng, đặc biệt hữu ích khi làm việc trong môi trường production.
10. Kết luận
Docker Image và Dockerfile là nền tảng giúp quy trình phát triển và triển khai ứng dụng trở nên nhất quán, tự động hóa và dễ dàng mở rộng. Khi nắm được cách xây dựng image chuẩn, tối ưu và có cấu trúc, bạn sẽ tạo được môi trường chạy ổn định trên mọi máy, đồng thời tích hợp dễ dàng vào các pipeline CI/CD hoặc hệ thống như Kubernetes.
Ở phần tiếp theo, chúng ta có thể tiếp tục tìm hiểu về Docker Compose hoặc cách quản lý volume và network để hoàn thiện kiến thức về Docker trong thực tế.
» Các tin khác: