集装箱港口转发
Posted
技术标签:
【中文标题】集装箱港口转发【英文标题】:Container port forwarding 【发布时间】:2019-09-19 11:19:05 【问题描述】:我有一个监听端口 3000
的二进制文件,但是,Google Cloud Run 希望我监听 $PORT
定义的端口,默认为 8080
。
有没有办法让我的容器绑定到 8080,然后将传入的请求转发到 3000?例如,通过向我的Dockerfile
添加一个简短的脚本和一行,它会使我的容器在 8080 上侦听并转发到我的二进制文件。
【问题讨论】:
您不能将您的应用程序修改为默认为 3000,但如果定义了 $PORT 则使用该端口代替吗? @codestation 问题指出这是一个二进制文件,大概是OP无法更改端口。 @dustin-ingram 是正确的。PORT
环境变量在 Cloud Run 中由系统指定。解决方案确实需要确保容器接受服务指定的任何PORT
值的流量;只是目前这始终是8080
,但这并不坚定。
【参考方案1】:
下面的代码未经测试,但大致思路是这样的:
-
使用基于 shell 的启动脚本
启用 iptables
将流量从 srcPort 路由到 dstPort
执行原始二进制文件
在 Dockerfile 中,将 ENTRYPOINT
替换为启动脚本:
FROM debian:9 # or another container that has iptables available
RUN apt-get install iptables
EXPOSE 8080
ENTRYPOINT /bin/startup.sh /bin/original
然后编写一个启动脚本,启用iptables并将容器内8080上的入站流量转发到3000:
#!/usr/bin/env bash
set -e
sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
sysctl -p
systemctl start iptables
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j REDIRECT --to-port 3000
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 8080 -j REDIRECT --to-port 3000
unshift
exec "$@"
【讨论】:
不幸的是,脚本失败了。 (1)debian:9
不包括 sysctl
但 debian:8
包括; (2)我认为(!?)如果既不以--privileged
运行容器也不使用--sysctl=net.ipv4.ip_forward=1
(他不能在Cloud Run 上),你不能在容器内修改net.ipv4.ip_forward
; (3) 您想在安装前使用sudo apt-get update && sudo apt-get -y install iptables
刷新软件包。 @steren -- 希望您有 FR 允许在 Cloud Run 中进行端口转发|发布 ;-)【参考方案2】:
如果您可以安装运行第二个进程并在主进程中启动它,则使用以下命令安装并运行 socat:
socat tcp-listen:8080,fork,reuseaddr tcp-connect:localhost:3000
这样,socat 将绑定到 8080 端口并将所有流量发送到您的二进制文件正在侦听的端口 3000。
在 Cloud Run 之外:如果您无法触摸映像或容器,那么您仍然可以在其他容器上运行 socat,例如:
version: '3.5'
services:
proxy:
image: alpine/socat:1.0.3
command: tcp-listen:8080,fork,reuseaddr tcp-connect:myservice:3000
networks:
- mynet
networks:
mynet:
external: true
mynet
是运行二进制文件的网络,myservice
是二进制文件的服务名称。
【讨论】:
您是否在 Google Cloud Run 上对此进行了测试和验证? @JohnHanley,不,但第一个选项应该可以正常工作(重定向流量的附加过程),否则 Cloud Run 中的某些内容已损坏(我过去曾成功使用 socat 与 docker 容器)。当然,如果其他一切都失败了,OP 可以对二进制文件进行十六进制编辑以更改端口号(假设二进制文件未签名/混淆)。 我认为 Cloud Run 无法实现您答案的第二部分。虽然 Cloud Run 运行的是容器,但它不是 Docker 容器平台。整个容器的监听端口(一个端口)由谷歌控制。无法通过名称等访问 Docker 网络。另一个容器的地址将是未知的。有多少个容器同时运行是未知的(此时)。 Cloud Run 被设计为一个 HTTP 请求/响应系统,可根据每秒请求进行扩展。 @john-hanley 是正确的,您不能(尽管这是一个很好的解决方案)在 Cloud Run 上运行类似“sidecar”的容器来代理流量(这是 Google 应该特别考虑的事情,因为这是( a) 将成为一个相当普遍的问题;(b) 底层模型是 Kubernetes Pod,这是 Kubernetes 的常见模式。 虽然在同一个容器中运行socat
可能会解决问题,但在容器中运行某种形式的代理可能是唯一的解决方案,但这与良好做法背道而驰在单个容器中运行多个进程。以上是关于集装箱港口转发的主要内容,如果未能解决你的问题,请参考以下文章