解决方案

解决方案

有什么方法可以释放我的 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 上找到向虚拟机添加启动脚本的说明这里

相关内容