Containerizing Applications Using Docker – Vì sao Containers trở thành nền tảng của DevOps?
Trong hạ tầng truyền thống, Virtual Machine (VM) từng là phương pháp tiêu chuẩn để triển khai ứng dụng. VM linh hoạt và có mức cô lập tốt, nhưng khi DevOps yêu cầu triển khai nhanh, tự động hóa và scale liên tục, một vấn đề xuất hiện: mỗi VM phải mang theo cả một hệ điều hành riêng.
Containers giải quyết bài toán này bằng cách đóng gói ứng dụng cùng dependencies nhưng chia sẻ kernel của hệ điều hành host. Đây là một trong những lý do container trở thành nền tảng quan trọng của Cloud Native và DevOps.
1. Virtual Machine có gì hạn chế?
Một VM thông thường bao gồm:
Physical Server → Host OS → Hypervisor → Guest OS → Libraries/Binaries → Application
Mỗi VM cần Guest OS riêng, vì vậy thường:
Ưu điểm lớn của VM là khả năng isolation: mỗi ứng dụng có môi trường OS và dependencies riêng, hạn chế xung đột giữa các ứng dụng.
2. Container khác VM ở điểm nào?
Với Docker, kiến trúc được đơn giản hóa:
Physical Server → Host OS → Docker Engine → Containers
Container về bản chất là các process được cô lập chạy trên host OS. Thay vì mang theo toàn bộ Guest OS, container chủ yếu chứa:
Application + Dependencies
Do đó container thường nhỏ và nhẹ hơn VM đáng kể. Một container image có thể dưới 100 MB trong một số trường hợp, trong khi VM image thường có kích thước nhiều GB.
Container cũng có thể chỉ cần vài trăm MB RAM tùy workload, trong khi production VM thường cần từ một đến nhiều GB.
Điểm quan trọng không phải container lúc nào cũng có các con số này, mà là container loại bỏ phần Guest OS riêng của từng VM, nhờ đó tăng mật độ workload trên cùng phần cứng.
3. Docker Image và Dockerfile
Để chạy container, trước tiên cần có Container Image.
Cách phổ biến là khai báo quá trình build bằng Dockerfile. Dockerfile mô tả:
Ví dụ logic:
FROM python:3.12
COPY app.py /app/
WORKDIR /app
CMD ["python", "app.py"]
Configuration thay đổi theo từng môi trường thường nên được tách khỏi image thay vì hard-code trực tiếp vào đó.
Sau khi build, image thường được push lên Container Registry để các môi trường khác có thể pull về triển khai.
4. Image Layers – một cơ chế rất quan trọng
Docker Image không phải một khối dữ liệu duy nhất mà được xây dựng từ nhiều layers.
Khi image mới chỉ thay đổi một phần nhỏ, các layer không thay đổi có thể được cache và tái sử dụng.
Điều này giúp:
Build nhanh hơn → truyền image hiệu quả hơn → tiết kiệm storage → deployment nhanh hơn.
Đây cũng là một trong những đặc điểm khiến Docker phù hợp với CI/CD.
5. Containers và CI/CD
Một pipeline có thể hoạt động theo chuỗi:
Source Code → Test → Build Image → Security/Test → Registry → Staging → Production
Sau khi source code vượt qua các bước kiểm tra ban đầu, pipeline build container image. Image đó tiếp tục được kiểm thử, chẳng hạn bằng Dynamic Application Security Testing (DAST), trước khi được đẩy sang staging hoặc production.
Một đặc tính quan trọng là image sau khi build nên được xem như immutable artifact.
Thay vì sửa trực tiếp container đang chạy, chúng ta tạo image mới và triển khai lại. Artifact được kiểm thử cũng chính là artifact được đưa lên production, giúp giảm vấn đề kinh điển:
Container có thể khởi động chỉ trong vài giây tùy ứng dụng, nhanh hơn đáng kể so với việc boot một VM hoàn chỉnh.
Khi tải tăng:
1 Container → 5 Containers → 20 Containers
Khi tải giảm:
20 Containers → 5 Containers → 1 Container
Khả năng scale-out/scale-in nhanh này rất phù hợp với Kubernetes, Microservices và Cloud Native Architecture.
VM cũng có thể autoscale, nhưng quá trình tạo và boot Guest OS thường nặng hơn.
7. Portability và Dependency Isolation
Container đóng gói application cùng dependencies cần thiết, giúp môi trường Development, Testing và Production nhất quán hơn.
Hai ứng dụng cũng có thể sử dụng các phiên bản library khác nhau mà không nhất thiết gây xung đột:
Container A → Library v1
Container B → Library v2
Đây chính là nguyên tắc Dependency Isolation mà chúng ta đã gặp trong 12-Factor App.
Tuy nhiên, portability không có nghĩa image có thể chạy trên mọi kiến trúc CPU hoặc mọi kernel tùy ý. Container vẫn phải tương thích với OS/kernel family, CPU architecture và container runtime của môi trường đích.
8. Docker hoạt động như thế nào?
Docker cung cấp CLI và API để quản lý container. Trong kiến trúc Docker truyền thống, phần lớn công việc được thực hiện bởi Docker daemon.
Luồng đơn giản:
Docker Client → Docker API → Docker Daemon → Images / Containers / Networks / Volumes
Nhờ API, Docker có thể được tích hợp với các công cụ automation và CI/CD. 9. Container nhẹ hơn, nhưng không có nghĩa mặc nhiên an toàn hơn
Containers chia sẻ kernel với host, vì vậy mô hình isolation khác VM. Nếu container runtime hoặc kernel bị khai thác, mức độ ảnh hưởng có thể rất nghiêm trọng.
Do đó cần triển khai nhiều lớp bảo vệ như:
Namespaces, cgroups, capabilities, seccomp, SELinux/AppArmor, non-root containers, image scanning và runtime security.
Điều này kết nối trực tiếp với bài trước về Cloud Native Application Security: bảo mật phải bắt đầu từ source code, dependencies và container image, tiếp tục qua Registry, CI/CD, Kubernetes cho đến runtime. Kết luận
Điểm mạnh của Container không đơn giản là “nhẹ hơn VM”. Giá trị thực sự nằm ở khả năng tạo ra một đơn vị triển khai chuẩn hóa, portable, có dependency isolation, khởi động nhanh và dễ tự động hóa.
Có thể hình dung sự chuyển dịch:
VM:
Hardware → OS → Hypervisor → Guest OS + App
Container:
Hardware → OS → Container Runtime → App + Dependencies
Và đây chính là nền móng để đi tiếp từ:
Docker → CI/CD → Container Registry → Kubernetes → Microservices → DevSecOps.
Trong hạ tầng truyền thống, Virtual Machine (VM) từng là phương pháp tiêu chuẩn để triển khai ứng dụng. VM linh hoạt và có mức cô lập tốt, nhưng khi DevOps yêu cầu triển khai nhanh, tự động hóa và scale liên tục, một vấn đề xuất hiện: mỗi VM phải mang theo cả một hệ điều hành riêng.
Containers giải quyết bài toán này bằng cách đóng gói ứng dụng cùng dependencies nhưng chia sẻ kernel của hệ điều hành host. Đây là một trong những lý do container trở thành nền tảng quan trọng của Cloud Native và DevOps.
1. Virtual Machine có gì hạn chế?
Một VM thông thường bao gồm:
Physical Server → Host OS → Hypervisor → Guest OS → Libraries/Binaries → Application
Mỗi VM cần Guest OS riêng, vì vậy thường:
- Tiêu tốn nhiều CPU, RAM và storage.
- Image có thể lên đến nhiều GB.
- Khởi động mất khoảng 30 giây đến vài phút.
- Scale-out chậm hơn khi cần tạo thêm nhiều instance.
Ưu điểm lớn của VM là khả năng isolation: mỗi ứng dụng có môi trường OS và dependencies riêng, hạn chế xung đột giữa các ứng dụng.
2. Container khác VM ở điểm nào?
Với Docker, kiến trúc được đơn giản hóa:
Physical Server → Host OS → Docker Engine → Containers
Container về bản chất là các process được cô lập chạy trên host OS. Thay vì mang theo toàn bộ Guest OS, container chủ yếu chứa:
Application + Dependencies
Do đó container thường nhỏ và nhẹ hơn VM đáng kể. Một container image có thể dưới 100 MB trong một số trường hợp, trong khi VM image thường có kích thước nhiều GB.
Container cũng có thể chỉ cần vài trăm MB RAM tùy workload, trong khi production VM thường cần từ một đến nhiều GB.
Điểm quan trọng không phải container lúc nào cũng có các con số này, mà là container loại bỏ phần Guest OS riêng của từng VM, nhờ đó tăng mật độ workload trên cùng phần cứng.
3. Docker Image và Dockerfile
Để chạy container, trước tiên cần có Container Image.
Cách phổ biến là khai báo quá trình build bằng Dockerfile. Dockerfile mô tả:
- Base image.
- Software cần cài đặt.
- Dependencies.
- Application files.
- Các bước cần thiết để tạo môi trường chạy ứng dụng.
Ví dụ logic:
FROM python:3.12
COPY app.py /app/
WORKDIR /app
CMD ["python", "app.py"]
Configuration thay đổi theo từng môi trường thường nên được tách khỏi image thay vì hard-code trực tiếp vào đó.
Sau khi build, image thường được push lên Container Registry để các môi trường khác có thể pull về triển khai.
4. Image Layers – một cơ chế rất quan trọng
Docker Image không phải một khối dữ liệu duy nhất mà được xây dựng từ nhiều layers.
Khi image mới chỉ thay đổi một phần nhỏ, các layer không thay đổi có thể được cache và tái sử dụng.
Điều này giúp:
Build nhanh hơn → truyền image hiệu quả hơn → tiết kiệm storage → deployment nhanh hơn.
Đây cũng là một trong những đặc điểm khiến Docker phù hợp với CI/CD.
5. Containers và CI/CD
Một pipeline có thể hoạt động theo chuỗi:
Source Code → Test → Build Image → Security/Test → Registry → Staging → Production
Sau khi source code vượt qua các bước kiểm tra ban đầu, pipeline build container image. Image đó tiếp tục được kiểm thử, chẳng hạn bằng Dynamic Application Security Testing (DAST), trước khi được đẩy sang staging hoặc production.
Một đặc tính quan trọng là image sau khi build nên được xem như immutable artifact.
Thay vì sửa trực tiếp container đang chạy, chúng ta tạo image mới và triển khai lại. Artifact được kiểm thử cũng chính là artifact được đưa lên production, giúp giảm vấn đề kinh điển:
“Code chạy tốt trên máy tôi, nhưng sang production lại lỗi.”
6. Containers giúp Elastic Scaling nhanh hơnContainer có thể khởi động chỉ trong vài giây tùy ứng dụng, nhanh hơn đáng kể so với việc boot một VM hoàn chỉnh.
Khi tải tăng:
1 Container → 5 Containers → 20 Containers
Khi tải giảm:
20 Containers → 5 Containers → 1 Container
Khả năng scale-out/scale-in nhanh này rất phù hợp với Kubernetes, Microservices và Cloud Native Architecture.
VM cũng có thể autoscale, nhưng quá trình tạo và boot Guest OS thường nặng hơn.
7. Portability và Dependency Isolation
Container đóng gói application cùng dependencies cần thiết, giúp môi trường Development, Testing và Production nhất quán hơn.
Hai ứng dụng cũng có thể sử dụng các phiên bản library khác nhau mà không nhất thiết gây xung đột:
Container A → Library v1
Container B → Library v2
Đây chính là nguyên tắc Dependency Isolation mà chúng ta đã gặp trong 12-Factor App.
Tuy nhiên, portability không có nghĩa image có thể chạy trên mọi kiến trúc CPU hoặc mọi kernel tùy ý. Container vẫn phải tương thích với OS/kernel family, CPU architecture và container runtime của môi trường đích.
8. Docker hoạt động như thế nào?
Docker cung cấp CLI và API để quản lý container. Trong kiến trúc Docker truyền thống, phần lớn công việc được thực hiện bởi Docker daemon.
Luồng đơn giản:
Docker Client → Docker API → Docker Daemon → Images / Containers / Networks / Volumes
Nhờ API, Docker có thể được tích hợp với các công cụ automation và CI/CD. 9. Container nhẹ hơn, nhưng không có nghĩa mặc nhiên an toàn hơn
Containers chia sẻ kernel với host, vì vậy mô hình isolation khác VM. Nếu container runtime hoặc kernel bị khai thác, mức độ ảnh hưởng có thể rất nghiêm trọng.
Do đó cần triển khai nhiều lớp bảo vệ như:
Namespaces, cgroups, capabilities, seccomp, SELinux/AppArmor, non-root containers, image scanning và runtime security.
Điều này kết nối trực tiếp với bài trước về Cloud Native Application Security: bảo mật phải bắt đầu từ source code, dependencies và container image, tiếp tục qua Registry, CI/CD, Kubernetes cho đến runtime. Kết luận
Điểm mạnh của Container không đơn giản là “nhẹ hơn VM”. Giá trị thực sự nằm ở khả năng tạo ra một đơn vị triển khai chuẩn hóa, portable, có dependency isolation, khởi động nhanh và dễ tự động hóa.
Có thể hình dung sự chuyển dịch:
VM:
Hardware → OS → Hypervisor → Guest OS + App
Container:
Hardware → OS → Container Runtime → App + Dependencies
Và đây chính là nền móng để đi tiếp từ:
Docker → CI/CD → Container Registry → Kubernetes → Microservices → DevSecOps.