Το container δεν φτάνει το API μόνο μέσω VPN; Κάντε proxy στον host
Το tunnel ζει στον host, άρα το container δεν έχει διαδρομή προς την ιδιωτική διεύθυνση. Δημοσιεύστε ένα στενό reverse proxy και καλέστε το ως host.docker.internal.
Η υπηρεσία σας στο Compose λήγει σε timeout απέναντι σε ένα API που το πρόγραμμα περιήγησης στο ίδιο μηχάνημα ανοίγει χωρίς παράπονο. Αυτή η διαφορά είναι το στοιχείο: το αίτημα που λειτουργεί φεύγει από host με tunnel VPN, και το αίτημα που κολλάει φεύγει από container με δική του στοίβα δικτύου. Τίποτα μέσα στο container δεν γνωρίζει τις διαδρομές του tunnel, οπότε ο ιδιωτικός προορισμός μένει απρόσιτος ό,τι όνομα κι αν γραφτεί. Η διόρθωση είναι ένα σκόπιμο άλμα μέσω του host, όχι ένας εξυπνότερος πίνακας δρομολόγησης.
Ξεκινήστε από το γιατί διαφέρουν οι δύο διαδρομές και μετά αποφασίστε πού πρέπει να ζει το tunnel.
Γιατί ο host λειτουργεί και το container όχι
Η ενεργοποίηση του tunnel δίνει στον host μια διεπαφή, ένα σύνολο διαδρομών και συνήθως μια εγγραφή resolver που παρέχει το VPN. Το container δεν κληρονομεί τίποτα από αυτά: ξεκινά με μία διεπαφή στη γέφυρα της μηχανής και μια προεπιλεγμένη διαδρομή που δείχνει σε αυτή τη γέφυρα. Οι διαδρομές που εγκαθίστανται στον host είναι αόρατες σε ό,τι τρέχει μέσα σε αυτόν τον χώρο ονομάτων.
Γι’ αυτό τα συμπτώματα φαίνονται ασυνεπή και όχι απλώς χαλασμένα. Ο host επιλύει το ιδιωτικό όνομα και συνδέεται, επειδή εκεί υπάρχουν και το όνομα και η διαδρομή. Το container στέλνει το πακέτο του σε μια ιδιωτική διεύθυνση που τίποτα στη διαδρομή της γέφυρας δεν μπορεί να φτάσει, και το αίτημα λήγει σε timeout. Η προσθήκη του ονόματος στο αρχείο hosts του container δεν αλλάζει τίποτα, επειδή η ίδια η διεύθυνση είναι απρόσιτη από εκεί που βρίσκεται το container.
Φτάστε τον host από μέσα στο container
Μια διεργασία μέσα στο container που καλεί το localhost καλεί το container. Το Docker Desktop δημοσιεύει το host.docker.internal ως όνομα που δείχνει πίσω στο μηχάνημα που εκτελεί τη μηχανή· οι μηχανές Linux το αφήνουν απροσδιόριστο εκτός αν το ζητήσει η υπηρεσία, και αυτό ακριβώς κάνει η αντιστοίχιση παρακάτω. Με αυτό, η εφαρμογή στοχεύει ένα όνομα και μια θύρα αντί για την ιδιωτική διεύθυνση.
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
INTERNAL_API_HOST: "host.docker.internal:8666"Το tunnel μένει στην πλευρά του host αυτού του άλματος, και η θύρα σε αυτή τη μεταβλητή είναι εκείνη στην οποία θα ακούει το proxy. Ένα container που χάνει το tunnel τώρα αποτυγχάνει σε ένα γνωστό άλμα αντί να δοκιμάζει μια διαδρομή που ποτέ δεν είχε.
Διαλέξτε πού ζει το tunnel
Τρεις μορφές είναι δυνατές για μια υπηρεσία Compose που χρειάζεται ιδιωτικό API, και διαφέρουν ως προς το ποια διεργασία κατέχει το tunnel. Ένας πελάτης VPN μπορεί να τρέχει μέσα στην εικόνα του container, κάτι που απαιτεί έκθεση συσκευής tunnel και παραχώρηση της δυνατότητας διαχείρισης δικτύου που τη συνοδεύει. Η εφαρμογή μπορεί να μοιράζεται τον χώρο ονομάτων δικτύου ενός ξεχωριστού container tunnel, ώστε και οι δύο διεργασίες να βλέπουν μία στοίβα και έναν πίνακα δρομολόγησης. Ή το tunnel μπορεί να μείνει στον host, με έναν στενό προωθητή από τον host στο container.
Τα δύο πρώτα τραβούν αρχεία προφίλ, συμπεριφορά επανασύνδεσης και πολιτική resolver μέσα στο έργο, και κάνουν κάθε υπηρεσία του αρχείου εξαρτημένη από την υγεία του tunnel. Είναι πολλή σύζευξη για μία κλήση API. Για μια στοίβα ανάπτυξης που διαβάζει ένα μόνο εσωτερικό endpoint, ο προωθητής στην πλευρά του host είναι η μικρότερη αλλαγή που κρατά τα διαπιστευτήρια εκεί όπου τα διαχειρίζεται η ομάδα πλατφόρμας.
Δημοσιεύστε μία στενή διαδρομή στον host
Ξεκινήστε από αυτό που κληρονομεί ο προωθητής: εκτελέστε τον με τον λογαριασμό που κατέχει το tunnel και οι εξερχόμενες υποδοχές του παίρνουν τις διαδρομές του host και τον resolver του host. Ένα μπλοκ 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, και κάθε μπλοκ πρέπει να επιτρέπει μόνο τις διαδρομές που καλεί αυτή η υπηρεσία, ώστε το proxy να μην γίνει γενική πόρτα στο ιδιωτικό δίκτυο. Δέστε τον ακροατή στη διεύθυνση της γέφυρας για πελάτες που φτάνουν μέσω host-gateway, στο loopback μόνο όταν ο πελάτης μοιράζεται τον χώρο ονομάτων δικτύου του host, και ποτέ στο 0.0.0.0. Διαλέξτε επίσης θύρα που είναι ακόμα ελεύθερη: ένας αριθμός που έχει ήδη καταληφθεί αφήνει το proxy να μην ακούει ενώ το container συνεχίζει να λήγει σε timeout, κάτι που δεν ξεχωρίζει από τη βλάβη δικτύου με την οποία ξεκινήσατε.
Θύρες, ονόματα και η απόφαση για TLS
Η επίλυση ονομάτων χωρίζεται όπως και η δρομολόγηση. Οι δημόσιες αναζητήσεις του container περνούν από τον resolver της μηχανής, οπότε ένα ιδιωτικό όνομα που επιλύεται στον host δεν θα επιλυθεί μέσα στο container. Το proxy είναι το συστατικό που επιλύει το ιδιωτικό όνομα, επειδή κληρονομεί τον resolver του host.
Το TLS είναι η απόφαση που αναβάλλεται και μετά εξηγεί την επόμενη αποτυχία. Αν το proxy προωθεί τα byte ανέπαφα, το container βλέπει το δικό του πιστοποιητικό του API και χρειάζεται την εσωτερική CA στο κατάστημα εμπιστοσύνης του. Αν το proxy τερματίζει το TLS, αυτή η εμπιστοσύνη μεταφέρεται στον host και η εφαρμογή αρχίζει να χτίζει συνδέσμους από την κεφαλίδα host που λαμβάνει. Διαλέξτε μία διάταξη και εφαρμόστε την σε κάθε πόρο, γιατί μια ανακατεύθυνση από την άλλη δείχνει σε όνομα host που το container δεν μπορεί να επιλύσει.
Επαληθεύστε από μέσα στην υπηρεσία
Στείλτε το αίτημα από το container, όχι από τον host: ένα απλό curl στη διαδρομή του proxy, μετά ο έλεγχος υγείας της ίδιας της εφαρμογής. Όταν το proxy απαντά αλλά η εφαρμογή εξακολουθεί να αποτυγχάνει, συγκρίνετε τρία πράγματα: το βασικό URL που χτίζει, οποιαδήποτε μεταβλητή proxy στο περιβάλλον του και την CA που εμπιστεύεται. Όλα βρίσκονται στο περιβάλλον και τα αρχεία καταγραφής του container, και η διόρθωση οποιουδήποτε από αυτά αφήνει το VPN ήσυχο.
Γράψτε τη διάταξη που επιλέξατε στο README του έργου όσο είναι φρέσκια. Αλλιώς το επόμενο άτομο που θα συναντήσει αυτό το timeout θα περάσει το ίδιο απόγευμα ανακαλύπτοντας ξανά ότι το tunnel ζει στον host.