从docker容器访问主机的ssh隧道

时间:2016-08-25 11:09:58

标签: bash ssh docker netcat ssh-tunnel

使用ubuntu tusty,在远程计算机上运行一项服务,我可以通过localhost:9999的ssh隧道通过端口转发进行访问。

我有一个docker容器正在运行。我需要通过主机的隧道从容器内访问该远程服务。

我尝试使用-L 9000:host-ip:9999从容器隧道传输到主机,然后从容器内通过127.0.0.1:9000访问服务无法连接。为了检查端口映射是否打开,我试过了 nc -luv -p 9999 # at host nc -luv -p 9000 # at container

跟随this, parag. 2,但即使在做的时候也没有感知到的沟通 容器上的 nc -luv host-ip -p 9000

我还尝试通过docker run -p 9999:9000映射端口,但是报告绑定失败,因为主机端口已经在使用中(可能是从主机隧道到远程计算机)。

所以我的问题是

1 - 如何实现连接?我是否需要为主机设置ssh隧道,或者仅通过docker端口映射实现这一点?

2 - 测试连接的快速方法是什么?通过bash,最好是。

感谢。

8 个答案:

答案 0 :(得分:13)

我认为你可以通过在你的docker run中添加--net=host来实现。但另请参阅此问题:Forward host port to docker container

答案 1 :(得分:9)

通过--net=host或通过network_mode: host在docker-compose中将主机网络用作容器的网络是一种选择,但这会带来不想要的副作用,即(a)您现在将容器端口暴露在您的主机系统;(b)您无法再连接到那些未映射到您的主机网络的容器。

对于您而言,一种更快捷,更清洁的解决方案是使ssh隧道可用于主机系统(即docker0网桥),而不是将docker容器暴露在主机环境中(如已接受的建议)答案)。

设置隧道:

为此,请通过以下方式检索您的docker0网桥使用的IP:

ifconfig

您将看到类似这样的内容:

docker0   Link encap:Ethernet  HWaddr 03:41:4a:26:b7:31  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0

现在,您需要告诉ssh bind to this ip来监听通过9000端口定向的流量

ssh -L 172.17.0.1:9000:host-ip:9999

如果不设置 bind_address :9000only可用于主机的环回接口,而本身不适用于Docker容器。

旁注:您还可以将隧道绑定到0.0.0.0,这将使ssh侦听所有接口。

设置您的应用程序:

在您的容器化应用程序中,使用相同的docker0 ip连接到服务器:172.17.0.1:9000。现在,通过docker0网桥路由的流量也将到达ssh隧道:)

例如,如果您有一个“ DOT.NET Core”应用程序需要连接到位于:9000的远程数据库,则您的“ ConnectionString”将包含"server=172.17.0.1,9000;

答案 2 :(得分:3)

在MacOS上(在v19.03.2中进行了测试)

1)在主机上创建隧道

ssh -i key.pem username@jump_server -L 3336:mysql_host:3306 -N

2)从容器中,您可以使用host.docker.internaldocker.for.mac.localhost docker.for.mac.host.internal来引用主机。

示例

mysql -h host.docker.internal -P 3336 -u admin -p

note from docker-for-mac official doc

  

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

     

主机的IP地址正在更改(如果没有网络访问权限,则没有IP地址)。   从18.03开始,我们建议您连接到特殊的DNS   名称host.docker.internal,解析为内部IP地址   由主机使用。 这是出于发展目的,不适用于   用于Mac的Docker Desktop之外的生产环境。

     

网关也可以通过gateway.docker.internal访问。

答案 3 :(得分:2)

我想分享我的解决方案。我的情况如下:我的主机上有一个PostgreSQL SSH隧道,我需要堆栈中的一个容器通过它连接到数据库。

我花了数小时试图找到解决方案(Ubuntu + Docker 19.03),但失败了。与其对newReq, err = http.NewRequest("PUT", signedurl, file) client = &http.Client{} res, err = client.Do(newReq) 进行巫术魔术,不如对Docker引擎本身的设置进行修改,我想出了一个解决方案,但令我震惊的是,我之前没有想到这一点。最重要的是我不想使用iptables模式:安全第一。

我没有尝试允许容器与主机进行通信,而是向堆栈中添加了另一个服务,该服务将创建隧道,因此其他容器可以轻松进行通信,而不会受到黑客攻击。

在我的host中配置主机后:

~/.ssh/config

并将服务添加到堆栈:

Host project-postgres-tunnel
    HostName remote.server.host
    User sshuser
    Port 2200
    ForwardAgent yes
    TCPKeepAlive yes
    ConnectTimeout 5
    ServerAliveCountMax 10
    ServerAliveInterval 15

PHP容器开始通过隧道通信,没有任何问题:

  postgres:
    image: cagataygurturk/docker-ssh-tunnel:0.0.1
    volumes:
      - $HOME/.ssh:/root/ssh:ro
    environment:
      TUNNEL_HOST: project-postgres-tunnel
      REMOTE_HOST: localhost
      LOCAL_PORT: 5432
      REMOTE_PORT: 5432
    # uncomment if you wish to access the tunnel on the host
    #ports:
    #  - 5432:5432

请记住,如果尚未将公钥放入该主机中,则:

postgresql://user:password@postgres/db?serverVersion=11&charset=utf8

我非常确定,无论使用哪种操作系统(MacOS / Linux),它都能正常工作。

答案 4 :(得分:1)

我对Ubuntu 18.04的2美分-一个非常简单的答案,不需要额外的隧道,额外的容器,额外的docker选项或暴露主机。

简单来说,在创建反向隧道时,请确保ssh绑定到所有接口,因为默认情况下,它将仅将反向隧道的端口绑定到localhost。例如,在腻子中,确保已选中选项Connection-> SSH-> Tunnels Remote ports do the same (SSH-2 only)。 这或多或少等同于为隧道的远程部分指定绑定地址0.0.0.0(更多详细信息here):

-R [bind_address:]port:host:hostport

但是,这对我不起作用,除非我允许,我的sshd服务器配置中的GatewayPorts选项。非常感谢Stefan Seidel出色的answer

简而言之:(1)将反向隧道绑定到0.0.0.0,(2)让sshd服务器接受此类隧道。

完成此操作后,我可以通过docker网关172.17.0.1和绑定到主机的端口从docker容器访问我的远程服务器。

答案 5 :(得分:1)

我同意@hlobit的观点,即@ B12Toaster答案应该是公认的答案。

万一有人遇到此问题,但在SSH隧道上的设置稍有不同,这是我的发现。就我而言,不是使用ssh -L创建从Docker主机到远程计算机的隧道,而是使用ssh -L创建了从远程计算机到Docker主机的远程转发SSH隧道。

在此设置中,默认情况下sshd不允许网关端口,即,在Docker主机上的文件/etc/ssh/sshd_config中,GatewayPorts no应当不加注释并设置为GatewayPorts yes或{{1} }。我配置了GatewayPorts clientspecified,并通过GatewayPorts clientspecified配置了远程转发SSH隧道。记住在更改ssh -L 172.17.0.1:dockerHostPort:localhost:sshClientPort user@dockerHost/etc/ssh/sshd_config)之后重新启动sshd。

您的Docker容器应该能够连接到sudo systemctl restart sshd上的Docker主机,这反过来又被隧穿回SSH客户端的172.17.0.1:dockerHostPort

参考:

答案 6 :(得分:0)

在我这方面,在Linux的Windows子系统(WSL v1)中运行Docker,我无法使用docker0连接方法。 host.docker.internal也无法解析(最新的docker版本)。

但是,我发现我可以直接在docker容器中使用host-ip内部人员。

  1. 获取您的主机IP(Windows cmd:ipconfig),例如192.168.0.5
  2. 扑向您的容器并测试是否可以ping您的主机ip:
    -docker exec -it d6b4be5b20f7 /bin/bash
    -apt-get update && apt-get install iputils-ping
    -ping 192.168.0.5
PING 192.168.0.5  (192.168.0.5) 56(84) bytes of data.
64 bytes from 192.168.0.5 : icmp_seq=1 ttl=37 time=2.17 ms
64 bytes from 192.168.0.5 : icmp_seq=2 ttl=37 time=1.44 ms
64 bytes from 192.168.0.5 : icmp_seq=3 ttl=37 time=1.68 ms

显然,在Windows中,您可以使用官方主机ip直接从容器内连接到主机。

答案 7 :(得分:0)

万一有人需要(就像我一样),Windows和WSL的解决方案与Mac OS提到的@prayagupd相同

使用您喜欢的工具或端口(例如3300)创建到远程服务的SSH隧道。

然后,您可以使用以下命令从Docker容器连接到隧道端口3300上的MySQL DB:

mysql -u user -p -h host.docker.internal -P 3300