有什么方法可以释放我的 GCE 实例上的 UDP 端口 53 以便我可以绑定到它?
我在 GCE 上运行一个容器,该容器需要监听 UDP 端口 53,因为它正在监听 DNS 连接。但是,当我尝试运行容器并绑定到 UDP 端口 53 时,我收到以下错误消息:
docker:守护进程的错误响应:驱动程序无法在端点上编程外部连接():启动用户空间代理时出错:监听 udp 0.0.0.0:53:绑定:地址已在使用中。
检查开放端口显示127.0.0.53
已连接到 UDP 端口 53:
$ netstat -tuln | grep 53
tcp 0 0 0.0.0.0:5355 0.0.0.0:* LISTEN
tcp6 0 0 :::5355 :::* LISTEN
udp 0 0 127.0.0.53:53 0.0.0.0:*
udp 0 0 0.0.0.0:5355 0.0.0.0:*
udp6 0 0 :::5355 :::*
阅读文档后,唯一提到这样的事情是区域 DNS,可以通过设置实例或项目元数据来禁用它VmDnsSetting=GlobalOnly
(文章在这里)。我这样做了,端口绑定仍然在那里。
答案1
解决方案
看起来罪魁祸首是systemd-resolved
服务。
您可以使用命令停止该服务$ sudo systemctl stop systemd-resolved
。
更多细节
为了使用 Google 的容器优化操作系统(“COS”)在 GCE 上执行此操作,我需要取消选择从容器映像启动的选项,然后手动进入并输入相关命令以启动并运行环境,如下所示。
从私有 GCR 注册表中提取数据需要以下 2 个命令:
$ docker-credential-gcr configure-docker
$ docker pull gcr.io/<project>/<container>
停止systemd-resolved
服务:
$ sudo systemctl stop systemd-resolved
启动 docker 容器(注意标志--network host
,这是当您在实例配置中选择从容器映像启动选项时 COS 默认执行的操作):
$ docker run -d --network host --restart=unless-stopped <container>
打开相关端口(配置实例时没有明确从容器映像启动时需要):
$ sudo iptables -w -A INPUT -p tcp --dport 22 -j ACCEPT
$ sudo iptables -w -A INPUT -p udp --dport 53 -j ACCEPT
关于自动化的说明
请注意,您不能将第一个命令($ docker-credential-gcr configure-docker
)放在启动脚本中,因为该命令会因/root/.docker/
目录是只读的而失败;一旦网络可用,启动脚本就会以 root 身份运行。
我还没有弄清楚这一点,但一旦我弄清楚了,我就会更新这个答案,以便让其他阅读此文章的人不需要花费太多精力。
自动化更新
事实证明,你可以在cloud-init
脚本中创建一个用户,然后在以该用户身份$ su - <user>
运行命令之前在启动脚本中使用$ docker-credential-gcr configure-docker
它来保存凭据(在此支持论坛帖子)。然而,这对我来说太过黑客化了,所以我选择在 GCE 实例启动后手动运行命令以使 Docker 正常运行。
总结:如何在启动时解除 53 端口的绑定
但是,对于任何可能只想在启动时解除绑定端口 53 的人来说,可以使用以下启动脚本来实现:
#! /bin/bash
systemctl stop systemd-resolved
可以在 GCE 上找到向虚拟机添加启动脚本的说明这里。