Services / Volumes / Networks (Docker Compose)
บทนี้จะพาคุณเข้าใจแกนหลักของ Docker Compose แบบผู้เริ่มต้น: services คือหน่วยแอปที่ Compose จัดการ, volumes คือการเก็บข้อมูลถาวรหรือการ mount ไฟล์, และ networks คือช่องทางการสื่อสารระหว่าง services เมื่อเข้าใจ 3 ส่วนนี้ คุณจะออกแบบระบบหลายคอนเทนเนอร์ (Multi-container) ได้ชัดเจนขึ้นมาก
ภาพระบบหลายคอนเทนเนอร์: web -> api -> db โดย Compose จัดการ service ทั้งหมดในไฟล์เดียว
ภาพการเก็บข้อมูลถาวร: service ฐานข้อมูลผูกกับ volume ทำให้ข้อมูลไม่หายตามวงจร container
ภาพการสื่อสารผ่าน network: services คุยกันด้วยชื่อ service เช่น api เรียก db:5432
ภาพจำสำคัญบทนี้
Services คือคนทำงาน, Volumes คือที่เก็บข้อมูลถาวร, Networks คือทางสื่อสารระหว่างคนทำงานในระบบเดียวกัน
ส่วนที่ 1
1) ภาพรวมของ Services / Volumes / Networks
เวลาเราสร้างระบบหลายคอนเทนเนอร์ (Multi-container) เราไม่ได้มีแค่โค้ดแอป แต่ต้องคิดเรื่องบทบาทของแต่ละส่วน, การเก็บข้อมูลให้ไม่หาย, และการสื่อสารระหว่างกัน Docker Compose ช่วยจัดการทั้งสามเรื่องผ่านโครงสร้างหลักเดียวในไฟล์ `docker-compose.yml`: - `services` บอกว่าในระบบมีคอนเทนเนอร์อะไรบ้าง - `volumes` บอกว่าข้อมูลไหนต้องเก็บถาวร - `networks` บอกว่า service ไหนคุยกับ service ไหนได้
ประเด็นที่ 1
Services = โครงร่างของงานในระบบ (web/api/db)
ประเด็นที่ 2
Volumes = ความต่อเนื่องของข้อมูล แม้คอนเทนเนอร์ถูกสร้างใหม่
ประเด็นที่ 3
Networks = เส้นทางสื่อสารภายในระบบด้วยชื่อ service
ประเด็นที่ 4
ทั้ง 3 ส่วนทำงานร่วมกันเพื่อให้ระบบเสถียรและดูแลง่าย
ส่วนที่ 2
2) Service คืออะไรใน Docker Compose
ใน Docker Compose, `service` คือคำประกาศว่ามีคอนเทนเนอร์ตัวหนึ่งในระบบของเรา พร้อมคอนฟิกที่จำเป็น เช่น image/build, ports, environment, command, volumes และ networks ให้คิดง่าย ๆ ว่า service คือ "บทบาท" ในระบบ ไม่ใช่แค่คอนเทนเนอร์เปล่า ๆ เช่น `web` มีหน้าที่แสดงหน้าเว็บ, `api` มีหน้าที่ประมวลผลธุรกิจ, `db` มีหน้าที่เก็บข้อมูล
- service หนึ่งตัว = หนึ่งหน้าที่หลักของระบบ
- Compose จะสร้างและจัดการ container จาก service ที่ประกาศไว้
- ชื่อ service ใช้เป็น host ภายใน network ได้ เช่น `api`, `db`
- การสเกลหรือปรับคอนฟิกเริ่มจากแก้ที่ service ก่อนเสมอ
ส่วนที่ 3
3) Volume คืออะไร
`volume` คือพื้นที่เก็บข้อมูลที่แยกจากวงจรชีวิตของคอนเทนเนอร์ ทำให้ข้อมูลยังอยู่แม้คอนเทนเนอร์ถูกลบแล้วสร้างใหม่ ใน Compose เรามักเจอ 2 รูปแบบหลัก: - Named volume: ให้ Docker จัดการพื้นที่เก็บข้อมูล - Bind mount: ผูกโฟลเดอร์จากเครื่องเราเข้า container
| รูปแบบ | แนวคิด | เหมาะกับงาน |
|---|---|---|
| Named volume | Docker จัดการตำแหน่งเก็บข้อมูลให้ | ข้อมูลถาวรของฐานข้อมูล (เช่น PostgreSQL) |
| Bind mount | ผูก path จาก host เข้า container | งานพัฒนาโลคัลที่อยากให้แก้โค้ดแล้วเห็นผลทันที |
ส่วนที่ 4
4) Network คืออะไร
`network` คือเครือข่ายเสมือนสำหรับให้ services คุยกันอย่างเป็นระบบ โดย Compose จะมี DNS ภายในให้ service เรียกกันด้วยชื่อ service ได้โดยตรง ตัวอย่าง: ถ้า `api` กับ `db` อยู่ใน network เดียวกัน, `api` สามารถเชื่อมฐานข้อมูลที่ host `db` ได้เลย โดยไม่ต้องใช้ IP แบบฮาร์ดโค้ด
- network ควบคุมขอบเขตการเข้าถึงกันระหว่าง services
- service discovery ผ่านชื่อ service ช่วยลดการผูกกับ IP
- แยกหลาย network ได้เพื่อเพิ่มความชัดเจนและความปลอดภัย
- พอร์ตภายในระหว่าง services ต่างจากพอร์ตที่ publish ออก host
ส่วนที่ 5
5) ทำไมระบบหลาย container มักต้องมีทั้ง 3 ส่วน
ระบบหลายคอนเทนเนอร์ที่ใช้งานได้จริงจะต้องตอบโจทย์ 3 คำถามพร้อมกัน: 1) ใครทำงานอะไร? -> ตอบด้วย services 2) ข้อมูลสำคัญเก็บที่ไหนให้ไม่หาย? -> ตอบด้วย volumes 3) แต่ละส่วนคุยกันอย่างไร? -> ตอบด้วย networks ถ้าขาดอย่างใดอย่างหนึ่ง ระบบจะเริ่มมีปัญหา เช่น รันได้แต่ข้อมูลหาย, หรือมีทุก service แต่คุยกันไม่ได้
ประเด็นที่ 1
มี service แต่ไม่มี volume: DB เสี่ยงข้อมูลหาย
ประเด็นที่ 2
มี service + volume แต่ไม่มี network ที่ถูกต้อง: ระบบคุยกันไม่ได้
ประเด็นที่ 3
มี network แต่ไม่แยกบทบาท service: โครงสร้างระบบสับสน
ประเด็นที่ 4
ครบทั้ง 3 ส่วน: ระบบชัดเจน ดูแลง่าย และทำซ้ำได้
ส่วนที่ 6
6) ตัวอย่างระบบจริง: web + api + db
ตัวอย่างมาตรฐานที่พบได้บ่อย: - `web` (Frontend): รับผู้ใช้ผ่านเบราว์เซอร์ - `api` (Backend): รับคำขอจาก web และคุยกับฐานข้อมูล - `db` (Database): เก็บข้อมูลถาวรของระบบ ทิศทางการไหลของคำขอโดยทั่วไปคือ `web -> api -> db`
ส่วนที่ 7
7) แต่ละ service มีหน้าที่อะไร
เมื่อแยกหน้าที่ชัด การพัฒนาและ debug จะง่ายขึ้นมาก เพราะรู้ว่าอาการปัญหาอยู่ชั้นไหน
| Service | หน้าที่หลัก | ตัวอย่างคอนฟิกที่เจอบ่อย |
|---|---|---|
| web | แสดง UI และเรียก API | ports, environment(API_BASE_URL), depends_on |
| api | ประมวลผลธุรกิจและเชื่อม db | build/image, environment(DATABASE_URL), networks |
| db | เก็บข้อมูลถาวร | image, volumes, environment(POSTGRES_*) |
ส่วนที่ 8
8) ทำไม database ควรใช้ volume
ข้อมูลฐานข้อมูลเป็นสินทรัพย์สำคัญของระบบ ถ้าเก็บไว้เฉพาะใน filesystem ของ container โดยไม่ใช้ volume, ข้อมูลอาจหายเมื่อ container ถูกลบหรือ recreate การใช้ named volume กับฐานข้อมูลทำให้ข้อมูลอยู่รอดข้ามการ `docker compose down`/`up` (ตราบใดที่ไม่สั่งลบ volume) และช่วยให้ workflow การพัฒนาเชื่อถือได้ขึ้น
- ลดความเสี่ยงข้อมูลหายเวลาปรับปรุงหรือรื้อ stack
- แยกวงจรข้อมูลออกจากวงจรชีวิต container
- รองรับการ backup/restore ได้ง่ายกว่า
- เหมาะกับข้อมูลที่ต้องคงอยู่ระยะยาว
ส่วนที่ 9
9) services คุยกันผ่าน network อย่างไร
ภายใน Compose, services ที่อยู่ network เดียวกันจะคุยกันผ่านชื่อ service ได้ เช่น `api` ต่อ `db:5432` โดยไม่ต้อง publish พอร์ต `db` ออก host จุดที่สับสนบ่อย: การ map `ports` มีไว้ให้ host ภายนอกเข้าถึง container แต่การคุยกันระหว่าง services ภายใน stack ใช้ network ภายในและชื่อ service เป็นหลัก
- ใช้ host เป็นชื่อ service (`db`) ไม่ใช่ `localhost`
- ไม่จำเป็นต้อง expose DB สู่ภายนอกเสมอไป
- ตรวจว่า services อยู่ network เดียวกัน
ส่วนที่ 10
10) ตัวอย่าง compose file ที่มีทั้ง services, volumes, networks
ตัวอย่างด้านล่างรวมองค์ประกอบหลักครบทั้ง 3 ส่วนในบริบทระบบ `web + api + db`
ตัวอย่างนี้ตั้งใจให้เห็นทั้งบทบาทของ service, การเก็บข้อมูล db แบบถาวร และการสื่อสารผ่าน network
ส่วนที่ 11
11) อธิบายทีละส่วนของตัวอย่าง
อ่านจากบนลงล่างจะเห็นว่าไฟล์ Compose ไม่ได้ยาวเกินไป ถ้าเรารู้ว่าต้องจับประเด็นไหนก่อน
| ส่วน | ทำอะไร | ประเด็นที่ควรจำ |
|---|---|---|
| services.web | ให้หน้าเว็บรับผู้ใช้และเรียก API | ค่า API ชี้ไป `http://api:8000` ผ่านชื่อ service |
| services.api | รับคำขอจาก web และคุย db | ใช้ `DATABASE_URL` host เป็น `db` |
| services.db | รันฐานข้อมูล PostgreSQL | mount `db_data` เพื่อให้ข้อมูลคงอยู่ |
| volumes.db_data | ประกาศ named volume | เป็นตัวเก็บข้อมูลถาวรของฐานข้อมูล |
| networks.app_net | เครือข่ายร่วมของทั้ง stack | ทำให้เรียกกันด้วยชื่อ service ได้ |
ส่วนที่ 12
12) ข้อผิดพลาดที่พบบ่อย
สามข้อด้านล่างเป็นปัญหาที่เจอบ่อยมากในระบบ Compose ช่วงเริ่มต้น
- ไม่ใช้ volume กับฐานข้อมูล แล้วข้อมูล db หายหลัง recreate container
- map port แล้ว แต่ service ยัง connect กันผิดชื่อ (เช่นใช้ `localhost` แทนชื่อ service `db`)
- สับสนระหว่าง host path (bind mount) กับ named volume จน mount ผิดตำแหน่ง
- คิดว่า `depends_on` รับประกัน readiness ทั้งหมด ทั้งที่จริงช่วยเรื่องลำดับ start เป็นหลัก
- แก้ไฟล์ Compose แล้วไม่ recreate service ทำให้เข้าใจว่าไฟล์ไม่ทำงาน
ส่วนที่ 13
13) สรุปท้ายบทแบบจำง่าย
สูตรจำสั้น ๆ ของบทนี้: `Service คือคนทำงาน` `Volume คือที่เก็บของสำคัญ` `Network คือถนนให้คนทำงานคุยกัน` ระบบ multi-container ที่ดีต้องมีทั้งสามอย่างครบและเชื่อมกันถูกต้อง
ประเด็นที่ 1
Services กำหนดบทบาทของแต่ละ container
ประเด็นที่ 2
Volumes ป้องกันข้อมูลสำคัญหาย
ประเด็นที่ 3
Networks ทำให้ services คุยกันเป็นระบบ
ประเด็นที่ 4
เมื่อทั้ง 3 ส่วนครบ ระบบจะดูแลง่ายและเสถียรกว่า
ส่วนที่ 14
14) แบบฝึกหัด 4 ข้อ พร้อมแนวเฉลย (กดแล้วค่อยแสดง)
ลองตอบด้วยตัวเองก่อน แล้วค่อยเปิดแนวเฉลยเพื่อตรวจความเข้าใจ