Docker :在多个容器上共享 /dev/snd 导致 "device or resource busy"
Docker : sharing /dev/snd on multiple containers leads to "device or resource busy"
当adding host device(--device /dev/snd
)到Docker容器时,我有时会遇到Device or resource busy
错误。
例子
我用一个涉及音频的最小示例重现了这个问题 (alsa
)。这是我的 Dockerfile
(生成图像 docker-device-example
):
FROM debian:buster
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
alsa-utils \
&& rm -rf /var/lib/apt/lists/*
我是运行下面的命令(speaker-test
是一个生成音调的工具,可以用来测试音箱),与/dev/snd
分享:
docker run --rm \
-i -t \
--device /dev/snd \
docker-device-example \
speaker-test
问题
当运行上一个命令时,会播放粉红噪音,但仅在某些情况下:
- 如果我没有在主机上播放任何声音:例如,如果我正在播放视频,即使视频暂停,命令也会失败
- 如果我不是运行另一个访问
/dev/snd
设备的容器
看起来 /dev/snd
在使用时是 "locked",如果是这样,我得到以下输出(错误由最后两行表示):
speaker-test 1.1.6
Playback device is default
Stream parameters are 48000Hz, S16_LE, 1 channels
Using 16 octaves of pink noise
ALSA lib pcm_dmix.c:1099:(snd_pcm_dmix_open) unable to open slave
Playback open error: -16,Device or resource busy
反之亦然,如果(在容器上)播放粉红噪音,那么我就无法在我的主机上播放任何声音 (Ubuntu)。但是我的主机上的命令不会因相同的消息而失败。相反,主机上的命令(如 aplay test.wav
播放简单的声音)被无限期地阻止(即使容器随后关闭)。
我尝试通过 运行 strace aplay test.way
进行调试,但该命令似乎在 poll
系统调用中被阻止:
poll([{fd=3, events=POLLIN|POLLERR|POLLNVAL}], 1, 4294967295
问题
如何同时播放来自 2 个(或更多)不同容器或来自我的主机和一个容器的声音?
附加信息
我已经用 /dev/snd
重现了这个问题,但我不知道在使用其他设备时是否会发生类似的事情,或者它是否只与声音设备或 alsa
有关。
另请注意,当 运行 多个 speaker-test
或 aplay
命令同时并且 全部在我的主机上 (不涉及容器)时,然后播放所有声音。
我不知道如何用 ALSA 解决这个问题,但可以提供 2 种可能的 pulseaudio 方法。如果这些设置失败,请在图像中安装 pulseaudio
以确保依赖项已满。
ALSA 直接访问声音硬件并阻止其他客户端访问它。但是可以设置 ALSA 来服务多个客户端。那得找别人来回答了。可能需要一些 ALSA dmix plugin 设置。
- 带共享套接字的 Pulseaudio:
创建 pulseaudio 套接字:
pactl load-module module-native-protocol-unix socket=/tmp/pulseaudio.socket
为 pulseaudio 客户端创建 /tmp/pulseaudio.client.conf
:
default-server = unix:/tmp/pulseaudio.socket
# Prevent a server running in the container
autospawn = no
daemon-binary = /bin/true
# Prevent the use of shared memory
enable-shm = false
与docker共享套接字和配置文件并设置环境变量PULSE_SERVER
和PULSE_COOKIE
。容器用户必须与主机相同:
docker run --rm \
--env PULSE_SERVER=unix:/tmp/pulseaudio.socket \
--env PULSE_COOKIE=/tmp/pulseaudio.cookie \
--volume /tmp/pulseaudio.socket:/tmp/pulseaudio.socket \
--volume /tmp/pulseaudio.client.conf:/etc/pulse/client.conf \
--user $(id -u):$(id -g) \
imagename
cookie 将由 pulseaudio 自己创建。
- 基于 TCP 的 Pulseaudio:
从主机获取 IP 地址:
# either an arbitrary IPv4 address
Hostip="$(ip -4 -o a | awk '{print }' | cut -d/ -f1 | grep -v 127.0.0.1 | head -n1)"
# or especially IP from docker daemon
Hostip="$(ip -4 -o a| grep docker0 | awk '{print }' | cut -d/ -f1)"
运行 docker 图片。您需要一个空闲的 TCP 端口,这里使用 34567
。
(TCP 端口号必须在 cat /proc/sys/net/ipv4/ip_local_port_range
范围内并且不能被使用。检查 ss -nlp | grep 34567
。)
docker run --rm \
--name pulsecontainer \
--env PULSE_SERVER=tcp:$Hostip:34567 \
imagename
在 docker run
获取容器的 IP 之后:
Containerip="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' pulsecontainer)"
加载使用容器 IP 验证的 pulseaudio TCP 模块:
pactl load-module module-native-protocol-tcp port=34567 auth-ip-acl=$Containerip
请注意,在容器启动 运行 之后 加载了 TCP 模块。 pulseaudio 服务器可用于容器应用程序需要一些时间。
如果 TCP 连接失败,请检查 iptables
和 ufw
设置。
总结这些设置的方法:https://github.com/mviereck/x11docker/wiki/Container-sound:-ALSA-or-Pulseaudio
当adding host device(--device /dev/snd
)到Docker容器时,我有时会遇到Device or resource busy
错误。
例子
我用一个涉及音频的最小示例重现了这个问题 (alsa
)。这是我的 Dockerfile
(生成图像 docker-device-example
):
FROM debian:buster
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
alsa-utils \
&& rm -rf /var/lib/apt/lists/*
我是运行下面的命令(speaker-test
是一个生成音调的工具,可以用来测试音箱),与/dev/snd
分享:
docker run --rm \
-i -t \
--device /dev/snd \
docker-device-example \
speaker-test
问题
当运行上一个命令时,会播放粉红噪音,但仅在某些情况下:
- 如果我没有在主机上播放任何声音:例如,如果我正在播放视频,即使视频暂停,命令也会失败
- 如果我不是运行另一个访问
/dev/snd
设备的容器
看起来 /dev/snd
在使用时是 "locked",如果是这样,我得到以下输出(错误由最后两行表示):
speaker-test 1.1.6
Playback device is default
Stream parameters are 48000Hz, S16_LE, 1 channels
Using 16 octaves of pink noise
ALSA lib pcm_dmix.c:1099:(snd_pcm_dmix_open) unable to open slave
Playback open error: -16,Device or resource busy
反之亦然,如果(在容器上)播放粉红噪音,那么我就无法在我的主机上播放任何声音 (Ubuntu)。但是我的主机上的命令不会因相同的消息而失败。相反,主机上的命令(如 aplay test.wav
播放简单的声音)被无限期地阻止(即使容器随后关闭)。
我尝试通过 运行 strace aplay test.way
进行调试,但该命令似乎在 poll
系统调用中被阻止:
poll([{fd=3, events=POLLIN|POLLERR|POLLNVAL}], 1, 4294967295
问题
如何同时播放来自 2 个(或更多)不同容器或来自我的主机和一个容器的声音?
附加信息
我已经用 /dev/snd
重现了这个问题,但我不知道在使用其他设备时是否会发生类似的事情,或者它是否只与声音设备或 alsa
有关。
另请注意,当 运行 多个 speaker-test
或 aplay
命令同时并且 全部在我的主机上 (不涉及容器)时,然后播放所有声音。
我不知道如何用 ALSA 解决这个问题,但可以提供 2 种可能的 pulseaudio 方法。如果这些设置失败,请在图像中安装 pulseaudio
以确保依赖项已满。
ALSA 直接访问声音硬件并阻止其他客户端访问它。但是可以设置 ALSA 来服务多个客户端。那得找别人来回答了。可能需要一些 ALSA dmix plugin 设置。
- 带共享套接字的 Pulseaudio:
创建 pulseaudio 套接字:
pactl load-module module-native-protocol-unix socket=/tmp/pulseaudio.socket
为 pulseaudio 客户端创建 /tmp/pulseaudio.client.conf
:
default-server = unix:/tmp/pulseaudio.socket
# Prevent a server running in the container
autospawn = no
daemon-binary = /bin/true
# Prevent the use of shared memory
enable-shm = false
与docker共享套接字和配置文件并设置环境变量PULSE_SERVER
和PULSE_COOKIE
。容器用户必须与主机相同:
docker run --rm \
--env PULSE_SERVER=unix:/tmp/pulseaudio.socket \
--env PULSE_COOKIE=/tmp/pulseaudio.cookie \
--volume /tmp/pulseaudio.socket:/tmp/pulseaudio.socket \
--volume /tmp/pulseaudio.client.conf:/etc/pulse/client.conf \
--user $(id -u):$(id -g) \
imagename
cookie 将由 pulseaudio 自己创建。
- 基于 TCP 的 Pulseaudio:
从主机获取 IP 地址:
# either an arbitrary IPv4 address
Hostip="$(ip -4 -o a | awk '{print }' | cut -d/ -f1 | grep -v 127.0.0.1 | head -n1)"
# or especially IP from docker daemon
Hostip="$(ip -4 -o a| grep docker0 | awk '{print }' | cut -d/ -f1)"
运行 docker 图片。您需要一个空闲的 TCP 端口,这里使用 34567
。
(TCP 端口号必须在 cat /proc/sys/net/ipv4/ip_local_port_range
范围内并且不能被使用。检查 ss -nlp | grep 34567
。)
docker run --rm \
--name pulsecontainer \
--env PULSE_SERVER=tcp:$Hostip:34567 \
imagename
在 docker run
获取容器的 IP 之后:
Containerip="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' pulsecontainer)"
加载使用容器 IP 验证的 pulseaudio TCP 模块:
pactl load-module module-native-protocol-tcp port=34567 auth-ip-acl=$Containerip
请注意,在容器启动 运行 之后 加载了 TCP 模块。 pulseaudio 服务器可用于容器应用程序需要一些时间。
如果 TCP 连接失败,请检查 iptables
和 ufw
设置。
总结这些设置的方法:https://github.com/mviereck/x11docker/wiki/Container-sound:-ALSA-or-Pulseaudio