Overlay filesystem, volumes và data lifecycle
Container writable layer là ephemeral implementation detail; durable data cần storage lifecycle riêng. Mục tiêu của phần này là phân biệt image/container layers với persistent mounts, hiểu permission boundary, và vận hành backup/cleanup mà không vô tình mất state.
1. Layered filesystem
Storage driver hoặc snapshotter ghép các image layer read-only với lớp writable của container thành một view thống nhất. Với OverlayFS, các lower layers là read-only và upper layer là phần writable; khi sửa một file vốn chỉ có ở lower layer, hệ thống phải thực hiện copy-up trước khi ghi. Deletion giữa các layer được biểu diễn bằng whiteout để file ở lower layer bị che khỏi view của container.
Vì copy-on-write tối ưu cho việc chia sẻ image layers hơn là write-heavy persistent state, database, queue data và workload ghi nhiều không nên đặt dữ liệu chính trong writable layer. Docker cũng khuyến nghị volumes cho dữ liệu cần persist, chia sẻ hoặc có cường độ ghi cao.
overlay2 thuộc classic storage-driver path và vẫn phổ biến ở hệ thống nâng cấp/legacy. Khi debug production, kiểm tra runtime thật bằng docker info thay vì giả định driver.docker info
# Kiểm tra Storage Driver / image store / backing filesystem phù hợp môi trường
2. Volume vs bind mount
Named volume do Docker quản lý lifecycle và location trên daemon host, nên application ít coupling với một host path cụ thể. Bind mount ánh xạ trực tiếp file/directory của host vào container, thuận tiện cho source code, config và local development nhưng coupling chặt hơn với path, permission và layout của host. tmpfs nằm trong memory của host và không persist qua stop/restart/reboot.
| Loại | Phù hợp khi | Trade-off / failure window |
|---|---|---|
| Named volume | Persistent application data, write-heavy state, data cần tách khỏi container lifecycle. | Không tự backup; vẫn phụ thuộc durability của host/storage backend. Xóa/prune nhầm có thể mất state. |
| Bind mount | Dev workflow, inject config/source, cần host và container cùng truy cập path. | Host-path coupling; permission/SELinux khác nhau giữa máy; container có thể sửa dữ liệu host nếu mount writable. |
| tmpfs | Scratch data hoặc secret-like transient files không cần ghi xuống disk. | Mất dữ liệu khi container/host lifecycle kết thúc; tiêu tốn memory. |
| Writable layer | Ephemeral runtime changes, cache nhỏ có thể tái tạo. | Biến mất khi container bị xóa; copy-on-write overhead; khó backup/migrate như application state. |
Một mount tại path đã có dữ liệu trong image sẽ che nội dung image ở path đó trong lúc container chạy. Đây là nguyên nhân thường gặp khi application “mất file mặc định” sau khi thêm volume/bind mount.
# Named volume
docker run --rm --mount type=volume,src=app-data,dst=/var/lib/app alpine
# Bind mount read-only
docker run --rm --mount type=bind,src="$PWD/config",dst=/etc/app,readonly alpine
3. Ownership
UID/GID bên trong container phải tương thích với ownership và mode bits của filesystem được mount. Khi chuyển từ process root sang non-root, lỗi permission thường mới lộ ra vì container không còn quyền ghi vào path từng “vô tình” hoạt động. Không dùng chmod 777 như cách sửa mặc định: nó mở rộng quyền không cần thiết và che giấu sai lệch ownership.
- Chọn UID/GID ổn định cho process và chuẩn bị directory ownership trước khi application start.
- Với bind mount, kiểm tra owner/mode trên host và mapping user namespace/rootless nếu có.
- Trên host bật SELinux, label của bind mount có thể chặn access dù Unix mode bits trông đúng; các option
:z/:Zthay đổi label host và phải dùng thận trọng. - Ưu tiên read-only mount cho config/reference data; chỉ cấp write access đúng path cần thiết.
4. Backup and cleanup
Volume không tự được backup. Chiến lược backup phải dựa trên datastore: copy filesystem chỉ an toàn nếu application có thể tạo snapshot consistent ở thời điểm đó; database thường cần quiesce, native backup hoặc snapshot có coordination để đạt application consistency. Backup chỉ có giá trị khi restore đã được test.
Failure window và recovery
- Container removal: xóa container không mặc định xóa named volume; state có thể còn lại và được gắn vào container mới.
- Host/storage loss: local volume có thể mất cùng host nếu không có replication/snapshot ở tầng storage. RPO/RTO phải được xác định bên ngoài Docker lifecycle.
- Bad deploy/data corruption: giữ backup/snapshot trước migration schema hoặc destructive maintenance, và xác định rollback có tương thích dữ liệu hay không.
- Accidental prune: prune chỉ nên chạy khi đã inventory resource, biết resource nào unused thật sự và có restore path cho state quan trọng.
Capacity và operational signals
Theo dõi disk usage của image data, writable layers, volumes, container logs và build cache. Dung lượng cạn có thể gây lỗi pull/build, application write failure hoặc daemon instability trước khi metric “container down” xuất hiện.
docker system df
# Xem resource trước khi cleanup
docker volume ls
# Chỉ prune khi đã xác minh volume unused và không chứa state cần giữ
# docker volume prune
Production checklist
- Persistent state không nằm trong container writable layer nếu cần survive container replacement.
- Mount type, owner/UID/GID, read-only/write access và SELinux/user-namespace behavior đã được test trên môi trường tương đương production.
- RPO/RTO, backup cadence, retention và restore verification được định nghĩa cho từng datastore.
- Có cảnh báo disk/inode usage và log growth trước ngưỡng gây sự cố.
- Cleanup/prune có scope rõ, change control và cách khôi phục nếu xóa nhầm.
- Migration storage driver/image store không làm tại chỗ mà không có backup/export và rollback plan.
Research note: nội dung version-sensitive được rà theo Docker Docs truy cập 2026-09-12; các command cần được xác nhận lại với Docker Engine/runtime thực tế của môi trường triển khai.