Dockerfile là gì? 9 lệnh cơ bản & cách tối ưu Image 2026

Tóm tắt nhanh: Dockerfile là một tập tin văn bản dạng kịch bản chứa chuỗi các lệnh liên tiếp mà Docker engine đọc để tự động đóng gói mã nguồn, môi trường và thư viện thành một Docker Image. Hiểu đơn giản, nếu ứng dụng của bạn là một chiếc xe, thì file này chính là bản vẽ kỹ thuật quy định chi tiết từng con ốc vít để bất kỳ nhà máy nào cũng lắp ráp ra thành phẩm giống hệt nhau.

  • Dockerfile định nghĩa môi trường từ con số 0, chấm dứt hoàn toàn tình trạng lỗi “chạy được trên máy tính của tôi nhưng chết trên server”.
  • Mỗi dòng lệnh (như RUN, COPY) tạo ra một lớp (layer) dạng chỉ đọc, xếp chồng lên nhau tạo thành cấu trúc hoàn chỉnh.
  • Cơ chế Build Caching giúp bỏ qua các bước không thay đổi, rút ngắn thời gian triển khai từ nhiều phút xuống chỉ còn vài giây.
  • Việc kết hợp Alpine Linux và Multi-stage builds là tiêu chuẩn bắt buộc để giữ dung lượng ứng dụng ở mức siêu nhẹ và an toàn.

Bao nhiêu lần bạn hoặc đồng nghiệp của mình phải thốt lên: “Rõ ràng code này chạy bình thường trên máy tôi mà sao lên server lại sập?” Nỗi ám ảnh muôn thuở này xuất phát từ việc sai lệch phiên bản hệ điều hành, thiếu hụt thư viện hay cấu hình biến môi trường không đồng nhất.

Tưởng tượng bạn có một công thức nấu ăn kỳ diệu. Dù bạn đưa tờ công thức đó cho một đầu bếp tại Việt Nam hay một người nghiệp dư ở Mỹ, nấu ở căn bếp gia đình hay nhà hàng 5 sao, món ăn ra lò cũng có hương vị giống hệt nhau 100%. Dockerfile chính là tờ công thức đó trong thế giới lập trình hiện đại.

Sự xuất hiện của công nghệ đóng gói ứng dụng đã thay đổi vĩnh viễn cách chúng ta phát triển phần mềm. Bài viết dưới đây từ InterData sẽ đi sâu phân tích Dockerfile là gì, giải phẫu chi tiết ý nghĩa của từng dòng lệnh cốt lõi, đồng thời hướng dẫn bạn cách viết một kịch bản tối ưu nhất để triển khai dự án thực tế.

Dockerfile là gì?

Dockerfile là một tệp văn bản thuần túy (plain text) không có phần mở rộng, chứa tập hợp các chỉ thị (instructions) được viết theo cú pháp quy chuẩn mà Docker Engine sử dụng để tự động xây dựng nên một Docker Image. Đây là bước đầu tiên và quan trọng nhất trong quy trình container hóa một ứng dụng.

Theo tài liệu chính thức từ Docker Docs, hệ thống sẽ đọc lần lượt các câu lệnh từ trên xuống dưới. Mỗi dòng lệnh đại diện cho một thao tác cụ thể: từ việc tải hệ điều hành gốc, thiết lập biến môi trường, sao chép mã nguồn, cho đến khai báo cổng mạng cần mở. Thay vì bạn phải SSH vào một máy chủ trống và gõ thủ công hàng chục lệnh cài đặt, kịch bản này tự động hóa toàn bộ quá trình đó với độ chính xác tuyệt đối.

Dockerfile

Để hiểu rõ hơn, chúng ta cần phân biệt ba khái niệm nền tảng thường gây nhầm lẫn trong hệ sinh thái Docker:

  • Dockerfile — Bản thiết kế hoặc kịch bản chi tiết.
  • Docker Image — Thành phẩm dạng nén (template) được tạo ra sau khi chạy bản thiết kế trên. Nó chứa mọi thứ cần thiết để ứng dụng hoạt động.
  • Docker Container — Phiên bản thực thể đang chạy (running instance) của Image. Bạn có thể khởi động hàng trăm Container độc lập từ chỉ một Image duy nhất.

Khác với các bash script thông thường vốn hay bị lỗi nếu chạy lại nhiều lần trên cùng một máy, tập tin này sở hữu tính bất biến (idempotent) cực cao nhờ cơ chế lưu trữ đệm phân lớp.

Cơ chế hoạt động của Dockerfile (Layer & Caching)

Bản chất kỹ thuật đằng sau quá trình build là kiến trúc phân lớp (Layered Architecture). Docker Engine biên dịch nội dung tệp từ trên xuống dưới (Top-down) và xử lý riêng biệt từng chỉ thị.

Mỗi câu lệnh làm thay đổi hệ thống tập tin (chẳng hạn như RUN, COPY, ADD) sẽ tạo ra một Read-only layer (lớp chỉ đọc). Các lớp này xếp chồng lên nhau một cách tuần tự. Miếng ghép cuối cùng được thêm vào khi bạn chạy ứng dụng chính là một Writable layer (lớp có thể ghi), nơi chứa các dữ liệu tạm thời sinh ra trong quá trình vận hành.

Mỗi layer trong Dockerfile giống như một miếng Lego nằm trong một tòa tháp. Nếu bạn chỉ muốn thay đổi màu sắc của miếng Lego ở trên cùng (ví dụ: sửa một dòng code), hệ thống đủ thông minh để không tháo dỡ toàn bộ nền móng bên dưới (như bước cài đặt hệ điều hành hay tải thư viện). Đó chính là Build Caching.

Việc tận dụng Cache đúng cách mang lại lợi thế khổng lồ về mặt tốc độ. Dữ liệu thực tế cho thấy, một dự án Node.js quy mô trung bình có thể mất 3-5 phút để xây dựng lần đầu. Tuy nhiên, ở những lần cập nhật mã nguồn tiếp theo, nếu bạn viết kịch bản tối ưu, thời gian này giảm xuống chỉ còn khoảng 2-4 giây do Engine tái sử dụng 90% các layer đã lưu đệm từ trước.

Sơ đồ cơ chế hoạt động của Dockerfile
Sơ đồ cơ chế hoạt động của Dockerfile

9 Câu lệnh (Instruction) cốt lõi trong Dockerfile

Dù dự án của bạn đơn giản hay phức tạp, việc nắm vững bảng từ vựng cú pháp là điều bắt buộc. Dưới đây là 9 chỉ thị thông dụng nhất, xuất hiện trong hầu hết các kịch bản thực tế.

  • FROM — Chỉ định Image gốc (Base Image) để bắt đầu. Đây luôn là câu lệnh bắt buộc và phải đứng đầu tiên trong tệp.
  • WORKDIR — Thiết lập thư mục làm việc mặc định bên trong container. Các lệnh chạy sau đó sẽ lấy thư mục này làm mốc.
  • RUN — Thực thi các lệnh Linux trong quá trình xây dựng Image (thường dùng để cài đặt thư viện như apt-get install hay npm install).
  • ENV — Khai báo các biến môi trường cấu hình cho hệ thống (ví dụ: DB_HOST, PORT).
  • EXPOSE — Báo cho Engine biết container sẽ lắng nghe trên cổng mạng nào khi hoạt động (chỉ mang tính chất tài liệu hóa, không tự động mở cổng trên máy chủ vật lý).

So sánh COPY và ADD

Cả hai lệnh đều dùng để đưa file từ máy tính gốc (host) vào bên trong Image, nhưng chúng có mức độ can thiệp khác nhau.

Tiêu chí COPY ADD
Chức năng chính Sao chép tệp/thư mục cục bộ vào Image Sao chép tệp, hỗ trợ thêm tải từ URL
Xử lý file nén (tar) Sao chép nguyên bản file nén Tự động giải nén file tar vào thư mục đích
Khuyên dùng Ưu tiên sử dụng cho 99% trường hợp Chỉ dùng khi thực sự cần tính năng giải nén tự động

So sánh CMD và ENTRYPOINT

Đây là hai lệnh dễ gây nhầm lẫn nhất cho người mới khi định nghĩa hành vi khởi chạy ứng dụng.

Đặc điểm CMD ENTRYPOINT
Mục đích Định nghĩa lệnh/tham số mặc định Định nghĩa tập tin thực thi cố định
Ghi đè lúc chạy Dễ dàng bị ghi đè hoàn toàn từ terminal Khó bị ghi đè, tham số ngoài sẽ được nối thêm vào đuôi lệnh
Trường hợp sử dụng Chạy shell tương tác hoặc app có thể thay đổi Container hoạt động như một công cụ chuyên biệt (CLI tool)

Hướng dẫn viết Dockerfile cơ bản (Ví dụ thực tế Node.js)

Để biến lý thuyết thành kinh nghiệm thực hành, chúng ta sẽ tiến hành đóng gói một ứng dụng Node.js đơn giản. Giả sử bạn có tệp server.jspackage.json trong cùng một thư mục.

1/ Tạo tệp cấu hình: Tại thư mục gốc của dự án, bạn tạo một tệp trống và đặt tên chính xác là Dockerfile (viết hoa chữ D).

2/ Viết kịch bản: Mở tệp vừa tạo và nhập vào chuỗi nội dung chuẩn mực sau đây.

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

3/ Thực thi tiến trình Build: Mở terminal tại thư mục đó và gõ lệnh docker build -t my-node-app:1.0 .. Dấu chấm ở cuối cực kỳ quan trọng, nó chỉ định đường dẫn ngữ cảnh (build context) là thư mục hiện tại.

4/ Khởi chạy ứng dụng: Chạy lệnh docker run -p 3000:3000 my-node-app:1.0 để khởi chạy container. Truy cập localhost:3000 trên trình duyệt để thấy kết quả.

🚀
Giải pháp VPS GIÁ RẺ, cấu hình cao — InterData

Bạn đã build thành công Docker Image trên máy cá nhân và muốn đưa lên Internet để mọi người cùng truy cập? Môi trường VPS Linux là lựa chọn hoàn hảo nhất để deploy Container.

Ổ cứng NVMe siêu tốc, đọc ghi dữ liệu cực nhanh
Hỗ trợ cài đặt sẵn Docker/Docker Compose
Toàn quyền quản trị Root, IPv4 riêng biệt

Thuê VPS Giá Rẻ Ngay →

5 lời khuyên tối ưu Dockerfile chuẩn chuyên gia

Một kịch bản chạy được ứng dụng chưa hẳn là một kịch bản tốt. Trong môi trường doanh nghiệp, sự cồng kềnh và lỗ hổng bảo mật là những rủi ro chí mạng. Dưới đây là 5 quy tắc vàng mà các System Admin tại InterData luôn tuân thủ.

1. Dùng thẻ Tag cụ thể, tránh xa “latest”

InterData khuyên bạn tuyệt đối không dùng tag latest trên môi trường Production. Phiên bản này cập nhật liên tục, khiến việc kiểm soát sự thay đổi môi trường trở nên bất khả thi. Hôm nay ứng dụng chạy tốt, nhưng ngày mai Base Image tự động cập nhật lên bản mới gây xung đột thư viện là sự cố cực kỳ phổ biến. Hãy dùng phiên bản cố định như python:3.10.12.

2. Sử dụng Base Image siêu nhỏ (Alpine)

Thay vì dùng hệ điều hành Ubuntu/Debian nguyên bản nặng nề, hãy tìm các image có hậu tố -alpine. Dữ liệu thực tế cho thấy, bản node:18 mặc định ngốn hơn 1GB dung lượng, trong khi phiên bản node:18-alpine chỉ chiếm khoảng ~170MB. Điều này không chỉ giảm chi phí lưu trữ mà còn thu hẹp đáng kể bề mặt tấn công của hacker.

3. Khai thác tối đa Layer Caching

Nguyên tắc vàng: Đưa các dòng lệnh ít bị thay đổi lên trên cùng. Trong ví dụ Node.js phía trên, chúng ta sao chép tệp `package.json` và chạy cài đặt thư viện trước khi sao chép toàn bộ mã nguồn. Tại sao? Vì mã nguồn của bạn thay đổi hàng giờ, còn danh sách thư viện rất ít khi thêm mới. Xếp theo thứ tự này giúp các lần sửa code sau không phải chạy lại lệnh npm install tốn thời gian.

4. Tận dụng Multi-stage builds

Với các ngôn ngữ biên dịch như Go hay Java, bạn cần SDK nặng nề để build mã nguồn thành file nhị phân (binary), nhưng lúc chạy thực tế thì không cần chúng nữa. Multi-stage build cho phép sử dụng nhiều câu lệnh FROM trong cùng một file. Bạn dùng môi trường “nặng” để build ở giai đoạn 1, sau đó chỉ nhặt lấy file thành phẩm ném sang giai đoạn 2 (một môi trường siêu nhẹ) để chạy. Cách tối ưu kích thước Docker Image hiệu quả này giúp ứng dụng giảm 90% dung lượng rác.

5. Luôn đi kèm file .dockerignore

Đừng bao giờ để lộ các thư mục như node_modules, .git hay các file biến môi trường chứa mật khẩu nhạy cảm (.env) vào trong Image. Khởi tạo một tệp .dockerignore bên cạnh kịch bản chính để giảm tải kích thước build context và ngăn chặn rò rỉ dữ liệu.

🚀
CLOUD SERVER hiệu năng cao — InterData

Khi ứng dụng Docker của bạn phát triển, chạy đa luồng hoặc sử dụng kiến trúc Microservices phức tạp, một VPS thông thường có thể trở nên quá tải. Hãy nâng cấp lên hạ tầng linh hoạt hơn.

Trải nghiệm hiệu năng vượt trội, ổn định 99.99%
Dễ dàng scale tài nguyên CPU/RAM tức thì không gián đoạn
Băng thông lớn, hoàn hảo cho các cụm container chuyên nghiệp

Thuê Cloud Server Giá Rẻ Ngay →

Câu hỏi thường gặp về Dockerfile

Khác biệt giữa Dockerfile và docker-compose.yml là gì?

Dockerfile dùng để đóng gói mã nguồn và môi trường thành một Docker Image duy nhất. Trong khi đó, tệp yml đại diện cho công cụ Docker Compose là một bản thiết kế cấp cao hơn. Nó có nhiệm vụ quản lý, cấu hình mạng lưới và khởi chạy nhiều container cùng một lúc (ví dụ: chạy một app React kết nối liền mạch với database PostgreSQL).

Một project có thể có nhiều Dockerfile không?

Hoàn toàn có thể. Thực tế trong môi trường làm việc nhóm, các dự án luôn tách biệt rõ ràng. Người ta thường dùng Dockerfile.dev chứa công cụ debug, hot-reload cho lập trình viên phát triển cục bộ, và Dockerfile.prod loại bỏ mọi thành phần thừa để đóng gói phiên bản siêu nhẹ đẩy lên máy chủ thật.

Làm sao để build Docker Image từ Dockerfile?

Mở giao diện dòng lệnh, điều hướng vào đúng thư mục chứa tệp và gõ docker build -t ten_ung_dung:v1 . (nhớ đừng bỏ sót dấu chấm ở cuối). Lệnh này ra chỉ thị cho hệ thống rà soát đường dẫn hiện hành, đọc các thiết lập bạn đã viết và tiến hành nén lại thành một Image mang tên “ten_ung_dung” với phiên bản “v1”.

Có thể chạy Dockerfile viết trên Linux sang máy Windows không?

Đây chính là vũ khí mạnh nhất của nền tảng này. Thành phẩm sinh ra từ kịch bản của bạn sẽ khởi chạy trơn tru, biểu hiện hành vi y hệt nhau trên bất kỳ hệ điều hành nào (Windows, macOS hay Linux). Bạn chỉ cần đảm bảo máy chủ đích đã cài Docker trên VPS hoặc máy tính cá nhân là đủ điều kiện vận hành.

Nên dùng base image nào cho Dockerfile?

Nên ưu tiên tuyệt đối các bản phân phối hệ điều hành siêu nhỏ có chứa từ khóa -alpine. Đây là phiên bản Linux đã được tinh gọn tối đa (nhân hệ điều hành chỉ nặng khoảng 5MB theo tài liệu từ Alpine Linux). Quyết định này giúp tiết kiệm băng thông tải xuống, bớt tốn ổ cứng và khiến tin tặc khó tìm ra công cụ để khai thác lỗ hổng.

Khi nào nên dùng ENTRYPOINT thay vì CMD?

Dùng ENTRYPOINT khi ứng dụng của bạn bắt buộc phải khởi chạy bằng một file cố định và bạn không muốn người dùng tự ý ghi đè tiến trình này. Ngược lại, CMD sinh ra để cung cấp các tham số mặc định dễ bị thay thế. Các nhà phát triển thường kết hợp cả hai: ENTRYPOINT để khóa chặt ứng dụng, còn CMD chứa các cờ (flags) điều hướng đi kèm.

Tại sao quá trình build Dockerfile lại mất quá nhiều thời gian?

Thủ phạm chính là do bạn chưa tối ưu vị trí dòng lệnh hoặc quên mất việc che giấu thư mục rác. Nếu bạn sao chép toàn bộ mã nguồn (COPY . .) ngay trước lệnh cài thư viện, bất kỳ thay đổi nào dù chỉ là sửa dấu phẩy trong file code cũng làm phá vỡ bộ đệm (cache). Máy tính sẽ phải gồng mình tải lại hàng trăm MB thư viện từ Internet một cách vô ích.

Lỗi “no space left on device” khi build là do đâu?

Sự cố này xuất hiện khi ổ cứng lưu trữ của máy tính hoặc server đã cạn kiệt dung lượng. Quá trình tạo Image sinh ra rất nhiều lớp dữ liệu thừa, các bản nháp không tên (dangling images) hoặc các container cũ đã ngừng chạy. Chỉ cần gõ lệnh dọn dẹp hệ thống docker system prune -a, bạn sẽ lấy lại được hàng chục GB ổ cứng ngay lập tức.

Lời kết

Server của bạn là một vùng đất trống. Mọi thứ bên trên — từ ứng dụng web, lượng truy cập, cho đến doanh thu của doanh nghiệp — đều đứng vững dựa trên độ ổn định của nền móng đó. Việc hiểu rõ Dockerfile là gì không chỉ giúp bạn chấm dứt chuỗi ngày gỡ lỗi môi trường mệt mỏi, mà còn đưa kỹ năng triển khai hệ thống của bạn lên cấp độ của một chuyên gia DevOps thực thụ.

Bằng cách nắm vững cú pháp nền tảng, khai thác triệt để bộ đệm Layer Caching và ứng dụng Multi-stage build, bạn hoàn toàn có thể tự tay tạo ra những ứng dụng siêu nhẹ, bảo mật và chạy mượt mà ở bất cứ đâu. Khởi đầu luôn cần môi trường thực hành tốt, đừng quên tham khảo hạ tầng Cloud Server linh hoạt tại InterData để tự do thử nghiệm các Container do chính bạn đóng gói ngay hôm nay.