Έχω λοιπόν ένα Nginx που τρέχει μέσα σε ένα δοχείο docker, έχω μια mysql που τρέχει στο localhost, θέλω να συνδεθώ στη MySql από το Nginx μου. Η MySql τρέχει στο localhost και δεν εκθέτει μια θύρα στον έξω κόσμο, οπότε δεσμεύεται στο localhost και όχι στη διεύθυνση ip του μηχανήματος.
Υπάρχει κάποιος τρόπος να συνδεθώ σε αυτή τη MySql ή σε οποιοδήποτε άλλο πρόγραμμα στο localhost από μέσα από αυτό το docker container;
Αυτή η ερώτηση διαφέρει από την ερώτηση "Πώς να λάβετε τη διεύθυνση IP του docker host από το εσωτερικό ενός docker container" λόγω του γεγονότος ότι η διεύθυνση IP του docker host θα μπορούσε να είναι η δημόσια IP ή η ιδιωτική IP στο δίκτυο, η οποία μπορεί να είναι προσβάσιμη ή όχι από το εσωτερικό του docker container (εννοώ τη δημόσια IP αν φιλοξενείται στο AWS ή κάτι τέτοιο). Ακόμα και αν έχετε τη διεύθυνση IP του docker host δεν σημαίνει ότι μπορείτε να συνδεθείτε στον docker host μέσα από το δοχείο με δεδομένη αυτή τη διεύθυνση IP, καθώς το δίκτυο του docker μπορεί να είναι overlay, host, bridge, macvlan, none κ.λπ. που περιορίζει την προσβασιμότητα αυτής της διεύθυνσης IP.
Επεξεργασία: Αν χρησιμοποιείτε Docker-for-mac ή Docker-for-Windows 18.03+, απλά συνδεθείτε στην υπηρεσία mysql χρησιμοποιώντας τον host host.docker.internal
.
Από το Docker 18.09.3, αυτό δεν λειτουργεί στο Docker-for-Linux. Μια διόρθωση έχει υποβληθεί στις 8 Μαρτίου 2019 και ελπίζουμε ότι θα συγχωνευτεί στη βάση κώδικα. Μέχρι τότε, μια λύση είναι η χρήση ενός container όπως περιγράφεται στην qoomon's answer.
Χρησιμοποιήστε --network="host"
στην εντολή docker run
, τότε το 127.0.0.1
στο docker container σας θα δείχνει στον docker host σας.
Σημείωση: Αυτή η λειτουργία λειτουργεί μόνο στο Docker για Linux, σύμφωνα με την τεκμηρίωση.
Το Docker προσφέρει διαφορετικούς τρόπους δικτύωσης κατά την εκτέλεση εμπορευματοκιβωτίων. Ανάλογα με τη λειτουργία που επιλέγετε θα συνδεθείτε με τη βάση δεδομένων MySQL που εκτελείται στον ξενιστή docker με διαφορετικό τρόπο.
Το Docker δημιουργεί μια γέφυρα με το όνομα docker0
από προεπιλογή. Τόσο ο κεντρικός υπολογιστής docker όσο και τα δοχεία docker έχουν μια διεύθυνση IP σε αυτή τη γέφυρα.
στον ξενιστή Docker, πληκτρολογήστε sudo ip addr show docker0
θα έχετε μια έξοδο που θα μοιάζει με:
[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::5484:7aff:fefe:9799/64 scope link
valid_lft forever preferred_lft forever
Έτσι εδώ ο docker host μου έχει τη διεύθυνση IP 172.17.42.1
στη διεπαφή δικτύου docker0
.
Τώρα ξεκινήστε ένα νέο container και ανοίξτε ένα κέλυφος σε αυτό: docker run --rm -it ubuntu:trusty bash
και μέσα στο κοντέινερ πληκτρολογήστε ip addr show eth0
για να ανακαλύψετε πώς είναι ρυθμισμένη η κύρια διεπαφή δικτύου του:
root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ff
inet 172.17.1.192/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::6432:13ff:fef0:f1e3/64 scope link
valid_lft forever preferred_lft forever
Εδώ το εμπορευματοκιβώτιό μου έχει τη διεύθυνση IP 172.17.1.192
. Τώρα κοιτάξτε τον πίνακα δρομολόγησης:
root@e77f6a1b3740:/# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 172.17.42.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 * 255.255.0.0 U 0 0 0 eth0
Έτσι, η διεύθυνση IP του docker host 172.17.42.1
έχει οριστεί ως προεπιλεγμένη διαδρομή και είναι προσβάσιμη από το container σας.
root@e77f6a1b3740:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms
Εναλλακτικά, μπορείτε να εκτελέσετε ένα δοχείο docker με ρυθμίσεις δικτύου που έχουν οριστεί σε host
. Ένα τέτοιο container θα μοιράζεται τη στοίβα δικτύου με τον docker host και από τη σκοπιά του container, το localhost
(ή 127.0.0.0.1
) θα αναφέρεται στον docker host.
Έχετε υπόψη σας ότι οποιαδήποτε θύρα ανοίγει στο δοχείο docker θα ανοίξει και στον host docker. Και αυτό χωρίς να απαιτείται η επιλογή -p
ή -P
docker run
.
Ρύθμιση IP στον υπολογιστή μου docker host:
[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
valid_lft forever preferred_lft forever
και από ένα δοχείο docker σε λειτουργία host:
[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
valid_lft forever preferred_lft forever
Όπως μπορείτε να δείτε, τόσο ο docker host όσο και το docker container μοιράζονται ακριβώς την ίδια διεπαφή δικτύου και ως εκ τούτου έχουν την ίδια διεύθυνση IP.
Για να αποκτήσετε πρόσβαση στη MySQL που εκτελείται στον ξενιστή docker από τα κοντέινερ σε λειτουργία γέφυρας, πρέπει να βεβαιωθείτε ότι η υπηρεσία MySQL ακούει για συνδέσεις στη διεύθυνση IP 172.17.42.1
.
Για να το κάνετε αυτό, βεβαιωθείτε ότι έχετε είτε bind-address = 172.17.42.1
είτε bind-address = 0.0.0.0.0
στο αρχείο ρυθμίσεων της MySQL (my.cnf).
Αν πρέπει να ορίσετε μια μεταβλητή περιβάλλοντος με τη διεύθυνση IP της πύλης, μπορείτε να εκτελέσετε τον ακόλουθο κώδικα σε ένα container :
export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')
στη συνέχεια, στην εφαρμογή σας, χρησιμοποιήστε τη μεταβλητή περιβάλλοντος DOCKER_HOST_IP
για να ανοίξετε τη σύνδεση με τη MySQL.
Σημείωση: αν χρησιμοποιήσετε την bind-address = 0.0.0.0.0
ο διακομιστής MySQL θα ακούει για συνδέσεις σε όλες τις διεπαφές δικτύου. Αυτό σημαίνει ότι ο MySQL διακομιστής σας μπορεί να είναι προσβάσιμος από το Διαδίκτυο, βεβαιωθείτε ότι έχετε ρυθμίσει ανάλογα τους κανόνες τείχους προστασίας.
Σημείωση 2: αν χρησιμοποιήσετε bind-address = 172.17.42.1
ο MySQL server σας δεν θα ακούει συνδέσεις που γίνονται στο 127.0.0.1
. Οι διεργασίες που εκτελούνται στον υποδοχέα docker και θέλουν να συνδεθούν με τη MySQL θα πρέπει να χρησιμοποιήσουν τη διεύθυνση IP 172.17.42.1
.
Για να αποκτήσετε πρόσβαση στη MySQL που εκτελείται στον docker host από containers σε host mode, μπορείτε να διατηρήσετε την bind-address = 127.0.0.0.1
στις ρυθμίσεις της MySQL και το μόνο που χρειάζεται να κάνετε είναι να συνδεθείτε στην 127.0.0.0.1
από τα containers σας:
[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
σημείωση: Χρησιμοποιήστε mysql -h 127.0.0.1
και όχι mysql -h localhost
- διαφορετικά ο πελάτης της MySQL θα προσπαθήσει να συνδεθεί χρησιμοποιώντας μια unix socket.
Αυτό λειτούργησε για μένα σε μια στοίβα NGINX/PHP-FPM χωρίς να αγγίξει οποιοδήποτε κώδικα ή δικτύωση όπου η εφαρμογή's απλά περιμένει να είναι σε θέση να συνδεθεί στο localhost
Τοποθετήστε το mysqld.sock
από τον κεντρικό υπολογιστή στο εσωτερικό του δοχείου.
Βρείτε τη θέση του αρχείου mysql.sock στον κεντρικό υπολογιστή που εκτελεί τη mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'
Προσαρτήστε αυτό το αρχείο στο σημείο όπου αναμένεται στο docker:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock
Πιθανές τοποθεσίες του mysqld.sock:
/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP
Διαφωνώ με την απάντηση του Thomasleveil.
Κάνοντας την mysql να δεσμευτεί στο 172.17.42.1 θα εμποδίσει άλλα προγράμματα που χρησιμοποιούν τη βάση δεδομένων στον κεντρικό υπολογιστή να την προσεγγίσουν. Αυτό θα λειτουργήσει μόνο αν όλοι οι χρήστες της βάσης δεδομένων σας είναι dockerized.
Κάνοντας το mysql bind στο 0.0.0.0.0 θα ανοίξει τη db στον έξω κόσμο, κάτι που όχι μόνο είναι πολύ κακό, αλλά και αντίθετο με αυτό που θέλει να κάνει ο συντάκτης της αρχικής ερώτησης. Λέει ρητά "Η MySql τρέχει στο localhost και δεν εκθέτει μια θύρα στον έξω κόσμο, οπότε δεσμεύεται στο localhost",
Για να απαντήσω στο σχόλιο του ivant
"Γιατί να μην δεσμεύσετε τη mysql και στο docker0; ",
Αυτό δεν είναι δυνατόν. Η τεκμηρίωση mysql/mariadb αναφέρει ρητά ότι δεν είναι δυνατή η σύνδεση σε διάφορες διεπαφές. Μπορείτε να συνδεθείτε μόνο σε 0, 1 ή σε όλες τις διασυνδέσεις.
Ως συμπέρασμα, ΔΕΝ έχω βρει κανέναν τρόπο να προσεγγίσω τη βάση δεδομένων (μόνο localhost) στον κεντρικό υπολογιστή από ένα δοχείο docker. Αυτό σίγουρα φαίνεται σαν ένα πολύ πολύ συνηθισμένο μοτίβο, αλλά δεν ξέρω πώς να το κάνω.