Dari dalam wadah Docker, bagaimana cara saya terhubung ke server lokal mesin?


1453

Jadi saya punya Nginx yang berjalan di dalam wadah buruh pelabuhan, saya punya mysql yang berjalan di localhost, saya ingin terhubung ke MySql dari dalam Nginx saya. MySql berjalan di localhost dan tidak mengekspos port ke dunia luar, jadi terikat pada localhost, tidak terikat pada alamat ip mesin.

Apakah ada cara untuk terhubung ke MySql ini atau program lain di localhost dari dalam wadah buruh pelabuhan ini?

Pertanyaan ini berbeda dari "Bagaimana cara mendapatkan alamat IP dari host buruh pelabuhan dari dalam wadah buruh pelabuhan" karena kenyataan bahwa alamat IP dari tuan rumah buruh pelabuhan dapat berupa IP publik atau IP pribadi dalam jaringan yang mungkin atau mungkin tidak dapat dijangkau dari dalam wadah buruh pelabuhan (maksud saya IP publik jika dihosting di AWS atau sesuatu). Bahkan jika Anda memiliki alamat IP dari host buruh pelabuhan itu tidak berarti Anda dapat terhubung ke host buruh pelabuhan dari dalam wadah mengingat bahwa alamat IP sebagai jaringan Docker Anda mungkin overlay, host, bridge, macvlan, tidak ada dll yang membatasi jangkauan alamat IP itu.


Mengapa tidak mengikat mysql ke docker0 juga?
ivant

2
Untuk Mesin Windows: - $ docker run -d --name MyWebServer -P httpd
Lokesh S


1
Tanpa network: hostAnda tidak dapat kembali dari wadah ke tuan rumah. Hanya menampung wadah. Ini adalah ideologi utama di balik wadah. Mereka terisolasi karena alasan stabilitas dan keamanan.
FreeSoftwareServers

Jawaban:


1971

Sunting: Jika Anda menggunakan Docker-for-mac atau Docker-for-Windows 18.03+, cukup sambungkan ke layanan mysql Anda menggunakan host host.docker.internal(bukan 127.0.0.1dalam string koneksi Anda).

Pada Docker 18.09.3, ini tidak berfungsi pada Docker-untuk-Linux. Sebuah memperbaiki telah disampaikan pada Maret 8, 2019 dan mudah-mudahan akan bergabung untuk basis kode. Sampai saat itu, solusinya adalah menggunakan wadah seperti yang dijelaskan dalam jawaban qoomon .

2020-01: beberapa kemajuan telah dibuat. Jika semuanya berjalan dengan baik, ini akan mendarat di Docker 20.04


TLDR

Gunakan --network="host"dalam docker runperintah Anda , maka 127.0.0.1dalam wadah buruh pelabuhan Anda akan menunjuk ke host buruh pelabuhan Anda.

Catatan: Mode ini hanya berfungsi di Docker untuk Linux, sesuai dokumentasinya .


Catatan tentang mode jaringan wadah buruh pelabuhan

Docker menawarkan berbagai mode jaringan saat menjalankan wadah. Tergantung pada mode yang Anda pilih, Anda akan terhubung ke database MySQL Anda yang berjalan pada host buruh pelabuhan secara berbeda.

docker run --network = "bridge" (default)

Docker membuat jembatan bernama docker0secara default. Baik host buruh pelabuhan dan wadah buruh pelabuhan memiliki alamat IP di jembatan itu.

pada host Docker, ketik sudo ip addr show docker0Anda akan memiliki output seperti:

[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

Jadi di sini host buruh pelabuhan saya memiliki alamat IP 172.17.42.1pada docker0antarmuka jaringan.

Sekarang mulai wadah baru dan dapatkan shell di atasnya: docker run --rm -it ubuntu:trusty bashdan dalam jenis wadah ip addr show eth0untuk menemukan bagaimana antarmuka jaringan utamanya diatur:

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

Di sini wadah saya memiliki alamat IP 172.17.1.192. Sekarang lihat tabel routing:

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

Jadi Alamat IP dari host buruh pelabuhan 172.17.42.1diatur sebagai rute default dan dapat diakses dari wadah Anda.

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 run --network = "host"

Atau Anda dapat menjalankan wadah buruh pelabuhan dengan pengaturan jaringan diatur kehost . Kontainer semacam itu akan berbagi tumpukan jaringan dengan host buruh pelabuhan dan dari sudut pandang wadah, localhost(atau 127.0.0.1) akan merujuk pada host buruh pelabuhan.

Ketahuilah bahwa port apa pun yang dibuka dalam wadah buruh pelabuhan Anda akan dibuka pada host buruh pelabuhan. Dan ini tanpa memerlukan opsi -patau-P docker run .

Konfigurasi IP pada host buruh pelabuhan saya:

[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

dan dari wadah buruh pelabuhan dalam mode 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

Seperti yang Anda lihat, kedua buruh pelabuhan dan wadah buruh pelabuhan berbagi antarmuka jaringan yang sama persis dan karenanya memiliki alamat IP yang sama.


Menghubungkan ke MySQL dari wadah

mode jembatan

Untuk mengakses MySQL yang berjalan pada host buruh pelabuhan dari wadah dalam mode bridge , Anda perlu memastikan layanan MySQL mendengarkan koneksi pada 172.17.42.1alamat IP.

Untuk melakukannya, pastikan Anda memiliki salah satu bind-address = 172.17.42.1atau bind-address = 0.0.0.0dalam file konfigurasi MySQL Anda (my.cnf).

Jika Anda perlu mengatur variabel lingkungan dengan alamat IP gateway, Anda dapat menjalankan kode berikut dalam sebuah wadah:

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')

kemudian di aplikasi Anda, gunakan DOCKER_HOST_IPvariabel lingkungan untuk membuka koneksi ke MySQL.

Catatan: jika Anda menggunakan bind-address = 0.0.0.0server MySQL Anda akan mendengarkan koneksi pada semua antarmuka jaringan. Itu berarti server MySQL Anda dapat dijangkau dari Internet; pastikan untuk mengatur aturan firewall yang sesuai.

Catatan 2: jika Anda menggunakan bind-address = 172.17.42.1server MySQL Anda tidak akan mendengarkan koneksi yang dibuat 127.0.0.1. Proses yang berjalan pada host buruh pelabuhan yang ingin terhubung ke MySQL harus menggunakan 172.17.42.1alamat IP.

mode tuan rumah

Untuk mengakses MySQL yang berjalan di host buruh pelabuhan dari wadah dalam mode host , Anda dapat tetap bind-address = 127.0.0.1menggunakan konfigurasi MySQL Anda dan yang perlu Anda lakukan hanyalah menyambung ke 127.0.0.1dari wadah Anda:

[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>

Catatan: Jangan gunakan mysql -h 127.0.0.1dan tidak mysql -h localhost; jika tidak, klien MySQL akan mencoba terhubung menggunakan soket unix.


8
Terima kasih atas jawaban yang mendetail! Dari apa yang saya kumpulkan, menggunakan mode host adalah satu-satunya cara untuk mendapatkan fungsi ini melalui localhost. Saya belum mencoba tetapi saya akan menganggap Anda dapat membuat jaringan terpisah untuk menghubungkan kontainer melalui jembatan mereka sendiri menawarkan mereka 'localhost' yang umum.
Ben

26
Catatan untuk pengguna OSX: masuk terlebih dahulu ke mesin virtual docker Anda (boot2docker), menggunakan "docker-machine ssh default", kemudian jalankan "sudo ip addr show docker0". Lanjutkan dengan instruksi Thomas dari sana.
Charlie Dalsass

30
Saya menjalankan Docker untuk Mac, dan tidak ada 172.17.42.1 lagi, tidak ada docker0 lagi. Itu 172.17.0.1 sebagai gateway, dan bahkan tidak bisatelnet 172.17.0.1 3306
zx1986

26
Anda dapat memasang soket mysql ke wadah alih-alih jaringan seperti -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockini.
chx

8
Dapatkah seseorang mengatasi situasi ketika Anda menjalankan Docker di Mac dan tidak menggunakan boot2docker karena tidak ada antarmuka docker0?
TheJKFever

350

Untuk macOS dan Windows

Docker v 18.03 dan lebih tinggi (sejak 21 Maret 2018)

Gunakan alamat IP internal Anda atau sambungkan ke nama DNS khusus host.docker.internalyang akan menyelesaikan ke alamat IP internal yang digunakan oleh tuan rumah.

Dukungan Linux tertunda https://github.com/docker/for-linux/issues/264

MacOS dengan versi Docker sebelumnya

Docker untuk Mac v 17.12 hingga v 18.02

Sama seperti di atas tetapi gunakan docker.for.mac.host.internalsebagai gantinya.

Docker untuk Mac v 17.06 hingga v 17.11

Sama seperti di atas tetapi gunakan docker.for.mac.localhostsebagai gantinya.

Docker untuk Mac 17.05 dan di bawah

Untuk mengakses mesin host dari wadah buruh pelabuhan Anda harus memasang alias IP ke antarmuka jaringan Anda. Anda dapat mengikat IP mana pun yang Anda inginkan, pastikan Anda tidak menggunakannya untuk hal lain.

sudo ifconfig lo0 alias 123.123.123.123/24

Kemudian pastikan server Anda mendengarkan IP yang disebutkan di atas atau 0.0.0.0. Jika mendengarkan di localhost, 127.0.0.1itu tidak akan menerima koneksi.

Kemudian arahkan saja buruh pelabuhan Anda ke IP ini dan Anda dapat mengakses mesin host!

Untuk menguji Anda dapat menjalankan sesuatu seperti curl -X GET 123.123.123.123:3000di dalam wadah.

Alias ​​akan mengatur ulang pada setiap reboot sehingga buat skrip start-up jika perlu.

Solusi dan dokumentasi lainnya di sini: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


5
brilian dan terima kasih, ini berhasil untuk saya dari dalam wadah. mysql -uroot -hdocker.for.mac.localhost
Richard Frank

1
docker.for.mac.localhost Persis seperti yang saya cari. Tapi ini kotor sekali sekaligus. DI buruh pelabuhan, orang akan mengharapkan bahwa kait docker.for.mac.localhost akan menjadi nama internal buruh pelabuhan generik yang akan berlaku untuk sistem operasi apa pun, bukan hanya untuk Mac. Tetapi untuk tujuan pengembangan ini cukup baik.
99Sono

Bagaimana cara mengakses port yang terbuka di katakan 9093 .. Saya mencoba telnet docker.for.mac.localhost 9093. Tidak dapat dijangkau tetapi jika saya melakukan ping docker.for.mac.localhost, ini dapat dijangkau. Apakah saya kehilangan sesuatu di sini?
Achilleus

1
Nama DNS docker.for.mac.host.internal harus digunakan alih-alih docker.for.mac.localhost (masih valid) untuk resolusi host dari kontainer, karena ada RFC yang melarang penggunaan subdomain localhost. Lihat tools.ietf.org/html/draft-west-let-localhost-be-localhost-06 .
Jya

Ini tidak berhasil untuk saya. Ketika saya docker run -e HOSTNAME= docker.for.mac.host.internal , wadah dibuat tetapi tidak terjadi panas. Saya kemudian harus crtl + C. Dengan --net=host -e HOSTNAME=localhostsetidaknya wadah berjalan dan mengeluh bahwa itu tidak dapat menemukan layanan yang saya butuhkan (MySQL db).
Jorge Orpinel

83

Saya melakukan hack mirip dengan posting di atas untuk mendapatkan IP lokal untuk memetakan ke nama alias (DNS) dalam wadah. Masalah utama adalah mendapatkan secara dinamis dengan skrip sederhana yang berfungsi baik di Linux dan OSX alamat IP host . Saya melakukan skrip ini yang berfungsi di kedua lingkungan (bahkan di distribusi Linux dengan "$LANG" != "en_*"konfigurasi):

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1

Jadi, menggunakan Docker Compose, konfigurasi lengkapnya adalah:

Skrip startup (docker-run.sh) :

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

docker-compose.yml :

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

Kemudian ubah http://localhostke http://dockerhostdalam kode Anda.

Untuk panduan lebih lanjut tentang cara mengkustomisasi DOCKERHOSTskrip, lihat posting ini dengan penjelasan tentang cara kerjanya.


1
Tergantung pada kasus penggunaan Anda, Anda bahkan mungkin hanya pergi dengan menggunakan DOCKERHOSTnilai di sini daripada "localhost" atau 0,0.0.0 dalam layanan apa pun yang harus disambungkan oleh wadah buruh pelabuhan Anda secara lokal.
enderland

2
Saya telah sedikit memodifikasi solusi Anda agar kompatibel dengan jaringan khusus: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') Di mana <NETWORK-NAME> dapat menjembatani atau nama jaringan seperti yang didefinisikan oleh komposisi buruh pelabuhan (biasanya path-name - network_name ).
dieresys

1
Anda perlu menambahkan komentar: gunakan dockerhostsebagai host untuk koneksi db (biasanya ganti untuk localhostdalam file konfigurasi).
Justin

solusi aneh, tapi itu satu-satunya yang membuat xdebug bekerja di bawah buruh pelabuhan dengan php cli
Eddie

Acl berhenti bekerja setelah solusi ini di haproxy. Ada yang tahu kenapa?
HyukHyukBoi

41

Ini bekerja untuk saya di tumpukan NGINX / PHP-FPM tanpa menyentuh kode atau jaringan apa pun di mana aplikasi hanya berharap dapat terhubung ke localhost

Pasang mysqld.sockdari host ke dalam wadah.

Temukan lokasi file mysql.sock di host yang menjalankan mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Pasang file itu ke tempat yang diharapkan di buruh pelabuhan:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Kemungkinan lokasi 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

2
Ini adalah solusi yang jauh lebih bersih, tidak mengekspos Mysql ke luar (jika tidak menggunakan firewall).
user1226868

5
Soket tidak menskala sebaik TCP karena mereka memblokir lebih sering dan dapat menyebabkan perilaku aneh. Gunakan TCP bila memungkinkan.
Joel E Salas

3
@ JoelESalas Apakah Anda memiliki sumber untuk klaim itu?
Prajurit

Saya menemukan ini sebagai solusi termudah. Thumbs up user833482! Anda harus berkontribusi lebih sering ke StackOverflow.
Prajurit

2
@ JoelESalas, saya pikir Anda salah. Pustaka klien mysql bahkan menggunakan soket unix secara default saat menghubungkan ke localhost daripada benar-benar membuat koneksi ke localhost. Soket unix menghindari overhead TCP stack dan routing, dan harus berjalan lebih cepat.
M Conrad

25

Sampai host.docker.internalberfungsi untuk setiap platform, Anda dapat menggunakan wadah saya bertindak sebagai gateway NAT tanpa pengaturan manual:

https://github.com/qoomon/docker-host


5
Saya dapat mengkonfirmasi ini tidak berfungsi di Docker untuk Windows 19.03.2 dengan wadah Windows.
KMC

ada ide bagaimana cara memperbaikinya? (Saya bukan pengguna windows)
qoomon

Jika lingkungan Anda tidak memblokir penggunaan mysql port, Anda dapat merujuk ke server dengan nama komputer yang dihosting. Jadi di string koneksi Anda, gunakan nama komputer Anda sebagai nama server.
KMC

24

Solusi untuk Linux (kernel> = 3.6).

Ok, server localhost Anda memiliki antarmuka docker0 standar docker0 dengan alamat ip 172.17.0.1 . Wadah Anda dimulai dengan pengaturan jaringan default --net = "jembatan" .

  1. Aktifkan route_localnet untuk antarmuka docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Tambahkan aturan ini ke iptables:
    $ iptables -t nat -I PREROUTING -i docker0 -d 172.17.0.1 -p tcp --dport 3306 -j DNAT --to 127.0.0.1:3306
    $ iptables -t filter -I INPUT -i docker0 -d 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
  3. Buat pengguna mysql dengan akses dari '%' yang berarti - dari siapa saja, tidak termasuk localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. Ubah skrip Anda alamat mysql-server menjadi 172.17.0.1


Dari dokumentasi kernel :

route_localnet - BOOLEAN : Jangan menganggap alamat loopback sebagai sumber atau tujuan Mars saat melakukan routing. Ini memungkinkan penggunaan 127/8 untuk tujuan perutean lokal ( FALSE default ).


1
Apa tujuan dari perintah iptable kedua? Saya bisa mengerti yang pertama adalah menulis ulang semua tujuan tcp yang cocok dengan 172.17.0.1:3306 hingga 127.0.0.1:3306 tetapi mengapa perintah iptable kedua diperlukan?
Patrick

17

Solusi untuk Windows 10

Edisi Komunitas Docker 17.06.0-ce-win18 2017-06-28 (stabil)

Anda dapat menggunakan nama DNS host docker.for.win.localhost, untuk menyelesaikan ke IP internal. (Peringatan beberapa sumber disebutkan windowstetapi harus win)

Gambaran Umum
Saya perlu melakukan sesuatu yang serupa, yaitu menyambung dari wadah Docker ke localhost saya, yang menjalankan Azure Storage Emulatordan CosmosDB Emulator.

Secara Azure Storage Emulatordefault mendengarkan pada 127.0.0.1 , sementara Anda dapat mengubah IP-nya terikat juga, saya sedang mencari solusi yang akan bekerja dengan pengaturan default.

Ini juga berfungsi untuk menghubungkan dari wadah Docker saya ke SQL Serverdan IIS, keduanya berjalan secara lokal di host saya dengan pengaturan port default.


13

Sangat sederhana dan cepat, periksa IP host Anda dengan ifconfig (linux) atau ipconfig (windows) lalu buat

docker-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"

Dengan cara ini, wadah Anda akan dapat mengakses host Anda. Saat mengakses DB Anda, ingatlah untuk menggunakan nama yang Anda tentukan sebelumnya, dalam hal ini "dockerhost" dan port host Anda di mana DB berjalan


Di HaProxy, solusi ini telah berhenti berfungsi dari acl untuk beberapa alasan, hanya pengaturan default yang berfungsi.
HyukHyukBoi

1
Satu-satunya solusi yang bekerja pada sistem linux. +1
Rafik Farhad

11

Tidak ada jawaban yang berfungsi untuk saya ketika menggunakan Docker Toolbox di Windows 10 Home, tetapi 10.0.2.2 melakukannya, karena menggunakan VirtualBox yang mengekspos host ke VM pada alamat ini.


2
Berhasil. Bahkan tidak perlu menentukan --network = host. sepertinya 10.0.2.2 diatur sebagai IP default untuk host. Terima kasih.
TheManish

Tapi, bisakah saya menggunakan IP statis ini untuk semua versi Windows dan Mac ?, bagaimana saya bisa mengatasinya untuk beberapa platform melalui skrip?
151291

Ini berhasil untuk saya. Jalankan ipconfig di host (windows) Anda dan dapatkan alamat IP di bawahEthernet adapter vEthernet (DockerNAT)
Kihats

10

Bagi mereka yang menggunakan Windows, dengan asumsi Anda menggunakan driver jaringan jembatan, Anda harus secara spesifik mengikat MySQL ke alamat ip dari antarmuka jaringan hyper-v.

Ini dilakukan melalui file konfigurasi di bawah folder C: \ ProgramData \ MySQL yang biasanya tersembunyi.

Mengikat ke 0.0.0.0 tidak akan berfungsi. Alamat yang diperlukan juga ditampilkan dalam konfigurasi buruh pelabuhan, dan dalam kasus saya adalah 10.0.75.1.


3
Anda layak mendapatkan medali! Saya telah mengerjakan ini selama dua hari penuh. Terima kasih telah membantu!
Michael

1
Saya juga mengerjakan ini selama dua hari penuh. Ini adalah satu-satunya tempat di web yang saya temukan disebutkan. Microsoft benar-benar diam mengenai hal ini ketika berbicara tentang menghubungkan ke MSSQL dari dalam wadah Docker. Itu membuat Anda bertanya-tanya apakah mereka pernah membuatnya bekerja sendiri!
Contango

8

Sunting: Saya akhirnya membuat prototip konsep di GitHub. Lihat: https://github.com/sivabudh/system-in-a-box


Pertama, jawaban saya diarahkan pada 2 kelompok orang: mereka yang menggunakan Mac, dan mereka yang menggunakan Linux.

The Host modus jaringan tidak bekerja pada Mac. Anda harus menggunakan alias IP, lihat: https://stackoverflow.com/a/43541681/2713729

Apa itu mode jaringan host? Lihat: https://docs.docker.com/engine/reference/run/#/network-settings

Kedua, bagi Anda yang menggunakan Linux (pengalaman langsung saya dengan Ubuntu 14,04 LTS dan saya segera memperbarui ke 16,04 LTS dalam produksi), ya , Anda dapat membuat layanan yang berjalan di dalam wadah Docker terhubung ke localhostlayanan yang berjalan di Host Docker (mis. Laptop Anda).

Bagaimana?

Kuncinya adalah ketika Anda menjalankan wadah Docker, Anda harus menjalankannya dengan mode host . Perintahnya terlihat seperti ini:

docker run --network="host" -id <Docker image ID>

Ketika Anda melakukan ifconfig(Anda perlu apt-get install net-toolswadah Anda ifconfigagar dapat dipanggil) di dalam wadah Anda, Anda akan melihat bahwa antarmuka jaringan sama dengan yang ada pada host Docker (mis. Laptop Anda).

Penting untuk dicatat bahwa saya adalah pengguna Mac, tetapi saya menjalankan Ubuntu di bawah Parallels, jadi menggunakan Mac bukanlah kerugian. ;-)

Dan ini adalah bagaimana Anda menghubungkan wadah NGINX ke MySQL yang berjalan pada a localhost.


1
Penting untuk dicatat bahwa mode host menawarkan kinerja yang lebih baik karena menggunakan tumpukan jaringan OS.
sivabudh

2
Poin yang sangat bagus di sana. Meskipun mungkin untuk terhubung dari wadah ke layanan host dengan IP terlampir, docs.docker.com/docker-for-mac/networking . Bukan solusi yang menyenangkan ... tetapi berhasil.
Xavier Huppé

Barang bagus di sini. Begitu berada di dalam wadah dengan --network="host", bagaimana seseorang terhubung ke host mysql misalnya?
Michael

1
@ Bunleuch Cukup gunakan localhost. Lihat kode sumber GitHub saya: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . Cari 'HOST', Anda akan melihat 127.0.0.1 untuk terhubung ke Postgresql.
sivabudh

Saya bisa mendapatkan akses ke host mysql database dengan memasang volume sesuai @ user833482, dan setelah menginstal mysql-client dan server pada wadah buruh pelabuhan tentu saja.
Michael

7

Solusi paling sederhana untuk Mac OSX

Cukup gunakan alamat IP Mac Anda. Di Mac jalankan ini untuk mendapatkan alamat IP dan menggunakannya dari dalam wadah:

$ ifconfig | grep 'inet 192'| awk '{ print $2}'

Selama server berjalan secara lokal di Mac Anda atau di wadah buruh pelabuhan lain mendengarkan 0.0.0.0, wadah buruh pelabuhan akan dapat menjangkau di alamat itu.

Jika Anda hanya ingin mengakses wadah buruh pelabuhan lain yang mendengarkan pada 0.0.0.0 Anda dapat menggunakan 172.17.0.1


1
Docker untuk Mac memperlihatkan docker.for.mac.host.internalnama host sekarang.
Matt

5

Ini bukan jawaban untuk pertanyaan aktual. Beginilah cara saya memecahkan masalah serupa. Solusinya benar-benar berasal dari: Tentukan Docker Container Networking sehingga Kontainer dapat Berkomunikasi . Terima kasih kepada Nic Raboy

Meninggalkan ini di sini untuk orang lain yang mungkin ingin melakukan panggilan REST antara satu wadah dan lainnya. Menjawab pertanyaan: apa yang harus digunakan sebagai pengganti localhost di lingkungan buruh pelabuhan?

Dapatkan seperti apa jaringan Anda docker network ls

Buat jaringan baru docker network create -d my-net

Mulai wadah pertama docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Periksa pengaturan jaringan untuk wadah pertama docker inspect first_container. "Jaringan": harus memiliki 'my-net'

Mulai wadah kedua docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Periksa pengaturan jaringan untuk wadah kedua docker inspect second_container. "Jaringan": harus memiliki 'my-net'

ssh ke wadah kedua Anda docker exec -it second_container shatau docker exec -it second_container bash.

Di dalam wadah kedua, Anda dapat melakukan ping wadah pertama ping first_container. Selain itu, panggilan kode Anda seperti http://localhost:5000dapat digantikan olehhttp://first_container:5000


Persis apa yang saya cari. Terima kasih: D
Simar Singh

5

Untuk windows,

Saya telah mengubah url basis data dalam konfigurasi pegas: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

Kemudian bangun gambar dan jalankan. Ini berhasil untuk saya.


menarik ....
Phil

bagi saya tidak bekerja. Saya memiliki mac dan mencoba dari wadah php untuk terhubung ke localhost mysql. Ada ide ?
A. Zalonis

4

Saya tidak setuju dengan jawaban dari Thomasleveil.

Membuat mysql mengikat ke 172.17.42.1 akan mencegah program lain menggunakan database pada host untuk mencapainya. Ini hanya akan berfungsi jika semua pengguna basis data Anda di-dock.

Membuat mysql bind ke 0.0.0.0 akan membuka db ke dunia luar, yang bukan hanya merupakan hal yang sangat buruk untuk dilakukan, tetapi juga bertentangan dengan apa yang ingin dilakukan oleh pertanyaan asli. Dia secara eksplisit mengatakan "MySql berjalan di localhost dan tidak mengekspos port ke dunia luar, jadi terikat pada localhost"

Untuk menjawab komentar dari ivant

"Kenapa tidak mengikat mysql ke docker0 juga?"

Ini tidak mungkin. Dokumentasi mysql / mariadb secara eksplisit mengatakan tidak mungkin untuk mengikat ke beberapa antarmuka. Anda hanya dapat mengikat ke 0, 1, atau semua antarmuka.

Sebagai kesimpulan, saya belum menemukan cara untuk mencapai database (localhost saja) pada host dari wadah buruh pelabuhan. Itu jelas terlihat seperti pola yang sangat umum, tetapi saya tidak tahu bagaimana melakukannya.


4
dari host buruh pelabuhan Anda masih bisa terhubung ke server MySQL menggunakan 172.17.42.1alamat tersebut. Tetapi catatan Anda benar sebaliknya. Aso, saya mengedit jawaban saya dengan hostmode jaringan yang memungkinkan untuk menjaga server MySQL terikat 127.0.0.1sementara memungkinkan wadah untuk terhubung
Thomasleveil

tidak, seperti yang saya katakan, Anda tidak dapat terhubung ke 172.17.42.1 jika mysql terikat ke localhost.
orzel

4
"Membuat ikatan mysql ke 172.17.42.1 akan mencegah program lain menggunakan database pada host untuk mencapainya." - Itu tidak benar. Program lain dapat menggunakan mysql, mereka hanya perlu terhubung ke 172.17.42.1 alih-alih localhost / 127.0.0.1.
0x89

Solusi untuk masalah dalam jawaban ini umumnya adalah untuk mendapatkan server MySQL untuk mengikat 0.0.0.0dan kemudian membuat firewall sehingga db tidak dapat diakses dari internet.
halfer

4

Inilah solusi saya: ini berfungsi untuk kasus saya

  • atur server mysql lokal ke akses publik dengan komentar #bind-address = 127.0.0.1 di /etc/mysql/mysql.conf.d

  • restart server mysql sudo /etc/init.d/mysql restart

  • jalankan perintah berikut untuk membuka akses root pengguna host apa pun mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • buat skrip sh: run_docker.sh

    #! bin / bash

    HOSTIP = `ip -4 addr tunjukkan cakupan global dev eth0 | grep inet | awk '{print \ $ 2}' | cut -d / -f 1`


      run docker -it -d --name web-app \
                  --add-host = lokal: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = demo \
                  -e DATABASE_USER = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • dijalankan dengan buruh pelabuhan-komposer

    versi: '2.1'

    jasa:
    tomcatwar: extra_hosts: - "lokal: 10.1.2.232" gambar: sopheamak / springboot_docker_mysql
    port: - 8080: 8080 lingkungan Hidup: - DATABASE_HOST = lokal - DATABASE_USER = root - DATABASE_PASSWORD = root - DATABASE_NAME = demo - DATABASE_PORT = 3306


4

Beberapa solusi muncul dalam pikiran:

  1. Pindahkan dependensi Anda ke dalam wadah terlebih dahulu
  2. Jadikan layanan Anda yang lain dapat diakses secara eksternal dan sambungkan dengan IP eksternal tersebut
  3. Jalankan wadah Anda tanpa isolasi jaringan
  4. Hindari menghubungkan melalui jaringan, gunakan soket yang dipasang sebagai volume sebagai gantinya

Alasan ini tidak berhasil di luar kotak adalah bahwa kontainer berjalan dengan namespace jaringan mereka sendiri secara default. Itu berarti localhost (atau 127.0.0.1 menunjuk ke antarmuka loopback) adalah unik per kontainer. Menghubungkan ke ini akan terhubung ke wadah itu sendiri, dan bukan layanan yang berjalan di luar buruh pelabuhan atau di dalam wadah buruh pelabuhan yang berbeda.

Opsi 1 : Jika ketergantungan Anda dapat dipindahkan ke wadah, saya akan melakukan ini terlebih dahulu. Itu membuat tumpukan aplikasi Anda portabel karena orang lain mencoba menjalankan wadah Anda di lingkungan mereka sendiri. Dan Anda masih dapat menerbitkan port di host Anda di mana layanan lain yang belum dimigrasi masih dapat mencapainya. Anda bahkan dapat mempublikasikan port ke antarmuka localhost pada host buruh pelabuhan Anda agar tidak diakses secara eksternal dengan sintaksis seperti: -p 127.0.0.1:3306:3306untuk port yang dipublikasikan.

Opsi 2 : Ada berbagai cara untuk mendeteksi alamat IP host dari dalam wadah, tetapi masing-masing memiliki sejumlah skenario di mana mereka bekerja (misalnya membutuhkan Docker untuk Mac). Opsi paling portabel adalah menyuntikkan IP host Anda ke dalam wadah dengan sesuatu seperti variabel lingkungan atau file konfigurasi, misalnya:

docker run --rm -e "HOST_IP=$(ip r s 0/0 | awk '{print $3}')" ...

Ini memang mengharuskan layanan Anda mendengarkan pada antarmuka eksternal itu, yang bisa menjadi masalah keamanan. Untuk metode lain untuk mendapatkan alamat IP host dari dalam wadah, lihat posting ini .

Opsi 3 : Berjalan tanpa isolasi jaringan, yaitu berjalan dengan--net host , berarti aplikasi Anda berjalan di namespace jaringan host. Ini lebih sedikit isolasi untuk wadah, dan itu berarti Anda tidak dapat mengakses wadah lain melalui jaringan buruh pelabuhan bersama dengan DNS (sebagai gantinya, Anda perlu menggunakan port yang diterbitkan untuk mengakses aplikasi kontainer lainnya). Tetapi untuk aplikasi yang perlu mengakses layanan lain pada host yang hanya mendengarkan pada 127.0.0.1host, ini bisa menjadi pilihan termudah.

Opsi 4 : Berbagai layanan juga memungkinkan akses melalui soket berbasis sistem file. Soket ini dapat dipasang ke wadah sebagai pengikat volume yang terpasang, memungkinkan Anda untuk mengakses layanan host tanpa melalui jaringan. Untuk akses ke mesin buruh pelabuhan, Anda sering melihat contoh pemasangan /var/run/docker.sockke wadah (memberikan akses root wadah ke host). Dengan mysql, Anda dapat mencoba sesuatu seperti -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sockdan kemudian terhubung ke localhostyang dikonversi mysql ke menggunakan soket.


3

Anda bisa mendapatkan ip host menggunakan gambar alpine

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

Ini akan lebih konsisten karena Anda selalu menggunakan alpine untuk menjalankan perintah.

Mirip dengan jawaban Mariano, Anda dapat menggunakan perintah yang sama untuk mengatur variabel lingkungan

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up

3

Untuk Linux, tempat Anda tidak dapat mengubah antarmuka, layanan localhost mengikat

Ada dua masalah yang harus kita pecahkan

  1. Mendapatkan IP host
  2. Membuat layanan localhost kami tersedia untuk Docker

Masalah pertama dapat dipecahkan dengan menggunakan image docker-host qoomon , seperti yang diberikan oleh jawaban lain.

Anda harus menambahkan wadah ini ke jaringan jembatan yang sama dengan wadah Anda yang lain sehingga Anda dapat mengaksesnya. Buka terminal di dalam wadah Anda dan pastikan Anda dapat melakukan ping dockerhost.

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms

Sekarang, masalah yang semakin sulit, membuat layanan dapat diakses oleh buruh pelabuhan.

Kita dapat menggunakan telnet untuk memeriksa apakah kita dapat mengakses port pada host (Anda mungkin perlu menginstal ini).

Masalahnya adalah bahwa wadah kami hanya akan dapat mengakses layanan yang mengikat semua antarmuka, seperti SSH:

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

Tetapi layanan yang hanya terikat pada localhost tidak akan dapat diakses:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

Solusi yang tepat di sini adalah untuk mengikat layanan ke jaringan jembatan buruh pelabuhan. Namun, jawaban ini mengasumsikan bahwa Anda tidak dapat mengubahnya. Jadi kita malah akan menggunakan iptables.

Pertama, kita perlu mencari nama jaringan jembatan yang digunakan buruh pelabuhan ifconfig. Jika Anda menggunakan jembatan tanpa nama, ini hanya akan menjadi docker0. Namun, jika Anda menggunakan jaringan bernama Anda akan memiliki jembatan dimulai dengan br-buruh pelabuhan itu akan menggunakan sebagai gantinya. Milik saya br-5cd80298d6f4.

Setelah kami memiliki nama jembatan ini, kami perlu mengizinkan perutean dari jembatan ini ke localhost. Ini dinonaktifkan secara default karena alasan keamanan:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

Sekarang untuk mengatur iptablesaturan kami . Karena kontainer kami hanya dapat mengakses port pada jaringan bridge docker, kami akan berpura-pura bahwa layanan kami sebenarnya terikat pada port pada jaringan ini.

Untuk melakukan ini, kami akan meneruskan semua permintaan <docker_bridge>:portkelocalhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>

Misalnya, untuk layanan saya di port 1025

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

Anda sekarang harus dapat mengakses layanan Anda dari wadah:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready

1
Ini sama dengan apa yang @ ray-d sebutkan di atas, tetapi dijelaskan dengan baik. Terima kasih! Selain itu, ketika menggunakan docker-compose, saya juga harus menambahkan aturan DNAT dalam rantai PREROUTING untuk semua paket yang tiba di antarmuka docker0 juga: karena, docker-compose tampaknya menggunakan docker0 selama pembuatan (tidak saat berjalan, secara mengejutkan): sysctl -w net.ipv4.conf.docker0.route_localnet=1daniptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd

3

Anda harus tahu gateway ! Solusi saya dengan server lokal adalah mengeksposnya di bawah 0.0.0.0:8000, kemudian jalankan buruh pelabuhan dengan subnet dan jalankan wadah seperti:

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>

Jadi, sekarang Anda dapat mengakses loopback melalui http://172.35.0.1:8000


3

Coba ini:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202

Mendapatkan 192.168.1.202 , gunakanifconfig

Ini berhasil untuk saya. Semoga bantuan ini!


2

CGroups dan Namespaces memainkan peran utama dalam Container Ecosystem.

Namespace menyediakan lapisan isolasi. Setiap kontainer berjalan di namespace terpisah dan aksesnya terbatas pada namespace itu. Cgroups mengontrol pemanfaatan sumber daya dari setiap wadah, sedangkan Namespace mengontrol apa yang dapat dilihat oleh suatu proses dan mengakses sumber daya masing-masing.

Inilah pemahaman dasar pendekatan solusi yang bisa Anda ikuti,

Gunakan Network Namespace

Ketika sebuah wadah memunculkan gambar, antarmuka jaringan didefinisikan dan dibuat. Ini memberikan wadah alamat IP dan antarmuka yang unik.

$ docker run -it alpine ifconfig

Dengan mengubah namespace menjadi host, jaringan cotainers tidak tetap terisolasi ke antarmuka, proses akan memiliki akses ke antarmuka jaringan mesin host.

$ docker run -it --net=host alpine ifconfig

Jika proses mendengarkan pada port, mereka akan mendengarkan pada antarmuka host dan dipetakan ke wadah.

Gunakan Namespace PID Dengan mengubah Namespace Pid memungkinkan wadah untuk berinteraksi dengan proses lain di luar ruang lingkup normal.

Kontainer ini akan berjalan di namespace-nya sendiri.

$ docker run -it alpine ps aux

Dengan mengubah namespace menjadi host, wadah juga dapat melihat semua proses lain yang berjalan pada sistem.

$ docker run -it --pid=host alpine ps aux

Berbagi Namespace

Ini adalah praktik buruk untuk melakukan ini dalam produksi karena Anda keluar dari model keamanan wadah yang mungkin terbuka untuk kerentanan, dan akses mudah ke penyadap. Ini hanya untuk alat debugging dan mengecilkan celah dalam keamanan kontainer.

Kontainer pertama adalah server nginx. Ini akan membuat jaringan baru dan proses namespace. Kontainer ini akan mengikat dirinya ke port 80 dari antarmuka jaringan yang baru dibuat.

$ docker run -d --name http nginx:alpine

Wadah lain sekarang dapat menggunakan kembali namespace ini,

$ docker run --net=container:http mohan08p/curl curl -s localhost

Juga, wadah ini dapat melihat antarmuka dengan proses dalam wadah bersama.

$ docker run --pid=container:http alpine ps aux

Ini akan memungkinkan Anda memberi lebih banyak hak istimewa kepada wadah tanpa mengubah atau memulai ulang aplikasi. Dengan cara yang sama Anda dapat terhubung ke mysql di host, jalankan dan debug aplikasi Anda. Tapi, itu tidak merekomendasikan untuk pergi dengan cara ini. Semoga ini bisa membantu.


1

Untuk Mesin Windows: -

Jalankan perintah di bawah ini untuk Mengekspos port buruh pelabuhan secara acak selama waktu pembuatan

$docker run -d --name MyWebServer -P mediawiki

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Dalam daftar kontainer di atas Anda dapat melihat port ditetapkan sebagai 32768. Coba akses

localhost:32768 

Anda dapat melihat halaman mediawiki


5
Meskipun jawaban ini dapat memberikan informasi yang berguna bagi beberapa pengguna, itu adalah cara yang salah ! Ini adalah tentang mengakses layanan yang berjalan dalam wadah dari mesin host. Namun, pertanyaannya adalah tentang mengakses layanan yang berjalan pada host dari wadah.
einjohn

1

Sampai perbaikan tidak digabung menjadi mastercabang, untuk mendapatkan host IP jalankan dari dalam wadah:

ip -4 route list match 0/0 | cut -d' ' -f3

(seperti yang disarankan oleh @Money di sini ).


1

Saya menyelesaikannya dengan membuat pengguna di MySQL untuk ip penampung:

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

Kemudian pada wadah: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name


Ini solusi paling sederhana. Ini berhasil bagi saya dan saya telah banyak merujuk
Sopia Alfred

-1

Cara saya melakukannya adalah melewatkan IP host sebagai variabel lingkungan ke wadah. Kontainer kemudian mengakses host oleh variabel itu.


Bisakah Anda menggambarkan bagaimana Anda melakukan ini? Saya telah mencoba pendekatan ini tetapi tidak menemukan banyak kesuksesan
kmjb

`buruh pelabuhan run -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 Mencoba 10.145.2.123 ... Terhubung ke 10.145.2.123. Karakter melarikan diri adalah '^]'. SSH-2.0-OpenSSH_7.4`
F. Kam
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.