หนึ่งในปัญหาที่พบบ่อยที่สุดเมื่อเริ่มใช้ Docker คือข้อมูลหายทุกครั้งที่ Container ถูกลบหรือสร้างใหม่ ปัญหานี้เกิดจากการเข้าใจผิดเกี่ยวกับวิธีที่ Docker จัดการ filesystem ภายใน Container ซึ่งโดยธรรมชาติแล้วเป็น ephemeral — สร้างขึ้นมาพร้อม Container และหายไปพร้อมกันเมื่อ Container ถูกลบ Docker Volumes คือกลไกที่ Docker ออกแบบมาเพื่อแก้ปัญหานี้โดยเฉพาะ ช่วยให้ข้อมูลที่สำคัญอย่างฐานข้อมูล ไฟล์ที่ผู้ใช้อัปโหลด หรือ configuration files ยังคงอยู่ได้แม้ Container จะถูกหยุดหรือลบไปแล้ว บทความนี้จะอธิบายแนวคิด Docker Volumes อย่างละเอียด พร้อมคำสั่งและตัวอย่างการใช้งานจริงที่ทดสอบบน VPS Ubuntu แล้ว
Docker Storage — เข้าใจ Writable Layer ก่อน
เพื่อเข้าใจว่าทำไม Volumes ถึงจำเป็น ต้องทราบก่อนว่า Docker จัดการ filesystem ของ Container อย่างไร Docker Image สร้างขึ้นจากหลาย Layer ที่ซ้อนกัน (Union Filesystem) และทุก Layer เป็น read-only เมื่อ Container ถูกสร้างจาก Image Docker จะเพิ่ม Writable Layer ด้านบนสุดเข้าไป การเขียน ลบ หรือแก้ไขไฟล์ใดๆ ภายใน Container จะเกิดขึ้นบน Writable Layer นี้เท่านั้น ไม่ได้แตะ Image Layer เดิม
ปัญหาคือ Writable Layer ผูกติดกับ Container instance นั้นๆ โดยตรง เมื่อ Container ถูกลบด้วย docker rm หรือ docker-compose down Writable Layer ก็ถูกลบไปด้วยพร้อมกันทั้งหมด นั่นหมายความว่าถ้าคุณรัน MySQL ใน Container และเก็บข้อมูลไว้ใน Writable Layer ข้อมูลทั้งหมดจะหายทันทีเมื่อ Container ถูกลบ Docker มีกลไก 3 แบบสำหรับจัดการข้อมูลที่ต้องการความคงทน ได้แก่ Volumes, Bind Mounts และ tmpfs Mounts
Docker Volume คืออะไร และทำงานอย่างไร
Docker Volume คือ directory พิเศษที่ Docker Engine จัดการแยกออกจาก Container lifecycle อย่างสมบูรณ์ ข้อมูลใน Volume ถูกเก็บอยู่ใน host filesystem ที่ path /var/lib/docker/volumes/<volume-name>/_data โดย Docker Engine เป็นผู้ดูแล ไม่ใช่ผู้ใช้งานโดยตรง ทำให้มีข้อดีหลายอย่างเหนือการเก็บข้อมูลแบบอื่น
Volume มีวงจรชีวิต (lifecycle) เป็นของตัวเองแยกจาก Container โดยสิ้นเชิง คุณสามารถลบ Container ได้โดยไม่กระทบข้อมูลใน Volume และสามารถ attach Volume เดิมกลับเข้า Container ใหม่ได้ทันที นอกจากนี้ Volume ยังรองรับ Volume Driver ที่ช่วยให้เก็บข้อมูลบน remote storage เช่น NFS, AWS EBS หรือ Azure Disk ได้อีกด้วย
- Lifecycle เป็นอิสระ — ลบ Container ไม่กระทบข้อมูลใน Volume
- จัดการโดย Docker — ไม่ต้องกังวลเรื่อง path และ permission บน host
- แชร์ระหว่าง Container — หลาย Container mount Volume เดียวกันได้พร้อมกัน
- Backup และ Migration ง่าย — ใช้คำสั่ง Docker มาตรฐานได้เลย
- รองรับ Volume Driver — เก็บข้อมูลบน cloud storage ได้
- ประสิทธิภาพดี — เขียนข้อมูลโดยตรงบน host filesystem ไม่ผ่าน Union FS Layer
ประเภทของ Docker Storage: Volume vs Bind Mount vs tmpfs
ก่อนจะเจาะลึก Volume ควรทำความเข้าใจทั้ง 3 ตัวเลือกเพื่อเลือกให้ถูกกับงาน
| ประเภท | เก็บข้อมูลที่ไหน | Persistence | เหมาะกับ |
|---|---|---|---|
| Named Volume | /var/lib/docker/volumes/ | ถาวร (ลบเองได้) | Database, user uploads, production data |
| Bind Mount | path บน host (กำหนดเอง) | ถาวร (ขึ้นกับ host) | Development, config files, source code |
| tmpfs Mount | RAM (ไม่เขียน disk) | ชั่วคราว (หายเมื่อ stop) | Session cache, temp data, secrets |
| Anonymous Volume | /var/lib/docker/volumes/ (random ID) | ถาวรแต่หาชื่อยาก | ไม่แนะนำสำหรับ production |
ในงาน production แนะนำให้ใช้ Named Volume เป็นหลัก เพราะ Docker จัดการ lifecycle ให้และตั้งชื่อที่มีความหมายได้ ส่วน Bind Mount เหมาะกับ development workflow ที่ต้องการแก้ไขโค้ดแล้วเห็นผลใน Container ทันที
การสร้างและจัดการ Docker Volume ด้วยคำสั่ง
เริ่มต้นด้วยคำสั่งพื้นฐานที่ต้องรู้:
# สร้าง Named Volume ใหม่ docker volume create myapp_data # ดูรายการ Volume ทั้งหมด docker volume ls # ดูรายละเอียดของ Volume docker volume inspect myapp_data # ลบ Volume (ต้องไม่มี Container ใช้งานอยู่) docker volume rm myapp_data # ลบ Volume ที่ไม่มี Container ใช้แล้ว (Prune) docker volume prune # ลบ Volume พร้อม Container ตอน docker-compose down docker-compose down -v
ตัวอย่าง output ของ docker volume inspect:
[
{
"CreatedAt": "2026-06-09T10:00:00+07:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/myapp_data/_data",
"Name": "myapp_data",
"Options": {},
"Scope": "local"
}
]
การใช้ Volume กับ Docker Run และ Docker Compose
มีสองวิธีหลักในการ mount Volume เข้า Container: ผ่าน flag -v หรือ --mount ใน docker run และผ่าน volumes: ใน docker-compose.yml
วิธีที่ 1 — docker run กับ -v flag
# รูปแบบ: -v <volume-name>:<path-ใน-container> docker run -d \ --name mysql_db \ -e MYSQL_ROOT_PASSWORD=secret \ -e MYSQL_DATABASE=myapp \ -v mysql_data:/var/lib/mysql \ mysql:8.0 # Bind Mount — ผูกกับ path จริงบน host docker run -d \ --name nginx_web \ -v /home/user/website:/usr/share/nginx/html:ro \ -p 80:80 \ nginx:alpine
วิธีที่ 2 — docker-compose.yml (แนะนำสำหรับ production)
version: '3.8'
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
app:
image: myapp:latest
depends_on:
- db
volumes:
- app_uploads:/app/uploads
- app_logs:/app/logs
ports:
- "8000:8000"
# ประกาศ Named Volume ในระดับ top-level
volumes:
postgres_data:
app_uploads:
app_logs:
การประกาศ volumes: ในระดับ top-level ของ docker-compose.yml ทำให้ Docker สร้าง Named Volume อัตโนมัติถ้ายังไม่มี และข้อมูลจะคงอยู่แม้รัน docker-compose down ต้องใช้ docker-compose down -v จึงจะลบ Volume ด้วย
การ Backup และ Restore Docker Volume
การ backup ข้อมูลจาก Volume เป็นส่วนสำคัญของการดูแล production server ต่อไปนี้คือวิธีมาตรฐานที่ใช้บ่อยที่สุด
Backup Volume เป็นไฟล์ tar.gz
# Backup Volume ชื่อ postgres_data ไปยังโฟลเดอร์ปัจจุบัน docker run --rm \ -v postgres_data:/source:ro \ -v $(pwd):/backup \ alpine \ tar czf /backup/postgres_data_$(date +%Y%m%d).tar.gz -C /source . # ตรวจสอบไฟล์ backup ls -lh postgres_data_*.tar.gz
Restore Volume จากไฟล์ backup
# สร้าง Volume ใหม่สำหรับ restore docker volume create postgres_data_restore # Restore จาก tar.gz docker run --rm \ -v postgres_data_restore:/target \ -v $(pwd):/backup \ alpine \ sh -c "cd /target && tar xzf /backup/postgres_data_20260609.tar.gz"
Backup Database โดยตรง (แนะนำสำหรับ PostgreSQL/MySQL)
# PostgreSQL — ใช้ pg_dump แทน tar (ได้ consistent dump) docker exec postgres_container pg_dump -U myuser mydb \ > backup_$(date +%Y%m%d).sql # MySQL — ใช้ mysqldump docker exec mysql_container mysqldump \ -u root -psecret myapp \ > mysql_backup_$(date +%Y%m%d).sql # Restore PostgreSQL cat backup_20260609.sql | docker exec -i postgres_container \ psql -U myuser mydb
เคล็ดลับสำหรับ Production: อย่า backup ด้วย tar ตรงๆ ขณะ Database กำลังทำงาน เพราะอาจได้ไฟล์ที่ไม่สอดคล้องกัน (inconsistent state) ให้ใช้ pg_dump หรือ mysqldump ซึ่งออกแบบมาให้ dump ได้ขณะ Database ยังรันอยู่อย่างปลอดภัย สำหรับ MongoDB ใช้ mongodump และตั้ง cron job ให้ backup อัตโนมัติทุกคืนแล้วส่งไป remote storage อีกที
การแชร์ Volume ระหว่างหลาย Container
หนึ่งในประโยชน์ที่ทรงพลังของ Docker Volume คือความสามารถในการแชร์ข้อมูลระหว่างหลาย Container พร้อมกัน ซึ่งมีประโยชน์มากสำหรับสถาปัตยกรรม microservices ที่ต้องการแชร์ไฟล์กัน
version: '3.8'
services:
# App server เขียนไฟล์ upload
app:
image: myapp:latest
volumes:
- shared_uploads:/app/uploads
# Nginx Proxy อ่านไฟล์ upload เพื่อ serve static files
nginx:
image: nginx:alpine
volumes:
- shared_uploads:/usr/share/nginx/html/uploads:ro
ports:
- "80:80"
# Worker process อ่านไฟล์ upload เพื่อ process
worker:
image: myworker:latest
volumes:
- shared_uploads:/worker/input:ro
volumes:
shared_uploads:
ในตัวอย่างนี้ Container ทั้ง 3 ตัวแชร์ Volume shared_uploads เดียวกัน แต่ nginx และ worker mount แบบ read-only (:ro) เพื่อป้องกันการเขียนทับโดยไม่ตั้งใจ ควรกำหนด :ro ให้กับ Container ที่ต้องการอ่านอย่างเดียวเสมอ เป็น best practice ด้านความปลอดภัย
Volume Permissions และการแก้ปัญหาเรื่อง User
ปัญหา permission เป็นเรื่องที่พบบ่อยมากเมื่อใช้ Volume บน Linux เนื่องจาก UID/GID ของ process ใน Container อาจไม่ตรงกับ ownership ของ directory บน host ทำให้เกิด Permission Denied error
# ตรวจสอบ ownership ของ Volume บน host
ls -la /var/lib/docker/volumes/myapp_data/_data
# วิธีแก้ปัญหา: กำหนด user ใน Dockerfile
# เพิ่มใน Dockerfile ของ app
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
RUN chown -R appuser:appgroup /app
USER appuser
# หรือ กำหนด user ตอน run
docker run -d \
--user 1000:1000 \
-v myapp_data:/app/data \
myapp:latest
# สำหรับ docker-compose.yml
services:
app:
image: myapp:latest
user: "1000:1000"
volumes:
- myapp_data:/app/data
สำหรับ database images อย่าง MySQL, PostgreSQL หรือ MongoDB ทีม Docker Official Image ออกแบบ entrypoint ให้จัดการ permission อัตโนมัติ ไม่ต้องกำหนดเอง แต่ถ้าสร้าง Image เองต้องระวังเรื่องนี้เป็นพิเศษ
Best Practices สำหรับ Docker Volume ใน Production
เมื่อใช้งาน Docker Volume บน VPS ที่ให้บริการจริง มีแนวปฏิบัติที่ควรทำตามเพื่อให้ระบบมีเสถียรภาพและข้อมูลปลอดภัย
- ตั้งชื่อ Volume ให้มีความหมาย — ใช้ชื่อแบบ
projectname_service_dataเช่นmyapp_postgres_dataแทน volume ที่ชื่อ random เพื่อให้รู้ทันทีว่าเป็นของโปรเจกต์ไหน - ประกาศ Volume ใน docker-compose.yml เสมอ — อย่าพึ่ง anonymous volume เพราะ ID random จำยาก และ
docker volume pruneจะลบทิ้งถ้าไม่มี Container ใช้ - Backup สม่ำเสมอ — ตั้ง cron job backup อย่างน้อยวันละครั้ง และทดสอบ restore จริงทุกเดือน
- Monitor disk usage — Volume ที่โตขึ้นเรื่อยๆ โดยไม่มีการ cleanup อาจทำให้ disk เต็มและ Container crash
- ใช้ read-only mount เมื่อทำได้ — Container ที่ต้องการแค่อ่านข้อมูลให้ mount
:roลดความเสี่ยงข้อมูลเสียหาย - แยก Volume ตามประเภทข้อมูล — อย่าเก็บ database data กับ log files ไว้ใน Volume เดียวกัน เพื่อให้ backup แยกกันได้และจัดการ retention policy ต่างกัน
- ระวัง Volume Driver บน Cluster — ถ้าใช้ Docker Swarm หรือ Kubernetes ต้องเลือก Volume Driver ที่รองรับ multi-host access เช่น NFS หรือ cloud storage
# ตัวอย่าง cron job backup อัตโนมัติ (เพิ่มใน crontab -e) # Backup ทุกวัน เวลา 02:00 น. 0 2 * * * docker run --rm \ -v myapp_postgres_data:/source:ro \ -v /backup/docker:/backup \ alpine \ tar czf /backup/postgres_$(date +\%Y\%m\%d).tar.gz \ -C /source . && \ find /backup/docker -name "postgres_*.tar.gz" -mtime +30 -delete
คำถามที่พบบ่อย (FAQ)
Docker Volume ต่างจาก Bind Mount อย่างไร
Docker Volume ถูกจัดการโดย Docker Engine เก็บข้อมูลใน /var/lib/docker/volumes/ และพกพาข้ามเครื่องได้ง่าย ส่วน Bind Mount ผูกกับ path บน host โดยตรง เหมาะสำหรับ development ที่ต้องการแก้ไขไฟล์ได้ทันที แต่ขึ้นกับโครงสร้าง directory บน host ในงาน production ควรใช้ Named Volume เป็นหลัก เพราะ Docker จัดการ lifecycle และ permission ให้ และย้าย host ได้ง่ายกว่า
ข้อมูลใน Docker Volume จะหายไปเมื่อ Container ถูกลบหรือไม่
ไม่หาย Volume มีวงจรชีวิตแยกจาก Container โดยสิ้นเชิง แม้จะรัน docker rm -f หรือ docker-compose down ข้อมูลใน Named Volume ยังคงอยู่บน host จนกว่าจะลบ Volume เองด้วย docker volume rm หรือ docker volume prune ดังนั้นการลบ Container จึงปลอดภัยสำหรับข้อมูล แต่ควร backup สม่ำเสมออยู่ดีเพื่อป้องกัน disk failure
วิธี backup ข้อมูลจาก Docker Volume ทำอย่างไร
วิธีมาตรฐานคือรัน Container ชั่วคราวที่ mount volume แล้วสร้าง tar archive เช่น: docker run --rm -v myvolume:/data -v $(pwd):/backup alpine tar czf /backup/backup.tar.gz -C /data . จะได้ไฟล์ backup.tar.gz ในโฟลเดอร์ปัจจุบัน สำหรับ PostgreSQL/MySQL ควรใช้ pg_dump/mysqldump แทนการ backup ไฟล์ raw เพื่อความสอดคล้องของข้อมูล
ควรใช้ Volume หรือ tmpfs สำหรับข้อมูลชั่วคราวใน Container
ถ้าข้อมูลไม่ต้องการ persistence ระหว่าง restart และต้องการความเร็วสูงสุด ให้ใช้ tmpfs mount แทน Volume เพราะเก็บใน RAM ไม่เขียน disk แต่ถ้า Container restart แล้วข้อมูลหายได้รับไม่ได้ ให้ใช้ Named Volume เสมอ tmpfs เหมาะกับ session cache, temp files ที่ regenerate ได้ ส่วน Volume เหมาะกับ database, user uploads, config files ที่ต้องคงอยู่
VPS KVM ประสิทธิภาพสูงของ AsiaGB
AsiaGB VPS Root Access เต็มรูปแบบ Docker MySQL Python Node.js เริ่มต้น 500 บาท/เดือน
ดูแพ็กเกจ VPS