Nếu bạn từng nghe đến việc “đóng gói” ứng dụng để chạy ở bất cứ đâu, thì chính Docker Image là thứ làm nên điều đó. Docker Image là nền tảng cốt lõi giúp container hoạt động. Hiểu rõ Docker Image là gì sẽ chính là bước đầu giúp bạn tiếp cận dễ dàng hơn với thế giới container hóa.
Đọc bài viết sau để hiểu hơn về:
- Docker Image là gì?
- Cấu trúc của Docker Image
- Lợi ích khi sử dụng Docker Image
- Cách thức hoạt động của Docker Image
- Quản lý và sử dụng Docker Image
- Cách tối ưu hoá Docker Image
Tổng quan Docker Image là gì
Docker Image là gì?
Docker Image là một tập hợp các file, thư viện, mã nguồn và hướng dẫn cấu hình được đóng gói sẵn để tạo ra các container trong môi trường Docker. Bạn có thể hình dung nó như một bản sao chụp (snapshot) của một hệ điều hành thu nhỏ, nơi mọi thứ đã được chuẩn bị sẵn để ứng dụng có thể chạy ngay lập tức. Docker Image có tính chất chỉ đọc (read-only), nghĩa là nội dung của chúng không thể thay đổi sau khi được tạo ra.
Mỗi khi bạn chạy một container, Docker sẽ sử dụng Docker Image làm nền tảng để tạo ra môi trường thực thi riêng biệt. Điều này giúp đảm bảo rằng ứng dụng luôn chạy nhất quán trên mọi hệ thống, bất kể là máy tính cá nhân, máy chủ hay nền tảng đám mây. Docker Image không chỉ hỗ trợ tăng tốc quá trình triển khai mà còn góp phần chuẩn hóa và tự động hóa trong phát triển phần mềm hiện đại.
Đọc thêm: Docker là gì? Hãy để Senior DevOps Engineer trả lời cho bạn!
Cấu trúc của Docker Image
Về bản chất, Docker Image được tạo thành từ nhiều lớp (layer) xếp chồng lên nhau. Mỗi layer là kết quả của một lệnh trong Dockerfile, chẳng hạn như RUN
, COPY
hay ADD
. Layer đầu tiên thường là hệ điều hành cơ bản (ví dụ: Alpine, Ubuntu), và các layer tiếp theo sẽ thêm dần các phần như thư viện, mã nguồn, file cấu hình,…
Một đặc điểm quan trọng là mỗi layer chỉ lưu trữ sự thay đổi so với layer trước đó và có tính chất không thể thay đổi (immutable). Docker sử dụng cơ chế copy-on-write, nghĩa là khi container chạy và cần thay đổi file từ image, nó sẽ tạo bản sao của file đó thay vì thay đổi trực tiếp file gốc trong image.
Mỗi khi bạn build một Docker Image mới, Docker sẽ kiểm tra xem layer nào đã tồn tại trước đó để tái sử dụng, giúp tiết kiệm thời gian và dung lượng lưu trữ. Nhờ cách tổ chức theo từng lớp như vậy, Docker không chỉ tăng hiệu suất mà còn giúp việc cập nhật hoặc thay đổi một phần trong Image trở nên linh hoạt và dễ dàng hơn. Đây cũng là lý do vì sao Docker Image trở thành công cụ mạnh mẽ trong việc đóng gói và triển khai ứng dụng.
Lợi ích khi sử dụng Docker Image
Docker Image giúp quá trình phát triển phần mềm trở nên nhanh chóng, linh hoạt và dễ dàng quản lý hơn. Dưới đây là một số lợi ích nổi bật:
- Đảm bảo tính nhất quán: Docker Image chứa toàn bộ môi trường cần thiết để ứng dụng chạy, giúp nó hoạt động giống nhau trên mọi hệ thống, từ máy tính cá nhân đến máy chủ hoặc nền tảng đám mây. Bạn không cần lo lắng về sự khác biệt giữa các môi trường.
- Giúp triển khai ứng dụng nhanh chóng và dễ dàng hơn: Thay vì cài đặt và cấu hình lại từ đầu, bạn chỉ cần tải về và chạy Docker Image.
- Tái sử dụng và chia sẻ: Docker Image cho phép bạn tái sử dụng các thành phần môi trường và dễ dàng chia sẻ Image với đồng đội hoặc cộng đồng, giảm thiểu lỗi phát sinh từ sự khác biệt môi trường.
- Quản lý phiên bản dễ dàng: Bạn có thể tạo và quản lý các phiên bản khác nhau của ứng dụng thông qua Docker Image, đảm bảo rằng mọi thay đổi đều có thể kiểm soát và quay lại khi cần thiết.
- Tính bảo mật cao hơn: Docker Image cho phép cô lập ứng dụng, giảm thiểu rủi ro bảo mật giữa các ứng dụng khác nhau trên cùng một hệ thống.
- Nhẹ và hiệu quả hơn so với máy ảo truyền thống: Docker Image thường nhẹ hơn nhiều vì chúng chia sẻ kernel của hệ điều hành máy chủ thay vì đóng gói toàn bộ hệ điều hành.
Cách thức hoạt động của Docker Image
Có thể tóm gọn cách hoạt động của Docker Image như sau: Docker Image giống như một bản “snapshot” chứa toàn bộ môi trường cần thiết để chạy ứng dụng. Mỗi Image được tạo ra từ Dockerfile – nơi chỉ định từng bước như: cách cấu hình hệ thống, cài đặt phần mềm, và sao chép các file cần thiết vào Image.
Sau khi quá trình build hoàn tất, Docker Image chứa một tập hợp các layer (lớp), mỗi lớp đại diện cho một thay đổi hoặc thao tác trong quá trình tạo Image.
Cùng tìm hiểu cụ thể các bước nhé:
Tạo Docker Image từ Dockerfile
- Khi bạn viết một Dockerfile, các lệnh trong đó (như
RUN
,COPY
,ADD
,EXPOSE
, v.v.) sẽ tạo ra các layer trong Docker Image. Mỗi layer lưu trữ các thay đổi, ví dụ: cài đặt một gói phần mềm, sao chép mã nguồn vào container, hoặc tạo thư mục mới. - Khi Docker Image được build, các layer này sẽ được xếp chồng lên nhau, và Docker sẽ lưu trữ chúng trong hệ thống của mình.
- Docker sử dụng cơ chế cache thông minh trong quá trình build, nếu một layer không thay đổi so với lần build trước, Docker sẽ sử dụng lại layer đã được cache để tăng tốc quá trình build.
Tạo Container từ Docker Image
- Khi bạn chạy lệnh
Docker run [image_name]
, Docker sử dụng Docker Image để tạo ra một container. Container này là một môi trường chạy ứng dụng, được tạo ra từ các layer trong Image. - Khi container được khởi chạy, Docker sẽ thêm một “writable layer” (lớp có thể ghi) ở trên cùng của các layer chỉ đọc từ image. Tất cả thay đổi trong container – như tạo file mới, sửa hoặc xóa file hiện có, cài đặt thêm phần mềm – chỉ ảnh hưởng đến container đó và đều được ghi vào lớp writable này.
- Container sẽ có một file system độc lập, tuy nhiên, nó chia sẻ các layer chung từ Image. Mỗi container được tạo ra từ cùng một Docker Image sẽ hoạt động giống nhau vì chúng đều sử dụng chung các layer của Image gốc.
Các thay đổi trong container không làm thay đổi Docker Image gốc. Điều này cho phép bạn thử nghiệm và thay đổi mà không làm ảnh hưởng đến các container khác được tạo từ cùng một Image.
Lưu lại các thay đổi với Docker Commit
Nếu bạn muốn giữ lại các thay đổi đã thực hiện trong container, bạn có thể tạo một Docker Image mới từ container đó bằng lệnh Docker commit [container_id] [new_image_name]
. Điều này tạo ra một Image mới với các thay đổi của bạn, và bạn có thể sử dụng Image mới này để tạo các container mới sau này.
Tái sử dụng các Layer trong Docker Image
Một trong những điểm mạnh của Docker Image là khả năng tái sử dụng các layer. Nếu một layer đã tồn tại (ví dụ, layer chứa hệ điều hành cơ bản hoặc thư viện phổ biến), Docker sẽ không cần phải xây dựng lại layer đó khi tạo container mới.
Điều này giúp tiết kiệm tài nguyên và thời gian, đặc biệt khi làm việc với nhiều container hoặc nhiều Image giống nhau. Các layer được chia sẻ giữa nhiều image cũng giúp tiết kiệm không gian lưu trữ, vì Docker chỉ lưu trữ mỗi layer một lần trên hệ thống.
Các lệnh để quản lý và sử dụng Docker Image hiệu quả
Lưu trữ và phục hồi Docker Image
Docker cung cấp hai phương pháp chính để lưu trữ và phục hồi Docker Image:
- Sử dụng Docker Save và Docker Load:
Phương pháp này cho phép bạn lưu và tải lại toàn bộ Docker Image, bao gồm tất cả các lớp (layers) và siêu dữ liệu.
Ví dụ:
# Lưu Image 'ubuntu:bionic' vào file
docker save -o /backup/ubuntu.tar ubuntu:bionic
# Xóa Image khỏi máy để kiểm tra
docker rmi ubuntu:bionic
# Tải lại Image từ file đã lưu
docker load -i /backup/ubuntu.tar
→ Phù hợp khi bạn muốn sao lưu hoặc chuyển Docker Image giữa các hệ thống mà không cần tải lại từ Docker Hub. Phương pháp này giữ nguyên cấu trúc layer của image, bao gồm cả lịch sử và metadata, nên file đầu ra thường lớn hơn nhưng hoàn toàn giống với image gốc.
Quy trình sử dụng Docker save và Docker load để lưu trữ và phục hồi Docker Image.
- Sử dụng Docker Export và Docker Import
Phương pháp này cho phép bạn xuất hệ thống tệp của một Container và nhập lại thành một Image mới. Tuy nhiên, nó không giữ lại siêu dữ liệu như tên Image hoặc tag.
Ví dụ:
# Chạy container từ Ubuntu
docker run -d --name mycontainer ubuntu:bionic
# Xuất container thành file .tar
docker export mycontainer -o /backup/container.tar
# Nhập file thành Image mới
docker import /backup/container.tar mycustomubuntu:v1
→ Phù hợp khi bạn muốn tạo một Image mới từ trạng thái hiện tại của container mà không cần giữ lại lịch sử build.
Quy trình sử dụng Docker export và Docker import để tạo Image mới từ container.
Tạo Docker Image mới
Bạn có thể tạo Docker Image mới bằng hai cách:
- Tạo Image bằng Docker Commit
Phương pháp này cho phép bạn lưu trạng thái hiện tại của một container đang chạy thành một Image mới.
Ví dụ:
# Truy cập vào container
docker exec -it mycontainer bash
# Cài đặt gói curl trong container
apt update && apt install -y curl
# Tạo Image mới từ container
docker commit mycontainer ubuntu_with_curl:v1
→ Phù hợp khi bạn đã thực hiện các thay đổi trong container và muốn lưu lại để sử dụng sau. Tuy nhiên, phương pháp này không được khuyến nghị cho môi trường production vì khó tái tạo chính xác (không có tính reproducible) và thiếu tính minh bạch trong quá trình tạo image. Image tạo bằng commit thường có kích thước lớn hơn và khó theo dõi các thay đổi.
- Tạo Image bằng Docker build từ Dockerfile – Được khuyến nghị
Phương pháp này cho phép bạn tự động hóa quá trình tạo Image bằng cách sử dụng Dockerfile.
Dockerfile mẫu:
FROM ubuntu:bionic
RUN apt update && apt install -y nginx
COPY ./index.html /var/www/html/index.html
CMD ["nginx", "-g", "daemon off;"]
Build Image:
docker build -t mynginx:v1 .
→ Phù hợp cho việc triển khai ứng dụng trong môi trường sản xuất hoặc tích hợp liên tục (CI/CD). Đây là phương pháp được khuyến nghị vì đảm bảo tính nhất quán, có thể tái tạo và dễ dàng quản lý phiên bản. Để tối ưu hóa kích thước image, bạn nên sử dụng multi-stage builds và tối ưu các lệnh RUN bằng cách kết hợp nhiều lệnh trong một layer.
Quy trình tạo Docker Image bằng Dockerfile.
Tổng hợp các lệnh cơ bản dùng để quản lý Docker Image
Sử dụng các lệnh này giúp bạn kiểm soát và duy trì kho Docker Image một cách hiệu quả.
- Liệt kê các Image hiện có:
docker Images
hoặcdocker image ls
- Xóa Image không còn sử dụng:
docker rmi mynginx:v1
hoặcdocker image rm mynginx:v1
- Gắn tag mới cho Image:
docker tag mynginx:v1 username/mynginx:latest
- Đẩy Image lên Docker Hub:
docker push username/mynginx:latest
- Tải Image từ Docker Hub:
docker pull username/mynginx:latest
- Kiểm tra chi tiết của một Image:
docker inspect mynginx:v1
- Tìm kiếm Image trên Docker Hub:
docker search nginx
- Xóa tất cả Image không sử dụng (dangling images):
docker image prune
- Dọn dẹp hệ thống (xóa containers không dùng, networks, images và build cache):
docker system prune -a
Các cách tối ưu hóa Docker Image tốt nhất
Việc tối ưu hóa Docker Image không chỉ giúp giảm dung lượng lưu trữ mà còn tăng tốc độ build, cải thiện hiệu suất CI/CD và giảm thời gian triển khai. Một Image nhỏ gọn, hiệu quả sẽ giúp tiết kiệm tài nguyên hệ thống và tránh các lỗi không mong muốn trong môi trường production.
Các cách làm tốt nhất là:
- Sử dụng image cơ sở nhỏ như Alpine Linux để giảm kích thước image
- Kết hợp nhiều lệnh RUN trong một dòng để giảm số lượng layer
- Dọn dẹp sau khi cài đặt để tránh giữ lại file không cần thiết
- Sử dụng .dockerignore để loại bỏ các file không cần thiết khi build
- Tách build thành nhiều stage để giảm kích thước image cuối cùng, đặc biệt với ứng dụng cần biên dịch
- Sử dụng người dùng không phải root giúp tăng bảo mật cho Image
- Dùng các Image chính thức
- Đặt những layer ít thay đổi ở đầu Dockerfile để tận dụng cache
- Luôn gắn tag cụ thể cho image thay vì sử dụng tag ‘latest’
Cùng đi vào chi tiết từng cách nhé:
Sử dụng Alpine Linux thay vì Ubuntu hoặc Debian
Alpine là một bản phân phối Linux siêu nhẹ (~5MB), giúp giảm đáng kể kích thước Image.
Ví dụ:
FROM alpine:latest
RUN apk add --no-cache curl
→ So với Ubuntu, Alpine giảm kích thước Image từ hàng trăm MB xuống còn vài MB. Tuy nhiên, Alpine sử dụng thư viện musl libc thay vì glibc như các distro phổ biến khác, có thể gây ra vấn đề tương thích với một số ứng dụng. Luôn kiểm tra ứng dụng của bạn chạy ổn định trên Alpine trước khi sử dụng trong môi trường production.
Sử dụng các lệnh RUN kết hợp
Mỗi lệnh RUN tạo ra một layer riêng biệt trong image. Do đó, bạn nên tránh dùng nhiều dòng RUN riêng biệt vì sẽ tạo nhiều lớp không cần thiết. Thay vào đó, bạn có thể kết hợp nhiều lệnh vào một RUN duy nhất như sau:
RUN apt update && apt install -y curl && rm -rf /var/lib/apt/lists/*
Cách này giúp giảm số lớp (layer), từ đó giảm overhead trong khi vẫn duy trì khả năng sử dụng cache của Docker.
Xoá bỏ file tạm và cache
Bạn cần nhớ phải luôn dọn dẹp sau khi cài đặt để tránh giữ lại file không cần thiết.
Ví dụ:
RUN apt update && \
apt install -y nginx && \
apt clean && \
rm -rf /var/lib/apt/lists/*
Điều này đặc biệt quan trọng khi làm việc với các package manager như apt, yum, hay npm. Nếu không xóa cache, các file tạm thời sẽ được giữ lại trong layer của image, làm tăng kích thước đáng kể. Trong các ứng dụng Node.js, xóa cache npm với npm cache clean –force sau khi cài đặt cũng rất hữu ích.
Sử dụng .dockerignore
Tương tự như .gitignore, tệp .dockerignore giúp loại trừ các file/thư mục không cần thiết khi build Image (như .git, node_modules, file log…), giúp giảm kích thước context build và thời gian gửi dữ liệu vào Docker Daemon
Ví dụ:
node_modules
.git
*.log
.env
Điều này đặc biệt quan trọng trong các dự án lớn, nơi thư mục build có thể chứa hàng GB dữ liệu không cần thiết cho image.
Tách build thành nhiều stage (Multi-stage build)
Kỹ thuật Multi-stage build giúp bạn build ứng dụng trong một Image, sau đó copy file kết quả sang một Image nhỏ gọn hơn để chạy.
Ví dụ:
# Stage 1: build app
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
# Stage 2: run app
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
→ Chỉ giữ lại thành phẩm cuối cùng, loại bỏ toàn bộ file không cần thiết.
Multi-stage build đặc biệt hữu ích cho các ngôn ngữ biên dịch như Go, Java, C++, Rust, nơi công cụ build và dependencies thường có kích thước lớn nhưng không cần thiết trong runtime. Ví dụ, một ứng dụng Go có thể giảm từ 1GB+ xuống chỉ còn vài MB.
Không chạy Container bằng quyền root
Chạy container với quyền root có thể dẫn đến rủi ro bảo mật nghiêm trọng – nếu container bị xâm nhập, kẻ tấn công có thể có toàn quyền truy cập vào máy chủ. Việc sử dụng người dùng không phải root giúp tăng bảo mật cho Image.
Ví dụ:
RUN adduser -D myuser
USER myuser
Sử dụng user không phải root cũng là một trong những yêu cầu của CIS Docker Benchmark và các tiêu chuẩn bảo mật container.
Dùng các Image chính thức
Docker Hub cung cấp nhiều Image chính thức đã được tối ưu và bảo trì tốt, bạn nên ưu tiên sử dụng chúng thay vì tạo từ đầu. Image chính thức được đánh dấu bằng nhãn “Official Image” trên Docker Hub và thường không có tiền tố namespace (ví dụ: nginx, node, python). Các image này được Docker và các nhà phát triển của từng công nghệ duy trì, thường xuyên cập nhật bản vá bảo mật và tuân thủ các best practices.
Sắp xếp các lệnh trong Dockerfile
Đặt các lệnh ít thay đổi ở đầu Dockerfile và các lệnh thường xuyên thay đổi ở cuối. Docker sẽ cache mỗi layer và chỉ rebuild từ layer đầu tiên thay đổi. Ví dụ, COPY package.json trước và cài đặt dependencies, sau đó mới COPY mã nguồn ứng dụng – vì mã nguồn thường thay đổi thường xuyên hơn file dependencies.
Câu hỏi thường gặp về Docker Image
Docker Image khác gì so với Docker Container?
Docker Image là một tệp bất biến chứa mã nguồn, thư viện và cấu hình cần thiết để tạo nên một ứng dụng. Trong khi đó, Docker container là một phiên bản đang chạy của Docker Image, hoạt động như một thể hiện (instance) sống động. Nói cách khác, Docker Image là khuôn mẫu, còn container là kết quả khi Image đó được chạy.
Docker Image có thể chạy trên Windows và Linux không?
Docker Image có thể chạy trên cả Windows và Linux, tuy nhiên cần đúng hệ điều hành nền tảng tương ứng với Image.
- Một Docker Image được xây dựng cho Linux sẽ chạy trên Docker Engine cho Linux hoặc qua máy ảo trên Windows.
- Tương tự, Image dành cho Windows yêu cầu Docker chạy trên Windows với chế độ Windows Containers. Windows cũng cung cấp Windows Subsystem for Linux (WSL) cho phép chạy container Linux trên Windows với hiệu suất tốt hơn so với sử dụng máy ảo.
Docker Image có liên quan gì đến CI/CD không?
Docker Image đóng vai trò quan trọng trong quy trình CI/CD khi giúp đóng gói ứng dụng một cách nhất quán qua các môi trường. Trong giai đoạn CI (Continuous Integration), Docker Image được tạo tự động sau mỗi lần cập nhật mã nguồn. Sau đó, trong giai đoạn CD (Continuous Deployment), Image này được triển khai nhanh chóng lên môi trường staging hoặc production.
Các công cụ CI/CD phổ biến như Jenkins, GitHub Actions, GitLab CI, và CircleCI đều có hỗ trợ tích hợp để build, test và push Docker Image.
Docker Image có thể chạy trực tiếp mà không cần Docker không?
Docker Image không thể chạy trực tiếp nếu không có Docker Engine hoặc công cụ tương thích hỗ trợ. Bởi vì Docker Image chỉ là một gói chứa ứng dụng và môi trường, cần có Docker để giải nén, quản lý và thực thi.
Do đó, để chạy được một Docker Image, bắt buộc phải có Docker hoặc công cụ container tương đương như Podman, containerd, CRI-O hoặc các runtime container OCI-compatible khác. Podman đặc biệt phổ biến vì có cú pháp tương tự Docker nhưng không yêu cầu daemon chạy với quyền root.
Tổng kết
Tóm lại, Docker Image chính là nền tảng giúp bạn xây dựng các ứng dụng hiện đại theo cách linh hoạt và dễ kiểm soát. Việc nắm vững cách tạo, quản lý và tối ưu hóa Docker Image sẽ giúp bạn làm chủ môi trường phát triển và triển khai một cách hiệu quả. Dù ứng dụng chạy trên máy cá nhân hay hệ thống Production, Docker Image luôn đảm bảo sự nhất quán và ổn định cần thiết.