MDNS、Avahi和Docker非根容器

2020-06-02 02:33:16

IP地址很难记住,这就是我们有DNS的原因。但是,在大多数本地系统上,我们没有DNS服务器,我们必须记住系统的IP地址。更糟糕的是,让Mesay I拥有一个包含1000个节点的集群。如果没有名称服务器或自动发现工具,我应该记住群集节点的所有IP地址。

现代集群体系结构支持的一件事是节点发现。现在,您有具有1000个节点的相同集群,您不必记住所有节点的IP地址,只需记住一个节点,并且该节点还充当到其他节点的服务发现。例如,如果您的应用程序要与Node4对话,而您只知道Node1的IP地址,则您可以像与Node4对话一样与Node1对话,由Node1将通信重定向到Node4,也可以向Node1请求Node4的IP地址。

但一个主要问题是,如果node1由于某种原因关闭,即使群集仍将与其余999个节点一起工作,或者添加了一个具有不同IP地址的新节点,您也无法访问整个群集,因为您所拥有的只有node1的IP地址,而node1当前不在群集中。(=。因此,我们有一个集群IP地址。集群系统的核心是节点发现服务。您的应用程序连接到群集IP,您不必担心出现故障,因为群集IP与它没有任何关系,只是充当群集中节点和其他服务的发现工具。

现在,我们又来了。现在我们必须记住群集的IP地址。如果是IPv6,几乎不可能记住地址。集群系统缺少人类可读的名称,即它缺少名称服务器。如果集群存在于云系统中,您不必担心记忆问题,因为外部DNS会出现在画面中,您可以设置域名。

大多数本地系统都没有名称服务器。如果您查找网络以了解所有系统都连接到机器上的是什么,您会得到一堆IP地址。您有本地群集、打印机、手机、笔记本电脑、物联网等。

让我们以打印机为例。您已连接到10台不同的打印机,每台打印机都属于不同的类型。如果您需要打印文件,并且您想要选择特定的打印机,让我们假设您不需要打印机的名称,而只需要IP地址。因此,您要做的是查找打印机的IP地址表,并获取正确的打印机的IP地址。不过,您仍只能键入或复制粘贴IP地址。要解决此问题,大多数专用网络会使用zeroconf技术在计算机的主机名末尾附加.local。现在,在打印机的示例中,如果您在网络中查找连接的打印机,您会得到。

现在,您不必记住所需打印机的IP地址。你所要记住的就是一个人类可读的名字。

集群也是如此。您可以通过my-awong-cluster.local访问您的集群。更棒的是,您可以在node1.my-awawy-cluster.local访问node1at,在node4.my-awawy-cluster.local访问node4。如果假设node1出现故障,并且如果群集使用不同的IP地址启动一个新节点来占据node1的位置,则可以在node1.my-awee-cluster.local上访问该新节点。(=。这称为FQDN。

早些时候,您使用群集的IP地址连接到群集,它可以正常工作。现在,当您告诉您的应用程序使用.local连接到集群时,它根本不知道如何连接。问题是应用程序不知道如何将.local域名解析为群集IP地址。它没有ADNS服务器。由于群集是本地群集,因此您的DNS服务器无法解析它。

在云系统的情况下,您将设置一个域名,并且您可以使用该域名访问集群。外部DNS帮助您将域名解析为集群IP地址。

为了解决这个问题,我们有了mDNS。mDNS是一种协议,它将主机名解析为缺少名称服务器的小型网络中的IP地址。默认情况下,mDNS以独占方式解析以.local结尾的主机名。但是,实现.local不支持mDNS协议的主机将会出现问题,并且可以通过传统的单播DNS服务器找到这些主机。在这些情况下,应更改必要的网络配置。

RedisLabs有一个Redis Enterprise docker映像,它可以做很多事情1,但我们这里需要的是企业集群。

我之所以选择Redis Enterprise docker映像,是因为它与前面的集群示例非常吻合。使用Redis EnterprisecContainer,我们可以创建一个Redis数据库集群。群集将拥有一个带有.local的域名(即my-awawy-cluster.local),并且群集中的每个节点都会收到一个FQDN(即node1.my-awawy-cluster.local)。

总结以上段落,我们得到一个具有<;my-cluster>;.local地址的集群和具有<;my-node>;.<;my-cluster>;.local的节点。

端口8443和9443应该强制暴露,以便容器为服务发挥其所有魔力。

.更多日志.2020-05-30 05:10:03,048信息成功:mdns_server进入运行状态,进程已保持>;超过1秒(开始).更多日志.

我们暴露的端口12000可以是任何空闲端口。这是我们创建的数据库将监听的端口。在当前的示例中,我只创建了一个节点。但是可以有很多种。

您不必编辑任何内容,在群集配置下,您可以这样为群集提供FQDN。

您可以跳过输入容器使用默认选项创建证书的证书。然后,您可以设置Redis企业容器要求您设置的一些凭据。一旦您设置了凭据,您的页面将被刷新,您将再次选择输入凭据。登录后,您就可以创建数据库了。

您可以选择Redis&34;作为您的数据库,然后会给您一张表格,让您输入数据库的配置。

我将该名称指定为node1,最重要的是,您必须将端口设置为12000,因为这是我们公开的唯一端口。单击打开显示高级选项,您可以找到您可以在其中输入端口的字段";Endpoint portnumber";。输入12000(因为这是我公开的端口)。单击激活以创建数据库。然后,您将被重定向到您创建的数据库的配置页面。

您可以在Endpoint字段中找到数据库的.local地址和IP地址。

现在,让我们创建示例应用程序,该应用程序只需连接到node1并ping数据库即可。

我们已经拍摄了python buster映像,即Debian10,其中包含mdns包,稍后我们将安装这些包。

$docker build-t py-mdns.将构建上下文发送到Docker后台进程3.072kB步骤1/3:从python:3.8-buster3.8-buster:正在从库中拉入/python376057ac6fa1:拉出完成5a63a0a859d8:拉出完成496548a8c952:拉出完成2adae3950d4d:拉出完成0ed5a9824906:拉出完成bb94ffe72389:在1d31f5312e3e中运行收集redis下载redis-3.5.2-py2.py3-one-any.whl(71 KB)安装收集的软件包:恢复成功安装redis-3.5.2删除中间容器1d31f5312e3e->;c21a8bc34782步骤3/3:cmd[";python3";]->;在7中运行。

请记住,节点1的.local地址是redis-12000.mycluster.local,IP地址是172.17.0.2,端口是12000。

$docker run-it py-mdnsPython 3.8.3(默认,May 16 2020,07:08:28)[GCC 8.3.0]在linuxType&34;Help&34;,";版权所有&34;,&34;或&34;License&34;了解详细信息。&>;&>;导入Redis;&>;&>redis.Redis(HOST=#39。,port=12000).ping()回溯(最近一次调用):文件";/usr/local/lib/python3.8/site-packages/redis/connection.py";,行550,在CONNECT SOCK=sel._connect()文件";/usr/local/lib/python3.8/site-packages/redis/connection.py";,行575,in_connect for res in socket.getaddrinfo(self.host,self.port,self.socket_type,file";/usr/local/lib/python3.8/socket.py";,第918行,在getaddrinfo for res in_socket.getaddrinfo(host,port,family,type,proto,flag):socket.gaierror:[Errno-2]名称或服务未知在处理上述异常的过程中,出现另一个异常:traceback(最近一次调用):file";<;stdin>;&#。执行命令行/usr/local/lib/python3.8/site-packages/redis/client.py";,=self.connection或pool.get_connection(命令名,**选项)文件";文件";/usr/local/lib/python3.8/site-packages/redis/client.py";,行898,在EXECUTE_COMMAND CONN=self.connection或pool.get_connection(命令名,**选项)文件";/usr/local/lib/python3.8/site-packages/redis/connection.py";,第1183行,在Get_Connection connection.connect()文件";/usr/local/lib/python3.8/site-packages/redis/connection.py";,行554中,在CONNECT RAISE ConnectionError(self._error_message(e))redis.exceptions.ConnectionError:Error-2\f25 Connecting to REDIS-12000.mycluster.local:12000。名称或服务未知。

发生的情况是,您的应用程序缺少mDNS服务发现,以至于它不知道要询问谁以及如何将.localhostname解析为IP地址。

默认情况下,libnss最多可以解析两个标签,这样它就可以解析mycluster.local的IP地址,但我们需要的是三标签。让我们也尝试配置添加该配置。

运行set-ex\&;&;apt-get update&;&;apt-get install-y--no-install-suggesavahi-daemon libnss-mdns\#允许解析具有更多标签的主机名。这样我们就可以#解析node1.mycluster.local。#(https://github.com/lathiat/nss-mdns#etcmdnsallow)&;&;ECHO&*&39;>;/etc/mdns.allow\#将NSSwitch配置为使用mdns4插件,以便尊重mdns.allow。&;&;sed-i&34;s/hosts:.*/hosts:files mdns4dns/g&34;/etc/nsswitch.conf。

现在,我们已经完成了配置,可以在容器使用入口点脚本启动时启动avahi-daemon。这里是入口点脚本。

这将启动dbus,它是avahi-daemon的依赖项。这就是Dockerfile的样子。

在python中:3.8-buster WORKDIR/app copy entrypoint.sh/app/run set-ex\&;&;apt-get update&;&;apt-get install-y--no-install-suggesavahi-daemon libnss-mdns\#允许解析具有更多标签的主机名。这样我们就可以#解析node1.mycluster.local。#(https://github.com/lathiat/nss-mdns#etcmdnsallow)&;&;ECHO&*&39;>;/etc/mdns.Allow\#将NSSwitch配置为使用mdns4插件,以便尊重mdns.allow:&;&;sed-i&34;s/hosts:.*/hosts:files mdns4DNS/g&34;/etc/nsswitch.conf\&;&;&;PIP3install redis入口点[&#。,";./entrypoint.sh";]cmd[";python3";]。

$docker run-it py-mdns[ok]正在linuxType";Help";,";版权";,";Credits";或";License";上启动avahi mdns/dns-sd后台进程:avahi-daemon.Python 3.8.3(默认,5月16日,07:08:28)[GCC 8.3.0],了解详细信息。redis.redis(host=';redis-12000.mycluster.local';,port=12000).ping()True。

现在让我们来谈谈这些安全问题。2许多容器平台只接受非根容器,例如:OpenShift。如果您希望您的应用程序部署在任何容器平台上,您可以尝试以非root用户身份运行容器。

$docker run-it--user 1001 py-mdnsmkdir:无法创建目录‘/var/run/dbus’:权限被拒绝。

USER参数采用用户UUID。它说要以任何其他用户身份运行,而不是以root用户身份运行。`1001`不是特殊用户。它可能只是与映像中的现有用户不匹配的任何UUID。您还可以将USER命令放入Dockefile中。

它需要root权限才能启动应用程序。您可以通过连接到容器进行检查。

$docker exec-it a701fb0d30e2bashroot@a701fb0d30e2:/app#ps-aux USER PID%CPU%MEMVSZ RSS TTY stat start time COMMANDroot 1 0.8 0.0 13340 8276pt/0 ss+06:27 0:00 python3message+19 0.0 0.08552 2368?SS 06:27 0:00/usr/bin/dbus-daemon--systemavahi 46 0.0 0.0 7868 2564?s 06:27 0:00 avahi-daemon:正在运行[a701fb0d30e2.local]avahi 47 0.0 0.0 7868 296?s 06:27 0:00 avahi-daemon:chroot helperroot 71 7.0 0.0 5748 3636分/1 SS 06:27 0:00 bashroot 76 0.0 0.0 9388 3092分/1 R+06:27 0:00 ps-aux root@a701fb0d30e2:/app#。

应用程序不能以非root用户身份启动的原因是,数据库(Avahi;的依赖项)需要root权限才能启动。

有一种方法可以在没有dbus的情况下运行Avahi,方法是将enable-dbus=no添加到avahi-daemon.conf文件的[server]部分。该文件位于/etc/avahi/avahi-daemon.conf中。

默认情况下,Avahi需要root权限才能启动。我们可以通过提供--no-drop-rootflag来绕过它。3您可以在这里查看所有的选项。让我们删除dbus。另外,让我们在不使用服务的情况下手动启动该过程。

#Dockerfile&;&;sed-i";s/hosts:.*/hosts:files mdns4 dns/g";/etc/nsswitch.conf\+&;&;printf";[server]\nenable-dbus=no\n";>;>;/etc/avahi/avahi-daemon.conf\&;&;pip3安装redis。

#entrypoint.sh-#start avahi&-service dbus start#start avahi-service avahi-daemon start+avahi-daemon--daemonize--no-drop-root。

$docker run-it--等待返回值时达到用户1001 py-mdns bashTimeout无法从后台进程接收返回值。

然后集装箱离开。我们仍然不能以非根用户身份运行容器。实际问题在于avahi-daemon正在访问的文件和文件夹。这些文件应该具有root或avahi权限才能访问它。

#Dockerfile&;&;printf";[server]\nenable-dbus=no\n";>;>;/etc/avahi/avahi-daemon.conf\&&;&;chmod 777/etc/avahi/avahi-daemon.conf\+&;&;mkdir-p/var/run/avahi-daemon\+&;PIP3安装Redis。

我们更改文件/etc/avahi-daemon.conf的权限,以便avahi守护进程可以访问该文件。我们还创建了/var/run/avahi-daemon目录,因为avahi守护进程需要。我们还会在创建后更改它们的权限。我们还可以添加用户标志,以便默认情况下它按照指定的UUID运行。

在python中:3.8-buster WORKDIR/app copy entrypoint.sh/app/run set-ex\&;&;apt-get update&;&;apt-get install-y--no-install-suggesavahi-daemon libnss-mdns\#允许解析具有更多标签的主机名。这样我们就可以#解析node1.mycluster.local。#(https://github.com/lathiat/nss-mdns#etcmdnsallow)&;&;ECHO&*&39;>;/etc/mdns.allow\#将NSSwitch配置为使用mdns4插件,以便尊重mdns.allow:&;&;sed-i&34;s/hosts:.*/hosts:files mdns4DNS/g#34;/etc/nsswitch.conf\&;&;printf";[服务器]\nenable-dbus=no\n";>;>;/etc/avahi/avahi-daemon.conf\&;&;chmod 777/etc/avahi/avahi-daemon.conf\&;&;&;mkdir-p/var/run/avahi-daemon\&;&;chown avahi:avahi/var/run/avahi。PIP3安装redis用户1001入口点[";bash";,";./entrypoint.sh";]cmd[";python3";]。

现在让我们启动容器。现在我们不必传递--user标志,因为我们已经将user命令放在Dockerfile中。

$docker run-it--user1001py-mdnsPython 3.8.3(Default,May 16 2020,07:08:28)[GCC 8.3.0]linuxType";Help";,";版权所有&34;,&34;或";License&34;有关详细信息,&>;&>;&>导入Redis;&>;&>redis.Redis(。,port=12000).ping()True。

$docker exec-it c641eeb8559f Bashi没有名字!@c641eeb8559f:/app$ps-aux USER PID%CPU%MEMVSZ RSS TTY STAT STAT开始时间COMMAND1001 1 0.4 0.0 27248 16220分/0 SS+08:22 0:00 python31001 8 0.0 0.0 80122524?s 08:22 0:00 Avahi-daemon:正在运行[c641eeb8559f.local]1001 10 11.0 0.0 5748 3612分/1 SS 08:23 0:00 bash1001 15 0.0 9388 3072分/1 R+08:23 0:00 ps-aux。

我们已经到了邮筒的尽头。您可以在此存储库中找到代码示例。

1 Redis Enterprise Software是企业级、分布式、内存中的NoSQL数据库服务器,完全兼容Redis Labs的开源Redis。

3avahi-daemon.conf有很多配置,我们的应用程序中不需要它,所以我只是将enable-dbus设置为no。