使用nc将文件从Docker容器发送到主机:为什么host nc太早closures连接?

以下BASH脚本在Docker容器中下载并构buildmpv ( https://github.com/mpv-player/mpv-build ),并使用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. 启动主机上的netcat( nc ),在后台监听连接
  2. 启动一个Docker容器,在其中我们克隆mpv回购,构buildmpv,使用nc连接到主机上的监听套接字,并将生成的二进制文件发送回主机

由于某种原因,在主机端接收到的文件尺寸会减小。 要么是0字节,要么是1024字节的倍数。 开始似乎是完整的,一个x86_64 ELF可执行文件。

这里有一个数据包捕获,其中docker容器将一些mpv二进制文件发送给主机,但是监听nc (在主机上)提前closures连接(它发送一个FIN标志设置的数据包,连接之后几毫秒build立):

搬运工-NC-packetdump

这里发送了49152个字节(它总是1024的倍数)。

并不总是TCP重传错误。 我又做了一个没有错误的捕获,但是仍然只有一小部分被发送(24576)总共21818582个字节的结果mpv二进制文件。

不知道这里发生了什么事情,为什么监听/主机侧的nc在连接打开之后不久就发送FIN TCP数据包?

使用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现在只用作一种消息传递机制,容器在完成构build时向主机发信号(因此主机可以启动复制),并且主机向容器发信号通知复制文件完成所以容器可以退出)。

另一个解决scheme是只使用streamredirect,即:

 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 

我没有解决netcat问题的具体问题,但是Docker提供了一个工具来完成这个任务。

您可以使用docker cp <containerId>:/path/to/file /host/path/to/file而不是混淆netcat。