Python docker контейнер получает пустой файл после монтирования в ~ 50% случаев - PullRequest
0 голосов
/ 07 февраля 2020

Я пытаюсь смонтировать файл с параметром bind в контейнер, но он работает очень нестабильно.

В следующем примере создается файл, монтируется в контейнер и печатается содержимое этого файла. .

import docker
import docker.types
import tempfile

def foo():

    temp_dir = tempfile.TemporaryDirectory()
    file_path = temp_dir.name + "/file.txt"
    with open(file_path, "w") as f:
        f.write("Hello")

    docker_client = docker.DockerClient()
    output = docker_client.containers.run(
        image="alpine",

        mounts=[
            docker.types.Mount("/file.txt", file_path, type="bind")
        ],
        command="cat /file.txt"
    )
    print(output)

for _ in range(10):
    foo()

Вот результаты выполнения:

b''
b'Hello'
b''
b''
b''
b''
b'Hello'
b'Hello'
b'Hello'
b'Hello'

Это случайное поведение действительно смущает меня. Я пробовал разные варианты, но все еще дает те же результаты.

что я делаю не так?

Заранее спасибо.

UPD:

Чтобы быть более понятным, я должен сказать, что я попробовал:

  • consistensy="consistent" вариант.
  • грипп sh файл и сон после того, как в него были записаны данные.

Ответы [ 2 ]

1 голос
/ 07 февраля 2020

Похоже, файл не полностью записывается на диск перед запуском контейнера. Если вы сначала напишите файл, а затем запустите контейнер, он будет печатать содержимое каждый раз. Вот вывод в i python:

In [7]: !echo "Hello" > /tmp/file.txt                                                                                                                                           

In [8]: import docker 
   ...: import docker.types 
   ...:  
   ...: def foo(file_path): 
   ...:     docker_client = docker.DockerClient() 
   ...:     output = docker_client.containers.run( 
   ...:         image="alpine", 
   ...:         mounts=[ 
   ...:             docker.types.Mount("/file.txt", file_path, type="bind") 
   ...:         ], 
   ...:         command="cat /file.txt" 
   ...:     ) 
   ...:     print(output) 
   ...:  
   ...: for _ in range(10): 
   ...:     foo("/tmp/file.txt") 
   ...:                                                                                                                                                                         
b'Hello\n'
b'Hello\n'
b'Hello\n'
b'Hello\n'
b'Hello\n'
b'Hello\n'
b'Hello\n'
b'Hello\n'
b'Hello\n'
b'Hello\n'

Это странно, однако, потому что принудительная запись на диск не решает проблему. См. https://docs.python.org/3/library/os.html#os .fsyn c

In [1]: import docker 
   ...: import docker.types 
   ...: import tempfile 
   ...: import os 
   ...:  
   ...: def foo(): 
   ...:  
   ...:     temp_dir = tempfile.TemporaryDirectory() 
   ...:     file_path = temp_dir.name + "/file.txt" 
   ...:     with open(file_path, "w") as f: 
   ...:         f.write("Hello") 
   ...:         f.flush()  # Added. 
   ...:         os.fsync(f.fileno())  # Added. 
   ...:  
   ...:     docker_client = docker.DockerClient() 
   ...:     output = docker_client.containers.run( 
   ...:         image="alpine", 
   ...:  
   ...:         mounts=[ 
   ...:             docker.types.Mount("/file.txt", file_path, type="bind") 
   ...:         ], 
   ...:         command="cat /file.txt" 
   ...:     ) 
   ...:     print(output) 
   ...:  
   ...: for _ in range(10): 
   ...:     foo() 
   ...:                                                                                                                                                                         
b''
b''
b''
b'Hello'
b''
b''
b''
b''
b''
b'Hello'
0 голосов
/ 07 февраля 2020

На самом деле, смонтированный файл не пустой и контейнеры работают нормально, проблема в нестабильном выводе функции DockerClient.containers.run. Какой сюрприз:)

Вот пример. Это не так элегантно, но должно работать.

import docker
import docker.types
import tempfile
import os


def foo():
    temp_dir = tempfile.TemporaryDirectory()
    file_path = temp_dir.name + "/file.txt"
    with open(file_path, "w") as f:
        f.write("Hello")

    output_path = temp_dir.name + "/output"

    os.mkdir(output_path)

    docker_client = docker.DockerClient()
    docker_client.containers.run(
        image="alpine",

        mounts=[
            docker.types.Mount("/file.txt", file_path, type="bind"),
            docker.types.Mount("/output", output_path, type="bind")  # mount new directory to store copy result.
        ],
        command="cp /file.txt /output/checkfile.txt",  # copy first file into mounted directory
    )

    checkfile_path = output_path + "/checkfile.txt"

    with open(checkfile_path) as f:
        print(f.read())


for _ in range(20):
    foo()

Вывод:

Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...