Skip to content

Module 1: Genesis & Architecture (Khởi nguyên & Kiến trúc)

🎓 Instructor Profile

Bài giảng được biên soạn bởi sự hợp tác giữa Giáo sư Tom (MIT) - chuyên gia về lý thuyết hệ thống, và Kỹ sư Raizo (Phó CTO HPN) - người có 10 năm kinh nghiệm vận hành Kubernetes quy mô lớn.

Chào mừng các kỹ sư đến với Docker Masterclass. Chúng ta không ở đây để học gõ lệnh vẹt. Chúng ta ở đây để thấu hiểu Deep Tech - trái tim của kỷ nguyên Cloud Native.

Trong module mở màn này, chúng ta sẽ mổ xẻ kiến trúc của Docker, giải mã tại sao nó lại chiến thắng trong cuộc chiến ảo hóa và nắm vững "Bộ ba quyền lực" kiến tạo nên thế giới Container.


🏗️ Phần 1: The Virtualization War (Cuộc chiến ảo hóa)

Để hiểu Docker, trước tiên ta phải hiểu "kẻ thù" mà nó đã đánh bại (hoặc chính xác hơn là bổ sung): Virtual Machines (VM).

1.1 The Metaphor: Biệt thự vs Chung cư

Hãy tưởng tượng bạn cần chỗ ở cho một ứng dụng.

  • Virtual Machine (VM) là một căn Biệt thự đơn lập:

    • Để xây nó, bạn phải làm móng, dựng cột, xây tường, lắp điện nước riêng biệt (Guest OS).
    • Mỗi biệt thự tốn rất nhiều đất (Tài nguyên phần cứng: RAM, CPU).
    • Muốn vào ở (Khởi động), bạn mất cả tháng xây dựng (Phút để boot).
    • Ưu điểm: Cách âm tuyệt đối. Hàng xóm cháy nhà, bạn vẫn an toàn (Isolation cực cao).
  • Container là một căn hộ trong Chung cư cao cấp:

    • Tòa chung cư đã có sẵn móng, cột, điện nước tổng (Host Kernel).
    • Bạn chỉ cần xách vali vào ở (Application + Libs). Không cần xây lại móng.
    • Tốn ít diện tích, chia sẻ tiện ích chung cực kỳ hiệu quả.
    • Vào ở ngay lập tức (Khởi động tính bằng mili-giây).

1.1b So sánh kiến trúc: VM vs Container

💡 Key Insight: Mỗi VM cần toàn bộ Guest OS (~1-2GB/VM). Container chỉ chứa App + Libraries (~50-200MB) và chia sẻ Kernel của Host — tiết kiệm tài nguyên gấp 10-100 lần.

1.2 Deep Dive: Tại sao Container nhanh thần tốc?

Bí mật nằm ở Kernel Sharing.

  • VM: Mỗi VM phải tải một nhân hệ điều hành (kernel) riêng. Việc boot một OS tốn hàng trăm MB RAM và hàng triệu chu kỳ CPU chỉ để... khởi động.
  • Container: Không boot OS mới. Nó tận dụng ngay Kernel của máy chủ đang chạy. Nó chỉ đơn giản là một Process (tiến trình) được "cách ly" bởi các công nghệ Linux Namespace bọc ngoài (cgroups, namespaces).
    • Boot VM = Khởi động máy tính.
    • Boot Container = Bật một phần mềm (như bật Chrome).

💡 Core Concept

Container KHÔNG phải là một cái máy tính thu nhỏ. Container một tiến trình (Process) bị nói dối rằng nó đang ở một mình.

1.3 Under the Hood: Linux Kernel Magic

Container không phải phép thuật — nó được xây dựng từ hai công nghệ cốt lõi của Linux Kernel:

🔒 Namespaces (Cách ly)

Namespace tạo ra "ảo ảnh" cho mỗi process, khiến nó nghĩ mình đang sở hữu một hệ thống riêng:

NamespaceCách ly cái gìVí dụ
PIDProcess IDsContainer thấy PID 1 là app của nó, không thấy process khác
NETNetwork stackMỗi container có IP, port table riêng biệt
MNTMount pointsFilesystem riêng, không thấy file của host
UTSHostnameContainer có hostname riêng
IPCInter-process CommunicationShared memory cách ly giữa containers
USERUser IDsRoot trong container ≠ Root trên host

📊 cgroups (Control Groups — Giới hạn tài nguyên)

Nếu Namespace là "bức tường" cách ly, thì cgroups là "đồng hồ điện" giới hạn mức tiêu thụ:

bash
# Giới hạn container chỉ dùng 512MB RAM và 0.5 CPU
docker run --memory=512m --cpus=0.5 nginx

Không có cgroups, một container "phàm ăn" có thể chiếm hết RAM của host, kéo sập toàn bộ hệ thống. Trong production, luôn đặt resource limits.


🧠 Phần 2: The Docker Engine Architecture (Kiến trúc động cơ)

Docker hoạt động theo mô hình Client-Server. Khi bạn gõ lệnh trên màn hình đen, thực ra bạn chỉ đang cầm cái điều khiển từ xa (Remote).

2.1 Các thành phần chính

  1. Docker Client (CLI): Giao diện dòng lệnh (docker build, docker run). Nơi bạn ra lệnh.
  2. Docker Daemon (dockerd): "Bộ não" thực sự. Nó chạy ngầm (background service) trên máy chủ, lắng nghe API requests từ Client và thực thi các công việc nặng nhọc (quản lý Container, Image, Network, Volume).
  3. Docker Registry: Nhà kho khổng lồ chứa các kiện hàng (Image). Nổi tiếng nhất là Docker Hub.

2.2 Data Flow: Chuyện gì xảy ra khi gõ docker run nginx?

  1. Client gửi lệnh đến Daemon.
  2. Daemon kiểm tra xem đã có bản thiết kế (Image) của nginx chưa.
  3. Nếu chưa, nó lên Registry tải về.
  4. Sau đó, nó dựng Container và báo cáo kết quả.

Phần 3: The Big 3 Concepts (Bộ ba quyền lực)

Để làm chủ Docker, hãy tư duy theo Lập trình hướng đối tượng (OOP).

Docker ConceptOOP AnalogyTính chất
DockerfileThe Source CodeBản thiết kế chi tiết, các bước để tạo ra một Image.
ImageThe ClassKhuôn mẫu. Chứa mọi thứ (Code, Libs, OS file system). Bất biến (Immutable).
ContainerThe Object (Instance)Thực thể sống. Được sinh ra từ Image. Có thể đọc/ghi dữ liệu.

Tính Bất biến (Immutability) của Image

Đây là "kinh thánh" của Docker. Một khi Image đã được build (đóng gói), nó KHÔNG BAO GIỜ thay đổi.

  • Bạn muốn sửa code? -> Sửa Dockerfile, build ra Image mới (V2).
  • Tuyệt đối không chui vào Container sửa code rồi lưu lại. Đó là tư duy sai lầm ("Pet vs Cattle").

-> Write Once, Run Anywhere. Vì Image không đổi, nên nó chạy trên máy dev thế nào, lên Server chạy y hệt thế nấy. Tạm biệt câu nói huyền thoại: "Ở máy em nó chạy bình thường mà!"


🔄 Phần 4: The Lifecycle (Vòng đời thực chiến)

Hãy hình dung quy trình nấu ăn để nhớ các lệnh CLI:

  1. Đi chợ (docker pull): Ra siêu thị (Registry) mua nguyên liệu đóng gói sẵn (Image) về.

    bash
    docker pull ubuntu:22.04
  2. Nấu ăn (docker run): Bật bếp chế biến nguyên liệu thành món ăn (Container).

    bash
    # -it: Interactive (chui vào trong container để tương tác)
    docker run -it ubuntu:22.04 /bin/bash
  3. Kiểm tra bếp (docker ps): Xem đang nấu món gì, món nào đang sôi (Running), món nào đã tắt bếp (Exited).

    bash
    docker ps -a # -a: Liệt kê cả container đã tắt
  4. Dọn dẹp (docker stop & docker rm): Ăn xong phải rửa bát.

    • Tắt bếp:
      bash
      docker stop [CONTAINER_ID]

      ⚠️ STOP vs KILL

      • docker stop: Gửi tín hiệu SIGTERM. Cho ứng dụng thời gian dọn dẹp, lưu file, đóng kết nối DB nhẹ nhàng (Graceful Shutdown).
      • docker kill: Gửi tín hiệu SIGKILL. Rút phích cắm điện ngay lập tức. Dễ gây lỗi dữ liệu. Hạn chế dùng.
    • Vứt rác:
      bash
      docker rm [CONTAINER_ID]

⚠️ Production Pitfalls (Bẫy thực chiến)

⚠️ Cạm bẫy

Vấn đề: Mặc định, process trong container chạy với quyền root. Nếu attacker escape khỏi container, họ có quyền root trên host.

Hậu quả thực tế: Năm 2019, lỗ hổng CVE-2019-5736 cho phép escape container → chiếm quyền root host. Mọi container chạy root đều bị ảnh hưởng.

Giải pháp: Luôn dùng USER directive trong Dockerfile để chạy với non-root user. Xem chi tiết ở Module 2.

⚠️ Cạm bẫy

Vấn đề: Dùng base image ubuntu:latest hoặc node:latest (>900MB) cho production.

Hậu quả: Pull image mất hàng phút, deploy chậm, tốn băng thông, tăng attack surface (nhiều package = nhiều lỗ hổng tiềm ẩn).

Giải pháp:

  • Dùng Alpine variants: node:20-alpine (~180MB), python:3.12-alpine (~50MB)
  • Dùng Multi-stage builds để chỉ giữ lại artifact cuối cùng
  • Quét image bằng docker scout cves hoặc Trivy

⚠️ Cạm bẫy

Vấn đề: Không tạo .dockerignore → Docker gửi toàn bộ thư mục (bao gồm node_modules/, .git/, .env) làm build context.

Hậu quả:

  • Build chậm gấp 10 lần (gửi hàng GB dữ liệu không cần thiết)
  • Leak secrets (.env, credentials) vào image
  • Image chứa rác, kích thước phình to vô nghĩa

Giải pháp: Tạo .dockerignore ngay từ đầu dự án, tương tự cách bạn tạo .gitignore.


🎯 Mini-Challenge: Hello Docker World

Đã đến lúc thực hành. Hãy chứng minh hệ thống của bạn đã sẵn sàng.

Nhiệm vụ:

  1. Chạy container kinh điển hello-world.
  2. Kiểm tra danh sách container để thấy nó đã chạy xong và tắt (Exited).
  3. Xóa sạch dấu vết của container đó (Không để rác trên máy).
👉 Xem đáp án (Chỉ mở khi đã thử làm!)
bash
# 1. Chạy container
docker run hello-world

# 2. Kiểm tra (sẽ thấy status Exited)
docker ps -a

# 3. Xóa container (Thay ID bằng ID thực tế của bạn)
docker rm [CONTAINER_ID]

# Pro-tip: Chạy xong tự hủy ngay lập tức
docker run --rm hello-world


📝 Quiz: Kiểm tra kiến thức

🧠 Quiz

Câu 1: Container được cách ly bằng công nghệ nào của Linux Kernel?

  • [ ] A. Virtual Machine Monitor (VMM)
  • [ ] B. Firewall và SELinux
  • [x] C. Namespaces và cgroups
  • [ ] D. Hypervisor và Guest OS

💡 Giải thích: Container sử dụng Linux Namespaces để cách ly (PID, Network, Mount...) và cgroups để giới hạn tài nguyên (CPU, RAM). Đây là công nghệ kernel-level, không cần hypervisor.

🧠 Quiz

Câu 2: Docker Daemon (dockerd) có vai trò gì?

  • [ ] A. Chỉ hiển thị giao diện dòng lệnh cho người dùng
  • [x] B. Quản lý vòng đời của Container, Image, Network, Volume
  • [ ] C. Chỉ lưu trữ Image trên Registry
  • [ ] D. Biên dịch source code thành Container

💡 Giải thích: Docker Daemon (dockerd) là "bộ não" chạy ngầm trên host, nhận API request từ Docker Client và thực hiện mọi thao tác nặng: tạo/xóa container, quản lý network, pull image từ registry.

🧠 Quiz

Câu 3: Tính chất quan trọng nhất của Docker Image là gì?

  • [ ] A. Mutable — có thể sửa đổi sau khi build
  • [ ] B. Stateful — lưu trữ dữ liệu người dùng
  • [x] C. Immutable — bất biến, không thay đổi sau khi build
  • [ ] D. Volatile — tự động xóa sau khi container tắt

💡 Giải thích: Docker Image là Immutable (bất biến). Khi cần thay đổi, bạn sửa Dockerfile và build Image mới. Điều này đảm bảo tính nhất quán: "Build once, run anywhere".


Production Readiness Checklist

✅ Checklist triển khai

Checklist trước khi deploy container lên Production:

  • [ ] Sử dụng base image minimal (Alpine/Slim/Distroless)
  • [ ] Container chạy với non-root user (USER directive)
  • [ ] Đã tạo .dockerignore loại bỏ files không cần thiết
  • [ ] Không hardcode secrets trong Dockerfile hoặc Image
  • [ ] Đã set resource limits (--memory, --cpus)
  • [ ] Image đã được scan vulnerabilities (Trivy/Scout)
  • [ ] Sử dụng specific tag (node:20-alpine) thay vì latest
  • [ ] Health check đã được cấu hình

💡 Next Steps

Bạn đã hiểu Kiến trúcVòng đời. Ở module tiếp theo, chúng ta sẽ học cách tự viết "Bản thiết kế" cho riêng mình với Dockerfile Deep Dive. Đừng bỏ lỡ!