将主机端口转发到docker容器
- 2024-10-12 10:28:00
- admin 原创
- 77
问题描述:
主机是否可以打开 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;
仅对于本地开发,请执行以下操作:
在您的笔记本电脑/计算机/PC/Mac 上启动服务或 SSH 隧道。
构建/运行 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 服务。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件