如何让Docker容器访问主机上的dnsmasq本地DNS解析程序?
Docker容器可能会以多种方式混淆DNS设置(只需在SO或更广泛的internet上搜索“Docker DNS”以了解我的意思),建议的常见解决方法之一是:如何让Docker容器访问主机上的dnsmasq本地DNS解析程序?,docker,dns,Docker,Dns,Docker容器可能会以多种方式混淆DNS设置(只需在SO或更广泛的internet上搜索“Docker DNS”以了解我的意思),建议的常见解决方法之一是: 将dnsmasq设置为主机系统上的本地DNS解析程序 将其绑定到docker0网络接口 将Docker配置为使用docker0IP地址进行DNS解析 然而,试图在许多现代Linux系统上天真地应用此解决方案将使您陷入Linux网络和进程管理复杂性的困境,因为systemd向您保证dnsmasq没有运行,但netstat告诉您它正在运行,实
docker0
网络接口docker0
IP地址进行DNS解析dnsmasq
没有运行,但netstat
告诉您它正在运行,实际上,尝试启动dnsmasq
失败,抱怨端口53已在使用中
那么,即使系统默认已经运行了一个本地解析器,您如何可靠地让容器访问主机上运行的本地解析器呢?这里的问题是许多现代Linux系统都隐式运行dnsmasq,所以您现在的目标是专门为Docker设置第二个实例。要正确执行此操作,实际上需要3种设置:
docker run -it centos curl google.com
监听默认的Docker网络接口--interface=docker0
跳过环回接口的隐式添加--except interface=lo
关闭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
ExecStart=/usr/bin/docker daemon \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$INSECURE_REGISTRY
EnvironmentFile=-/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald'
OPTIONS='--selinux-enabled --log-driver=journald --dns=172.17.0.1'
我们编辑该部分以定义其他选项:
[Service]
ExecStart=/usr/sbin/dnsmasq -k --interface=docker0 --except-interface=lo --bind-interfaces
事实上,这个时间很短:
[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
[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>
配置主机防火墙
为了能够从本地Docker容器中使用解析器,我们还需要删除主机和容器中运行的系统之间的网络防火墙:
sudo firewall-cmd --permanent --zone=trusted --change-interface=docker0
sudo firewall-cmd --reload
(对于生产容器主机来说,这绝对是一个糟糕的想法,但对于开发人员工作站来说,这是一个有益的风险与便利的权衡)
使用systemd环境文件配置Docker
现在我们已经运行了本地解析器,我们需要将Docker配置为默认使用它。Docker需要的是docker0
接口的IP地址,而不是接口名称,因此我们使用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
我们要查找的第一件事是用于启动守护进程的确切命令,该命令应如下所示:
[Service]
ExecStart=/usr/sbin/dnsmasq -k
ExecStart=/usr/bin/docker daemon \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$INSECURE_REGISTRY
EnvironmentFile=-/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald'
OPTIONS='--selinux-enabled --log-driver=journald --dns=172.17.0.1'
我们要查找的第二部分是服务是否配置为使用环境文件,如下面的一行所示:
[Service]
ExecStart=/usr/sbin/dnsmasq -k
ExecStart=/usr/bin/docker daemon \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$INSECURE_REGISTRY
EnvironmentFile=-/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald'
OPTIONS='--selinux-enabled --log-driver=journald --dns=172.17.0.1'
当使用环境文件时(如Fedora 23上的情况),更改Docker后台程序设置的方法是编辑该文件并更新相关环境变量:
$ sudoedit /etc/sysconfig/docker
Fedora 23上现有的选项
条目如下所示:
[Service]
ExecStart=/usr/sbin/dnsmasq -k
ExecStart=/usr/bin/docker daemon \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$INSECURE_REGISTRY
EnvironmentFile=-/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald'
OPTIONS='--selinux-enabled --log-driver=journald --dns=172.17.0.1'
要更改默认DNS解析设置,我们将其修改为如下所示:
[Service]
ExecStart=/usr/sbin/dnsmasq -k
ExecStart=/usr/bin/docker daemon \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$INSECURE_REGISTRY
EnvironmentFile=-/etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald'
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
用给您带来问题的主机名替换google.com
(因为只有在Docker容器中运行进程时遇到名称解析问题时,您才应该找到这个答案)
使用系统内置文件配置Docker
(注意:由于我的系统使用环境文件,我无法测试下面基于文件的插入式方法,但它应该可以工作-我将其包括在内,因为Docker文档似乎表明他们现在更喜欢使用systemd插入式文件而不是使用环境文件)
如果系统服务文件未使用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配置参考:
-