docker-compose เป็นเครื่องมือสำหรับจัดการคอนเทนเนอร์ Docker ซึ่งช่วยแก้ปัญหาการดีพลอยแอปพลิเคชันที่ซับซ้อน แต่ยังไม่เพียงพอสำหรับการ self-hosting แบบง่าย ๆ สำหรับตลาดมวลชน
- จำเป็นต้องมี abstraction ระดับสูงกว่าที่รวมแนวคิดอย่างฐานข้อมูล SQL, local cache, persistent storage, service discovery และ resource management
บทบาทของ Docker
- Docker เป็นเครื่องมือที่ทำให้คอนเทนเนอร์ได้รับความนิยมในวงกว้าง โดยสามารถเปรียบระบบโฮสต์ได้เหมือนเรือ
- มีทั้งฮาร์ดแวร์ ระบบปฏิบัติการ และ container runtime โดยคอนเทนเนอร์จะรันอยู่ภายใน runtime และสื่อสารกับบริการอื่น ๆ เช่น ฐานข้อมูลหรือเว็บเซิร์ฟเวอร์
บทบาทของ Docker-compose
docker-compose เป็นเครื่องมือสำหรับกำหนดกลุ่มคอนเทนเนอร์ที่ทำงานร่วมกัน และช่วยให้การดีพลอยแอปพลิเคชันแบบ self-hosting ทำได้ง่ายขึ้น
- อย่างไรก็ตาม มันทำลายอินเทอร์เฟซที่เป็นมาตรฐานและทำให้เกิดปัญหาแบบเดียวกับที่คอนเทนเนอร์พยายามแก้ไว้แต่แรก
- ตัวอย่าง: Pihole
- Pihole เป็น DNS server ที่ต้องใช้ไฟล์
docker-compose ที่ซับซ้อน
- ต้องตั้งค่าชื่อคอนเทนเนอร์, image, port, environment variable, volume, ความสามารถเพิ่มเติม, restart policy และอื่น ๆ
- ผู้ใช้ต้องจัดการการตั้งค่าที่ซับซ้อนเหล่านี้เอง ซึ่งเป็นข้อเสียของ Docker Compose
- ตัวอย่าง: Jitsi Meet
- Jitsi Meet เป็นซอฟต์แวร์ที่ซับซ้อน โดยสร้างคอนฟิก
docker-compose ที่มี 4 คอนเทนเนอร์, 7 วอลุ่ม, 9 พอร์ต และการตั้งค่า environment มากกว่า 200 รายการ
- ตัวอย่าง: แอป self-hosting ยอดนิยมอื่น ๆ ก็ประสบปัญหาแบบเดียวกัน
- มีแอปหลากหลาย เช่น Authentik, Nextcloud, Immich, Jellyfin, Paperless NGX เป็นต้น และคอนฟิก
docker-compose ของแต่ละแอปก็แทนที่คำสั่ง docker ตั้งแต่หลายสิบถึงหลายร้อยคำสั่ง
- แต่ละแอปอาจมีฐานข้อมูล แคช และ HTTP handler ของตัวเอง ซึ่งนำไปสู่การใช้ทรัพยากรซ้ำซ้อน
ปัญหา
docker-compose ยืดหยุ่นเกินไป ละเอียดเกินไป และทำงานอยู่บนชั้น abstraction ที่ไม่เหมาะสม
- แต่ละแอปมี process สำหรับจัดการ HTTP, แคช หรือฐานข้อมูลของตัวเอง และการสำรองข้อมูลฐานข้อมูลก็กลายเป็นภาระของผู้ดูแลระบบ
- ตัวอย่าง: Reverse HTTP proxy
- Reverse HTTP proxy คือโปรแกรมที่ส่งต่อคำขอ HTTP ที่เข้ามาไปยังโปรแกรมอื่น โดยแต่ละโปรแกรมต้องตัดสินใจเองว่าจะรวมเว็บเซิร์ฟเวอร์มาด้วยหรือไม่
- รวมเว็บเซิร์ฟเวอร์
- หากรวมเว็บเซิร์ฟเวอร์มา โปรแกรมก็จะทำงานได้ แต่จะทำงานได้เฉพาะบนพอร์ตที่กำหนด และถ้ามีหลายคอนเทนเนอร์ก็ต้อง remap พอร์ต
- ไม่รวมเว็บเซิร์ฟเวอร์
- หากไม่รวมเว็บเซิร์ฟเวอร์ก็จะไม่เปลืองทรัพยากร แต่ต้องคอนฟิกแอปพลิเคชันโดยไม่มีอินเทอร์เฟซสำหรับจัดการ
- DNS
- เว็บอินเทอร์เฟซต้องมีที่อยู่ และหากต้องการ TLS ก็ต้องมีชื่อด้วย หากรันหลายบริการบนโฮสต์เดียวกัน ก็ต้อง route คำขอด้วยชื่อโดเมนหรือ path
- พอร์ต
docker-compose อนุญาตให้ expose และ remap พอร์ตได้ แต่ในทางปฏิบัติแล้วควรรองรับการตั้งค่าเครือข่ายที่ซับซ้อนกว่านั้น
- ตัวอย่าง: ฐานข้อมูล
- ฐานข้อมูลจะสูญเสียการเปลี่ยนแปลงทั้งหมดของไฟล์เมื่อคอนเทนเนอร์ถูกลบ ดังนั้นคอนเทนเนอร์ฐานข้อมูลจึงต้องเพิ่ม volume เพื่อเก็บเนื้อหาของฐานข้อมูลไว้
- N+1=2 หรือมากกว่า
- หากต้องการสำรองฐานข้อมูล ก็จำเป็นต้องมี offsite backup และถ้าแต่ละบริการ bundle database server process แยกของตัวเองมาด้วย ก็จะเป็นการสิ้นเปลืองทรัพยากรคอมพิวต์
ทางแก้
- ย้ายไปยังชั้น abstraction ที่สูงขึ้น และเพิ่ม semantics ที่แยกประเภทคอนเทนเนอร์ เช่น ฐานข้อมูล, reverse web proxy, cache และ static web asset
- ตัวอย่างของ semantics
- แนะนำรูปแบบคอนฟิกใหม่สำหรับระบุชื่อแอปพลิเคชัน, การ build, HTTPS reverse proxy และบริการ cache
- ทางแก้ #1
- ให้แต่ละโปรแกรมร้องขอ reverse proxy เพื่อหลีกเลี่ยงความซ้ำซ้อนและความสิ้นเปลือง โดย reverse proxy จะให้ชื่อ DNS และส่งต่อทุก path ไปยังโปรแกรม
- ทางแก้ #1.5
- เพิ่มส่วนของฐานข้อมูลเพื่อให้สามารถร้องขอฐานข้อมูลที่เป็นไปตามมาตรฐาน SQL และให้โปรแกรมคาดหวังสิทธิ์แบบ "full"
- ทางแก้สำหรับพอร์ต
- แต่ละโปรแกรมจะได้รับ IPv6 address ของตัวเอง จึงสามารถใช้หมายเลขพอร์ตมาตรฐานได้ และเพื่อความปลอดภัย ให้ใช้ firewall เพื่อให้มีเพียง reverse proxy เท่านั้นที่เข้าถึงพอร์ตได้
Tealok - container runtime แบบใหม่
- Tealok เป็น container runtime ใหม่ที่ให้ abstraction ระดับสูงขึ้นและอินเทอร์เฟซที่เป็นมาตรฐาน
- จัดการ ใบรับรอง TLS, การตั้งค่า reverse proxy, ระเบียน DNS, การจัดการ backup และอื่น ๆ ให้อัตโนมัติ
- ใช้ IPv6 เพื่อให้แต่ละคอนเทนเนอร์มี IP address ของตัวเอง และสามารถใช้หมายเลขพอร์ตมาตรฐานได้
- นักพัฒนาแอปสามารถดีพลอยแอปผ่านอินเทอร์เฟซมาตรฐานได้โดยไม่ต้องตั้งค่าที่ซับซ้อน
- สำหรับ ผู้ดูแลระบบ จะได้รับแนวปฏิบัติที่ดีอย่างสม่ำเสมอ ลดการสิ้นเปลืองทรัพยากร และลดภาระในการดูแลจัดการ
- สำหรับ นักพัฒนา จะช่วยให้วิธีการดีพลอยง่ายขึ้นและลดภาระในการตัดสินใจ
- ผู้ใช้จะได้รับการรับประกันเรื่อง ความเป็นเจ้าของข้อมูล และ ความเป็นอิสระจากคลาวด์คอมพิวติ้ง
6 ความคิดเห็น
พอเข้าไปดู tealok แล้ว มันยังไม่อยู่ในสภาพที่จะเป็นทางเลือกทดแทนได้เลยนะ?
น่าเสียดาย ถ้าลบ runtime ออกไปด้วยได้ก็คงจะดีมาก
ฉันยังคิดว่า การใช้ docker-compose เพื่อสร้างสภาพแวดล้อมการใช้งานจริงและเข้าไปทดสอบนั้นยังคงจำเป็นอยู่...
แต่การบอกว่า จากประสบการณ์ในสภาพแวดล้อมเฉพาะของตัวเอง เลยสรุปว่าสิ่งนั้นผิดแล้วสร้างของใหม่ขึ้นมา... แบบนี้เห็นด้วยได้ยากนะครับ.. 5555
เป็นเนื้อหาที่ถ้าไม่ระวังก็อาจทำให้เข้าใจผิดได้ครับ 555555...
เพราะตอนเห็นแค่ชื่อก็คิดว่า 'เอ๊ะ ไม่ค่อยชอบที่เอาไปใช้ในสภาพแวดล้อมพัฒนาจริง ๆ เลยนะ....' น่ะครับ.. 555
ผมคิดว่าการพยายามใช้ docker compose เพื่อวัตถุประสงค์แบบเดียวกับในบทความตั้งแต่แรกนั้นเป็นแนวทางที่ผิด
ผมเห็นด้วยกับบางส่วน แต่ไม่คิดว่าแนวทางนั้นจะผิดไปเสียทีเดียว
มันน่าจะเป็นทางเลือกที่ดีที่สุดในสภาพแวดล้อมที่พวกเขาทำได้ :)
ความคิดเห็นจาก Hacker News
มีวิธีแก้ปัญหาเรื่องการแมปพอร์ตและการสำรองข้อมูลโวลุมแบบง่าย ๆ อยู่
docker-composeแยกสำหรับสภาพแวดล้อมการพัฒนา เพื่อกำหนดค่าที่ต่างกันตามแต่ละสภาพแวดล้อมได้ในฐานะคนที่ใช้ Docker ทำ self-hosting บนเซิร์ฟเวอร์ส่วนตัว มองว่าความยืดหยุ่นของการตั้งค่า Docker เป็นข้อดี
macvlanเพื่อกำหนด IP และ MAC address เฉพาะให้แต่ละคอนเทนเนอร์docker-composeมักใช้เป็นหลักในงานพัฒนาหรือการใช้งานส่วนตัว และ V2 เป็นปลั๊กอินที่รวมเข้ากับ Docker ต่างจาก V1ในสภาพแวดล้อม production ควรใช้ Kubernetes ส่วน
docker-composeเหมาะกับการพัฒนาแบบโลคัลdocker-composeเป็นผลิตภัณฑ์สำหรับ self-hosting ขนาดเล็ก โดยมุ่งเป้าไปที่คนที่ไม่มีพื้นฐานด้านเทคนิคการเขียนโปรแกรมเพื่อควบคุม Docker นั้นง่ายกว่าที่คิด และสามารถใช้สคริปต์ Python เพื่อแก้ปัญหาได้
กำลังพัฒนา
canine.shเพื่อให้ใช้งาน Kubernetes cluster ได้ง่ายเหมือน Herokuน่าสนใจที่ Tealok กำลังพัฒนาทางเลือกแทน
docker-composeมองว่า
docker-compose, Kubernetes และ Helm เป็นชั้นนามธรรมที่ผิดที่ผิดทางรู้สึกสับสนกับคำกล่าวที่ว่า
docker-composeเป็นชั้นนามธรรมที่ผิดที่ผิดทาง