Giao diện
Module 4: Persistence & Networking (Lưu trữ và Mạng lưới)
🎓 Instructor Profile
Kỹ sư Raizo (Phó CTO HPN) - Chuyên gia hệ thống Linux & Storage. Sẽ giải thích vì sao dữ liệu của bạn "bay màu" và cách giữ nó lại vĩnh viễn với Giáo sư Tom.
Xin chào! Nếu Container là "Vô thường" (Ephemeral) - sinh ra rồi mất đi như những đám mây, thì Dữ liệu (Networking & Storage) chính là mặt đất vững chãi. Để xây dựng hệ thống bền vững, bạn phải biết cách "khoan lỗ" kết nối Container với thế giới bên ngoài.
☁️ Phần 1: The Ephemeral Problem (Vấn đề "Phù du")
Mặc định, mọi dữ liệu sinh ra bên trong Container đều được lưu ở một lớp gọi là Writable Layer.
- Khi bạn
docker stopcontainer: Dữ liệu vẫn còn. - Khi bạn
docker rmcontainer: Toàn bộ dữ liệu BIẾN MẤT vĩnh viễn. 💀
Kiến trúc Layers
Hãy hình dung Container giống như một chồng bánh kếp:
- Image Layers (Read-only): Là phần cốt lõi bất biến (Ubuntu, Node.js binaries...).
- Container Layer (Read-write): Là lớp mỏng trên cùng nơi ứng dụng ghi log, tạo file tạm. Khi xóa container, lớp này bị hủy.
👉 Nhu cầu: Chúng ta cần một cơ chế lưu trữ độc lập với vòng đời của Container.
💾 Phần 2: The Storage Trinity (Bộ ba Lưu trữ)
Docker cung cấp 3 cách để "mount" (gắn) dữ liệu vào container.
1. Volumes (Khuyên dùng cho Database) 🏆
Là khu vực được Docker quản lý và isolat hóa hoàn toàn trên máy Host (/var/lib/docker/volumes/...).
- Ưu điểm:
- Hiệu năng cao nhất (Tư duy @[/db-expert]): Vượt qua layers của filesystem ảo.
- An toàn: Các tiến trình khác trên Host khó can thiệp bậy bạ.
- Dễ dàng backup/migration.
- Best Practice: Dùng cho Database (Postgres, MySQL, Redis data).
2. Bind Mounts (Khuyên dùng cho Dev) 🛠️
Ánh xạ trực tiếp một thư mục từ máy Host vào Container.
- Ví dụ: Map thư mục code
./srccủa bạn vào/app/srcbên trong container. - Tính năng: Hot-reload. Bạn sửa code trên VS Code -> Container nhận thấy thay đổi và cập nhật ngay lập tức.
- Nhược điểm: Hiệu năng thấp hơn Volumes, phụ thuộc vào cấu trúc file của Host OS.
🚫 Production Warning
Tuyệt đối KHÔNG dùng Bind Mount cho Database khi chạy trên Production. Sự khác biệt về File System (NTFS vs ext4) có thể gây lỗi corrupt dữ liệu cực kỳ nguy hiểm.
3. tmpfs Mounts (Bộ nhớ tạm) ⚡
Lưu trữ trực tiếp trên RAM của máy Host.
- Đặc điểm: Siêu nhanh, nhưng mất dữ liệu khi tắt container (hoặc restart máy).
- Ứng dụng: Lưu cache session, lưu mật khẩu tạm thời (security purpose).
Storage Architecture (Kiến trúc tổng quan)
Volume Management (Quản lý Volume nâng cao)
Các lệnh quan trọng để quản lý Volume trong production:
bash
# Tạo volume với driver cụ thể (VD: NFS cho shared storage)
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/dir \
nfs_shared_data
# Kiểm tra chi tiết volume (mountpoint, driver, labels)
docker volume inspect db_data
# Liệt kê tất cả volume (bao gồm dangling)
docker volume ls --filter dangling=true
# 🧹 Dọn dẹp volume không sử dụng
docker volume prune --force
# 📦 Backup volume sang file tar
docker run --rm \
-v db_data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/db_backup_$(date +%Y%m%d).tar.gz -C /source .
# 📥 Restore volume từ backup
docker run --rm \
-v db_data:/target \
-v $(pwd):/backup \
alpine sh -c "cd /target && tar xzf /backup/db_backup_20240101.tar.gz"💡 Production Tip
Luôn có chiến lược backup cho Named Volumes. Volume bị xóa = dữ liệu mất vĩnh viễn. Kết hợp cronjob + lệnh backup ở trên để tự động hóa. Đối với database, ưu tiên dùng pg_dump / mysqldump thay vì backup raw volume.
Data Persistence Strategy (Chiến lược bền vững dữ liệu)
| Loại dữ liệu | Storage Type | Lý do |
|---|---|---|
| Database (MySQL, Postgres) | Named Volume | Hiệu năng cao, Docker quản lý, dễ backup |
| Source code (Development) | Bind Mount | Hot-reload, IDE integration |
| Config files (nginx.conf) | Bind Mount hoặc Config | Version control được |
| Session/Cache tạm | tmpfs | Nhanh, tự xóa khi restart |
| Logs | Named Volume hoặc Log Driver | Persistent, centralized logging |
| Secrets (passwords, keys) | Docker Secrets / tmpfs | Không lưu trên disk |
🛡️ Phần 3: The Permission Nightmare (Cơn ác mộng phân quyền)
Đây là kiến thức Deep Tech mà ít tutorial nhắc tới.
Vấn đề:
- Container thường chạy với user
root(UID 0). - Máy Host của bạn (đặc biệt là Linux) chạy với user thường (UID 1000).
Khi bạn dùng Bind Mount, container (UID 0) ghi file ra Host -> File đó sẽ thuộc quyền sở hữu của root. 👉 Hậu quả: Bạn (UID 1000) không thể sửa/xóa file log/data do container tạo ra. Bị lỗi Permission Denied.
Giải pháp (Tư duy @[/security-scan]):
- User Remapping: Cấu hình Docker Daemon để map UID 0 trong container thành UID 1000 ngoài Host.
- Entrypoint
chown: Viết script khởi động container tự độngchownquyền sở hữu thư mục data về đúng user mong muốn.
🔌 Phần 4: Networking Modes (Các chế độ mạng)
Làm sao các container nói chuyện với nhau và với Internet?
1. Bridge Network (Mặc định) 🌉
Mỗi container được cấp một IP riêng trong dải mạng ảo (VD: 172.17.0.2, 172.17.0.3). Chúng giao tiếp qua một "cây cầu ảo" (docker0).
- Ưu điểm: Cô lập tốt.
- Kết nối: Cần dùng Port Mapping (
-p 8080:80) để Host truy cập được.
2. Host Network 🚀
Container dùng chung card mạng với máy Host.
- Ưu điểm: Hiệu năng mạng cực cao (Tư duy @[/performance]), loại bỏ overhead của NAT/Bridge.
- Nhược điểm: Dễ bị đụng độ Port. Nếu máy Host đã chạy Nginx port 80, container không thể chạy port 80 nữa.
- Lưu ý: Chỉ hoạt động trên Linux.
3. None Network 🔒
Cắt đứt toàn bộ kết nối mạng. Container "tự kỷ".
- Ứng dụng: Các tác vụ xử lý dữ liệu nhạy cảm cần bảo mật tuyệt đối, không cần Internet.
4. Overlay Network (Multi-host) 🌐
Cho phép container trên nhiều máy chủ khác nhau giao tiếp — công nghệ nền tảng của Docker Swarm và Kubernetes.
- Cơ chế: Sử dụng VXLAN tunneling để tạo mạng ảo xuyên qua physical network.
- Ứng dụng: Microservices chạy trên cluster nhiều máy.
- Yêu cầu: Docker Swarm mode hoặc external key-value store (Consul, etcd).
bash
# Khởi tạo Swarm (trên node manager)
docker swarm init
# Tạo overlay network (encrypted traffic)
docker network create \
--driver overlay \
--attachable \
--opt encrypted \
my_overlay
# Deploy service sử dụng overlay
docker service create --name api \
--network my_overlay \
--replicas 3 \
my-api:latest5. Macvlan Network (Direct Access) 🔌
Gán MAC address riêng cho mỗi container, khiến nó xuất hiện như một thiết bị vật lý trên mạng LAN.
- Ưu điểm: Container nhận IP thật từ DHCP router, không cần port mapping.
- Ứng dụng: Legacy applications cần direct network access, IoT gateways.
- Nhược điểm: Phức tạp, cần cấu hình NIC promiscuous mode.
bash
# Tạo macvlan network
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
my_macvlan
# Chạy container với IP cố định trên LAN
docker run --rm --network my_macvlan \
--ip=192.168.1.200 \
nginxNetwork Architecture (Kiến trúc mạng Docker)
DNS & Service Discovery (Khám phá dịch vụ)
Trong Docker, container không nên giao tiếp qua IP cứng. Hãy dùng DNS tự động của Docker.
yaml
# docker-compose.yml — DNS tự động hoạt động
services:
api:
build: .
depends_on:
- db
- redis
environment:
# 👇 Dùng tên service thay vì IP cứng
DATABASE_URL: postgres://user:pass@db:5432/myapp
REDIS_URL: redis://redis:6379
db:
image: postgres:16-alpine
# Tự động có DNS name = "db"
redis:
image: redis:7-alpine
# Tự động có DNS name = "redis"⚠️ Default Bridge vs Custom Bridge
Default bridge (docker0) KHÔNG hỗ trợ DNS resolution giữa các container. Phải dùng --link (deprecated) hoặc IP cứng.
Custom bridge (tạo bởi docker network create hoặc Docker Compose) hỗ trợ DNS tự động. Luôn dùng Custom Bridge cho production.
Network Troubleshooting (Gỡ lỗi mạng)
Khi container không thể giao tiếp, đây là quy trình debug:
bash
# 1. Kiểm tra container đang ở network nào
docker inspect <container> \
--format='{{json .NetworkSettings.Networks}}' | jq
# 2. Liệt kê tất cả container trong một network
docker network inspect my_network \
--format='{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
# 3. Ping giữa các container
docker exec api ping -c 3 db
# 4. Kiểm tra DNS resolution
docker exec api nslookup db
# 5. Xem port đang listen
docker exec api ss -tlnp
# 6. Debug nâng cao với netshoot (đầy đủ network tools)
docker run --rm -it --network my_network nicolaka/netshoot
# Bên trong: tcpdump, nslookup, curl, iperf, traceroute...📝 Phần 5: Syntax & Practice (Cú pháp & Thực hành)
Ví dụ cấu hình docker-compose.yml chuẩn mực:
yaml
version: "3.8"
services:
# --- Database (Dùng Named Volume) ---
db:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
volumes:
- db_data:/var/lib/mysql # 📦 Persist Data an toàn
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASS}
# --- Backend API (Dùng Bind Mount) ---
api:
build: .
volumes:
- ./src:/app/src # 🛠️ Hot-reload code
ports:
- "3000:3000"
# Khai báo Volume
volumes:
db_data:So sánh -v và --mount
-v ./src:/app: Cú pháp cũ, ngắn gọn. Rất phổ biến.--mount type=bind,source=./src,target=/app: Cú pháp mới, dài dòng nhưng rõ ràng (explicit).
👉 Lời khuyên: Dùng -v cho gọn, trừ khi bạn làm cho Docker Swarm.
🏆 Challenge: The Immortal Data (Dữ liệu Bất tử)
Nhiệm vụ: Chứng minh sức mạnh của Volume.
- Chạy container MySQL với volume:
docker run -d -v my-sql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret --name db-test mysql:8. - Vào container tạo bảng
Users, thêm dòng tên bạn vào (INSERT INTO Users...). - Xóa sạch container:
docker rm -f db-test. - Chạy lại container mới, gắn đúng volume cũ (
my-sql-data). - Query lại dữ liệu. Nếu tên bạn vẫn còn đó -> Chúc mừng, bạn đã nắm giữ sự vĩnh hằng! 🎉
⚠️ Production Pitfalls (Bẫy thực chiến)
⚠️ Cạm bẫy
Vấn đề: Dùng bind mount (./data:/var/lib/mysql) cho database production.
Hậu quả thực tế: File system của Host (đặc biệt NTFS trên Windows, NFS trên shared storage) không tương thích với cách database ghi dữ liệu (fsync, write-ahead log). Kết quả: corruption dữ liệu không thể phục hồi.
Giải pháp: Luôn dùng Named Volume cho database. Docker quản lý volume trên filesystem native (ext4/xfs trên Linux), đảm bảo data integrity.
⚠️ Cạm bẫy
Vấn đề: Mỗi lần docker-compose down và docker-compose up với config volume mới, volume cũ vẫn tồn tại (dangling).
Hậu quả: Sau vài tháng, ổ cứng server đầy volume rác. Disk full → service crash.
Giải pháp:
- Định kỳ:
docker volume prune - Monitoring disk usage:
docker system df - Alert khi disk usage > 80%
⚠️ Cạm bẫy
Vấn đề: Kết nối database bằng IP cứng: DATABASE_HOST=172.17.0.3.
Hậu quả: Container restart → IP thay đổi → toàn bộ service mất kết nối. Đặc biệt nguy hiểm khi auto-scaling.
Giải pháp: Sử dụng DNS name (tên service trong Docker Compose). VD: DATABASE_HOST=db. Docker DNS tự động resolve.
📝 Quiz: Kiểm tra kiến thức
🧠 Quiz
Câu 1: Loại storage nào được khuyến nghị cho Database trên Production?
- [ ] A) Bind Mount — vì dễ quản lý từ Host
- [x] B) Named Volume — vì hiệu năng cao và Docker quản lý lifecycle
- [ ] C) tmpfs — vì tốc độ đọc ghi nhanh nhất
- [ ] D) Host Path — vì truy cập trực tiếp filesystem
💡 Giải thích: Named Volume được Docker quản lý trên native filesystem (ext4/xfs), đảm bảo data integrity và hiệu năng tốt nhất cho database. Bind Mount phụ thuộc vào Host OS filesystem, có thể gây corruption. tmpfs mất dữ liệu khi restart.
Câu 2: Custom Bridge Network khác Default Bridge Network ở điểm nào quan trọng nhất?
- [ ] A) Custom Bridge có tốc độ mạng nhanh hơn
- [ ] B) Custom Bridge hỗ trợ nhiều container hơn
- [x] C) Custom Bridge hỗ trợ DNS tự động giữa các container
- [ ] D) Custom Bridge không cần port mapping
💡 Giải thích: Điểm khác biệt quan trọng nhất là DNS resolution. Trên Custom Bridge, container có thể giao tiếp bằng tên service (VD:
ping db). Default Bridge không hỗ trợ tính năng này, buộc phải dùng IP cứng hoặc--link(deprecated).
Câu 3: Khi container bị xóa (docker rm), dữ liệu ở đâu sẽ BỊ MẤT?
- [ ] A) Named Volume
- [ ] B) Bind Mount trên Host
- [x] C) Container Writable Layer
- [ ] D) tmpfs mount
💡 Giải thích: Khi
docker rm, chỉ Writable Layer của container bị hủy. Named Volume và Bind Mount tồn tại độc lập với container lifecycle. tmpfs cũng mất nhưng vì nó trên RAM và gắn với container process. Writable Layer là đáp án chính xác nhất vì đây là lớp dữ liệu "bên trong" container.
✅ Production Readiness Checklist
✅ Checklist triển khai
Checklist Storage & Networking cho Production:
- [ ] Database sử dụng Named Volume (không dùng Bind Mount)
- [ ] Có chiến lược backup volume định kỳ (cronjob + tar/pg_dump)
- [ ] Bind Mount chỉ dùng cho development (hot-reload code)
- [ ] Secrets không lưu trên volume thông thường (dùng Docker Secrets hoặc tmpfs)
- [ ] Container giao tiếp qua DNS name, không dùng IP cứng
- [ ] Sử dụng Custom Bridge Network (không dùng Default Bridge)
- [ ] Overlay Network đã bật encryption cho cross-host traffic
- [ ] Đã cấu hình monitoring cho disk usage (
docker system df) - [ ] Dangling volumes được dọn dẹp định kỳ
- [ ] Network policies đã được review (không expose port không cần thiết)
💡 Next Steps
Bạn đã nắm vững Storage và Networking — hai trụ cột của stateful applications. Module tiếp theo sẽ dạy bạn cách gia cố bảo mật container để sẵn sàng cho production thực sự!