简体   繁体   English

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

[英]access host's ssh tunnel from docker container

Using ubuntu tusty, there is a service running on a remote machine, that I can access via port forwarding through an ssh tunnel from localhost:9999 .使用 ubuntu tusty,有一个在远程机器上运行的服务,我可以通过来自localhost:9999的 ssh 隧道通过端口转发进行访问。

I have a docker container running.我有一个 docker 容器正在运行。 I need to access that remote service via the host's tunnel, from within the container.我需要从容器内通过主机的隧道访问该远程服务。

I tried tunneling from the container to the host with -L 9000:host-ip:9999 , then accessing the service through 127.0.0.1:9000 from within the container fails to connect.我尝试使用-L 9000:host-ip:9999从容器隧道到主机,然后从容器内通过127.0.0.1:9000访问服务无法连接。 To check wether the port mapping was on, I tried nc -luv -p 9999 # at host nc -luv -p 9000 # at container为了检查端口映射是否打开,我尝试了nc -luv -p 9999 # at host nc -luv -p 9000 # at container

following this, parag.此之后,第。 2 but there was no perceived communication, even when doing nc -luv host-ip -p 9000 at the container 2但没有感知到通信,即使在容器上执行nc -luv host-ip -p 9000

I also tried mapping the ports via docker run -p 9999:9000 , but this reports that the bind failed because the host port is already in use (from the host tunnel to the remote machine, presumably).我还尝试通过docker run -p 9999:9000映射端口,但这报告绑定失败,因为主机端口已在使用中(大概是从主机隧道到远程机器)。

So my questions are所以我的问题是

1 - How will I achieve the connection? 1 - 我将如何实现连接? Do I need to setup an ssh tunnel to the host, or can this be achieved with the docker port mapping alone?我是否需要设置到主机的 ssh 隧道,或者可以单独使用 docker 端口映射来实现?

2 - What's a quick way to test that the connection is up? 2 - 测试连接是否正常的快速方法是什么? Via bash, preferably.通过 bash,最好。

Thanks.谢谢。

Using your hosts network as network for your containers via --net=host or in docker-compose via network_mode: host is one option but this has the unwanted side effect that (a) you now expose the container ports in your host system and (b) that you cannot connect to those containers anymore that are not mapped to your host network.通过--net=host或在--net=host -compose 中通过network_mode: host使用您的主机网络作为容器的网络network_mode: host是一种选择,但这会产生不必要的副作用,即 (a) 您现在公开主机系统中的容器端口和 ( b) 您无法再连接到那些未映射到您的主机网络的容器。

In your case, a quick and cleaner solution would be to make your ssh tunnel "available" to your docker containers (eg by binding ssh to the docker0 bridge) instead of exposing your docker containers in your host environment (as suggested in the accepted answer).在你的情况下,一个快速和更干净的解决方案是让你的 ssh 隧道对你的docker0容器“可用”(例如,通过将 ssh 绑定到docker0桥)而不是在你的主机环境中公开你的docker0容器(如已接受的答案中所建议的那样) )。

Setting up the tunnel:设置隧道:

For this to work, retrieve the ip your docker0 bridge is using via:为此,请通过以下方式检索docker0网桥正在使用的 IP:

ifconfig

you will see something like this:你会看到这样的事情:

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

Now you need to tell ssh to bind to this ip to listen for traffic directed towards port 9000 via现在你需要告诉 ssh绑定到这个 ip来监听通过端口 9000 的流量

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

Without setting the bind_address , :9000 would only be available to your host's loopback interface and not per se to your docker containers.如果不设置bind_address:9000可用于您主机的环回接口,而不能用于您的 docker 容器。

Side note: You could also bind your tunnel to 0.0.0.0 , which will make ssh listen to all interfaces.旁注:您还可以将隧道绑定到0.0.0.0 ,这将使 ssh 侦听所有接口。

Setting up your application:设置您的应用程序:

In your containerized application use the same docker0 ip to connect to the server: 172.17.0.1:9000 .在您的容器化应用程序中,使用相同的docker0 ip 连接到服务器: 172.17.0.1:9000 Now traffic being routed through your docker0 bridge will also reach your ssh tunnel :)现在,通过您的docker0网桥路由的流量也将到达您的 ssh 隧道 :)

For example, if you have a "DOT.NET Core" application that needs to connect to a remote db located at :9000 , your "ConnectionString" would contain "server=172.17.0.1,9000; .例如,如果您有一个“DOT.NET Core”应用程序需要连接到位于:9000的远程数据库,则您的“ConnectionString”将包含"server=172.17.0.1,9000;

Forwarding multiple connections:转发多个连接:

When dealing with multiple outgoing connections (eg a docker container needs to connect to multiple remote DB's via tunnel), several valid techniques exist but an easy and straightforward way is to simply create multiple tunnels listening to traffic arriving at different docker0 bridge ports.在处理多个传出连接时(例如,一个 docker 容器需要通过隧道连接到多个远程数据库),存在几种有效的技术,但一个简单而直接的方法是简单地创建多个隧道,监听到达不同docker0桥端口的流量。

Within your ssh tunnel command ( ssh -L [bind_address:]port:host:hostport] [user@]hostname ), the port part of the bind_address does not have to match the hostport of the host and, therefore, can be freely chosen by you.内你的ssh隧道命令( ssh -L [bind_address:]port:host:hostport] [user@]hostname ),所述port的一部分bind_address不必匹配hostport所述的host ,并且因此,可以自由选择由你。 So within your docker containers just channel the traffic to different ports of your docker0 bridge and then create several ssh tunnel commands (one for each port you are listening to) that intercept data at these ports and then forward it to the different host s and hostport s of your choice.因此,在您的 docker 容器中,只需将流量引导至docker0网桥的不同端口,然后创建多个 ssh 隧道命令(您正在侦听的每个端口一个),这些命令在这些端口拦截数据,然后将其转发到不同的hosthost hostport您的选择。

on MacOS (tested in v19.03.2 ),在 MacOS 上(在v19.03.2测试),

1) create a tunnel on host 1)在主机上创建隧道

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

2) from container, you can use host.docker.internal or docker.for.mac.localhost or docker.for.mac.host.internal to reference host. 2) 从容器中,您可以使用host.docker.internaldocker.for.mac.localhostdocker.for.mac.host.internal来引用主机。

example,例如,

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

note from docker-for-mac official doc来自 docker-for-mac 官方文档的说明

I WANT TO CONNECT FROM A CONTAINER TO A SERVICE ON THE HOST我想从容器连接到主机上的服务

The host has a changing IP address (or none if you have no network access).主机有一个不断变化的 IP 地址(如果您没有网络访问权限,则没有)。 From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal , which resolves to the internal IP address used by the host.从 18.03 开始​​,我们的建议是连接到特殊的 DNS 名称host.docker.internal ,该名称解析为主机使用的内部 IP 地址。 This is for development purpose and will not work in a production environment outside of Docker Desktop for Mac.这是出于开发目的,不适用于 Docker Desktop for Mac 之外的生产环境。

The gateway is also reachable as gateway.docker.internal .网关也可以作为gateway.docker.internal访问。

I think you can do it by adding --net=host to your docker run.我认为您可以通过将--net=host添加到您的--net=host run 来实现。 But see also this question: Forward host port to docker container但另请参见这个问题:将主机端口转发到 docker 容器

I'd like to share my solution to this.我想分享我的解决方案。 My case was as follows: I had a PostgreSQL SSH tunnel on my host and I needed one of my containers from the stack to connect to a database through it.我的情况如下:我的主机上有一个 PostgreSQL SSH 隧道,我需要堆栈中的一个容器通过它连接到数据库。

I spent hours trying to find a solution (Ubuntu + Docker 19.03) and I failed.我花了几个小时试图找到解决方案(Ubuntu + Docker 19.03),但失败了。 Instead of doing voodoo magic with iptables , doing modifications to the settings of the Docker engine itself I came up with a solution and was shocked I didn't thought of this earlier.我没有用iptables做巫术魔法,而是对 Docker 引擎本身的设置进行修改,我想出了一个解决方案,但很震惊我之前没有想到这一点。 The most important thing was I didn't want to use the host mode: security first.最重要的是我不想使用host模式:安全第一。

Instead of trying to allow a container to talk to the host, I simply added another service to the stack, which would create the tunnel, so other containers could talk to easily without any hacks.我没有试图让容器与主机通信,而是简单地向堆栈添加了另一个服务,这将创建隧道,因此其他容器可以轻松地进行通信而无需任何黑客攻击。

After configuring a host inside my ~/.ssh/config :在我的~/.ssh/config配置主机后:

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

And adding a service to the stack:并向堆栈添加服务:

  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

The PHP container started talking through the tunnel without any problems: PHP 容器开始通过隧道通信,没有任何问题:

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

Just remember to put your public key inside that host if you haven't already:如果您还没有,请记住将您的公钥放入该主机中:

ssh-copy-id project-postgres-tunnel

I'm pretty sure this will work regardless of the OS used (MacOS / Linux).我很确定无论使用什么操作系统(MacOS / Linux),这都可以工作。

My 2 cents for Ubuntu 18.04 - a very simple answer, no need for extra tunnels, extra containers, extra docker options or exposing host.我的 Ubuntu 18.04 2 美分 - 一个非常简单的答案,不需要额外的隧道、额外的容器、额外的 docker 选项或暴露主机。

Simply, when creating a reverse tunnel make sure ssh binds to all interfaces as, by default, it binds ports of the reverse tunnel to localhost only.简单地说,在创建反向隧道时,请确保 ssh 绑定到所有接口,因为默认情况下,它仅将反向隧道的端口绑定到 localhost。 For example, in putty make sure that option Connection->SSH->Tunnels Remote ports do the same (SSH-2 only) is ticked.例如,在 putty 中确保勾选选项 Connection->SSH->Tunnels Remote ports do the same (SSH-2 only) This is more or less equivalent to specifying the binding address 0.0.0.0 for the remote part of the tunnel (more details here ):这或多或少相当于为隧道的远程部分指定绑定地址0.0.0.0 (更多详细信息在这里):

-R [bind_address:]port:host:hostport

However, this did not work for me unless I allowed the GatewayPorts option in my sshd server configuration.但是,除非我在 sshd 服务器配置中允许GatewayPorts选项,否则这对我GatewayPorts Many thanks to Stefan Seidel for his great answer .非常感谢 Stefan Seidel 的出色回答

In short: (1) you bind the reverse tunnel to 0.0.0.0, (2) you let the sshd server to accept such tunnels.简而言之:(1)您将反向隧道绑定到 0.0.0.0,(2)您让 sshd 服务器接受此类隧道。

Once this is done I can access my remote server from my docker containers via the docker gateway 172.17.0.1 and port bound to the host.完成此操作后,我可以通过 docker 网关172.17.0.1和绑定到主机的端口从我的 docker 容器访问我的远程服务器。

I agree with @hlobit that @B12Toaster answer should be the accepted answer.我同意@hlobit 的观点,@B12Toaster 的答案应该是公认的答案。

In case anyone hits this problem but with a slightly different setup with the SSH tunnel, here are my findings.如果有人遇到此问题,但 SSH 隧道的设置略有不同,以下是我的发现。 In my case, instead of creating a tunnel from Docker host machine to remote machine using ssh -L , I was creating remote forward SSH tunnel from remote machine to Docker host machine using ssh -L .在我的情况,而不是使用创建从码头工人主机隧道到远程机器ssh -L ,我用的是从创建远程机器遥控前进SSH隧道来泊坞主机ssh -L

In this setup, by default sshd does NOT allow gateway ports, ie in file /etc/ssh/sshd_config on Docker host, the GatewayPorts no should be uncommented and set to GatewayPorts yes or GatewayPorts clientspecified .在这种设置中,默认的sshd不允许网关端口,即文件/etc/ssh/sshd_config泊坞主机上,在GatewayPorts no应该取消注释并设置为GatewayPorts yesGatewayPorts clientspecified I configured GatewayPorts clientspecified and configured the remote forward SSH tunnel by ssh -L 172.17.0.1:dockerHostPort:localhost:sshClientPort user@dockerHost .我配置了GatewayPorts clientspecified并通过ssh -L 172.17.0.1:dockerHostPort:localhost:sshClientPort user@dockerHost配置了远程转发 SSH 隧道。 Remember to restart sshd after changing /etc/ssh/sshd_config ( sudo systemctl restart sshd ).请记住在更改/etc/ssh/sshd_config ( sudo systemctl restart sshd ) 后sudo systemctl restart sshd

Your Docker container should be able to connect to Docker host on 172.17.0.1:dockerHostPort and this in turn gets tunnelled back to SSH client's localhost:sshClientPort .您的 Docker 容器应该能够连接到172.17.0.1:dockerHostPort上的 Docker 主机,这反过来又会通过隧道返回到 SSH 客户端的localhost:sshClientPort

References:参考资料:

On my side, running Docker in Windows Subsystem for Linux (WSL v1), I couldn't use docker0 connection approach.在我这边,在 Windows Subsystem for Linux (WSL v1) 中运行 Docker,我无法使用 docker0 连接方法。 host.docker.internal also doesn't resolve (latest docker version). host.docker.internal也无法解析(最新的host.docker.internal版本)。

However, I found out I could directly use the host-ip insider my docker container.但是,我发现我可以直接使用我的 docker 容器内的 host-ip。

  1. Get your Host IP (Windows cmd: ipconfig ), eg 192.168.0.5获取您的主机 IP (Windows cmd: ipconfig ),例如192.168.0.5
  2. Bash into your Container and test if you can ping your host ip: Bash 进入您的容器并测试您是否可以 ping 您的主机 IP:
    - docker exec -it d6b4be5b20f7 /bin/bash - docker exec -it d6b4be5b20f7 /bin/bash
    - apt-get update && apt-get install iputils-ping - apt-get update && apt-get install iputils-ping
    - ping 192.168.0.5 - 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

Apparently, in Windows, you can directly connect from within containers to the host using the official host ip.显然,在 Windows 中,您可以使用官方主机 ip 从容器内直接连接到主机。

In case anyone needs it (like I did), solution for Windows and WSL is same as @prayagupd mentioned for Mac OS如果有人需要它(就像我一样),Windows 和 WSL 的解决方案与针对 Mac OS 提到的 @prayagupd 相同

Create an SSH tunnel to your remote service with whatever tool you prefer to whatever port you prefer, for example 3300.使用您喜欢的任何工具创建到您的远程服务的 SSH 隧道,以及您喜欢的任何端口,例如 3300。

Then, from Docker container you can connect to, for example, MySQL DB on tunnel port 3300 using following command:然后,您可以使用以下命令从 Docker 容器连接到隧道端口 3300 上的 MySQL 数据库:

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

An easy example to reproduce the situation and ssh to host一个简单的例子来重现情况和 ssh 到主机

  1. Run a container.运行一个容器。 Use --network="host使用--network="host
docker container run --network="host" --interactive --tty --rm ubuntu bash
  1. Now you can access your host using localhost现在您可以使用localhost访问您的主机
    Now your host machine is a Linux machine that has a public-private key file to ssh into it.现在你的主机是一台 Linux 机器,它有一个公私密钥文件可以通过 ssh 进入它。 So copy the contents of your private key file and reproduce the key file inside your host.因此,复制您的私钥文件的内容并在您的主机内复制该密钥文件。 (However, this is just a demonstration. This is not a good way to copy key files) (不过,这只是一个演示。这不是复制关键文件的好方法)
  2. Now ssh into your host.现在通过 ssh 进入您的主机。 Use localhost to access it.使用localhost访问它。
ssh -i key_file.pem ec2-user@localhost

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM