docker-compose.yml structure
บทนี้จะพาคุณอ่านโครงสร้างไฟล์ docker-compose.yml แบบเป็นระบบจากภาพรวมไปสู่รายละเอียด เพื่อให้เข้าใจว่าแต่ละส่วนทำหน้าที่อะไร ควรอ่านจากตรงไหนก่อน และหลีกเลี่ยงข้อผิดพลาด YAML ที่พบบ่อยได้ตั้งแต่เริ่มต้น
ภาพแยกส่วนของไฟล์ docker-compose.yml: เห็นชัดว่าด้านบนเป็น services และส่วนล่างเป็น volumes กับ networks
ภาพลำดับชั้น YAML: การย่อหน้า 2 ช่องว่างต่อระดับช่วยบอกความสัมพันธ์ parent-child ของ key
ภาพจำสำคัญบทนี้
อ่าน Compose ให้เร็ว: ดู services ก่อน แล้วไล่ key สำคัญ (image/build, ports, environment) จากนั้นค่อยเช็ก volumes กับ networks
ส่วนที่ 1
1) docker-compose.yml คืออะไร
`docker-compose.yml` คือไฟล์คอนฟิกที่ใช้อธิบายระบบหลายคอนเทนเนอร์ในที่เดียว เช่น เว็บแอป, API, และฐานข้อมูล แล้วใช้ `docker compose up` สั่งให้ระบบทั้งหมดเริ่มทำงานตามที่ประกาศไว้ มุมมองง่ายที่สุด: ไฟล์นี้คือ "แบบแปลนระบบ" ที่บอกว่าเรามี service อะไรบ้าง แต่ละ service ใช้อิมเมจอะไร เปิดพอร์ตอะไร ใช้ environment อะไร และเก็บข้อมูลถาวรตรงไหน
ประเด็นที่ 1
ไฟล์เดียวอธิบายหลาย service
ประเด็นที่ 2
ลดการพิมพ์คำสั่ง docker run ยาว ๆ ซ้ำ ๆ
ประเด็นที่ 3
ทำให้ทีมรันระบบได้ผลลัพธ์เหมือนกัน
ส่วนที่ 2
2) ทำไมต้องเข้าใจโครงสร้างของไฟล์นี้
ถ้าอ่านโครงสร้างไฟล์เป็น คุณจะ debug ได้เร็วขึ้นทันที เช่น เปิดเว็บไม่ได้ให้เช็ก `ports`, ต่อฐานข้อมูลไม่ได้ให้เช็ก `environment` กับ `networks`, ข้อมูลหายให้เช็ก `volumes` การเข้าใจโครงสร้างยังช่วยรีวิวไฟล์ของทีมได้เร็ว เพราะเรารู้ว่าคีย์ไหนควรอยู่ระดับไหน และอะไรคือจุดที่ผิดพลาดบ่อย
- แก้ปัญหาได้ไวขึ้น เพราะรู้ว่าต้องดู key ไหนก่อน
- ลดบั๊กจากการวาง key ผิดระดับ indentation
- ต่อยอดไปไฟล์ที่ซับซ้อนกว่าได้มั่นใจขึ้น
ส่วนที่ 3
3) YAML คืออะไรแบบสั้น ๆ
YAML คือรูปแบบไฟล์ข้อความสำหรับเก็บโครงสร้างข้อมูลแบบอ่านง่าย โดยใช้ "การย่อหน้า" (indentation) แทนวงเล็บปีกกาแบบ JSON ใน `docker-compose.yml` เราจึงเห็นการจัดลำดับชั้นด้วยช่องว่าง เช่น `services` อยู่ระดับบน แล้ว `web`, `db` อยู่ชั้นถัดลงมา
ส่วนที่ 4
4) ทำไม indentation สำคัญ
YAML มองช่องว่างด้านหน้าเป็น "โครงสร้าง" โดยตรง ถ้าย่อหน้าเพี้ยนแม้แต่นิดเดียว ความหมายอาจเปลี่ยนทันที หรือไฟล์พังจนรันไม่ได้ กฎจำง่ายสำหรับผู้เริ่มต้น: - ใช้ช่องว่าง 2 ตัวต่อ 1 ชั้น - อย่าผสม tab กับ space - key ที่อยู่ระดับเดียวกันต้องย่อหน้าเท่ากัน
ด้านบนคือถูกต้อง ด้านล่างคือผิดเพราะ `image` ถูกย่อหน้าผิดระดับ
ส่วนที่ 5
5) โครงสร้างหลักของ compose file
เวลามองภาพรวม ให้จำโครงสร้างหลัก 3 ส่วนนี้ก่อนเสมอ: - `services` = บอกคอนเทนเนอร์แต่ละตัวทำอะไร - `volumes` = พื้นที่เก็บข้อมูลถาวร - `networks` = เครือข่ายให้ service คุยกัน อ่านแบบเร็ว: มองบนลงล่างจาก `services` ก่อน เพราะเป็นหัวใจหลักของระบบ จากนั้นค่อยดู `volumes` และ `networks` ที่ support services
| ส่วนหลัก | หน้าที่ | อ่านเมื่อไร |
|---|---|---|
| services | ประกาศ service ทั้งหมด | อ่านเป็นอันดับแรก |
| volumes | เก็บข้อมูลให้ไม่หาย | อ่านเมื่อมี DB หรือไฟล์ถาวร |
| networks | ควบคุมการเชื่อมต่อระหว่าง service | อ่านเมื่อมีหลายเครือข่าย |
ส่วนที่ 6
6) services คืออะไร
`services` คือส่วนที่ประกาศ "หน่วยทำงาน" ของระบบ เช่น `app`, `api`, `db` โดยแต่ละ service จะมีคีย์ย่อยเป็นของตัวเอง เช่น `image`, `ports`, `environment` โดยทั่วไปเวลามีปัญหา 80% เรามักเริ่มไล่จาก service ที่มีอาการก่อน แล้วดูคีย์ย่อยของ service นั้น
ประเด็นที่ 1
service หนึ่ง = คอนเทนเนอร์หนึ่งบทบาท (หรือหลาย replica ในกรณีขยาย)
ประเด็นที่ 2
ชื่อ service ใช้เป็น host name ภายใน network เดียวกันได้
ประเด็นที่ 3
service เป็นจุดที่กำหนดพฤติกรรม runtime เกือบทั้งหมด
ส่วนที่ 7
7) volumes คืออะไร
`volumes` คือพื้นที่เก็บข้อมูลที่ Docker จัดการให้ เพื่อให้ข้อมูลไม่หายเมื่อ container ถูกลบหรือสร้างใหม่ เช่น ข้อมูลใน PostgreSQL ถ้าคุณไม่ใช้ volume กับฐานข้อมูล ข้อมูลมีโอกาสหายเมื่อทำ `docker compose down` หรือ recreate container
ส่วนที่ 8
8) networks คืออะไร
`networks` กำหนดว่าบริการไหนอยู่เครือข่ายไหน และคุยกันอย่างไร โดยค่าเริ่มต้น Compose จะสร้าง network กลางให้อัตโนมัติ แต่เราประกาศเองได้ถ้าต้องการแยกโซน ตัวอย่างแนวคิด: `frontend` คุยกับ `api` ได้ แต่ `frontend` ไม่จำเป็นต้องคุยตรงกับ `db` ก็สามารถแยกเครือข่ายเพิ่มได้
ส่วนที่ 9
9) อธิบาย key สำคัญใน service
คีย์ต่อไปนี้คือชุดพื้นฐานที่เจอบ่อยที่สุดในงานจริง - `image`: ระบุอิมเมจที่จะใช้รัน container - `build`: สร้างอิมเมจจาก Dockerfile ในโปรเจกต์ - `ports`: map พอร์ตระหว่างเครื่องเราและใน container - `environment`: กำหนดตัวแปรแวดล้อมให้ service - `volumes`: mount พื้นที่เก็บข้อมูลหรือ source code - `depends_on`: จัดลำดับการเริ่ม service เบื้องต้น - `command`: คำสั่งที่ให้ container รันตอน start - `container_name`: ตั้งชื่อ container แบบกำหนดเอง
| Key | ความหมายสั้น ๆ | ตัวอย่าง |
|---|---|---|
| image | ใช้ image ที่มีอยู่แล้ว | image: postgres:16 |
| build | สั่ง build image จากโค้ด | build: ./api |
| ports | เปิดพอร์ตให้เข้าจากภายนอก | - "8080:80" |
| environment | ส่งค่าคอนฟิกเข้า container | - NODE_ENV=production |
| volumes | ผูกข้อมูลถาวรหรือไฟล์ | - db_data:/var/lib/postgresql/data |
| depends_on | กำหนดลำดับการ start | depends_on: [db] |
| command | override คำสั่งเริ่มต้น | command: npm run dev |
| container_name | ตั้งชื่อ container เอง | container_name: compose-api |
ส่วนที่ 10
10) ยกตัวอย่าง compose file แบบครบพื้นฐาน
ตัวอย่างนี้จงใจใส่โครงสร้างหลักครบทั้ง `services`, `volumes`, `networks` และ key สำคัญที่ผู้เริ่มต้นต้องรู้
ตัวอย่างระบบ 2 service: api + db โดย api build จากโค้ด และ db ใช้ image สำเร็จรูป
ส่วนที่ 11
11) อธิบายทีละบรรทัด
ตารางนี้ช่วยให้คุณ map "บรรทัด" กับ "หน้าที่" ได้เร็วขึ้น โดยอิงจากตัวอย่างด้านบน
| บรรทัด | ข้อความ | อธิบาย |
|---|---|---|
| 1 | services: | เริ่มส่วนบริการทั้งหมด |
| 2 | api: | ประกาศ service ชื่อ api |
| 3 | container_name: compose-api | ตั้งชื่อ container ให้อ่านง่าย |
| 4 | build: ./api | สั่ง build image จากโฟลเดอร์ ./api |
| 5 | command: npm run dev | คำสั่งที่รันตอน container เริ่ม |
| 6-7 | ports | เปิดพอร์ต 3000 ของเครื่องไปยัง 3000 ใน container |
| 8-10 | environment | ส่งค่าคอนฟิกให้แอป รวมถึง DATABASE_URL |
| 11-12 | volumes | mount โค้ดจากเครื่องเข้า container เพื่อ dev |
| 13-14 | depends_on | ให้ api เริ่มหลัง db |
| 15-16 | networks | ต่อ api เข้าเครือข่าย app_net |
| 18 | db: | ประกาศ service ฐานข้อมูล |
| 19 | image: postgres:16 | ใช้ image postgres เวอร์ชัน 16 |
| 20 | container_name: compose-db | ตั้งชื่อ container ของฐานข้อมูล |
| 21-22 | ports | เปิดพอร์ตฐานข้อมูลจากเครื่องไป container |
| 23-26 | environment | กำหนด user/password/db เริ่มต้นของ postgres |
| 27-28 | volumes | เก็บข้อมูล DB ไว้ใน named volume |
| 29-30 | networks | ต่อ db เข้า app_net |
| 32-33 | volumes: db_data | ประกาศ named volume ที่ถูกอ้างถึง |
| 35-36 | networks: app_net | ประกาศเครือข่ายที่ services ใช้งานร่วมกัน |
ส่วนที่ 12
12) ข้อผิดพลาดที่พบบ่อย
ข้อผิดพลาดเหล่านี้เกิดบ่อยมากในผู้เริ่มต้น โดยเฉพาะเรื่อง indentation และการวาง key ผิดที่
- ย่อหน้า YAML ผิด เช่น `image` ไม่ได้อยู่ใต้ชื่อ service
- วาง `volumes` หรือ `networks` ผิดระดับ ทำให้ parser อ่านไม่ตรงเจตนา
- เขียน `ports` ผิดรูปแบบ เช่น ลืมใส่เครื่องหมายคำพูดในบางกรณี
- ตั้ง `depends_on` แล้วเข้าใจผิดว่า service ปลายทางพร้อมใช้งานทันที
- ใช้ `localhost` ใน container เพื่อชี้ไป service อื่น แทนที่จะใช้ชื่อ service เช่น `db`
- ผสม tab กับ space ในไฟล์ YAML
ส่วนที่ 13
13) แนวทางอ่าน compose file ให้เข้าใจเร็ว
ใช้ลำดับอ่านนี้เพื่อประหยัดเวลาเวลา debug: 1. อ่านชื่อ service ทั้งหมดก่อนว่าใครบ้าง 2. เข้า service ที่มีปัญหาแล้วดู `image/build` 3. เช็ก `ports` ว่า map ถูกไหม 4. เช็ก `environment` โดยเฉพาะ host/port ของ service ที่เรียกหา 5. เช็ก `volumes` ถ้าเป็นปัญหาเรื่องข้อมูลไม่คงอยู่ 6. เช็ก `networks` ถ้า service คุยกันไม่ได้
ประเด็นที่ 1
เริ่มที่ services ก่อนเสมอ
ประเด็นที่ 2
ไล่จาก key ที่กระทบการรันจริง: image/build -> ports -> environment
ประเด็นที่ 3
ปิดท้ายด้วย volumes และ networks
ส่วนที่ 14
14) สรุปท้ายบทแบบจำง่าย
สูตรจำสั้น ๆ สำหรับ `docker-compose.yml`: "บริการอยู่ใน services, ข้อมูลอยู่ใน volumes, การสื่อสารอยู่ใน networks" ถ้าจำประโยคนี้ได้ คุณจะอ่านไฟล์ compose ได้เร็วขึ้นมาก
ประเด็นที่ 1
`services` = ใครทำงานอะไร
ประเด็นที่ 2
`volumes` = อะไรต้องไม่หาย
ประเด็นที่ 3
`networks` = ใครคุยกับใคร
ประเด็นที่ 4
YAML indentation = โครงสร้างของความหมาย
ส่วนที่ 15
15) แบบฝึกหัด 4 ข้อ พร้อมแนวเฉลย (กดแล้วค่อยแสดง)
ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลยเพื่อเช็กความเข้าใจ