Dockerized Python 脚本在访问存储到 /tmp 的文件时出现问题

Dockerized Python Scripts Having Issues Accessing Files Stored to /tmp

我想提前道歉,我没有具体的代码示例可以分享(尽管我在下面包含了我的 docker-compose 文件,它可能有用也可能没有用)。我遇到了一个似乎无法追踪的奇怪问题,而且我也不是 100% 确定要分享什么。

我在 Docker 中设置了 django + celery 运行ning(基于 cookiecutter-django)。一开始一切似乎都很好。我已经广泛测试并使用了 outside of Docker 的这个设置,并且 Dockerized Celery 任务通常表现得像我期望的那样(即,就像他们在他们没有 Docker化)。

不过,这就是事情变得奇怪的地方。由于各种原因,我需要加载一些数据文件并在 运行 时间创建临时文件,而我不能只将这些文件放入我的 docker 文件中。一个示例是使用 NamedTemporaryFile。另一个是从 Spacy 安装数据文件。在这两种情况下,我的脚本都将数据存储到 /tmp(我知道这里的简单答案是将它们放在我的 docker 文件中,但遗憾的是我无法提前预测我需要哪些文件)。当我的 celery task worker 试图访问它应该创建、下载、and/or 存储到 /tmp 的数据文件时,我不断收到文件未找到错误。奇怪的是,我的日志中没有发现文件创建或下载失败的任何错误...

然而,当我 /bin/bash 进入我的 celeryworker 容器并 cd 到 /tmp 目录时,果然,那里没有文件......如果在我的容器中使用 python 控制台,我 运行 相同 代码,我没有问题,文件确实显示在 /tmp 中。我没有收到一致的错误消息,并且行为在不同的脚本中以不同的方式表现出来,因此很难为您提供特定的错误消息/堆栈跟踪。共同元素似乎源于当我的 celery 任务尝试将数据动态存储在 /tmp 中然后立即访问它时出现的一些问题。我是 Docker 新手,不知道下一步该怎么做。我怀疑这可能是一个许可问题,但我已经尝试将 /tmp 更改为 777,但没有解决任何问题。我还认为这可能是一个体积问题,但是,如果是这样的话,我不确定如果我在我的容器中使用 bash 为什么我可以使一切正常工作。

有人在这里有什么建议吗?在这一点上花了几天时间试图追踪问题的根源,但我陷入了死胡同。我的 docker 文件和配置几乎是 Django Cookiecutter 默认值的普通副本。

version: '3'

volumes:
  local_postgres_data: {}
  local_postgres_data_backups: {}

services:
  django: &django
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: gremlin_gplv3_local_django
    container_name: django
    depends_on:
      - postgres
      - tika
      - redis
    volumes:
      - .:/app
    env_file:
      - ./.envs/.local/.django
      - ./.envs/.local/.postgres
    ports:
      - "8000:8000"
    command: /start

  postgres:
    build:
      context: .
      dockerfile: ./compose/production/postgres/Dockerfile
    image: gremlin_gplv3_production_postgres
    container_name: postgres
    volumes:
      - local_postgres_data:/var/lib/postgresql/data
      - local_postgres_data_backups:/backups
    env_file:
      - ./.envs/.local/.postgres

  redis:
    image: redis:5.0
    container_name: redis

  celeryworker:
    <<: *django
    image: gremlin_gplv3_local_celeryworker
    container_name: celeryworker
    depends_on:
      - redis
      - postgres

    ports: []
    command: /start-celeryworker

  celerybeat:
    <<: *django
    image: gremlin_gplv3_local_celerybeat
    container_name: celerybeat
    depends_on:
      - redis
      - postgres

    ports: []
    command: /start-celerybeat

  flower:
    <<: *django
    image: gremlin_gplv3_local_flower
    container_name: flower
    ports:
      - "5555:5555"
    command: /start-flower

  tika:
    image: lexpredict/tika-server
    command: /start-tika

我想通了……好吧,主要是。问题是 Spacy(以及其他类似的下载数据文件的库和工具)将它们放入文件系统的本地目录中,并可能创建指向它们的符号链接)。但是,在 docker 容器中,这些文件和符号链接不是持久的,除非父目录位于 docker 卷中。

我最后做的是为 Spacy(或任何库)用来存储数据文件/库的文件夹创建 docker 卷。在我的例子中,Spacy 总是通过 Celery 调用,它在我的 docker-compose 堆栈中有自己的 docker 图像,所以我需要像这样将我的每个 Spacy 数据目录的卷附加到我的 celeryworker :

version: '3'

volumes:
  local_postgres_data: {}
  local_postgres_data_backups: {}
  worker_usr: {}
  worker_root: {}
  worker_tmp: {}

services:
  
  [...]

  celeryworker:
    <<: *django
    image: local_django:latest
    container_name: celeryworker
    depends_on:
      - redis
      - postgres
    volumes:
      - worker_usr:/usr
      - worker_tmp:/tmp
      - worker_root:/root
      - .:/app

    ports: []
    command: /start-celeryworker

综上所述,我注意到有些情况下,首先在我的工作容器中安装数据文件(如 Spacy 模型)会引发数据文件仍然无法访问的错误,但是,当这种情况发生时(并非总是如此),我可以 运行 再次安装,并且在 99% 的情况下,这似乎可以解决问题。我没有时间尝试解决这个问题。也许其他人可以弄清楚那部分。