Cách truy cập cổng máy chủ từ container docker


277

Tôi có một container docker chạy jenkins. Là một phần của quá trình xây dựng, tôi cần truy cập vào một máy chủ web được chạy cục bộ trên máy chủ. Có cách nào để máy chủ web (có thể được cấu hình để chạy trên một cổng) có thể được hiển thị với bộ chứa jenkins không?

EDIT: Tôi đang chạy docker tự nhiên trên máy Linux.

CẬP NHẬT:

Ngoài câu trả lời @larsks bên dưới, để lấy địa chỉ IP của IP máy chủ từ máy chủ, tôi làm như sau:

ip addr show docker0 | grep -Po 'inet \K[\d.]+'

Sử dụng một nhận xét vì đây là một câu trả lời khủng khiếp, nhưng tôi tin rằng bạn thường có thể truy cập nó vào ngày 172.17.1.78 - trừ khi đây là một thiết lập boot2docker.
CashIsClay

@CashIsClay Tôi đã thử điều đó và vẫn nhận được lỗi nàycurl: (7) Failed to connect to 172.17.1.78 port 7000: No route to host
Tri Nguyen

Bạn đã không chỉ định; Bạn đang chạy boot2docker hay bạn đang chạy Docker tự nhiên trên Linux?
larsks

@larsks xin lỗi, tôi vừa cập nhật câu hỏi - Tôi đang chạy nó trên Linux.
Tri Nguyễn

Câu trả lời:


206

Khi chạy Docker tự nhiên trên Linux, bạn có thể truy cập các dịch vụ máy chủ bằng địa chỉ IP của docker0giao diện. Từ bên trong container, đây sẽ là tuyến đường mặc định của bạn.

Ví dụ: trên hệ thống của tôi:

$ 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

Và bên trong một container:

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

Thật dễ dàng để trích xuất địa chỉ IP này bằng cách sử dụng tập lệnh shell đơn giản:

#!/bin/sh

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

Bạn có thể cần sửa đổi các iptablesquy tắc trên máy chủ của mình để cho phép kết nối từ các container Docker. Một cái gì đó như thế này sẽ thực hiện các mẹo:

# iptables -A INPUT -i docker0 -j ACCEPT

Điều này sẽ cho phép truy cập vào bất kỳ cổng nào trên máy chủ từ các container Docker. Lưu ý rằng:

  • Các quy tắc iptables được sắp xếp và quy tắc này có thể hoặc không thể thực hiện đúng tùy thuộc vào những quy tắc khác xuất hiện trước nó.

  • bạn sẽ chỉ có thể truy cập các dịch vụ máy chủ đang (a) lắng nghe INADDR_ANY(còn gọi là 0.0.0.0) hoặc đang nghe rõ ràng trên docker0giao diện.


1
Cảm ơn. Lấy địa chỉ IP là tất cả những gì tôi cần, mà không cần sửa đổi iptables :)
Tri Nguyen


7
Làm thế nào về Docker cho MAC? AFAIK không có mạng docker0 có sẵn cho "Docker cho MAC". Trong trường hợp đó, làm thế nào tôi có thể kết nối với máy chủ từ container?
Vijay

17
Nếu bạn sử dụng Docker cho MAC v 17,06 trở lên, chỉ cần sử dụng docker.for.mac.localhostthay vì localhosthoặc 127.0.0.1. Đây là tài liệu .
merito

1
Tôi đã sử dụng tên máy chủ của máy chủ của mình thay vì nhận địa chỉ IP (lệnh tên máy chủ trên máy chủ)
Marek F

311

Dành cho macOS và Windows

Docker v 18.03 trở lên (kể từ ngày 21 tháng 3 năm 2018)

Sử dụng địa chỉ IP nội bộ của bạn hoặc kết nối với tên DNS đặc biệt host.docker.internalsẽ phân giải thành địa chỉ IP nội bộ được sử dụng bởi máy chủ lưu trữ.

Hỗ trợ Linux đang chờ xử lý https://github.com/docker/for-linux/issues/264

MacOS với các phiên bản trước của Docker

Docker cho Mac v 17.12 đến v 18.02

Tương tự như trên nhưng sử dụng docker.for.mac.host.internalthay thế.

Docker cho Mac v 17,06 đến v 17.11

Tương tự như trên nhưng sử dụng docker.for.mac.localhostthay thế.

Docker cho Mac 17.05 trở xuống

Để truy cập máy chủ từ bộ chứa docker, bạn phải đính kèm bí danh IP vào giao diện mạng của mình. Bạn có thể liên kết bất kỳ IP nào bạn muốn, chỉ cần đảm bảo rằng bạn không sử dụng nó cho bất kỳ thứ gì khác.

sudo ifconfig lo0 alias 123.123.123.123/24

Sau đó, đảm bảo rằng máy chủ của bạn đang nghe IP được đề cập ở trên hoặc 0.0.0.0. Nếu nó nghe trên localhost, 127.0.0.1nó sẽ không chấp nhận kết nối.

Sau đó, chỉ cần trỏ container của bạn vào IP này và bạn có thể truy cập vào máy chủ!

Để kiểm tra bạn có thể chạy một cái gì đó như curl -X GET 123.123.123.123:3000bên trong container.

Bí danh sẽ đặt lại trên mỗi lần khởi động lại, vì vậy hãy tạo một kịch bản khởi động nếu cần thiết.

Giải pháp và nhiều tài liệu khác tại đây: https://docs.docker.com/docker-for-mac/networking/#use-case-and-workaround


Tôi đã thử nghiệm thành công điều này. Không cần tắt tường lửa
alvaro g

15
Từ ngày 17 tháng 6 trở đi, phát hành vào tháng 6 năm 2017, khuyến nghị của họ là kết nối với tên DNS đặc biệt chỉ dành cho máy Mac docker.for.mac.localhostsẽ phân giải địa chỉ IP nội bộ được sử dụng bởi máy chủ lưu trữ! ... Tôi đã thử nó và nó thực sự hoạt động! :)
Tiếng Nhật

Tại chỗ trả lời cho người dùng Mac như tôi. Cảm ơn. Một điều tôi không nhận được là tại sao lại ip route show | awk '/default/ {print $3}'tặng một IP và một IP docker.for.mac.localhostkhác.
dmmd

8
đã đổi thành host.docker.internal docs.docker.com/docker-for-mac/networking/ từ
Snowball

1
Đề nghị sử dụng host.docker.internaltrong container docker và cấu hình 127.0.0.1 host.docker.internaltrong tập tin máy chủ .
Junlin

82

Sử dụng --net="host"trong docker runlệnh của bạn , sau đó localhosttrong container docker của bạn sẽ trỏ đến máy chủ docker của bạn.


15
Tôi không làm việc cho những người sử dụng Dpcker cho Windows / Docker cho Mac theo như tôi hiểu do thực tế là các container chạy trong môi trường ảo hóa: Hyper-V (Windows) / xhyve (Mac)
ninjaboy

6
ĐIỀU NÀY! Đây là câu trả lời!
dùng3751385

12
Chỉ dành cho bản ghi: trong Docker Componse, network_mode: "host"
jbarros

Điều này không hoạt động với tôi trên Docker cho Mac phiên bản 19.03.1 trên máy khách và máy chủ. Tôi ước nó hoạt động, nhưng không phải.
đất sét

1
Ngay cả khi tôi đang sử dụng mac, nó vẫn hoạt động khi bạn muốn liên lạc giữa hai container docker và khi tôi chuyển đổi tất cả ứng dụng sang hình ảnh
docker,

26

Giải pháp với docker-compose: Để truy cập vào dịch vụ dựa trên máy chủ, bạn có thể sử dụng network_modetham số https://docs.docker.com/compose/compose-file/#network_mode

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

EDIT 2020-04-27: chỉ được khuyến nghị sử dụng trong môi trường phát triển địa phương.


Vậy thì làm thế nào để truy cập jenkins? Có vẻ như cổng chuyển tiếp không hoạt động nếu sử dụng chế độ mạng máy chủ
Jeff Tian

1
đó là một giải pháp rất rủi ro và hoàn toàn không được khuyến nghị. chúng ta KHÔNG nên mở mạng máy chủ của mình vào các container trừ khi rõ ràng là cần thiết
FHReh Majd

12

Hiện tại, cách dễ nhất để làm điều này trên Mac và Windows là sử dụng máy chủ host.docker.internal, giải quyết địa chỉ IP của máy chủ. Thật không may, nó không hoạt động trên linux (kể từ tháng 4 năm 2018).


Giải pháp này đã làm việc với Docker phiên bản 19.03.1. Nhiều giải pháp khác được đưa ra ở đây không hoạt động. Điều này được ghi lại tại docs.docker.com/docker-for-mac/networking/iêu
đất sét

12

Tôi đã tạo một container docker để thực hiện chính xác https://github.com/qoomon/docker-host

Sau đó, bạn có thể chỉ cần sử dụng dns tên container để truy cập hệ thống máy chủ, vd curl http://dockerhost:9200


Đó là một giải pháp thông minh. Bạn có biết bất cứ điều gì sử dụng điều này với rất nhiều lưu lượng truy cập? Có thể có phí để ủy quyền tất cả lưu lượng truy cập thông qua container này.
bcoughlan

3
Vâng, nó hoạt động khá tốt, hầu như không có chi phí nào cả vì nó chỉ hoạt động trên thiết bị loopback
qoomon

11

Chúng tôi thấy rằng một giải pháp đơn giản hơn cho tất cả các mạng rác này là chỉ sử dụng ổ cắm tên miền cho dịch vụ. Nếu bạn đang cố gắng kết nối với máy chủ, chỉ cần gắn ổ cắm dưới dạng âm lượng và bạn đang trên đường đến. Đối với postgresql, điều này đơn giản như:

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

Sau đó, chúng tôi chỉ cần thiết lập kết nối cơ sở dữ liệu của chúng tôi để sử dụng ổ cắm thay vì mạng. Nghĩa đen mà dễ.


Đây là một giải pháp tuyệt vời. Công việc tốt!
một mọt sách được trả tiền

2
FYI, chúng tôi gặp phải một vấn đề lớn với điều này: Docker cho Mac không hỗ trợ ổ cắm dưới dạng khối lượng được gắn. Điều này diễn ra sôi nổi cho đến khi một người Mac thử nó. :(
mlissner

Cảm ơn! Làm việc như một cơ duyên trên Linux!
Marcelo Cardoso

7

Tôi đã khám phá các giải pháp khác nhau và tôi thấy đây là giải pháp ít hack nhất:

  1. Xác định một địa chỉ IP tĩnh cho IP cổng cầu.
  2. Thêm IP gateway như một mục bổ sung trong extra_hostschỉ thị.

Nhược điểm duy nhất là nếu bạn có nhiều mạng hoặc dự án thực hiện việc này, bạn phải đảm bảo rằng phạm vi địa chỉ IP của chúng không xung đột.

Dưới đây là ví dụ về Docker Compose:

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

Sau đó, bạn có thể truy cập các cổng trên máy chủ từ bên trong container bằng tên máy chủ "dockerhost".



3

Bạn có thể truy cập máy chủ web cục bộ đang chạy trong máy chủ của mình theo hai cách.

  1. Cách tiếp cận 1 với IP công cộng

    Sử dụng địa chỉ IP công cộng của máy chủ để truy cập máy chủ web trong bộ chứa docker Jenkins.

  2. Cách tiếp cận 2 với mạng máy chủ

    Sử dụng "--net host" để thêm bộ chứa docker Jenkins trên ngăn xếp mạng của máy chủ. Các container được triển khai trên ngăn xếp của máy chủ có toàn quyền truy cập vào giao diện máy chủ. Bạn có thể truy cập máy chủ web cục bộ trong bộ chứa docker với địa chỉ IP riêng của máy chủ.

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

Bắt đầu một bộ chứa với mạng máy chủ Eg: docker run --net host -it ubuntuvà chạy ifconfigđể liệt kê tất cả các địa chỉ IP mạng có sẵn có thể truy cập được từ bộ chứa docker.

Ví dụ: Tôi đã khởi động máy chủ nginx trong máy chủ lưu trữ cục bộ của mình và tôi có thể truy cập URL trang web nginx từ bộ chứa docker 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

Truy cập máy chủ web Nginx (chạy trong máy chủ cục bộ) từ bộ chứa docker Ubuntu với địa chỉ IP mạng riêng.

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

3

Để docker-composesử dụng mạng cầu nối để tạo một mạng riêng giữa các container, giải pháp được chấp nhận sử dụng docker0không hoạt động vì giao diện đầu ra từ các container không phải docker0mà thay vào đó là id giao diện được tạo ngẫu nhiên, chẳng hạn như:

$ 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

Thật không may, id ngẫu nhiên không thể dự đoán được và sẽ thay đổi mỗi lần soạn thảo phải tạo lại mạng (ví dụ: khi khởi động lại máy chủ). Giải pháp của tôi cho vấn đề này là tạo mạng riêng trong mạng con đã biết và định cấu hình iptablesđể chấp nhận phạm vi đó:

Soạn đoạn tập tin:

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"

Bạn có thể thay đổi mạng con nếu môi trường của bạn yêu cầu. Tôi tùy ý chọn 192.168.32.0/20bằng cách sử dụng docker network inspectđể xem những gì đang được tạo theo mặc định.

Định cấu hình iptablestrên máy chủ để cho phép mạng con riêng tư làm nguồn:

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

Đây là iptablesquy tắc đơn giản nhất có thể . Bạn có thể muốn thêm các hạn chế khác, ví dụ như cổng đích. Đừng quên duy trì các quy tắc iptables của bạn khi bạn vui vẻ làm việc.

Cách tiếp cận này có ưu điểm là có thể lặp lại và do đó có thể tự động hóa. Tôi sử dụng templatemô-đun của ansible để triển khai tệp soạn thảo của mình với sự thay thế thay đổi và sau đó sử dụng các mô-đun iptablesshellđể cấu hình và duy trì các quy tắc tường lửa tương ứng.


Tôi đã thấy nhiều câu trả lời gợi ý iptables -A INPUT -i docker0 -j ACCEPT, nhưng điều đó không giúp tôi, trong khi iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPTđề xuất ở đây đã giải quyết vấn đề của tôi.
Terry Brown

1

Đây là một câu hỏi cũ và có nhiều câu trả lời, nhưng không có câu hỏi nào phù hợp với bối cảnh của tôi. Trong trường hợp của tôi, các container rất gọn gàng và không chứa bất kỳ công cụ mạng nào cần thiết để trích xuất địa chỉ IP của máy chủ từ bên trong container.

Ngoài ra, sử dụng --net="host"cách tiếp cận này là một cách tiếp cận rất thô sơ không thể áp dụng khi người ta muốn có cấu hình mạng cách ly tốt với một số container.

Vì vậy, cách tiếp cận của tôi là trích xuất địa chỉ của máy chủ ở phía máy chủ và sau đó chuyển nó đến vùng chứa với --add-hosttham số:

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

hoặc, lưu địa chỉ IP của máy chủ trong biến môi trường và sử dụng biến sau:

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

Và sau đó docker-host, tệp được thêm vào tệp máy chủ chứa và bạn có thể sử dụng tệp đó trong chuỗi kết nối cơ sở dữ liệu hoặc URL API.


0

Khi bạn có hai hình ảnh docker "đã" được tạo và bạn muốn đặt hai container để liên lạc với nhau.

Vì thế, bạn có thể thuận tiện chạy từng container với --name riêng và sử dụng cờ --link để cho phép liên lạc giữa chúng. Bạn không nhận được điều này trong quá trình xây dựng docker.

Khi bạn ở trong một kịch bản như tôi, và đó là của bạn

docker build -t "centos7/someApp" someApp/ 

Điều đó vỡ khi bạn cố gắng

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

và bạn bị kẹt khi "curl / wget" không trả lại "tuyến đường đến máy chủ".

Lý do là bảo mật được đặt tại chỗ bởi docker mà theo mặc định là cấm liên lạc từ một container tới máy chủ hoặc các container khác đang chạy trên máy chủ của bạn. Điều này khá ngạc nhiên đối với tôi, tôi phải nói rằng, bạn sẽ mong đợi hệ thống siêu âm của các máy docker chạy trên một máy cục bộ hoàn hảo có thể truy cập lẫn nhau mà không gặp quá nhiều trở ngại.

Giải thích cho điều này được mô tả chi tiết trong tài liệu sau đây.

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

Hai cách giải quyết nhanh được đưa ra giúp bạn di chuyển bằng cách hạ thấp bảo mật mạng.

Cách thay thế đơn giản nhất là tắt tường lửa - hoặc cho phép tất cả. Điều này có nghĩa là chạy lệnh cần thiết, có thể là systemctl dừng tường lửa, iptables -F hoặc tương đương.

Hi vọng thông tin này sẽ giúp bạn.


3
Cũng như một ghi chú, --linkhiện không được chấp nhận
Mr.Budris

0

Đối với tôi (Windows 10, Docker Engine v19.03.8), đó là sự pha trộn của https://stackoverflow.com/a/43541732/7924573https://stackoverflow.com/a/50866007/7924573 .

  1. thay đổi máy chủ / ip thành host.docker.iternal,
    ví dụ: LOGGER_URL = " http: //host.docker.i INTERNal: 8085 / log "
  2. đặt network_mode thành cầu nối (nếu bạn muốn duy trì chuyển tiếp cổng; nếu không sử dụng máy chủ ):
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge hoặc cách khác: Sử dụng --net="bridge"nếu bạn không sử dụng docker-compose (tương tự https://stackoverflow.com/a/48806927/7924573 )
    Như đã chỉ ra trong các câu trả lời trước: Điều này chỉ nên được sử dụng trong môi trường phát triển địa phương .
    Để biết thêm thông tin, hãy đọc: https://docs.docker.com/compose/compose-file/#network_modehttps://docs.docker.com/docker-for-windows/networking/#use-case-and-workaround
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.