Назад | Перейти на главную страницу

Отправка файла из контейнера Docker на хост с помощью nc: почему хост nc закрывает соединение слишком рано?

Следующие загрузки и сборки сценария BASH mpv (https://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. Запускает netcat (nc) на хосте, прослушивая соединения в фоновом режиме
  2. Запускает контейнер Docker, в котором мы клонируем репозиторий mpv, строим mpv, используем nc для подключения к прослушивающему сокету на хосте и отправить полученный двоичный файл обратно на хост

По какой-то причине результирующий файл уменьшается в размере при получении на стороне хоста. Либо это 0 байтов, либо несколько 1024 байтов. Начало кажется неповрежденным, исполняемый файл x86_64 ELF.

Вот один захват пакета, где докер-контейнер отправляет часть двоичного файла mpv на хост, но где прослушивание nc (на хосте) преждевременно закрывает соединение (отправляет пакет с установленным флагом FIN, через несколько миллисекунд после установления соединения):

Здесь было передано 49152 байта (это всегда кратно 1024).

Ошибки повторной передачи TCP возникают не всегда. Я сделал еще один захват без ошибок, но все же была отправлена ​​лишь небольшая часть (24576) из общих 21818582 байтов, полученных в результате двоичного файла mpv.

Не уверен, что здесь происходит, почему nc на стороне прослушивания / хоста отправить пакет FIN TCP вскоре после открытия соединения?

Другое решение - просто использовать перенаправление потока, то есть:

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

Используя 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 теперь используется только как своего рода механизм обмена сообщениями, чтобы контейнер сигнализировал хосту, когда он завершил сборку (чтобы хост мог инициировать копирование), и для хоста, чтобы сигнализировать контейнеру, что он завершил копирование файла ( чтобы контейнер мог выйти).

У меня нет решения конкретных странностей проблемы netcat, но Докер действительно предоставляет возможность для этого.

Ты можешь использовать docker cp <containerId>:/path/to/file /host/path/to/file а не связываться с netcat.