DevOps
น้องๆ หลายคนอาจจะคุ้นเคยกับ Docker แล้ว แต่พอต้องรันหลายๆ Container พร้อมๆ กัน ชีวิตมันเริ่มวุ่นวายใช่ไหมล่ะ? Docker Compose นี่แหละคือพระเอกที่จะมาช่วยเราจัดการปัญหานี้ สมัยผมทำร้านเน็ต SiamCafe เนี่ย ก็เคยเจอปัญหาคล้ายๆ กัน คือต้องคอยดูแล Server หลายตัว แล้ว Config แต่ละตัวก็ไม่เหมือนกัน Docker Compose มันเหมือนเรามี Script อัตโนมัติที่ช่วยให้เราสั่งให้ Container ต่างๆ ทำงานพร้อมกันได้ง่ายๆ
Docker Compose คือเครื่องมือที่ช่วยให้เรา Define และ Run Application ที่ประกอบไปด้วยหลาย Container ได้ง่ายๆ โดยเราจะเขียน Configuration ทั้งหมดลงในไฟล์ docker-compose.yml ไฟล์เดียว แล้วสั่ง docker-compose up ทีเดียวจบเลย ไม่ต้องมานั่งพิมพ์คำสั่ง Docker ยาวๆ ให้เมื่อยมือ
ทำไมถึงสำคัญน่ะเหรอ? ลองนึกภาพว่าเรามีเว็บแอปพลิเคชันที่ต้องใช้ Web Server, Database, และ Cache Server ถ้าเราต้อง Run แต่ละ Container แยกกัน มันจะยุ่งยากมาก Docker Compose ช่วยให้เราจัดการทุกอย่างได้ในไฟล์เดียว แถมยังช่วยให้เรา Reproduce Environment ได้ง่ายขึ้นด้วย ใครที่เคยเจอปัญหา "ทำไมมัน Run บนเครื่องผมได้ แต่บน Server จริงไม่ได้" จะเข้าใจเลยว่า Docker Compose มันช่วยชีวิตเราได้ยังไง
ก่อนจะไปลงมือทำจริง เรามาทบทวนพื้นฐาน Docker กันก่อนนิดนึงนะ
Docker Image คือ Template ที่ใช้สร้าง Container เปรียบเหมือนพิมพ์เขียวที่เราใช้สร้างบ้าน เราสามารถ Pull Image จาก Docker Hub หรือสร้าง Image เองก็ได้ SiamCafe Blog เราเคยเขียนเรื่อง Docker Image ไว้ ลองไปอ่านเพิ่มเติมได้นะ
Docker Container คือ Instance ที่ Run จาก Docker Image เปรียบเหมือนบ้านที่สร้างจากพิมพ์เขียว Container แต่ละตัวจะมี Environment และ Resources เป็นของตัวเอง
Docker Volume คือพื้นที่เก็บข้อมูลที่ Container สามารถเข้าถึงได้ ข้อมูลที่อยู่ใน Volume จะไม่หายไปแม้ว่า Container จะถูก Stop หรือ Remove ทำให้เราสามารถเก็บข้อมูลสำคัญ เช่น Database ไว้ใน Volume ได้อย่างปลอดภัย
การใช้งาน Docker Compose ไม่ยากอย่างที่คิด เริ่มจาก Install Docker Compose ก่อนเลย (ถ้ายังไม่ได้ Install นะ)
จากนั้นสร้างไฟล์ docker-compose.yml ใน Directory ของ Project เรา ไฟล์นี้จะเป็นตัวกำหนดว่าเราต้องการ Run Container อะไรบ้าง
ตัวอย่างไฟล์ docker-compose.yml ง่ายๆ:
version: "3.9"
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: postgres:14
environment:
POSTGRES_USER: example
POSTGRES_PASSWORD: example
จากตัวอย่างนี้ เรา Define 2 Services คือ web (ใช้ Image nginx:latest) และ db (ใช้ Image postgres:14)
web จะ Map Port 80 ของ Host ไปยัง Port 80 ของ Container และ Mount Volume ./html ไปยัง /usr/share/nginx/html
db จะ Set Environment Variables POSTGRES_USER และ POSTGRES_PASSWORD
หลังจากที่เรามีไฟล์ docker-compose.yml แล้ว เราก็สามารถสั่ง Run Application ได้เลย
เปิด Terminal แล้ว Navigate ไปยัง Directory ที่มีไฟล์ docker-compose.yml จากนั้น Run คำสั่ง:
docker-compose up -d
Option -d คือ Detached Mode หมายความว่า Container จะ Run อยู่เบื้องหลัง
Docker Compose จะทำการ Pull Image ที่จำเป็น (ถ้ายังไม่มี) แล้วสร้างและ Run Container ตามที่เรา Define ไว้ในไฟล์ docker-compose.yml
ถ้าเราต้องการ Stop Application ให้ Run คำสั่ง:
docker-compose down
Docker Compose จะทำการ Stop และ Remove Container, Network, และ Volume ที่สร้างขึ้น
อยากดู Log ของ Container ทำได้ง่ายๆ ด้วยคำสั่ง:
docker-compose logs -f web
คำสั่งนี้จะแสดง Log ของ Service web (เราสามารถเปลี่ยน web เป็นชื่อ Service อื่นได้)
Option -f คือ Follow หมายความว่า Log จะถูกแสดงผลแบบ Real-time
Docker Compose ไม่ใช่เครื่องมือเดียวที่เราใช้จัดการ Container ได้ ยังมีทางเลือกอื่นๆ อีก เช่น Docker Swarm, Kubernetes, และ Ansible แต่ละเครื่องมือก็มีข้อดีข้อเสียแตกต่างกัน
Docker Compose เหมาะสำหรับ Application ขนาดเล็กถึงกลาง ที่ต้องการความเรียบง่ายและรวดเร็วในการ Setup Docker Swarm เหมาะสำหรับ Application ขนาดใหญ่ ที่ต้องการ Scalability และ High Availability Kubernetes เหมาะสำหรับ Application ขนาดใหญ่ ที่มีความซับซ้อนสูง และต้องการ Features ขั้นสูง เช่น Auto-scaling, Rolling Updates, และ Service Discovery Ansible เหมาะสำหรับ Automation และ Configuration Management ที่มีความยืดหยุ่นสูง
| เครื่องมือ | ข้อดี | ข้อเสีย | เหมาะสำหรับ |
|---|---|---|---|
| Docker Compose | ใช้งานง่าย, รวดเร็วในการ Setup | ไม่เหมาะสำหรับ Application ขนาดใหญ่ | Application ขนาดเล็กถึงกลาง |
| Docker Swarm | Scalable, High Availability | ซับซ้อนกว่า Docker Compose | Application ขนาดใหญ่ |
| Kubernetes | Features ขั้นสูง, Auto-scaling | ซับซ้อนมาก, ต้องใช้ความรู้ความเข้าใจสูง | Application ขนาดใหญ่ ที่มีความซับซ้อนสูง |
| Ansible | ยืดหยุ่นสูง, Automation | ต้องเขียน Playbook, เรียนรู้นาน | Automation และ Configuration Management |
เลือกเครื่องมือที่เหมาะสมกับความต้องการของ Project เรานะ ไม่มีเครื่องมือไหนที่ดีที่สุดเสมอไป SiamCafe Blog มีบทความเกี่ยวกับ DevOps อีกเยอะ ลองเข้าไปอ่านดูนะ เผื่อเจอเครื่องมือที่ใช่สำหรับน้องๆ
ดูวิดีโอเพิ่มเติมเกี่ยวกับDocker Compose Practical Guide:
เอาล่ะน้องๆ มาถึงส่วนที่สำคัญที่สุดแล้ว นั่นคือเคล็ดลับที่พี่บอมสั่งสมมาตลอด 20 กว่าปีที่คลุกคลีกับ IT ตั้งแต่สมัยทำร้านเน็ต SiamCafe ยันมาถึงยุค DevOps เนี่ยแหละ บอกเลยว่าแต่ละข้อ กลั่นมาจากหยาดเหงื่อจริงๆ
Docker Compose มันเหมือนเครื่องมือสารพัดประโยชน์ แต่ถ้าใช้ไม่ถูกวิธี แทนที่จะช่วยงาน กลับจะสร้างปัญหาให้ปวดหัวกว่าเดิมอีกนะ
อย่าเอาทุกอย่างยัดไว้ใน docker-compose.yml ไฟล์เดียว! สมัยก่อนตอนหัดเขียนใหม่ๆ พี่ก็เคยทำ พอโปรเจ็กต์มันใหญ่ขึ้นมาเท่านั้นแหละ แก้กันตาลายเลย
ให้แบ่งไฟล์ Compose ตามหน้าที่การทำงาน เช่น docker-compose.db.yml สำหรับ database, docker-compose.web.yml สำหรับ web application แล้วใช้ docker-compose -f docker-compose.db.yml -f docker-compose.web.yml up ตอนรัน
version: "3.9"
services:
db:
image: postgres:14
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: example
POSTGRES_PASSWORD: example
POSTGRES_DB: example
volumes:
db_data:
อย่าใส่ค่า config ต่างๆ ไว้ในไฟล์ Compose โดยตรง! พวก password, API key, database URL อะไรพวกนี้ ต้องใส่ใน Environment Variables เท่านั้น
สมัยก่อนตอนทำร้านเน็ต เคยเจอเคสที่ config หลุดไป เพราะดันใส่ password ไว้ในไฟล์ config ที่ push ขึ้น git เลยโดนแฮกไป โดนไปเยอะเลยน้อง จำไว้เป็นบทเรียน
version: "3.9"
services:
web:
image: nginx:latest
ports:
- "80:80"
environment:
DB_HOST: ${DB_HOST}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
Docker Compose มันแค่สั่งให้ container รันเฉยๆ มันไม่ได้เช็คว่า container ของเรามันทำงานได้จริงๆ หรือเปล่า ดังนั้นเราต้องกำหนด Health Check ให้มัน
Health Check มันเหมือนยามที่คอยตรวจตราว่า container ของเรายังโอเคอยู่ไหม ถ้าไม่โอเค ก็จะ restart ให้เอง
version: "3.9"
services:
web:
image: nginx:latest
ports:
- "80:80"
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]
interval: 30s
timeout: 10s
retries: 3
การ Mount Volume แบบ Named Volumes จะช่วยให้จัดการ Volume ได้ง่ายกว่า bind mount ในระยะยาว และสามารถ Share Volume ข้าม Container ได้อีกด้วย
สมัยก่อนตอนใช้ bind mount เวลามีปัญหาทีนึงก็ต้องไล่หา path กันวุ่นวาย Named Volumes ช่วยชีวิตได้เยอะ
version: "3.9"
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- web_data:/usr/share/nginx/html
volumes:
web_data:
docker-compose up แล้วมัน error?อันนี้เจอบ่อยมาก สาเหตุหลักๆ คือ
docker-compose.yml ไม่ถูกต้อง ลองใช้ docker-compose config เช็คดูdocker-compose.yml ไม่มีอยู่จริงใช้คำสั่ง docker-compose up --scale web=3 เพื่อรัน service "web" จำนวน 3 instances แต่ต้องระวังเรื่อง data consistency ด้วยนะ ถ้า service นั้นต้องอ่านเขียน database
ใช้คำสั่ง docker-compose pull เพื่อ download image เวอร์ชั่นล่าสุด แล้วใช้ docker-compose up -d เพื่อ restart container โดยใช้ image ใหม่
ใช้คำสั่ง docker-compose exec -it web bash เพื่อเข้าไปใน container "web" แล้วรันคำสั่งต่างๆ เพื่อตรวจสอบปัญหา
อันนี้ต้องใช้ docker command ร่วมด้วย เช่น docker run --rm -v myvolume:/data -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /data
Docker Compose เป็นเครื่องมือที่ powerful มากๆ ในการจัดการ container แต่การใช้งานให้ได้ประสิทธิภาพสูงสุด ต้องอาศัยความเข้าใจและประสบการณ์
หวังว่าเคล็ดลับที่พี่บอมแชร์ไป จะเป็นประโยชน์กับน้องๆ นะ ลองเอาไปปรับใช้กับโปรเจ็กต์ของตัวเองดู แล้วจะรู้ว่า Docker Compose มันเจ๋งจริง!
อย่าลืมแวะไปอ่านบทความอื่นๆ ใน SiamCafe Blog นะ มีเรื่อง IT สนุกๆ อีกเยอะเลย
ถ้าสนใจเรื่องการลงทุน Forex ลองดู iCafeForex ได้นะ