微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

docker 生产环境中文件写入失败

如何解决docker 生产环境中文件写入失败

在我的生产环境中,我无法写入文件。例如,我用 Celery 设置了一个测试任务,每分钟将时间写入一个文件

@celery_app.task(name='print_time')
def print_time():
    Now = datetime.datetime.Now().strftime('%Y %b %d %a @%H:%M')
    cur_time = {"Now": Now}
    print(f'The date and time sent: {cur_time}')
    json.dump(cur_time,open(PATH.abspath(PATH.join(APP_DIR,"data","cur_time.json")),"w"))
    t = json.load(open(PATH.abspath(PATH.join(APP_DIR,"cur_time.json"))))
    print(f'The date and time received: {t}')

这两个打印语句都将给出预期的结果,在我写这篇文章时,它们最后一次打印:

The date and time sent: {'Now': '2021 May 26 Wed @18:57'}
The date and time received: {'Now': '2021 May 26 Wed @18:57'}

但是,当我设置一个视图来显示内容时:

class TimeView(TemplateView):
    def get_context_data(self,**kwargs):
        time = json.load(open(PATH.abspath(PATH.join(APP_DIR,"cur_time.json"))))
        return time

很明显,当我转到 url 时,该文件并未在开发环境中真正更新,并且时间继续保持与我最初从开发环境 rsync 文件时的时间相同(已成功更新文件内容

为了进一步验证这一点,我还运行了 cat cur_time.jsonstat cur_time.json 以验证文件未成功写入。

知道文件没有更新,我的问题有两个。一,为什么我的 celery 任务中的打印语句打印结果就像文件正在更新一样?二、这个问题最可能的原因和解决方法是什么?

我认为这与我的 Docker 容器文件写入权限有关,但我已经通过运行 chmod -R 777 data 更改了数据目录中的写入权限。此外,我还没有收到任何权限错误消息,当权限是手头的问题时,这些消息似乎会被抛出。我开始触及我的知识极限,想知道是否有人知道问题/解决方案可能是什么。谢谢

根据评论进行编辑:

我正在使用 docker-compose。这是我的 production.yml 文件

version: '3'

volumes:
    production_postgres_data: {}
    production_postgres_data_backups: {}
    production_traefik: {}

services:
  django: &django
    build:
      context: .
      dockerfile: ./compose/production/django/Dockerfile
    image: myapp_production_django
    depends_on:
      - postgres
      - redis
    env_file:
      ...
    command: /start

  postgres:
    ...

  traefik:
    ...

  redis:
    image: redis:5.0

  celeryworker:
    <<: *django
    image: myapp_production_celeryworker
    command: /start-celeryworker

  celerybeat:
    <<: *django
    image: myapp_production_celerybeat
    command: /start-celerybeat

  flower:
    <<: *django
    image: myapp_production_flower
    command: /start-flower

针对评论的第二次编辑:

这是我的 local.yml 文件的视图

version: '3'

volumes:
  local_postgres_data: {}
  local_postgres_data_backups: {}

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

  postgres:
    build:
      context: .
      dockerfile: ./compose/production/postgres/Dockerfile
    image: myapp_production_postgres
    container_name: postgres
    volumes:
      - local_postgres_data:/var/lib/postgresql/data:Z
      - local_postgres_data_backups:/backups:z
    env_file:
      ...

  redis:
    image: redis:5.0
    container_name: redis

  celeryworker:
    <<: *django
    image: myapp_local_celeryworker
    container_name: celeryworker
    depends_on:
      - redis
      - postgres
    ports: []
    command: /start-celeryworker

  celerybeat:
    <<: *django
    image: myapp_local_celerybeat
    container_name: celerybeat
    depends_on:
      - redis
      - postgres
    ports: []
    command: /start-celerybeat

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

解决方法

在到期时给予信用。 @IainShelvington 在上面的评论中优雅地提出了问题和解决方案。

问题原因:“除非您挂载卷并写入该卷,否则您在 docker 容器中写入的任何文件都不会写入主机。”

问题的解决方案:“在您的撰写配置中向全局“volumes:”添加一个新卷。将该卷安装在“django”服务中,所有celery服务都继承自该服务,因此应该共享。编写和从你挂载的位置读取文件(这应该与应用挂载完全不同,比如“/celery-logs”之类的)”

为了在我的具体示例中演示此解决方案的外观,我将以下内容添加到我的 production.yml 文件中:

volumes:
  ...
  production_celery: {}

services:
  django: &django
    build:
      ...
    image: myapp_production_django
    depends_on:
      ...
    volumes:
      - production_celery:/app/celerydata:z
    env_file:
      ...
    command: /start

然后,从我的 celery 脚本派生的所有数据文件都被发送到名为“celerydata”的新卷/目录中并从中提取

正如评论中提到的,我的应用程序之前一直依赖于 APScheduler,我已经习惯于将数据文件快速写入主机并能够轻松查看它们。为了再次在主机上查看它们并作为安全预防措施(数据冗余),我开始使用以下命令序列将文件从 celerydata 目录复制到我的本地机器中,在那里我可以更轻松地查看它们图形界面:

docker ps # note container_id == ${CID} below
export CID=foobarbaz123
docker cp ${CID}:/app/celerydata ./celery_storage

在未来的某个时候,我可能会将其编写为启动容器时运行的脚本,并会相应地更新答案。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。