บอกลาการจำพอร์ต Docker ด้วย Tailscale Services
Homelab ของผมรันบนเครื่อง 5 เครื่องพร้อมกับ Docker container อีกประมาณ 30 ตัว เป็นเวลานานมากที่ผมต้องเข้าถึงพวกมันผ่านโฟลเดอร์บุ๊กมาร์กที่เต็มไปด้วย URL อย่าง http://100.101.12.4:8096 ซึ่งไม่สะดวกเอาเสียเลย
แม้ Tailscale จะช่วยให้ผมเข้าสู่เครือข่ายจากที่ไหนก็ได้ แต่ปัญหาเดิมก็ยังอยู่คือผมต้องคอยจำว่าแอปไหนรันอยู่บนพอร์ตอะไรของเครื่องไหน
วิธีแก้ปัญหาทั่วไปต่างก็มีข้อจำกัด การใช้ reverse proxy พร้อมโดเมนส่วนตัวนั้นทำได้จริง แต่ก็กลายเป็นภาระในการบำรุงรักษาเพิ่มขึ้น ทุกครั้งที่มีแอปใหม่ต้องแก้ไฟล์คอนฟิกซ้ำซ้อน ส่วนการใช้ Tailscale sidecar ให้แต่ละ container ก็ทำให้รายชื่อในหน้า Machines ยาวเหยียดจนจัดการยาก
เมื่อ Tailscale เปิดตัว Services มันคือคำตอบที่ผมต้องการ นั่นคือการตั้งชื่อให้ "แอป" แทนที่จะเป็น "เครื่อง" ผมจึงเปลี่ยนมาใช้รูปแบบนี้ตั้งแต่นั้นมา และนี่คือสรุปวิธีการตั้งค่ารวมถึงสิ่งที่ควรรู้ก่อนเริ่มต้นครับ
Tailscale Service คืออะไรกันแน่
Service คือการกำหนดชื่อพร้อม Virtual IP บน tailnet ของคุณ เช่น jellyfin.your-tailnet.ts.net โดยไม่ได้ผูกติดกับอุปกรณ์ใดเครื่องหนึ่ง แต่จะใช้วิธีให้เครื่องในเครือข่ายทำหน้าที่โฆษณา (advertise) บริการนั้นออกมา เพื่อให้ Tailscale ส่งเส้นทาง (route) จากไคลเอนต์ไปยังเครื่องปลายทางได้อย่างถูกต้อง
ด้วยวิธีนี้ Docker host ของคุณจะยังคงเป็นเครื่องเดียวใน tailnet แต่แอปต่างๆ จะปรากฏเป็น Services แยกต่างหาก ข้อดีคือคุณสามารถกำหนดกฎการเข้าถึง (Access rules) ไปที่ Service ได้โดยตรง เช่น อนุญาตให้บางคนเข้าถึง Jellyfin ได้โดยไม่ต้องให้สิทธิ์เข้าถึงโฮสต์ทั้งเครื่อง
นี่คือแผนผังการทำงานเมื่อตั้งค่าเสร็จสิ้น:

รายละเอียดสำคัญในภาพคือ tailscaled บนโฮสต์จะทำหน้าที่จบการเชื่อมต่อ HTTPS และสื่อสารด้วย plain HTTP ไปยังแอปของคุณ พร้อมส่งส่วนหัว X-Forwarded-For ไปด้วย ซึ่งทำให้ Tailscale ทำหน้าที่เสมือนเป็น reverse proxy ในตัวนั่นเอง
ขั้นตอนการตั้งค่าด้วยตัวเอง
ก่อนจะเริ่มทำระบบอัตโนมัติ ผมแนะนำให้ลองตั้งค่าด้วยตัวเองกับแอปเดียวก่อน โดยมีสิ่งที่ต้องเตรียม 3 ส่วน ดังนี้
1. โฮสต์ที่ติดแท็ก (tagged host): Services จะถูกโฆษณาผ่านเครื่องที่ติดแท็กไว้เท่านั้น ให้คุณกำหนดแท็กให้กับ Docker host ดังนี้:
sudo tailscale up --advertise-tags=tag:server --reset2. นโยบายการเข้าถึง: ในหน้า admin console ส่วน Access controls ต้องมีแท็กเหล่านั้นอยู่ และการตั้งค่า auto-approver จะช่วยลดขั้นตอนการกดอนุมัติด้วยมือในภายหลัง:
{
"tagOwners": {
"tag:server": ["autogroup:admin"],
"tag:container": ["tag:server"]
},
"autoApprovers": {
"services": {
"tag:container": ["tag:server"]
}
}
}3. การสร้าง Service: ในหน้า Services ของ admin console ให้เลือก Advertise และ Define a Service ตั้งชื่อว่า jellyfin พร้อมกำหนดแท็ก tag:container จากนั้นสั่งให้โฮสต์ชี้ไปยังแอปเป้าหมาย:
tailscale serve --service=svc:jellyfin --https=443 127.0.0.1:8096หากคุณเปิดใช้งาน HTTPS ในหน้า DNS ของ admin console ไว้ ตอนนี้คุณจะสามารถเข้าถึง https://jellyfin.your-tailnet.ts.net ได้ทันทีจากทุกอุปกรณ์ที่เชื่อมต่อ Tailscale
ทำไมผมถึงจบลงด้วยการเขียนสคริปต์
ปัญหาคือหากคุณมี 30 แอป ขั้นตอนข้างต้นจะน่าเบื่อมาก เพราะต้องตั้งค่าทั้งในคอนโซลและรันคำสั่ง serve แยกทุกแอป แถมเมื่อมีการย้ายหรือลบ container ข้อมูลก็ไม่อัปเดตตามอัตโนมัติ
ผมจึงเขียนโปรแกรมด้วยภาษา Go ชื่อว่า DockTail เพื่อมาแก้ปัญหานี้ โดยมันจะคอยเฝ้าดู Docker events และเปลี่ยน Docker labels ให้กลายเป็นค่าคอนฟิกโดยอัตโนมัติ ดังตัวอย่างใน Compose file นี้:
services:
docktail:
image: ghcr.io/marvinvr/docktail:latest
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/run/tailscale:/var/run/tailscale
environment:
- TAILSCALE_OAUTH_CLIENT_ID=${TAILSCALE_OAUTH_CLIENT_ID}
- TAILSCALE_OAUTH_CLIENT_SECRET=${TAILSCALE_OAUTH_CLIENT_SECRET}
jellyfin:
image: jellyfin/jellyfin:latest
restart: unless-stopped
labels:
- "docktail.service.enable=true"
- "docktail.service.name=jellyfin"
- "docktail.service.port=8096"
- "docktail.service.service-port=443"การใช้เครื่องมือช่วยเฝ้าดู Docker สำคัญมาก เพราะเมื่อ container ถูกสร้างใหม่ IP ภายในเครือข่าย Docker มักจะเปลี่ยนไป หากเราตั้งค่า serve แบบคงที่ (static) ระบบจะใช้งานไม่ได้เมื่อ IP เปลี่ยนไปจากเดิมครับ

สองสิ่งที่ควรรู้ก่อนใช้งาน
หาก Service ไม่ปรากฏ: มักเกิดจากปัญหาเรื่องแท็ก ต้องตรวจสอบว่าโฮสต์ติดแท็กถูกต้องหรือไม่ผ่านคำสั่ง tailscale status และเช็คว่าคุณได้กดยืนยัน Service ในหน้าจัดการแล้วหรือยัง
การตรวจสอบ proxy headers: บางแอปเช่น Home Assistant จะปฏิเสธคำขอ (400 Bad Request) เพราะเห็น header X-Forwarded-For จาก Tailscale คุณต้องตั้งค่าให้แอปเชื่อถือ proxy ในไฟล์ configuration.yaml ก่อนจึงจะใช้งานได้
สรุป: คุ้มค่าที่จะเปลี่ยนไหม?
สำหรับผมถือว่าคุ้มค่ามาก เพราะคอนฟิกเครือข่ายย้ายมาอยู่รวมกับ Compose file ของแอปโดยตรง การจัดการแอปจึงทำได้เบ็ดเสร็จในที่เดียว และหน้า Machines ก็ดูสะอาดตาขึ้นมาก
อย่างไรก็ตาม ผมยังคงใช้ reverse proxy สำหรับบริการสาธารณะที่ต้องการโดเมนของตัวเองอยู่ ส่วน Tailscale Services เหมาะที่สุดสำหรับการใช้งานภายในที่ต้องการความสะดวกและปลอดภัยครับ
หากใครสนใจลองใช้วิธีแบบ label สามารถดูรายละเอียดได้ที่ github.com/marvinvr/docktail หรือแวะไปอ่านคู่มือได้ที่ docktail.org/docs ครับ
ความคิดเห็น (0)
เข้าสู่ระบบเพื่อร่วมแสดงความเห็น
สมัครสมาชิกมาเป็นคนแรกที่แสดงความเห็นกันเลยโบร
