遇到的问题
现在有三台机器:
- prometheus-server所在机器 [记作host1]
- VPN机器 [记作host2]
- 远程机器 [记作host3]
现在远程机器上面有node-exporter,需要采集远程机器上面的信息,可是prometheus这台机器不能直接访问远程机器的9100端口(没有开9100端口转发权限),只能ssh到那台机器上面(ssh也是通过VPN转发到远程机器上面)。需求是要把远程机器的信息通过prometheus采集到prometheus-server机器上面。
解决办法
通过ssh的端口转发可以做到
具体步骤
- 保证可以ssh到远程机器上面:
ssh user_name@host3
- 在prometheus-server机器(host1)上面输入下面的命令或者使用 runit or Supervisor来管理这个转发:
ssh -NL *:local_port:localhost:9100 user_name@host3
这条命令的意思是:
转发 host1上面的local_port端口到host3上面的9100端口
- 如果上面的步骤好了的话,可以访问相应端口,就可以采集到远程机器的信息了:
curl http://127.0.0.1/local_port/metrics
ssh -N -L选项
可以看到主要的ssh选项就是N和L,在man page里面可以看到这两个选项的详细解释:
-N : Do not execute a remote command. This is useful for just forwarding port(porotocal version 2 only)
-L : Specifies that connections to the given TCP port or Unix socket
on the local (client) host are to be forwarded to the given
host and port, or Unix socket, on the remote side. This works
by allocating a socket to listen to either a TCP port on the
local side, optionally bound to the specified bind_address, or
to a Unix socket. Whenever a connection is made to the local
port or socket, the connection is forwarded over the secure
channel, and a connection is made to either host port hostport,
or the Unix socket remote_socket, from the remote machine.
-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
-N选项很好理解:只是不执行远程命令而已
-L选项才是重点:可以看到他设置的形式:
[bind_address:]port:host:hostport
bind_address是本地的主机,port是本地的端口,host是远程的主机,hostport是远程的端口。
在man page的描述中我们也可以看到这个选项的作用:在本地的地址上面(可能有多块网卡之类的情况,可以指定地址)起一个socket监听port端口,任何向这个本地端口发送的tcp请求都会通过ssh转发到远程机器的hostport端口上面。
好了,到这里应该就可以很清晰地知道整个http请求的路径了:
- prometheus-server scrap target : Prometheus-Server会定时地发送http请求到target:这里的target为 host1:local_port
- 因为ssh已经起了一个程序在监听host1:local_port,那么这个请求就会被转发到host3:9100上面,实现了采集
- 再次通过ssh转发metrics信息到Prometheus-Server这边。
额外选项
其实还有一个-R选项,这是远程端口转发
-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket
-R [bind_address:]port
Specifies that connections to the given TCP port or Unix socket
on the remote (server) host are to be forwarded to the local
side.
This works by allocating a socket to listen to either a TCP
port or to a Unix socket on the remote side. Whenever a con‐
nection is made to this port or Unix socket, the connection is
forwarded over the secure channel, and a connection is made
from the local machine to either an explicit destination speci‐
fied by host port hostport, or local_socket, or, if no explicit
destination was specified, ssh will act as a SOCKS 4/5 proxy
and forward connections to the destinations requested by the
remote SOCKS client.
可以看到这个选项跟-L选项是反过来的,是把远程机器的请求转发到本地的机器上面。
两个选项可以理解成:从左往右转发,和从右往左转发,这样就好理解了。
在host2上面执行这条命令:
ssh -R :port1:host2:port2 host3
就相当于把 host3 的 port1 端口 转发到 host2 上面的 port2端口,这条命令会在host3上面创建一个监听套接字,绑定端口port1,之后所有访问 host3:port1的请求都会被转发到host2:port2上面。
记忆
形式:
ssh -Nf *:port1:host2:port2 user@host3 -p port3
- 如果是-L选项的话:在执行命令的机器上面会起一个port1端口,可以访问host2:port2
- 如果是-R选项的话:在host3上面会起一个port1端口,可以通过host2:port2访问host3:port1
GatewayPorts 参数
这个参数默认值是no,代表在设置端口转发的时候,如果bind_address设置是空或者*的话,不会绑定到所有的网络接口上面只会绑定到环回接口上面,如果这个参数设置成yes的话,那么端口转发的时候可以绑定到所有的端口上
netstat -nao
设置成no:
127.0.0.1:port .....
设置成yes
0.0.0.0:port
因为在云主机上面,不一定能转发到环回接口上面, 所以需要绑定到任意接口上面,所以这个参数必须设置成yes