如何在Docker中使用mDNS(mDNS系列1)

起因

为了方便在自家局域网中发布自己由Docker启动的服务,故有了本文中所叙的解决方案,以作记录。

分析

该问题有两种解决方案:

  1. Docker采用macvlan网络发布服务,此时容器中拿到的是独立的IP,可以通过在容器内起完整的mDNS服务来发布地址。但是我的NAS及开发板等是使用WiFi联网的,而WiFi网络是不支持macvlan的,故此方案不可行。

  2. 通过宿主机的IP发布服务,此时因已与宿主机耦合,故进一步可以利用宿主机上本来就在运行的avahi-daemon来降低容器的资源消耗,经测试该方案可行。

在方案2中,有以下几点需要注意:

  1. host网络模式下,可以通过获取默认路由对应的IP来拿到宿主机的出口IP。
  2. 在使用avahi的avahi-publish命令发布时注意添加-R参数,否则会报Failed to add address: Local name collision错误,这是由于avahi默认一个IP只能绑定一个域名,需要添加-R参数来允许同一个IP绑定多个域名。关于这个参数,还有个插曲可参见后文描述。
  3. 在通过dbus与宿主机上的avahi-daemon通信时注意权限问题,因是本人在自家使用,故直接给了privileged的权限,此处可以进一步研究一下,给予更低的使用权限。

处理

Docker容器内执行的run.sh如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/sh 
set -e
host=""

while getopts ":H:" arg
do
case $arg in
H)
host=$OPTARG
;;
:)
echo "the option -$OPTARG require an arguement"
exit 1
;;
\?)
echo "Invaild option: -$OPTARG"
exit 1
;;
esac
done

if [ -z $host ]; then
echo "-H must exists"
exit 1
fi

interface=`ip route | grep default | awk '{print $5}' | head -n 1`

ip=`ip route |grep ${interface}| grep -v default | awk '{print $7}' | head -n 1`

exec avahi-publish -R -a $host $ip

Dockerfile文件内容如下:

1
2
3
4
FROM alpine:latest
RUN apk add avahi-tools
COPY run.sh /run.sh
CMD ["/run.sh", "-H", "test.local"]

使用的Docker-Compose文件示例内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
version: "3"

services:
librespeed:
image: linuxserver/librespeed:latest
container_name: librespeed
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
- TELEMETRY=false
- MODE=standalone
ports:
- 9000:80
restart: unless-stopped
mdns:
image: cubestone/avahi-publish-address:latest
container_name: librespeed_mdns
command: ["/run.sh", "-H", "librespeed.local"]
privileged: true
volumes:
- /var/run/dbus:/var/run/dbus
network_mode: host
depends_on:
- librespeed
restart: unless-stopped

插曲

查询avahi-publish命令的-R参数说明时,发现使用avahi-publish -h命令时有说明,但是想通过man avahi-publish命令查看详细说明时,却发现没有-R参数的说明。在查阅了avahi最新的源码后,发现确实存在该问题,故于2022年9月17日向github上的项目提交了PR以期待向开源项目做出自己的贡献。该问题同样在2022年10月28日由其他人提的PR中被修复,且由于他的PR被工作人员先接受,故我的这个PR被关闭。详情可以参见参考1中的链接。在进一步了解及后续跟踪的过程中,还了解了这个项目经历的一系列人员变更及里面发生的故事,比如Issues388[avahi] Commit and issue editing rights to Avahi repositories,发现即使是如此出名的开源项目背后,也存在一些值得探讨的问题。

参考

  1. 为avahi提的PR