คอนเทนเนอร์เข้าถึง API ที่ใช้ได้เฉพาะผ่าน VPN ไม่ได้? ทำพร็อกซี่บนโฮสต์
อุโมงค์อยู่บนโฮสต์ คอนเทนเนอร์จึงไม่มีเส้นทางไปยังที่อยู่ส่วนตัว เผยแพร่รีเวิร์สพร็อกซี่แบบแคบแล้วเรียกใช้เป็น host.docker.internal
บริการ Compose ของคุณหมดเวลากับ API ที่เบราว์เซอร์บนเครื่องเดียวกันเปิดได้โดยไม่มีปัญหาอะไร ความต่างนั้นคือเบาะแส คำขอที่ทำงานได้ออกจากโฮสต์ที่มีอุโมงค์ VPN ส่วนคำขอที่ค้างออกจากคอนเทนเนอร์ที่มีสแต็กเครือข่ายของตัวเอง ไม่มีอะไรในคอนเทนเนอร์รู้เส้นทางของอุโมงค์ จุดหมายส่วนตัวจึงยังเข้าไม่ถึงไม่ว่าจะเขียนชื่ออย่างไร ทางแก้คือการกระโดดผ่านโฮสต์อย่างตั้งใจ ไม่ใช่ตารางเส้นทางที่ฉลาดกว่า
เริ่มจากทำไมสองเส้นทางจึงต่างกัน แล้วจึงตัดสินใจว่าอุโมงค์ควรอยู่ที่ไหน
ทำไมโฮสต์จึงได้ผลแต่คอนเทนเนอร์ไม่ได้
การยกอุโมงค์ขึ้นทำให้โฮสต์มีอินเทอร์เฟซ ชุดเส้นทาง และโดยปกติมีรายการตัวแก้ไขชื่อที่ VPN จัดให้ คอนเทนเนอร์ไม่ได้รับสิ่งใดเลย มันเริ่มด้วยอินเทอร์เฟซเดียวบนบริดจ์ของเอนจินและเส้นทางเริ่มต้นที่ชี้ไปยังบริดจ์นั้น เส้นทางที่ติดตั้งบนโฮสต์นั้นมองไม่เห็นสำหรับทุกสิ่งที่รันอยู่ในเนมสเปซนั้น
นี่คือเหตุผลที่อาการดูไม่สอดคล้องกันมากกว่าแค่เสีย โฮสต์แก้ชื่อส่วนตัวและเชื่อมต่อได้ เพราะทั้งชื่อและเส้นทางมีอยู่ที่นั่น คอนเทนเนอร์ส่งแพ็กเก็ตไปยังที่อยู่ส่วนตัวที่ไม่มีสิ่งใดบนเส้นทางบริดจ์เข้าถึงได้ และคำขอก็หมดเวลา การเพิ่มชื่อลงในไฟล์ hosts ของคอนเทนเนอร์ไม่เปลี่ยนอะไร เพราะที่อยู่เองนั้นเข้าไม่ถึงจากที่ที่คอนเทนเนอร์ตั้งอยู่
เข้าถึงโฮสต์จากภายในคอนเทนเนอร์
โปรเซสในคอนเทนเนอร์ที่ต่อ localhost กำลังต่อคอนเทนเนอร์เอง Docker Desktop เผยแพร่ host.docker.internal เป็นชื่อที่ชี้กลับไปยังเครื่องที่รันเอนจิน เอนจินของ Linux ปล่อยให้ไม่มีการนิยามไว้จนกว่าบริการจะขอ และนั่นคือสิ่งที่การแมปด้านล่างทำ ด้วยเหตุนี้แอปพลิเคชันจึงเล็งชื่อและพอร์ตแทนที่อยู่ส่วนตัว
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
INTERNAL_API_HOST: "host.docker.internal:8666"อุโมงค์ยังอยู่ฝั่งโฮสต์ของการกระโดด และพอร์ตในตัวแปรนั้นคือพอร์ตที่พร็อกซี่จะรับฟัง คอนเทนเนอร์ที่สูญเสียอุโมงค์ตอนนี้ล้มเหลวที่การกระโดดที่รู้จักเพียงครั้งเดียว แทนที่จะลองเส้นทางที่มันไม่มีอยู่จริง
เลือกว่าอุโมงค์อยู่ที่ไหน
บริการ Compose ที่ต้องการ API ส่วนตัวมีสามรูปแบบ และต่างกันที่โปรเซสใดเป็นเจ้าของอุโมงค์ ไคลเอนต์ VPN สามารถรันภายในอิมเมจของคอนเทนเนอร์ ซึ่งต้องเปิดเผยอุปกรณ์อุโมงค์และให้ความสามารถในการดูแลเครือข่ายที่มาด้วยกัน แอปพลิเคชันสามารถใช้เนมสเปซเครือข่ายร่วมกับคอนเทนเนอร์อุโมงค์แยกต่างหาก เพื่อให้ทั้งสองโปรเซสเห็นสแต็กเดียวและตารางเส้นทางเดียว หรืออุโมงค์อาจอยู่บนโฮสต์ต่อไป โดยมีตัวส่งต่อแบบแคบจากโฮสต์เข้าไปในคอนเทนเนอร์
สองแบบแรกดึงไฟล์โปรไฟล์ พฤติกรรมการเชื่อมต่อใหม่ และนโยบายตัวแก้ไขชื่อเข้าไว้ในโปรเจกต์ และทำให้ทุกบริการในไฟล์ขึ้นอยู่กับสุขภาพของอุโมงค์ นั่นคือการผูกมัดมากเกินไปสำหรับการเรียก API เพียงครั้งเดียว สำหรับสแต็กพัฒนาที่อ่านปลายทางภายในเพียงจุดเดียว ตัวส่งต่อฝั่งโฮสต์คือการเปลี่ยนแปลงที่เล็กที่สุดซึ่งยังเก็บข้อมูลรับรองไว้ที่ที่ทีมแพลตฟอร์มดูแลอยู่
เผยแพร่เส้นทางแคบเพียงหนึ่งเส้นบนโฮสต์
เริ่มจากสิ่งที่ตัวส่งต่อสืบทอดมา รันมันด้วยบัญชีที่เป็นเจ้าของอุโมงค์ แล้วซ็อกเก็ตขาออกของมันจะรับเส้นทางของโฮสต์และตัวแก้ไขชื่อของโฮสต์ บล็อก location หนึ่งของ nginx ครอบคลุมหนึ่งเส้นทาง
server {
listen 8666;
location /search/ {
proxy_pass http://10.20.30.40:8090/;
proxy_set_header Host internal-api.example;
proxy_read_timeout 60s;
}
}มองที่อยู่และพอร์ตเป็นตัวแทนชั่วคราว แล้วใส่คู่ที่ API รับฟังจริง ทุก upstream ที่เพิ่มขึ้นได้บล็อก location ของตัวเอง และแต่ละบล็อกควรอนุญาตเฉพาะเส้นทางที่บริการนี้เรียก เพื่อให้พร็อกซี่ไม่กลายเป็นประตูทั่วไปสู่เครือข่ายส่วนตัว ผูกตัวรับฟังกับที่อยู่บริดจ์สำหรับไคลเอนต์ที่มาผ่าน host-gateway ผูกกับ loopback เฉพาะเมื่อไคลเอนต์ใช้เนมสเปซเครือข่ายของโฮสต์ร่วมกัน และอย่าผูกกับ 0.0.0.0 เลย เลือกพอร์ตที่ยังว่างด้วย หมายเลขที่ถูกใช้ไปแล้วจะทำให้พร็อกซี่ไม่รับฟังในขณะที่คอนเทนเนอร์ยังหมดเวลาต่อไป ซึ่งแยกไม่ออกจากความผิดพลาดของเครือข่ายที่คุณเริ่มต้นไว้
พอร์ต ชื่อ และการตัดสินใจเรื่อง TLS
การแก้ชื่อแยกแบบเดียวกับการกำหนดเส้นทาง การค้นหาสาธารณะของคอนเทนเนอร์ผ่านตัวแก้ไขชื่อของเอนจิน ชื่อส่วนตัวที่แก้ได้บนโฮสต์จึงจะแก้ไม่ได้ภายในคอนเทนเนอร์ พร็อกซี่คือองค์ประกอบที่แก้ชื่อส่วนตัว เพราะมันสืบทอดตัวแก้ไขชื่อของโฮสต์
TLS คือการตัดสินใจที่ถูกเลื่อนออกไปแล้วอธิบายความล้มเหลวครั้งถัดไป หากพร็อกซี่ส่งไบต์ต่อโดยไม่แตะต้อง คอนเทนเนอร์จะเห็นใบรับรองของ API เองและต้องมี CA ภายในในที่เก็บความเชื่อถือของมัน หากพร็อกซี่สิ้นสุด TLS ความเชื่อถือนั้นจะย้ายไปที่โฮสต์และแอปพลิเคชันเริ่มสร้างลิงก์จากส่วนหัว host ที่ได้รับ เลือกการจัดวางอย่างเดียวและใช้กับการเรียกทรัพยากรทุกครั้ง เพราะการเปลี่ยนเส้นทางที่อีกแบบออกมาชี้ไปยังชื่อโฮสต์ที่คอนเทนเนอร์แก้ไม่ได้
ตรวจสอบจากภายในบริการ
ส่งคำขอจากคอนเทนเนอร์ ไม่ใช่จากโฮสต์ ใช้ curl ธรรมดากับเส้นทางพร็อกซี่ แล้วตามด้วยการตรวจสุขภาพของแอปพลิเคชันเอง เมื่อพร็อกซี่ตอบแต่แอปพลิเคชันยังล้มเหลว ให้เทียบสามอย่าง URL ฐานที่มันสร้าง ตัวแปรพร็อกซี่ใด ๆ ในสภาพแวดล้อมของมัน และ CA ที่มันเชื่อถือ ทั้งหมดอยู่ในสภาพแวดล้อมและบันทึกของคอนเทนเนอร์ และการแก้อย่างใดอย่างหนึ่งก็ปล่อย VPN ไว้ตามเดิม
เขียนการจัดวางที่เลือกไว้ลงใน README ของโปรเจกต์ขณะที่ยังสดอยู่ ไม่เช่นนั้นคนถัดไปที่เจอการหมดเวลานี้จะใช้บ่ายวันเดียวกันในการค้นพบอีกครั้งว่าอุโมงค์อยู่บนโฮสต์