容器端口转发

3
我有一个监听端口为3000的二进制文件,但是Google Cloud Run希望我监听由$PORT定义的端口,默认为8080
是否有一种方法让我的容器绑定到8080端口,然后将传入的请求转发到3000端口?例如,通过向我的Dockerfile添加一个简短的脚本和一行代码,它将使我的容器监听8080并转发到我的二进制文件。请注意保留HTML标签。

你不能将你的应用程序修改为默认使用3000端口吗?但是如果$PORT已定义,则使用该端口代替。 - codestation
@codestation 这个问题说明这是一个二进制文件,很可能是因为提问者无法更改端口。 - Dustin Ingram
@dustin-ingram 是正确的。在Cloud Run中,“PORT”环境变量是系统指定的。解决方案确实需要确保容器接受由服务指定的任何“PORT”值的流量;只是目前始终为8080,但这不是绝对的。 - DazWilkin
2个回答

2
以下代码未经测试,但大致思路如下:
  1. 使用基于shell的启动脚本
  2. 启用iptables
  3. 将来自srcPort的流量路由到dstPort
  4. 执行原始二进制文件
在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端口:

(注:iptables是Linux下的一种防火墙软件)

#!/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)在安装iptables之前,您需要使用sudo apt-get update && sudo apt-get -y install iptables来刷新软件包。@steren -- 希望您有一个FR来允许在Cloud Run中进行端口转发或发布;-) - DazWilkin

1
如果您可以安装并运行第二个进程并将其与主进程一起启动,则可以使用以下命令安装并运行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是您的二进制文件的服务名称。


1
你在Google Cloud Run上测试并验证过这个了吗? - John Hanley
@JohnHanley,不,但第一种选项应该可以正常工作(附加进程以重定向流量),否则Cloud Run中的某些内容可能出现问题(我过去已经成功地使用过socat与docker容器)。当然,如果其他所有方法都失败了,OP可以使用hexedit编辑二进制文件以更改端口号(假设二进制文件未签名/混淆)。 - codestation
1
我认为你回答的第二部分在Cloud Run中不可能实现。虽然Cloud Run正在运行一个容器,但它不是Docker容器平台。整个容器的侦听端口(一个端口)由Google控制。无法通过名称等访问Docker网络。另一个容器的地址是未知的。同时运行多少个容器是未知的(目前)。Cloud Run被设计为基于每秒请求进行缩放的HTTP请求/响应系统。 - John Hanley
@john-hanley 是正确的,您不能(尽管这是一个好的解决方案)在Cloud Run上运行类似“旁路”容器来代理流量(这是Google应该考虑的事情,特别是因为这是一个相当普遍的问题;底层模型是Kubernetes Pod,这是Kubernetes的常见模式之一)。 - DazWilkin
在同一容器中运行socat可能会解决问题,而在容器中运行某种形式的代理可能是唯一的解决方案,但在单个容器中运行多个进程与良好的实践背道而驰。 - DazWilkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接