Cara mengakses port host dari wadah buruh pelabuhan

281

Saya memiliki wadah buruh pelabuhan menjalankan jenkins. Sebagai bagian dari proses pembangunan, saya perlu mengakses server web yang dijalankan secara lokal di mesin host. Apakah ada cara server web host (yang dapat dikonfigurasi untuk berjalan pada port) dapat terkena wadah jenkins?

EDIT: Saya menjalankan buruh pelabuhan secara native di mesin Linux.

MEMPERBARUI:

Selain jawaban @ larsks di bawah ini, untuk mendapatkan alamat IP Host IP dari mesin host, saya melakukan hal berikut:

ip addr show docker0 | grep -Po 'inet \K[\d.]+'
Tri Nguyen
sumber
Menggunakan komentar karena ini adalah jawaban yang buruk, tapi saya yakin Anda biasanya dapat mengaksesnya di 172.17.1.78 - kecuali ini adalah pengaturan boot2docker.
CashIsClay
@CashIsClay Saya mencobanya, dan masih mendapatkan kesalahan inicurl: (7) Failed to connect to 172.17.1.78 port 7000: No route to host
Tri Nguyen
Anda tidak menentukan; apakah Anda menjalankan boot2docker, atau Anda menjalankan Docker secara asli di Linux?
larsks
@ larsks maaf, saya baru saja memperbarui pertanyaan - Saya menjalankannya secara native di Linux.
Tri Nguyen

Jawaban:

206

Saat menjalankan Docker secara native di Linux, Anda dapat mengakses layanan host menggunakan alamat IP docker0antarmuka. Dari dalam wadah, ini akan menjadi rute default Anda.

Misalnya, di sistem saya:

$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link 
       valid_lft forever preferred_lft forever

Dan di dalam sebuah wadah:

# ip route show
default via 172.17.0.1 dev eth0 
172.17.0.0/16 dev eth0  src 172.17.0.4 

Cukup mudah untuk mengekstrak alamat IP ini menggunakan skrip shell sederhana:

#!/bin/sh

hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip

Anda mungkin perlu mengubah iptablesaturan pada host Anda untuk mengizinkan koneksi dari wadah Docker. Sesuatu seperti ini akan melakukan trik:

# iptables -A INPUT -i docker0 -j ACCEPT

Ini akan memungkinkan akses ke setiap port di host dari wadah Docker. Perhatikan bahwa:

  • Aturan iptables dipesan, dan aturan ini mungkin atau tidak bisa melakukan hal yang benar tergantung pada aturan lain yang datang sebelumnya.

  • Anda hanya akan dapat mengakses layanan host yang (a) mendengarkan INADDR_ANY(alias 0,0.0.0) atau yang secara eksplisit mendengarkan pada docker0antarmuka.

larsks
sumber
1
Terima kasih. Mendapatkan alamat IP adalah semua yang diperlukan untuk saya, tanpa mengubah iptables :)
Tri Nguyen
2
Tautan yang relevan: menambahkan entri ke / etc / hosts
chronos
7
Bagaimana dengan Docker untuk MAC? AFAIK tidak ada jaringan docker0 yang tersedia untuk "Docker for MAC". Dalam hal itu bagaimana saya bisa terhubung ke host dari wadah?
Vijay
17
Jika Anda menggunakan Docker untuk MAC v 17.06 atau lebih baru, gunakan docker.for.mac.localhostsaja localhostatau 127.0.0.1. Ini dok .
merito
1
Saya telah menggunakan nama host dari host saya alih-alih mendapatkan alamat IP (perintah hostname pada host)
Marek F
313

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

Janne Annala
sumber
Saya sudah berhasil menguji ini. Tidak perlu mematikan firewall
alvaro g
15
Mulai 17.06 dan seterusnya, dirilis pada Juni 2017, rekomendasi mereka adalah untuk terhubung ke nama DNS khusus Mac docker.for.mac.localhostyang akan menyelesaikan ke alamat IP internal yang digunakan oleh tuan rumah! ... Saya telah mengujinya dan itu benar-benar berfungsi! :)
Kyrgystan
Temukan jawaban untuk pengguna Mac seperti saya. Terima kasih. Satu hal yang saya tidak mengerti adalah mengapa saya memberikan ip route show | awk '/default/ {print $3}'satu IP dan docker.for.mac.localhostyang lainnya.
dmmd
8
diubah menjadi host.docker.internal docs.docker.com/docker-for-mac/networking/…
Snowball
1
Merekomendasikan penggunaan host.docker.internaldalam wadah buruh pelabuhan dan config 127.0.0.1 host.docker.internaldi host file yang.
junlin
85

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

samthebest
sumber
15
Tidak akan bekerja untuk mereka yang menggunakan Dpcker untuk Windows / Docker untuk Mac sejauh yang saya mengerti karena kenyataan bahwa kontainer berjalan di lingkungan tervirtualisasi: Hyper-V (Windows) / xhyve (Mac)
ninjaboy
6
INI! Ini jawabannya!
user3751385
15
Sebagai catatan: di dalam Docker Componse, network_mode: "host"
jbarros
Ini tidak berfungsi untuk saya di Docker untuk Mac versi 19.03.1 di klien dan server. Saya berharap itu berhasil, tetapi tidak.
clay
1
Bahkan jika saya menggunakan mac, itu berfungsi ketika Anda ingin komunikasi antara dua kontainer buruh pelabuhan dan ketika saya mengubah semua aplikasi ke gambar buruh pelabuhan itu sudah cukup bagi saya
bormat
27

Solusi dengan docker-compose: Untuk mengakses layanan berbasis host, Anda dapat menggunakan network_modeparameter https://docs.docker.com/compose/compose-file/#network_mode

version: '3'
services:
  jenkins:
    network_mode: host

EDIT 2020-04-27: direkomendasikan untuk digunakan hanya di lingkungan pengembangan lokal.

vovan
sumber
Lalu bagaimana cara mengakses jenkins? Tampaknya penerusan port tidak berfungsi jika menggunakan mode jaringan host
Jeff Tian
1
ini adalah solusi yang sangat berisiko dan sama sekali tidak direkomendasikan. kita TIDAK boleh membuka jaringan host kita ke wadah kecuali diperlukan secara eksplisit
Fatemeh Majd
12

Saya membuat wadah buruh pelabuhan untuk melakukan hal itu https://github.com/qoomon/docker-host

Anda kemudian dapat menggunakan nama wadah dns untuk mengakses sistem host misalnya curl http://dockerhost:9200

qoomon
sumber
Itu solusi cerdas. Apakah Anda mengetahui ada yang menggunakan ini dengan banyak lalu lintas? Mungkin ada overhead untuk memproksi semua lalu lintas melalui wadah ini.
bcoughlan
3
Ya itu bekerja cukup baik hampir tidak ada overhead sama sekali karena hanya bekerja di atas loopback-perangkat
qoomon
11

Kami menemukan bahwa solusi yang lebih sederhana untuk semua sampah jaringan ini adalah dengan menggunakan soket domain untuk layanan ini. Jika Anda tetap mencoba terhubung ke host, cukup pasang soket sebagai volume, dan Anda sedang menuju ke sana. Untuk postgresql, ini sesederhana:

docker run -v /var/run/postgresql:/var/run/postgresql

Kemudian kami hanya mengatur koneksi database kami untuk menggunakan soket, bukan jaringan. Secara harfiah itu mudah.

mlissner
sumber
Ini solusi hebat. Pekerjaan yang baik!
kutu buku yang dibayar
2
FYI, kami mengalami masalah besar dengan ini: Docker untuk Mac tidak mendukung soket sebagai volume yang dipasang. Ini berjalan lancar sampai orang Mac mencobanya. :(
mlissner
Terima kasih! Bekerja seperti pesona di Linux!
Marcelo Cardoso
7

Saya telah menjelajahi berbagai solusi dan saya menemukan ini solusi paling tidak hacky:

  1. Tetapkan alamat IP statis untuk IP gateway jembatan.
  2. Tambahkan IP gateway sebagai entri tambahan dalam extra_hostsarahan.

Satu-satunya downside adalah jika Anda memiliki beberapa jaringan atau proyek melakukan ini, Anda harus memastikan bahwa rentang alamat IP mereka tidak bertentangan.

Berikut adalah contoh Tulis Docker:

version: '2.3'

services:
  redis:
    image: "redis"
    extra_hosts:
      - "dockerhost:172.20.0.1"

networks:
  default:
    ipam:
      driver: default
      config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

Anda kemudian dapat mengakses port pada host dari dalam wadah menggunakan nama host "dockerhost".

bcoughlan
sumber
3

Anda dapat mengakses server web lokal yang berjalan di mesin host Anda dengan dua cara.

  1. Pendekatan 1 dengan IP publik

    Gunakan alamat IP publik mesin host untuk mengakses server web dalam wadah buruh pelabuhan Jenkins.

  2. Pendekatan 2 dengan jaringan host

    Gunakan "--net host" untuk menambahkan wadah buruh pelabuhan Jenkins di tumpukan jaringan host. Kontainer yang digunakan pada stack host memiliki seluruh akses ke antarmuka host. Anda dapat mengakses server web lokal dalam wadah buruh pelabuhan dengan alamat IP pribadi dari mesin host.

NETWORK ID          NAME                      DRIVER              SCOPE
b3554ea51ca3        bridge                    bridge              local
2f0d6d6fdd88        host                      host                local
b9c2a4bc23b2        none                      null                local

Mulai wadah dengan jaringan host Eg: docker run --net host -it ubuntudan jalankan ifconfiguntuk mendaftar semua alamat IP jaringan yang tersedia yang dapat dijangkau dari wadah buruh pelabuhan.

Misalnya: Saya memulai server nginx di mesin host lokal saya dan saya dapat mengakses URL situs web nginx dari wadah buruh pelabuhan Ubuntu.

docker run --net host -it ubuntu

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a604f7af5e36        ubuntu              "/bin/bash"         22 seconds ago      Up 20 seconds                           ubuntu_server

Mengakses server web Nginx (berjalan di mesin host lokal) dari wadah buruh pelabuhan Ubuntu dengan alamat IP jaringan pribadi.

root@linuxkit-025000000001:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes
Sreenivasa Reddy
sumber
3

Untuk docker-composemenggunakan jembatan jaringan untuk membuat jaringan pribadi antara kontainer, solusi yang diterima menggunakan docker0tidak berfungsi karena antarmuka jalan keluar dari wadah tidak docker0tetapi sebaliknya itu adalah antarmuka yang dihasilkan secara acak, seperti:

$ ifconfig

br-02d7f5ba5a51: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.32.1  netmask 255.255.240.0  broadcast 192.168.47.255

Sayangnya id acak itu tidak dapat diprediksi dan akan berubah setiap kali penulisan harus membuat ulang jaringan (mis. Pada host reboot). Solusi saya untuk ini adalah membuat jaringan pribadi di subnet yang dikenal dan mengkonfigurasi iptablesuntuk menerima rentang itu:

Tulis cuplikan file:

version: "3.7"

services:
  mongodb:
    image: mongo:4.2.2
    networks:
    - mynet
    # rest of service config and other services removed for clarity

networks:
  mynet:
    name: mynet
    ipam:
      driver: default
      config:
      - subnet: "192.168.32.0/20"

Anda dapat mengubah subnet jika lingkungan Anda mengharuskannya. Saya secara sewenang-wenang memilih 192.168.32.0/20dengan menggunakan docker network inspectuntuk melihat apa yang sedang dibuat secara default.

Konfigurasikan iptablespada host untuk mengizinkan subnet pribadi sebagai sumber:

$ iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT

Ini adalah aturan yang paling sederhana iptables. Anda mungkin ingin menambahkan batasan lain, misalnya dengan port tujuan. Jangan lupa untuk mempertahankan aturan iptables Anda saat Anda senang mereka sedang bekerja.

Pendekatan ini memiliki keuntungan karena dapat diulang dan karena itu dapat diautomatisasi. Saya menggunakan templatemodul ansible untuk menyebarkan file penulisan saya dengan substitusi variabel dan kemudian menggunakan modul iptablesdan shelluntuk mengkonfigurasi dan bertahan aturan firewall, masing-masing.

Andy Brown
sumber
Saya melihat beberapa jawaban menyarankan iptables -A INPUT -i docker0 -j ACCEPT, tetapi itu tidak membantu saya, sedangkan yang iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPTdisarankan di sini menyelesaikan masalah saya.
Terry Brown
1

Ini adalah pertanyaan lama dan memiliki banyak jawaban, tetapi tidak ada yang cocok dengan konteks saya. Dalam kasus saya, wadah sangat ramping dan tidak mengandung alat jaringan yang diperlukan untuk mengekstrak alamat ip host dari dalam wadah.

Juga, dalam --net="host"pendekatan ini adalah pendekatan yang sangat kasar yang tidak berlaku ketika seseorang ingin memiliki konfigurasi jaringan yang terisolasi dengan beberapa wadah.

Jadi, pendekatan saya adalah mengekstraksi alamat host di sisi host, dan kemudian meneruskannya ke wadah dengan --add-hostparameter:

$ docker run --add-host=docker-host:`ip addr show docker0 | grep -Po 'inet \K[\d.]+'` image_name

atau, simpan alamat IP host dalam variabel lingkungan dan gunakan variabel nanti:

$ DOCKERIP=`ip addr show docker0 | grep -Po 'inet \K[\d.]+'`
$ docker run --add-host=docker-host:$DOCKERIP image_name

Dan kemudian docker-hostditambahkan ke file host penampung, dan Anda dapat menggunakannya dalam string koneksi database atau URL API.

Passiday
sumber
0

Ketika Anda memiliki dua gambar buruh pelabuhan "sudah" dibuat dan Anda ingin menempatkan dua wadah untuk berkomunikasi satu sama lain.

Untuk itu, Anda dapat dengan mudah menjalankan setiap wadah dengan --nama sendiri dan menggunakan bendera --link untuk mengaktifkan komunikasi di antara mereka. Anda tidak mendapatkan ini selama pembuatan buruh pelabuhan.

Ketika Anda berada dalam skenario seperti saya, dan itu adalah Anda

docker build -t "centos7/someApp" someApp/ 

Itu rusak ketika Anda mencoba

curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz

dan Anda terjebak pada "curl / wget" tidak mengembalikan "rute ke host".

Alasannya adalah keamanan yang ditetapkan oleh buruh pelabuhan yang secara default melarang komunikasi dari wadah ke host atau kontainer lain yang berjalan di host Anda. Ini cukup mengejutkan bagi saya, saya harus mengatakan, Anda akan mengharapkan echosystem mesin docker yang berjalan pada mesin lokal tanpa cacat dapat saling mengakses tanpa terlalu banyak rintangan.

Penjelasan untuk ini dijelaskan secara rinci dalam dokumentasi berikut.

http://www.dedoimedo.com/computers/docker-networking.html

Dua solusi cepat diberikan yang membantu Anda bergerak dengan menurunkan keamanan jaringan.

Alternatif paling sederhana adalah mematikan firewall - atau mengizinkan semua. Ini berarti menjalankan perintah yang diperlukan, yang dapat berupa systemctl stop firewalld, iptables -F atau yang setara.

Semoga informasi ini membantu Anda.

99Sono
sumber
3
Sama seperti catatan, --linksekarang sudah ditinggalkan
Mr.Budris
0

Bagi saya (Windows 10, Docker Engine v19.03.8) itu adalah campuran dari https://stackoverflow.com/a/43541732/7924573 dan https://stackoverflow.com/a/50866007/7924573 .

  1. ubah host / ip ke host.docker.internal
    misalnya: LOGGER_URL = " http: //host.docker.internal: 8085 / log "
  2. atur network_mode untuk menjembatani (jika Anda ingin mempertahankan penerusan port; jika tidak menggunakan host ):
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge atau sebagai alternatif: Gunakan --net="bridge"jika Anda tidak menggunakan docker-compose (mirip dengan https://stackoverflow.com/a/48806927/7924573 )
    Seperti yang ditunjukkan dalam jawaban sebelumnya: Ini hanya boleh digunakan di lingkungan pengembangan lokal .
    Untuk informasi lebih lanjut baca: https://docs.docker.com/compose/compose-file/#network_mode dan https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds
tschomacker
sumber