Docker не сохраняет файл, созданный с помощью python - приложение Flask - PullRequest
2 голосов
/ 03 октября 2019

Я создал приложение Flask. Это приложение получает XML с URL-адреса и сохраняет его:

  response = requests.get(base_url)
  with open('currencies.xml', 'wb') as file:
      file.write(response.content)

Когда я запускаю приложение без Docker, файл currencies.xml правильно создается в папке моего приложения. Однако такое поведение не возникает при использовании docker.

В Docker я запускаю следующие команды:

docker build -t my-api-docker:latest .
docker run -p 5000:5000 my-api-docker ~/Desktop/myApiDocker # This is where I want the file to be saved: inside the main Flask folder

Когда я запускаю вторую команду, я получаю:

docker: Ответ об ошибке от демона: Ошибка создания среды выполнения OCI: container_linux.go: 345: запуск процесса контейнера вызвал "exec: \" / Users / name / Desktop / myApiDocker \ ": stat / Users / name/ Desktop / myApiDocker: нет такого файла или каталога ": неизвестно. ERRO [0001] ошибка ожидания контейнера: контекст отменен

Но Если я запустил:

docker build -t my-api-docker:latest .
docker run -p 5000:5000 my-api-docker # Without specifying the PATH

Я могу получить доступ к веб-сайту (нобез файла это бесполезно currencies.xml

Dockerfile

FROM python:3.7
RUN pip install --upgrade pip

COPY ./requirements.txt /app/requirements.txt

WORKDIR /app

RUN pip install -r requirements.txt

COPY . /app

EXPOSE 5000

CMD [ "flask", "run", "--host=0.0.0.0" ]

Ответы [ 2 ]

2 голосов
/ 03 октября 2019

Когда вы

docker run -p 5000:5000 my-api-docker ~/Desktop/myApiDocker

Docker интерпретирует все после имени образа (my-api-docker) как команду для запуска. Он запускает /Users/name/Desktop/myApiDocker как команду, вместо , что у вас есть как CMD в Dockerfile, и когда этот путь не существует в контейнере, вы получаете сообщение об ошибке.

Маловероятно, что вы сможете передать этот путь вашей команде flask run в качестве аргумента командной строки. Типичный способ справиться с этим - использовать вместо этого переменную окружения. В вашем коде

download_dir = os.environ.get('DOWNLOAD_DIR', '.')
currencies_xml = os.path.join(download_dir, 'currencies.xml')
with open(currencies_xml, 'wb') as file:
  ...

Затем, когда вы запускаете свой контейнер, вы можете передать это как переменную окружения с опцией docker run -e. Обратите внимание, что это имя пути внутри контейнера;для этого нет особой необходимости совпадать с путем на хосте.

docker run \
  -p 5000:5000 \
  -e DOWNLOAD_DIR=/data \
  -v $HOME/Desktop/myApiDocker:/data \
  my-api-docker

Также довольно распространено помещать оператор ENV в ваш файл Docker или иным образом выбирать фиксированный путь для этого и просто указывать, чтоИнтерфейс вашего образа состоит в том, что он загружает файл во все, что смонтировано на /data.

1 голос
/ 03 октября 2019

Когда вы docker run получаете изображение, контекстом процесса является файловая система контейнера, а не файловая система вашего хоста. Поэтому my-api-docker ~/Desktop/myApiDocker (пытается) поместить файл в контейнер (!) ~/Desktop.

Вместо этого вам необходимо смонтировать один из каталогов вашего хоста в файловую систему контейнера и сохранить файл в смонтированном каталоге. ,

Что-то вроде:

docker run ... \
--volume=[HOST-PATH]:[CONTAINER-PATH] \
... \
my-api-docker [CONTAINER-PATH]/thefile

Затем контейнер записывает файл в [CONTAINER-PATH]/thefile, но он сопоставляется с [HOST-PATH]/thefile.

NB *. 1016 * Значения [HOST-PATH] и [CONTAINER-PATH] должны быть абсолютными, а не относительными путями.

Вы можете доказать это поведение самостоятельно, используя, например, python:3.7 или busybox:

# List my host's root
ls -l /

# List the container's root
docker run --rm busybox ls -l /

# Mount the host's /tmp into the container's /tmp
ls -l /tmp
docker run --rm --volume=/tmp:/tmp busybox ls -l /tmp

НТН!

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