使用 nc 将文件从 Docker 容器发送到主机:为什么主机 nc 过早关闭连接?

使用 nc 将文件从 Docker 容器发送到主机:为什么主机 nc 过早关闭连接?

以下 BASH 脚本下载并构建mpvhttps://github.com/mpv-player/mpv-build) 放在 Docker 容器中,并使用 netcat 将文件发送到主机(主机正在使用 netcat 进行监听):

HOSTIP="192.168.1.100"
PORT="62514"

nc -v -l $PORT > mpv &

sleep 1

sudo docker run ubuntu:14.04 /bin/bash -c "\
sed -i -e 's/# deb/deb/g' /etc/apt/sources.list; \
cat /etc/apt/sources.list; \
apt-get update; \
apt-get install --yes --force-yes git python-minimal; \
git clone https://github.com/mpv-player/mpv-build.git; \
cd mpv-build/; \
./update; \
apt-get install --yes --force-yes devscripts equivs; \
rm -f mpv-build-deps_*_*.deb; \
mk-build-deps -i -t \"apt-get --yes --force-yes --no-install-recommends\"; \
./build -j\$(nproc); \
cat mpv/build/mpv | nc $HOSTIP $PORT; \
echo Done"

#close any nc process that might be left running
nc $HOSTIP $PORT

因此脚本:

  1. nc在主机上启动 netcat ( ),在后台监听连接
  2. 启动一个 Docker 容器,在其中克隆 mpv repo、构建 mpv、用于nc连接主机上的监听套接字,并将生成的二进制文件发送回主机

由于某种原因,主机端接收到生成的文件时,文件大小会减小。要么是 0 字节,要么是 1024 字节的倍数。开头看起来完好无损,是一个 x86_64 ELF 可执行文件。

下面是一个数据包捕获,其中 docker 容器将一些 mpv 二进制文件发送到主机,但监听nc(在主机上)过早关闭连接(它发送一个设置了 FIN 标志的数据包,在连接建立后几毫秒):

docker-nc-packetdump

这里传输了 49152 个字节(它始终是 1024 的倍数)。

TCP 重传错误并不总是存在。我又进行了一次捕获,没有出现任何错误,但仍然只发送了一小部分(24576),而生成的 mpv 二进制文件总共有 21818582 个字节。

不确定这里发生了什么,为什么nc在连接打开后不久,监听/主机端会发送 FIN TCP 数据包?

答案1

使用该docker cp命令,可以像这样重写脚本:

HOSTIP="192.168.1.100"
PORT="62514"

set -e

CONTAINERID=$(sudo docker run -d ubuntu:14.04 /bin/bash -c "\
sed -i -e 's/# deb/deb/g' /etc/apt/sources.list; \
cat /etc/apt/sources.list; \
apt-get update; \
apt-get install --yes --force-yes git python-minimal; \
git clone https://github.com/mpv-player/mpv-build.git; \
cd mpv-build/; \
./update; \
apt-get install --yes --force-yes devscripts equivs; \
rm -f mpv-build-deps_*_*.deb; \
mk-build-deps -i -t \"apt-get --yes --force-yes --no-install-recommends\"; \
./build -j\$(nproc); \
echo \"From container: done building!\" | nc $HOSTIP $PORT; \
nc -v -l $PORT")

CONTAINERIP=$(sudo docker inspect $CONTAINERID|grep IPAddress|sed 's/.*IPAddress": "//'|sed 's/",$//')

echo "Started mpv-build container with Docker container ID: $CONTAINERID and IP: $CONTAINERIP" 
echo "Waiting to hear from container that the build has finished..."

#listen on host. wait for container to connect and disconnect
nc -l $PORT

#copy file from running container, while it's listening for a connection with nc
sudo docker cp $CONTAINERID:/mpv-build/mpv/build/mpv ./

#connect to the listening socket in the container to make the container finish running
echo "bye" | nc  $CONTAINERIP $PORT

echo "Done"

netcat 现在仅用作一种消息传递机制,用于容器在构建完成时向主机发出信号(以便主机可以启动复制),以及用于主机向容器发出信号,表示它已完成文件复制(以便容器可以退出)。

答案2

另一个解决方案是仅使用流重定向,即:

docker run /bin/sh -c '/my/build/command 1>&2 && cat /my/build/artifact' > artifact

对于多个文件,添加 tar:

docker run /bin/sh -c '/my/build/command 1>&2 && tar -cf- -C /my/build/artifacts .' | tar -xf- -C artifacts

答案3

我没有针对 netcat 问题的具体解决方案,但是Docker 确实提供了一个工具来实现这一点。

您可以使用docker cp <containerId>:/path/to/file /host/path/to/filenetcat,而不必担心弄乱它。

相关内容