Appearance
Buổi 4: Docker Volumes & Networking
🎯 Mục tiêu
- Hiểu vấn đề mất dữ liệu khi container bị xóa
- Sử dụng bind mount và named volume
- Hiểu các loại Docker network
- Kết nối các container với nhau qua network
- Thực hành: WordPress + MySQL với volume và network
1. Vấn đề: Dữ liệu trong container
Container là ephemeral (tạm thời)
┌─────────────────────────────────────┐
│ Container (nginx) │
│ │
│ /usr/share/nginx/html/ │
│ └── index.html (sửa ở đây) │
│ │
│ ⚠️ Writable Layer (tạm thời) │
└─────────────────────────────────────┘
│
docker rm ← XÓA container
│
▼
💀 Mất hết dữ liệu!Vấn đề: Khi xóa container, toàn bộ dữ liệu bên trong bị mất.
Giải pháp: Dùng Volumes để lưu dữ liệu bên ngoài container.
2. Các cách lưu trữ dữ liệu
┌────────────────────────────────────────────────┐
│ Host Machine │
│ │
│ ┌──────────────┐ ┌───────────────────────┐ │
│ │ Bind Mount │ │ Named Volume │ │
│ │ │ │ │ │
│ │ /home/user/ │ │ /var/lib/docker/ │ │
│ │ data/ │ │ volumes/mydata/ │ │
│ └──────┬───────┘ └───────────┬───────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Container │ │
│ │ /app/data ◀── bind mount │ │
│ │ /var/data ◀── named volume │ │
│ └─────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘So sánh các phương pháp
| Đặc điểm | Bind Mount | Named Volume | tmpfs Mount |
|---|---|---|---|
| Vị trí | Đường dẫn host | Docker quản lý | RAM |
| Tạo bởi | User chỉ định | Docker | Docker |
| Persist | ✅ | ✅ | ❌ (mất khi stop) |
| Performance | Tốt | Tốt nhất | Nhanh nhất |
| Chia sẻ | Giữa host & container | Giữa containers | Không |
| Use case | Dev (live reload) | Database, data | Secrets, cache |
3. Bind Mount
Cú pháp
bash
# Cú pháp đầy đủ (khuyến nghị)
$ docker run -v /đường/dẫn/host:/đường/dẫn/container IMAGE
# Hoặc dùng --mount
$ docker run --mount type=bind,source=/host/path,target=/container/path IMAGEVí dụ: Live reload cho development
bash
# Tạo thư mục và file HTML
$ mkdir -p ~/mysite
$ echo "<h1>Hello Docker Volume!</h1>" > ~/mysite/index.html
# Chạy nginx với bind mount
$ docker run -d \
--name web \
-p 8080:80 \
-v ~/mysite:/usr/share/nginx/html:ro \
nginx
# Sửa file trên host → container tự cập nhật!
$ echo "<h1>Updated!</h1>" > ~/mysite/index.html
# → Refresh trình duyệt để thấy thay đổi| Flag | Ý nghĩa |
|---|---|
:ro | Read-only – container không ghi được |
:rw | Read-write (mặc định) |
Use case cho Bind Mount
bash
# Development: mount source code
$ docker run -d -v $(pwd)/src:/app/src -p 3000:3000 node-app
# Config file
$ docker run -d -v ./nginx.conf:/etc/nginx/nginx.conf:ro nginx
# Logs ra host
$ docker run -d -v ./logs:/var/log/app my-app4. Named Volume
Quản lý volumes
bash
# Tạo volume
$ docker volume create mydata
# Liệt kê volumes
$ docker volume ls
DRIVER VOLUME NAME
local mydata
# Xem chi tiết volume
$ docker volume inspect mydata
[
{
"CreatedAt": "2025-01-15T10:30:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/mydata/_data",
"Name": "mydata",
"Options": {},
"Scope": "local"
}
]
# Xóa volume
$ docker volume rm mydata
# Xóa tất cả volume không dùng
$ docker volume pruneVí dụ: PostgreSQL với Named Volume
bash
# Tạo volume cho database
$ docker volume create pgdata
# Chạy PostgreSQL với volume
$ docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=mydb \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16
# Tạo dữ liệu
$ docker exec -it postgres psql -U postgres -d mydb \
-c "CREATE TABLE users (id SERIAL, name TEXT); INSERT INTO users (name) VALUES ('Docker Fan');"
# Xóa container
$ docker rm -f postgres
# Chạy container mới với cùng volume → DỮ LIỆU VẪN CÒN!
$ docker run -d \
--name postgres-new \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16
# Kiểm tra dữ liệu
$ docker exec -it postgres-new psql -U postgres -d mydb \
-c "SELECT * FROM users;"
# id | name
# ----+------------
# 1 | Docker Fan💡 Key Point
Named Volume giữ dữ liệu ngay cả khi container bị xóa. Đây là cách lưu trữ database trong Docker.
5. Docker Networking
Các loại network
┌─────────────────────────────────────────────────┐
│ Host Machine │
│ │
│ ┌─── bridge (default) ──────────────────────┐ │
│ │ Container A ◄──────► Container B │ │
│ │ 172.17.0.2 172.17.0.3 │ │
│ └────────────────────────────────────────────┘ │
│ │
│ ┌─── custom-net (user-defined) ─────────────┐ │
│ │ Container C ◄──────► Container D │ │
│ │ "app" (DNS) "db" (DNS) │ │
│ └────────────────────────────────────────────┘ │
│ │
│ ┌─── host ──────────────────────────────────┐ │
│ │ Container E (dùng trực tiếp port host) │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘So sánh các loại network
| Network | Cách ly | DNS | Performance | Use case |
|---|---|---|---|---|
bridge (default) | ✅ | ❌ Chỉ IP | Tốt | Container đơn lẻ |
bridge (custom) | ✅ | ✅ Tên container | Tốt | Multi-container |
host | ❌ | N/A | Tốt nhất | Cần performance |
none | ✅✅ | ❌ | N/A | Cách ly hoàn toàn |
overlay | ✅ | ✅ | Tốt | Docker Swarm |
6. Quản lý Networks
bash
# Liệt kê networks
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a1b2c3d4e5f6 bridge bridge local
f6e5d4c3b2a1 host host local
1a2b3c4d5e6f none null local
# Tạo custom network
$ docker network create my-network
# Xem chi tiết
$ docker network inspect my-network
# Xóa network
$ docker network rm my-network
# Dọn dẹp networks không dùng
$ docker network pruneKết nối container vào network
bash
# Tạo custom network
$ docker network create app-network
# Chạy container trong network
$ docker run -d --name db --network app-network \
-e POSTGRES_PASSWORD=secret postgres:16
$ docker run -d --name app --network app-network \
-e DATABASE_URL=postgres://postgres:secret@db:5432/postgres \
-p 3000:3000 my-app
# Container "app" có thể kết nối "db" bằng TÊN!
# → postgres://postgres:secret@db:5432/postgresKết nối/ngắt container khỏi network
bash
# Thêm container vào network
$ docker network connect app-network existing-container
# Ngắt container khỏi network
$ docker network disconnect app-network existing-container7. Thực hành: WordPress + MySQL
Tạo stack hoàn chỉnh
bash
# Bước 1: Tạo network
$ docker network create wp-network
# Bước 2: Tạo volumes
$ docker volume create wp-db-data
$ docker volume create wp-content
# Bước 3: Chạy MySQL
$ docker run -d \
--name wp-mysql \
--network wp-network \
-e MYSQL_ROOT_PASSWORD=rootpass \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wpuser \
-e MYSQL_PASSWORD=wppass \
-v wp-db-data:/var/lib/mysql \
mysql:8
# Bước 4: Chạy WordPress
$ docker run -d \
--name wp-app \
--network wp-network \
-e WORDPRESS_DB_HOST=wp-mysql \
-e WORDPRESS_DB_USER=wpuser \
-e WORDPRESS_DB_PASSWORD=wppass \
-e WORDPRESS_DB_NAME=wordpress \
-v wp-content:/var/www/html/wp-content \
-p 8080:80 \
wordpress:latest
# Bước 5: Mở http://localhost:8080 → Setup WordPress!Kiến trúc
Browser
│
▼ :8080
┌─────────────────┐ ┌─────────────────┐
│ WordPress │────▶│ MySQL │
│ (wp-app) │ │ (wp-mysql) │
│ Port 80 │ │ Port 3306 │
│ │ │ │
│ 📁 wp-content │ │ 📁 mysql data │
│ (volume) │ │ (volume) │
└─────────────────┘ └─────────────────┘
wp-network (custom bridge)🏋️ Bài tập thực hành
Bài 1: Bind Mount
- Tạo thư mục
~/docker-lab/sitevới fileindex.html - Mount vào nginx:
-v ~/docker-lab/site:/usr/share/nginx/html:ro - Sửa file HTML trên host, refresh trình duyệt
Bài 2: Named Volume cho Database
- Tạo volume
testdb-data - Chạy PostgreSQL với volume
- Tạo bảng và thêm dữ liệu
- Xóa container, tạo container mới với cùng volume
- Kiểm tra dữ liệu còn không
Bài 3: Custom Network
- Tạo network
lab-network - Chạy 2 containers:
alpine-1vàalpine-2trong cùng network - Từ
alpine-1, pingalpine-2bằng tên:docker exec alpine-1 ping alpine-2
Bài 4: WordPress stack
- Triển khai WordPress + MySQL như hướng dẫn ở mục 7
- Hoàn thành setup WordPress
- Viết một bài post
- Xóa container WordPress (giữ MySQL & volumes)
- Tạo lại container WordPress → kiểm tra bài post vẫn còn