
ปัญหา Data ใน Container — ทำไมต้อง Volumes?
Container เป็น Ephemeral (ชั่วคราว) เมื่อ Container ถูกลบ ข้อมูลทั้งหมดใน Container จะหายไปด้วย ถ้าคุณรัน Database ใน Container แล้วลบ Container ข้อมูลทั้งหมดจะ หายหมด! Docker Volumes แก้ปัญหานี้โดยเก็บข้อมูลไว้นอก Container
# ปัญหา: ไม่ใช้ Volume
docker run -d --name mydb mysql:8.0
# → ข้อมูล MySQL อยู่ใน Container
docker rm -f mydb
# → ข้อมูลทั้งหมดหายไป!
# วิธีแก้: ใช้ Volume
docker run -d --name mydb -v mysql-data:/var/lib/mysql mysql:8.0
# → ข้อมูล MySQL อยู่ใน Volume "mysql-data"
docker rm -f mydb
# → Volume ยังอยู่! ข้อมูลไม่หาย!
docker run -d --name mydb2 -v mysql-data:/var/lib/mysql mysql:8.0
# → Container ใหม่ใช้ข้อมูลเดิมได้ทันที!
3 วิธีจัดการ Data ใน Docker
| วิธี | คำสั่ง | ข้อดี | ข้อเสีย | เหมาะกับ |
|---|---|---|---|---|
| Named Volumes | -v mydata:/app/data | Docker จัดการให้ พกพาง่าย Backup ง่าย | ไม่รู้ว่าเก็บไว้ที่ไหนบน Host | Database, Application Data |
| Bind Mounts | -v /host/path:/container/path | ควบคุม Path เอง แก้ไขจาก Host ได้ | ขึ้นกับ Host Path, ปัญหา Permission | Development, Config Files |
| tmpfs Mounts | –tmpfs /app/temp | เร็วมาก (RAM) ปลอดภัย | ข้อมูลหายเมื่อ Container Stop | Sensitive Data, Cache |
Named Volumes — วิธีที่แนะนำ
# สร้าง Volume:
docker volume create myapp-data
docker volume create mydb-data
# ดู Volumes ทั้งหมด:
docker volume ls
# DRIVER VOLUME NAME
# local myapp-data
# local mydb-data
# ดูรายละเอียด Volume:
docker volume inspect myapp-data
# [
# {
# "CreatedAt": "2026-04-16T10:00:00Z",
# "Driver": "local",
# "Labels": {},
# "Mountpoint": "/var/lib/docker/volumes/myapp-data/_data",
# "Name": "myapp-data",
# "Options": {},
# "Scope": "local"
# }
# ]
# ใช้ Volume กับ Container:
docker run -d --name webapp \
-v myapp-data:/app/uploads \
-v mydb-data:/var/lib/mysql \
-p 8080:80 \
myapp:latest
# ลบ Volume (ระวัง! ข้อมูลจะหายถาวร):
docker volume rm myapp-data
# ลบ Volumes ที่ไม่ได้ใช้:
docker volume prune
# → ลบเฉพาะ Volumes ที่ไม่มี Container ใช้อยู่
Bind Mounts — Mount Path จาก Host
# Bind Mount: เชื่อม Directory บน Host กับ Container
#
# ใช้ -v flag:
docker run -d --name nginx \
-v /home/user/website:/usr/share/nginx/html:ro \
-p 80:80 \
nginx:latest
# → :ro = Read-Only (Container อ่านได้อย่างเดียว)
# ใช้ --mount flag (ชัดเจนกว่า):
docker run -d --name nginx \
--mount type=bind,source=/home/user/website,target=/usr/share/nginx/html,readonly \
-p 80:80 \
nginx:latest
# Development: Mount Source Code
docker run -d --name devapp \
-v $(pwd)/src:/app/src \
-v $(pwd)/config:/app/config \
-p 3000:3000 \
node:20
# → แก้ Code บน Host → เห็นผลใน Container ทันที!
# ข้อควรระวัง:
# 1. Path บน Host ต้องมีอยู่จริง (ไม่สร้างให้อัตโนมัติ)
# 2. Permission: Container ใช้ UID/GID ต่างจาก Host
# 3. Performance: บน macOS/Windows ช้ากว่า Linux
# 4. Security: Container เข้าถึงไฟล์บน Host ได้
Docker Compose กับ Volumes
# docker-compose.yml สำหรับ WordPress + MySQL:
version: '3.8'
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: wppass2026
WORDPRESS_DB_NAME: wordpress
volumes:
- wp-content:/var/www/html/wp-content
- ./custom-theme:/var/www/html/wp-content/themes/custom
depends_on:
- db
restart: unless-stopped
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass2026
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: wppass2026
volumes:
- db-data:/var/lib/mysql
- ./mysql-config/my.cnf:/etc/mysql/conf.d/custom.cnf:ro
restart: unless-stopped
volumes:
wp-content:
driver: local
db-data:
driver: local
# คำสั่ง:
# docker compose up -d → Start ทั้งหมด
# docker compose down → Stop (Volumes ยังอยู่)
# docker compose down -v → Stop + ลบ Volumes (ระวัง!)
# docker compose ps → ดู Status
Backup & Restore Volumes
# Backup Volume ด้วย tar:
# =============================================
# 1. Backup Volume ไปเป็น tar.gz:
docker run --rm \
-v mydb-data:/source:ro \
-v $(pwd)/backups:/backup \
alpine \
tar czf /backup/mydb-backup-$(date +%Y%m%d).tar.gz -C /source .
# อธิบาย:
# → สร้าง Container ชั่วคราว (--rm = ลบเมื่อเสร็จ)
# → Mount Volume ที่ต้องการ Backup เป็น /source (Read-Only)
# → Mount Directory บน Host เป็น /backup
# → ใช้ tar บีบอัดข้อมูล
# 2. Restore Volume จาก tar.gz:
docker volume create mydb-data-restored
docker run --rm \
-v mydb-data-restored:/target \
-v $(pwd)/backups:/backup:ro \
alpine \
tar xzf /backup/mydb-backup-20260416.tar.gz -C /target
# 3. Automated Backup Script:
#!/bin/bash
BACKUP_DIR="/backups/docker"
DATE=$(date +%Y%m%d_%H%M%S)
for VOL in $(docker volume ls -q); do
echo "Backing up: $VOL"
docker run --rm \
-v "$VOL":/source:ro \
-v "$BACKUP_DIR":/backup \
alpine \
tar czf "/backup/${VOL}_${DATE}.tar.gz" -C /source .
done
# ลบ Backup เก่ากว่า 30 วัน:
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete
echo "Backup completed!"
# ตั้ง Cron:
# 0 2 * * * /opt/scripts/backup-volumes.sh >> /var/log/docker-backup.log
Volume Drivers — เก็บข้อมูลที่อื่น
# Docker รองรับ Volume Driver หลายตัว:
#
# local (default):
# → เก็บบน Host Machine
# → เหมาะกับ Single Server
#
# nfs:
# → เก็บบน NFS Server
# → เหมาะกับ Shared Storage
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/exports/docker-data \
nfs-volume
# cifs (SMB/Windows Share):
docker volume create --driver local \
--opt type=cifs \
--opt o=username=user,password=pass,addr=192.168.1.100 \
--opt device=//192.168.1.100/share \
smb-volume
# PlugIns สำหรับ Cloud Storage:
# → rexray/s3fs (AWS S3)
# → rexray/ebs (AWS EBS)
# → azure-file (Azure File Share)
# → local-persist (Persistent local path)
Volume Permission Problems & Solutions
# ปัญหา Permission ที่พบบ่อย:
#
# 1. Container ใช้ UID ต่างจาก Host:
# Container user = UID 1000
# Host user = UID 501
# → Permission Denied!
# วิธีแก้ 1: กำหนด User ใน Dockerfile:
# FROM node:20
# RUN groupadd -g 1000 appgroup && \
# useradd -u 1000 -g appgroup appuser
# USER appuser
# วิธีแก้ 2: ใช้ --user flag:
docker run -d --user $(id -u):$(id -g) \
-v mydata:/app/data \
myapp:latest
# วิธีแก้ 3: Init Container (Docker Compose):
services:
init-permissions:
image: alpine
command: chown -R 1000:1000 /data
volumes:
- mydata:/data
app:
image: myapp:latest
volumes:
- mydata:/app/data
depends_on:
init-permissions:
condition: service_completed_successfully
# วิธีแก้ 4: SELinux (CentOS/RHEL):
docker run -v /host/data:/container/data:Z myapp:latest
# → :Z = SELinux relabel (Single Container)
# → :z = Shared between Containers
Volume Best Practices
| Practice | คำอธิบาย |
|---|---|
| ใช้ Named Volumes สำหรับ Production | Docker จัดการให้ ไม่ขึ้นกับ Host Path |
| ใช้ Bind Mounts สำหรับ Development | แก้ไข Code ได้สะดวก เห็นผลทันที |
| Backup เป็นประจำ | ตั้ง Cron Backup อย่างน้อยวันละครั้ง |
| ใช้ :ro เมื่อ Container ไม่ต้องเขียน | ลด Risk ข้อมูลถูกแก้ไข |
| ตั้งชื่อ Volume ให้มีความหมาย | ใช้ project-service-type เช่น myapp-db-data |
| อย่าเก็บ Sensitive Data ใน Image | ใช้ Volume หรือ Docker Secrets แทน |
| ทดสอบ Restore จาก Backup | Backup ที่ Restore ไม่ได้ = ไม่มี Backup |
| Monitor Volume Usage | ดู Disk Space เป็นประจำ docker system df |
Volume สำหรับ Database Containers
# MySQL:
docker run -d --name mysql \
-v mysql-data:/var/lib/mysql \
-v ./mysql-init:/docker-entrypoint-initdb.d:ro \
-v ./mysql-conf:/etc/mysql/conf.d:ro \
-e MYSQL_ROOT_PASSWORD=rootpass \
mysql:8.0
# PostgreSQL:
docker run -d --name postgres \
-v pg-data:/var/lib/postgresql/data \
-v ./pg-init:/docker-entrypoint-initdb.d:ro \
-e POSTGRES_PASSWORD=pgpass \
postgres:16
# MongoDB:
docker run -d --name mongo \
-v mongo-data:/data/db \
-v mongo-config:/data/configdb \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=mongopass \
mongo:7
# Redis (with persistence):
docker run -d --name redis \
-v redis-data:/data \
redis:7 redis-server --appendonly yes
# Volume Paths สำคัญ:
# MySQL: /var/lib/mysql
# PostgreSQL: /var/lib/postgresql/data
# MongoDB: /data/db
# Redis: /data
# Elasticsearch: /usr/share/elasticsearch/data
# Prometheus: /prometheus
Monitoring Docker Volumes
# ดู Disk Usage ของ Docker:
docker system df
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 15 5 3.2GB 1.8GB (56%)
# Containers 8 5 50MB 20MB (40%)
# Volumes 10 6 5.5GB 1.2GB (21%)
# Build Cache 20 0 800MB 800MB (100%)
# ดู Volume Usage รายตัว:
docker system df -v | grep -A5 "VOLUME NAME"
# ดูขนาดจริงบน Disk:
sudo du -sh /var/lib/docker/volumes/*
# ลบ Resource ที่ไม่ใช้:
docker system prune # ลบ Container, Network, Image ที่ไม่ใช้
docker system prune --volumes # รวม Volumes ด้วย (ระวัง!)
docker volume prune # ลบเฉพาะ Volumes ที่ไม่ใช้
# Alert เมื่อ Disk เต็ม:
#!/bin/bash
USAGE=$(df /var/lib/docker | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$USAGE" -gt 80 ]; then
echo "Docker disk usage: ${USAGE}%" | mail -s "Docker Disk Alert" [email protected]
fi
สรุป: Docker Volumes สำหรับ Data Persistence
Docker Volumes เป็นวิธีมาตรฐานในการจัดการ Data ใน Container ทั้ง Named Volumes สำหรับ Production, Bind Mounts สำหรับ Development และ tmpfs สำหรับ Sensitive Data การเข้าใจ Volumes อย่างลึกซึ้งจะช่วยให้คุณรัน Container ได้อย่างมั่นใจ ไม่ต้องกังวลเรื่องข้อมูลหายเมื่อ Container ถูกลบหรือ Restart