如何让 Docker 容器访问主机上的 dnsmasq 本地 DNS 解析器?

2024-05-01

Docker 容器可能会通过多种方式对 DNS 设置感到困惑(只需在 SO 或更广泛的互联网上搜索“Docker DNS”即可了解我的意思),建议的常见解决方法之一是:

  1. 将 dnsmasq 设置为主机系统上的本地 DNS 解析器
  2. 将其绑定到docker0网络接口
  3. 配置 Docker 以使用docker0DNS解析的IP地址

然而,尝试在许多现代 Linux 系统上天真地应用此解决方法将使您陷入 Linux 网络和进程管理复杂性的困境,因为 systemd 向您保证:dnsmasq没有运行,但是netstat告诉你它是,并且实际上正在尝试开始dnsmasq失败并抱怨端口 53 已被使用。

那么,即使系统已经默认运行一个解析器,如何可靠地让容器访问主机上运行的本地解析器呢?


这里的问题是许多现代 Linux 系统隐式运行 dnsmasq,所以你现在要做的是设置一个second专门供 Docker 使用的实例。实际上需要 3 个设置才能正确执行此操作:

  • --interface=docker0监听默认的 Docker 网络接口
  • --except-interface=lo跳过环回接口的隐式添加
  • --bind-interfaces关闭 dnsmasq 功能,默认情况下它仍然侦听所有接口,即使它只处理其中一个接口的流量

设置专用 dnsmasq 实例

这些说明显示了在已定义默认 dnsmasq 服务的系统上使用 systemd 设置专用 dnsmasq 实例,而不是更改默认系统范围 dnsmasq 实例的设置:

$ sudo cp /usr/lib/systemd/system/dnsmasq.service /etc/systemd/system/dnsmasq-docker.service
$ sudoedit /etc/systemd/system/dnsmasq-docker.service

首先,我们将默认服务设置复制到专用服务文件中。然后我们编辑该服务文件,并查找服务定义部分,它应该是这样的:

[Service]
ExecStart=/usr/sbin/dnsmasq -k

我们编辑该部分来定义我们的附加选项:

[Service]
ExecStart=/usr/sbin/dnsmasq -k --interface=docker0 --except-interface=lo --bind-interfaces

The 整个文件 https://github.com/ncoghlan/container-utils/blob/master/services/dnsmasq-docker.service实际上很短:

[Unit]
Description=DNS caching server.
After=network.target
After=docker.service
Wants=docker.service

[Service]
ExecStart=/usr/sbin/dnsmasq -k --interface=docker0 --except-interface=lo --bind-interfaces

[Install]
WantedBy=multi-user.target

The [Unit]部分告诉 systemd 等待,直到网络堆栈和主 docker 守护进程都可以启动此服务,而[Install]指示启用服务时将服务添加到哪个系统状态目标。

然后,我们将新服务配置为在系统启动时启动,并显式启动它以立即使用:

$ sudo systemctl enable dnsmasq-docker
$ sudo systemctl start dnsmasq-docker

作为让服务运行的最后一步,我们检查它是否确实按预期启动:

$ sudo systemctl status dnsmasq-docker

我们在该输出中寻找的两行关键行是:

Loaded: loaded (/etc/systemd/system/dnsmasq-docker.service; enabled; vendor preset: disabled)
Active: active (running) since <date & time>

在第一行,注意“启用”状态,而在第二行,注意“活动(运行)”状态。如果服务没有正确启动,那么额外的诊断信息将有望解释原因(尽管不幸的是有时它可能很神秘,因此这篇文章)。

注意:此配置可能会启动失败dnsmasq-docker系统重新启动时出现错误docker0接口未定义。在等待的同时docker.service似乎在避免该问题方面非常可靠,如果系统重新启动后 docker 容器的名称解析不起作用,则尝试运行:

$ sudo systemctl start dnsmasq-docker

配置主机防火墙

为了能够从本地 Docker 容器使用解析器,我们还需要删除主机和容器中运行的系统之间的网络防火墙:

sudo firewall-cmd --permanent --zone=trusted --change-interface=docker0
sudo firewall-cmd --reload

(这在生产容器主机上绝对是一个糟糕的主意,但在开发人员工作站上可能是一个有用的风险与便利权衡)

使用 systemd 环境文件配置 Docker

现在我们已经运行了本地解析器,我们需要配置 Docker 以默认使用它。 Docker 需要 IP 地址docker0接口而不是接口名称,所以我们使用ifconfig检索:

$ ifconfig docker0 | grep inet
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0

所以,对于我的系统,主机的接口默认为docker0桥可访问为172.17.0.1(附加| cut -f 10 -d ' '该命令应将输出过滤为仅 IP 地址)

由于我假设基于 systemd 的 Linux 具有系统提供的 Docker 包,因此我们将查询系统包的服务文件以了解服务是如何启动的:

$ cat /usr/lib/systemd/system/docker.service

我们要寻找的第一件事是用于启动守护进程的确切命令,它应该如下所示:

ExecStart=/usr/bin/docker daemon \
          $OPTIONS \
          $DOCKER_STORAGE_OPTIONS \
          $DOCKER_NETWORK_OPTIONS \
          $INSECURE_REGISTRY

我们要查找的第二部分是服务是否配置为使用环境文件,如以下多行之一所示:

EnvironmentFile=-/etc/sysconfig/docker

当环境文件正在使用时(就像在 Fedora 23 上一样),更改 Docker 守护进程设置的方法是编辑该文件并更新相关环境变量:

$ sudoedit /etc/sysconfig/docker

现有的OPTIONSFedora 23 上的条目如下所示:

OPTIONS='--selinux-enabled --log-driver=journald'

要更改默认的 DNS 解析设置,我们将其修改为如下所示:

OPTIONS='--selinux-enabled --log-driver=journald --dns=172.17.0.1'

然后重新启动 Docker 守护进程:

$ sudo systemctl restart docker

实施此更改后,Docker 容器现在应该能够可靠地访问主机系统可以访问的任何系统(包括通过 VPN 隧道,这是我自己需要解决这个问题的原因)

你可以运行curl在容器内检查名称解析是否正常工作:

docker run -it centos curl google.com

Replace google.com无论哪个主机名给你带来了问题(因为如果你在 Docker 容器内运行进程时遇到名称解析问题,你应该最终找到这个答案)

使用 systemd 插入文件配置 Docker

(警告:由于我的系统使用环境文件,我无法测试下面基于直接文件的方法,但它应该可以工作 - 我已经将其包含在内,因为 Docker 文档似乎表明他们现在更喜欢使用systemd 插入文件的使用环境文件)

如果系统服务文件doesn't use EnvironmentFile,那么整个ExecStart可以使用嵌入式配置文件来替换条目:

$ sudo mkdir -p /etc/systemd/system/docker.service.d
$ sudoedit /etc/systemd/system/docker.service.d/daemon.conf

然后,我们告诉 Docker 清除现有的 ExecStart 条目,并将其替换为带有附加设置的新条目:

[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon \
          $OPTIONS \
          --dns 172.17.0.1 \
          $DOCKER_STORAGE_OPTIONS \
          $DOCKER_NETWORK_OPTIONS \
          $INSECURE_REGISTRY

然后我们告诉 systemd 加载配置更改并重新启动 Docker:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

参考:

  • Docker systemd 配置参考:https://docs.docker.com/engine/admin/systemd/ https://docs.docker.com/engine/admin/systemd/
  • systemd服务文件参考:https://www.freedesktop.org/software/systemd/man/systemd.exec.html https://www.freedesktop.org/software/systemd/man/systemd.exec.html
  • dnsmasq 参考:http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html
  • 防火墙参考:https://fedoraproject.org/wiki/FirewallD https://fedoraproject.org/wiki/FirewallD
  • 在主机上没有现有本地解析器的情况下设置 dnsmasq:http://docs.blob.org/setup-host/dnsmasq.html http://docs.blowb.org/setup-host/dnsmasq.html
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何让 Docker 容器访问主机上的 dnsmasq 本地 DNS 解析器? 的相关文章

随机推荐

  • 高效快速的线程参数方法

    创建带参数的线程最有效的方法是什么 参数是一个结构体 如果该结构体不能保留在父线程堆栈上 有两种解决方案 具有动态内存分配 struct Arg int x int y void my thread void v arg Arg arg A
  • Fortran if stop 需要 endif 吗?

    在 fortran 90 中 if stop 语句是否需要结束 endif example if foo eq 1 stop do some stuff do some stuff 是循环的一部分还是 stop 意味着程序结束时 endif
  • 移动 SVN 存储库后的 git-svn ?

    我们最近将 SVN 服务器从一个数据中心迁移到另一个数据中心 并且服务器的 IP 发生了变化 我用了svn switch relocate old url new url更新我的实际工作副本 这很高兴 然而 我的大部分工作都是在本地 git
  • 如何在 MATLAB 中创建带有分级标记颜色的散点图?

    我想在 MATLAB 中绘制一个简单的散点图 标记颜色从光谱的一端到另一端各不相同 例如红色 橙色 黄色 蓝色 紫色 我的数据比较了一段时间内河流的水量和水质 3 个简单的列 时间 水量 质量 我想绘制数量与质量的 x y 散点图 但颜色随
  • C#中私有类的概念

    除了内部类之外 C 中是否可以存在私有类 根本不 除非它在嵌套类中 否则什么都没有 未嵌套在其他类或结构中的类和结构可以是public or internal 声明为 public 的类型可由任何其他类型访问 声明为内部的类型只能由同一程序
  • android-sdk/tools/ant/build.xml:698: 返回 null: 1

    我正在尝试测试 Android 版本 以确保不会发生意外情况 尝试从命令行使用 ant 构建时 usr local bin ant release BUILD FAILED android sdk tools ant build xml 6
  • Node.js + Express + Redis,什么时候关闭连接?

    我有一个使用的节点应用程序Express http expressjs com and 节点redis https github com mranney node redis 我正在遵循中概述的方法学习节点 http shop oreill
  • 每次我们想在应用程序中更改字体时,是否都必须复制 Font TTF

    以前 为了使我的应用程序可以在 Gingerbread 及以上设备中运行 我必须将 Robotto 字体资源复制到 asset 文件夹中 这是因为 Gingerbread 本身不附带 Robotto 字体 但是 假设我决定仅将我的应用程序部
  • Eclipse 在不存在的断点处停止

    我有一个 Eclipse java 项目 它在不存在的断点处停止 这个位置曾经有一个断点 但我把它删除了 有什么想法为什么会发生这种情况吗 注意 这与这里提到的问题不同 幻象断点让我发疯 https stackoverflow com qu
  • 如何在 Vim 中转置文件中的行和列的内容?

    我知道我可以使用 Awk 但我使用的是 Windows 机器 并且我正在为可能没有 Awk 的其他人创建一个函数 我也知道我可以编写 C 程序 但我不希望我正在制作的 Vim 实用程序需要编译和维护 原始文件可能是 THE DAY WAS
  • Rmarkdown:同一页面上的多个图具有单独的标题

    我正在用 R markdown 编写一份带有 pdf 输出的报告 我有几个图 我想在 2x2 矩阵中每页显示四个图 有没有办法让它们像这样显示并带有单独的标题 这是我到目前为止所尝试过的 包 gridExtra 我可以轻松设置我想要的布局
  • jquery给输入框添加百分号

    我想要一个输入框 在输入数字时自动向用户添加可见的百分号 而不仅仅是在提交时将其识别为百分比 因此 用户点击 2 并看到 2 我假设人们可以使用 Jquery 相当轻松地做到这一点 但我不知道如何做 有任何想法吗 感谢大家 您可以处理cha
  • 使用 React Hooks 输入千位分隔符

    我想使用 React Hooks 在输入上添加千位分隔符 但我不知道如何操作 到目前为止我已经尝试过下面的代码但不起作用 您能否指出可能出现的问题以及我该如何实施 谢谢 const MainComponent gt const value
  • 表达式树序列化器

    我想在客户端使用 Linq 表达式 序列化它们并在服务器端执行它们 为此我想使用 http expresstree codeplex com http expressiontree codeplex com 但我想针对自己的 WCF 调用执
  • jquery 克隆组合框无法运行

    我有下表 当我按下第一个按钮时 我调用 jquery 来克隆第一行并添加新行 table class table table striped table bordered bootstrap datatable style font siz
  • 论文中的概率密度函数,使用 C++ 实现,未按预期工作

    所以我正在实现一个启发式算法 并且我遇到了这个函数 我有一个 1 到 n 的数组 C 上的 0 到 n 1 w e 我想选择一些要复制到另一个数组的元素 给定参数 y 0 根据作者的说法 l 是一个随机数 0 所以我编写了函数的第一部分 对
  • Django 添加类到表单 字段

    我们正在寻找一种解决方案 将 CSS 类属性添加到 Django 表单的
  • 在 Makefile 的先决条件列表中使用目标的目录路径

    我编写了一个脚本 它接收两个以 cfg 结尾的文件并输出一个以 cmp 结尾的文件 我想将其包含在我的 Makefile 中 因为一些源代码文件依赖于此 cmp 文件 在我的 Makefile 中 我想这样做 cmp cfg dir def
  • Spring休眠异常

    当我启动 SpringMVC 时 出现以下异常 Apr 28 2012 6 08 23 PM org apache catalina core AprLifecycleListener init INFO The APR based Apa
  • 如何让 Docker 容器访问主机上的 dnsmasq 本地 DNS 解析器?

    Docker 容器可能会通过多种方式对 DNS 设置感到困惑 只需在 SO 或更广泛的互联网上搜索 Docker DNS 即可了解我的意思 建议的常见解决方法之一是 将 dnsmasq 设置为主机系统上的本地 DNS 解析器 将其绑定到do