将主机端口转发到docker容器

2024-10-12 10:28:00
admin
原创
77
摘要:问题描述:主机是否可以打开 Docker 容器访问端口?具体来说,我在主机上运行了 MongoDB 和 RabbitMQ,我想在 Docker 容器中运行一个进程来监听队列并(可选)写入数据库。我知道我可以将端口从容器转发到主机(通过 -p 选项)并从 Docker 容器内部连接到外界(即互联网),但我不想将...

问题描述:

主机是否可以打开 Docker 容器访问端口?具体来说,我在主机上运行了 MongoDB 和 RabbitMQ,我想在 Docker 容器中运行一个进程来监听队列并(可选)写入数据库。

我知道我可以将端口从容器转发到主机(通过 -p 选项)并从 Docker 容器内部连接到外界(即互联网),但我不想将 RabbitMQ 和 MongoDB 端口从主机暴露到外界。

编辑:一些澄清:

Starting Nmap 5.21 ( http://nmap.org ) at 2013-07-22 22:39 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00027s latency).
PORT     STATE SERVICE
6311/tcp open  unknown

joelkuiper@vps20528 ~ % docker run -i -t base /bin/bash
root@f043b4b235a7:/# apt-get install nmap
root@f043b4b235a7:/# nmap 172.16.42.1 -p 6311 # IP found via docker inspect -> gateway

Starting Nmap 6.00 ( http://nmap.org ) at 2013-07-22 20:43 UTC
Nmap scan report for 172.16.42.1
Host is up (0.000060s latency).
PORT     STATE    SERVICE
6311/tcp filtered unknown
MAC Address: E2:69:9C:11:42:65 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 13.31 seconds

我必须使用这个技巧才能在容器内建立任何互联网连接:我的防火墙阻止了从 docker 容器到外部的网络连接

编辑:最终,我决定使用管道创建自定义桥接,并让服务监听桥接 IP。我采用这种方法,而不是让 MongoDB 和 RabbitMQ 监听 docker 桥接,因为它提供了更大的灵活性。


解决方案 1:

一种简单但相对不安全的方法是使用--net=host选项docker run

此选项使容器使用主机的网络堆栈。然后,您只需使用“localhost”作为主机名即可连接到主机上运行的服务。

这更容易配置,因为您不必配置服务来接受来自您的 docker 容器的 IP 地址的连接,也不必告诉 docker 容器要连接的特定 IP 地址或主机名,只需一个端口即可。

例如,您可以通过运行以下命令进行测试,该命令假设您的映像名为my_image,您的映像包含telnet实用程序,并且您要连接的服务位于端口 25 上:

docker run --rm -i -t --net=host my_image telnet localhost 25

如果您考虑这样做,请参阅此页面上的安全警告:

https://docs.docker.com/articles/networking/

它说:

--net=host -- 告诉 Docker 跳过将容器放置在单独的网络堆栈内的步骤。本质上,这个选择告诉 Docker 不要将容器的网络容器化!虽然容器进程仍将局限于它们自己的文件系统和进程列表以及资源限制,但快速 ip addr 命令将向您显示,从网络角度来看,它们位于主 Docker 主机的“外部”,并可以完全访问其网络接口。请注意,这不允许容器重新配置主机网络堆栈(这需要 --privileged=true),但它允许容器进程像任何其他根进程一样打开低编号端口。它还允许容器访问本地网络服务,如 D-bus。这可能导致容器中的进程能够执行意外操作,如重启计算机。您应该谨慎使用此选项。

解决方案 2:

您的 docker 主机向所有容器公开一个适配器。假设您使用的是最新的 ubuntu,您可以运行

ip addr

这将为您提供网络适配器列表,其中一个看起来像

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 22:23:6b:28:6b:e0 brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
inet6 fe80::a402:65ff:fe86:bba6/64 scope link
   valid_lft forever preferred_lft forever

您需要告诉 rabbit/mongo 绑定到该 IP (172.17.42.1)。之后,您应该能够从容器内打开到 172.17.42.1 的连接。

解决方案 3:

正如其中一条评论所述,这适用于 Mac(可能也适用于 Windows/Linux):

我想从容器连接到主机上的服务

主机具有不断变化的 IP 地址(如果您没有网络访问权限,则没有)。我们建议您连接到特殊的 DNS 名称host.docker.internal,该名称解析为主机使用的内部 IP 地址。这是为了开发目的,不适用于 Docker Desktop for Mac 之外的生产环境。

您还可以使用 到达网关gateway.docker.internal

引自https://docs.docker.com/docker-for-mac/networking/

这对我来说很有效,无需使用--net=host

解决方案 4:

您还可以创建一个 ssh 隧道。

docker-compose.yml

---

version: '2'

services:
  kibana:
    image: "kibana:4.5.1"
    links:
      - elasticsearch
    volumes:
      - ./config/kibana:/opt/kibana/config:ro

  elasticsearch:
    build:
      context: .
      dockerfile: ./docker/Dockerfile.tunnel
    entrypoint: ssh
    command: "-N elasticsearch -L 0.0.0.0:9200:localhost:9200"

docker/Dockerfile.tunnel

FROM buildpack-deps:jessie

RUN apt-get update && \ n    DEBIAN_FRONTEND=noninteractive \ n    apt-get -y install ssh && \ n    apt-get clean && \ n    rm -rf /var/lib/apt/lists/*

COPY ./config/ssh/id_rsa /root/.ssh/id_rsa
COPY ./config/ssh/config /root/.ssh/config
COPY ./config/ssh/known_hosts /root/.ssh/known_hosts
RUN chmod 600 /root/.ssh/id_rsa && \ n    chmod 600 /root/.ssh/config && \ n    chown $USER:$USER -R /root/.ssh

config/ssh/config

# Elasticsearch Server
Host elasticsearch
    HostName jump.host.czerasz.com
    User czerasz
    ForwardAgent yes
    IdentityFile ~/.ssh/id_rsa

这样,elasticsearch就有一个到正在运行服务(Elasticsearch、MongoDB、PostgreSQL)的服务器的隧道,并通过该服务公开端口 9200。

解决方案 5:

TLDR;

仅对于本地开发,请执行以下操作:

  1. 在您的笔记本电脑/计算机/PC/Mac 上启动服务或 SSH 隧道。

  2. 构建/运行 Docker 镜像/容器以连接到主机名host.docker.internal:<hostPort>

注意:还有gateway.docker.internal,我还没有尝试过。

结束_TLDR;

例如,如果您在容器中使用它:

PGPASSWORD=password psql -h localhost -p 5432 -d mydb -U myuser

将其更改为:

PGPASSWORD=password psql -h host.docker.internal -p 5432 -d mydb -U myuser

这神奇地连接到了主机上运行的服务。您不需要使用--net=host-p "hostPort:ContainerPort"-P

背景

有关详细信息,请参阅: https: //docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

我使用它通过 SSH 隧道连接到 Windows 10 上的 AWS RDS Postgres 实例。我只需要将从localhost:containerPort在容器中使用更改为host.docker.internal:hostPort

解决方案 6:

我在从docker容器访问LDAP服务器时遇到了类似的问题。我为容器设置了一个固定IP并添加了防火墙规则。

docker-compose.yml:

version: '2'
services:
  containerName:
    image: dockerImageName:latest
    extra_hosts:
      - "dockerhost:192.168.50.1"
    networks:
      my_net:
        ipv4_address: 192.168.50.2
networks:
  my_net:
    ipam:
      config:
      - subnet: 192.168.50.0/24

iptables 规则:

iptables -A INPUT -j ACCEPT -p tcp -s 192.168.50.2 -d $192.168.50.1 --dport portnumberOnHost

容器内部访问dockerhost:portnumberOnHost

解决方案 7:

现在所有平台下更简单的方法是使用host.docker.internal。让我们首先从 Docker 运行命令开始:

docker run --add-host=host.docker.internal:host-gateway [....]

或者在使用 Docker Compose 时将以下内容添加到您的服务中:

extra_hosts:
  - "host.docker.internal:host-gateway"

此类 Docker Compose 文件的完整示例应如下所示:

version: "3"
services:
  your_service:
    image: username/docker_image_name
    restart: always
    networks:
      - your_bridge_network
    volumes:
      - /home/user/test.json:/app/test.json
    ports:
      - "8080:80"
    extra_hosts:
      - "host.docker.internal:host-gateway"

networks:
  your_bridge_network:

再次强调,这只是一个例子。但是如果这个 docker 镜像将在端口 80 上启动服务,它将在端口 8080 上的主机上可用。

对于您的用例来说,更重要的是;如果 Docker 容器想要使用主机系统中的服务,现在可以使用特殊host.docker.internal名称。该名称将自动解析为内部 Docker IP 地址(docker0接口的)。

无论如何,假设...您还在主机上运行 Web 服务(端口 80)。您现在应该能够在 Docker 容器访问该服务。试试看:nc -vz host.docker.internal 80

全部无需使用network_mode: "host"

解决方案 8:

host.docker.internal或者gateway.docker.internal通常对 docker mac 桌面容器来说效果很好,但对于kafka来说也会失败,因为 kafka 在设置的接受监听器方面非常吝啬。

我通过运行 socat 将容器内的 9092 端口转发到主机来绕过这个问题

apt-get install -y socat && socat tcp-l:9092,fork tcp:host.docker.internal:9092 &

基本上,我有 1 个运行 kafka 的容器,还有另一个需要连接到 kafka 的应用容器。将应用容器 kafka 代理设置为["host.docker.internal:9092"]不起作用。因此,我将 kafka 代理设置为["localhost:9092"],并使用socat将端口转发到主机,该主机与 kafka 容器具有端口转发功能。

经过多次尝试和错误,我找到了这个解决方案。希望这对大家有帮助!

解决方案 9:

我不确定我是否回答了正确的问题,但如果您需要允许通过 ssh 隧道从容器内部访问远程服务,则可以这样做:

使用 ssh 连接并创建如下隧道(注意开头的 0.0.0.0),假设远程主机上的服务可通过端口 8081 访问:

ssh ubuntu@remoteIp -L 0.0.0.0:8080:localhost:8081

这将允许任何具有(网络)访问您计算机权限的人连接到端口 8080,从而访问所连接服务器上的端口 8081。

然后,在容器内部只需使用“host.docker.internal”,例如:

curl host.docker.internal:8081

解决方案 10:

如果 MongoDB 和 RabbitMQ 在主机上运行,​​那么端口应该已经暴露,因为它不在 Docker 内。

您不需要该-p选项即可将容器中的端口暴露给主机。默认情况下,所有端口均暴露。该-p选项允许您将容器中的端口暴露给主机外部。

-p所以,我猜你根本不需要它,而且它应该可以正常工作:)

解决方案 11:

为什么不使用稍微不同的解决方案,像这样?

services:
  kubefwd:
    image: txn2/kubefwd
    command: ...
  app:
    image: bash
    command:
     - sleep
     - inf
    init: true
    network_mode: service:kubefwd

REF: txn2/kubefwd:用于本地开发的批量端口转发 Kubernetes 服务。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用