Docker容器中的子进程无法工作

9
我简直快要疯了,因为我似乎无法解决这个特定的问题。
问题是这样的:我有两个容器:Django和celery。用户上传一个word文档,celery worker将该word文档转换为pdf并上传到s3存储桶中。我使用libreoffice --headless进行转换。因此,用户将文件发送到API端点,并将word文档保存在名为original的文件夹中,然后celery调用convert_office_to_pdf.delay来转换文件并将其放入另一个名为converted的文件夹中。除了celery函数之外,一切都按预期工作。以下是代码的样子:
import subprocess    
def convert_office_to_pdf(original_file):
    ws = websocket.WebSocket()
        ws.connect('ws://web:8000/ws/converter/public/')
    #how the command will look like
        print('libreoffice --headless --convert-to pdf original/{} --outdir ./converted'.format(original_file))
        subprocess.call('libreoffice --headless --convert-to pdf original/{} --outdir ./converted'.format(original_file), shell=True)
     ws.send(json.dumps({
            'message': '{}.pdf'.format(pure_file_name), 
            'progress': 75}))
        upload_file_to_s3(pure_file_name, 'pdf', ws)

然而,该函数已被执行,但没有任何反应。这是来自 docker-compose 的输出。
web_1       | [2018/03/22 22:57:52] HTTP GET /converter/ 200 [0.06, 172.17.0.1:32788]
web_1       | [2018/03/22 22:57:52] HTTP GET /static/css/normalize.css 304 [0.02, 172.17.0.1:32788]
web_1       | [2018/03/22 22:57:52] WebSocket HANDSHAKING /ws/converter/public/ [172.17.0.1:32798]
web_1       | [2018/03/22 22:57:52] WebSocket CONNECT /ws/converter/public/ [172.17.0.1:32798]
fileshiffty_data_1 exited with code 0
worker_1    | [2018-03-22 22:58:04,413: INFO/MainProcess] Received task: api.tasks.convert_office_to_pdf[287805aa-3c9c-4212-92d4-cac5872076f2]  
worker_1    | [2018-03-22 22:58:04,414: DEBUG/MainProcess] TaskPool: Apply <function _fast_trace_task at 0x7fb72d567e18> (args:('api.tasks.convert_office_to_pdf', '287805aa-3c9c-4212-92d4-cac5872076f2', {'lang': 'py', 'task': 'api.tasks.convert_office_to_pdf', 'id': '287805aa-3c9c-4212-92d4-cac5872076f2', 'eta': None, 'expires': None, 'group': None, 'retries': 0, 'timelimit': [None, None], 'root_id': '287805aa-3c9c-4212-92d4-cac5872076f2', 'parent_id': None, 'argsrepr': "('1521759484.3458297-Doc1.docx',)", 'kwargsrepr': '{}', 'origin': 'gen8@a478d8966021', 'reply_to': 'adf32365-ef93-327e-842f-7eff10fda37a', 'correlation_id': '287805aa-3c9c-4212-92d4-cac5872076f2', 'delivery_info': {'exchange': '', 'routing_key': 'celery', 'priority': 0, 'redelivered': None}}, b'[["1521759484.3458297-Doc1.docx"], {}, {"callbacks": null, "errbacks": null, "chain": null, "chord": null}]', 'application/json', 'utf-8') kwargs:{})
web_1       | [2018/03/22 22:58:04] HTTP PUT /api/v1/fileupload/word/pdf/ 200 [0.07, 172.17.0.1:32788]
worker_1    | [2018-03-22 22:58:04,417: DEBUG/MainProcess] Task accepted: api.tasks.convert_office_to_pdf[287805aa-3c9c-4212-92d4-cac5872076f2] pid:9
web_1       | [2018/03/22 22:58:04] WebSocket HANDSHAKING /ws/converter/public/ [172.17.0.2:58928]
web_1       | [2018/03/22 22:58:04] WebSocket CONNECT /ws/converter/public/ [172.17.0.2:58928]
worker_1    | [2018-03-22 22:58:04,426: WARNING/ForkPoolWorker-2] /data/web/fileshiffty
worker_1    | [2018-03-22 22:58:04,427: WARNING/ForkPoolWorker-2] libreoffice --headless --convert-to pdf original/1521759484.3458297-Doc1.docx --outdir ./converted
web_1       | {"message": "1521759484.3458297-Doc1.pdf", "progress": 50}
web_1       | {"message": "1521759484.3458297-Doc1.pdf", "progress": 75}

当我上传文件时,可以确认该文件已添加到original文件夹,并且日志条目worker_1 | [2018-03-22 22:58:04,427:WARNING/ForkPoolWorker-2] libreoffice --headless --convert-to pdf original/1521759484.3458297-Doc1.docx --outdir ./converted显示了subprocess将调用的命令。然而,当我查看converted文件夹时,我发现里面什么都没有。它完全是空的。然而,奇怪的是,当我进入docker容器并运行完全相同的东西时,文件被转换并放入文件夹中。就像这样。

root@4b9da6f71226:/data/web/fileshiffty/api# python3
Python 3.6.4 (default, Mar 14 2018, 17:49:05) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.call('libreoffice --headless --convert-to pdf original/1521759484.3458297-Doc1.docx --outdir ./converted', shell=True)
convert /data/web/fileshiffty/api/original/1521759484.3458297-Doc1.docx -> /data/web/fileshiffty/api/converted/1521759484.3458297-Doc1.pdf using writer_pdf_Export
0

为什么我在命令行中执行子进程时可以正常工作,但从文件中执行却不行。请有人帮帮我吗?
编辑说明:似乎subprocess命令根本没有被执行。我将代码更改如下,以查找subprocess命令之后会发生什么,并且使用了绝对路径:
def convert_office_to_pdf(original_file):
    ws = websocket.WebSocket()
    ws.connect('ws://web:8000/ws/converter/public/')
    pure_file_name = os.path.splitext(os.path.basename(original_file))[0]
    ws.send(json.dumps({
        'message': '{}.pdf'.format(pure_file_name), 
        'progress': 50}))
    print(os.getcwd())
    print('libreoffice --headless --convert-to pdf original/{} --outdir ./converted'.format(original_file))
    command = ['libreoffice', '--headless', '--convert-to', 'pdf', '{}/original/{}'.format(os.getcwd(), original_file), '--outdir', '{}/converted'.format(os.getcwd())]
    process = subprocess.Popen(command, stdout=subprocess.PIPE)
    out, err = process.communicate()
    print(out)
    print(err)
    print('------------------------------------------------')
    ws.send(json.dumps({
        'message': '{}.pdf'.format(pure_file_name), 
        'progress': 75}))
    upload_file_to_s3(pure_file_name, 'pdf', ws)

然后我得到了以下输出结果

 [2018-03-22 23:44:54,668: DEBUG/MainProcess] Task accepted: api.tasks.convert_office_to_pdf[721ed2db-6a74-4fd2-9484-0fca14df7c01] pid:9
web_1       | [2018/03/22 23:44:54] WebSocket HANDSHAKING /ws/converter/public/ [172.17.0.2:60898]
web_1       | [2018/03/22 23:44:54] WebSocket CONNECT /ws/converter/public/ [172.17.0.2:60898]
worker_1    | [2018-03-22 23:44:54,696: WARNING/ForkPoolWorker-2] /data/web/fileshiffty
worker_1    | [2018-03-22 23:44:54,696: WARNING/ForkPoolWorker-2] libreoffice --headless --convert-to pdf original/1521762293.8511283-Doc1.docx --outdir ./converted
web_1       | {"message": "1521762293.8511283-Doc1.pdf", "progress": 50}
worker_1    | [2018-03-22 23:44:55,283: WARNING/ForkPoolWorker-2] b''
worker_1    | [2018-03-22 23:44:55,283: WARNING/ForkPoolWorker-2] None
worker_1    | [2018-03-22 23:44:55,283: WARNING/ForkPoolWorker-2] ------------------------------------------------
web_1       | {"message": "1521762293.8511283-Doc1.pdf", "progress": 75}

print(out) 只会打印一个空字节,而 print(err) 则只会打印 None。

编辑 2 - 这是 docker-compose 文件。

web:
  restart: always
  tty: true
  build: ./web/
  working_dir: /data/web/fileshiffty
  expose:
    - "8000"
  ports:
    - "8000:8000"
  links:
    - postgres:postgres
    - redis:redis
  env_file: env
  volumes:
    - ./web:/data/web
  command: bash -c "python3 manage.py runserver 0.0.0.0:8000"
  # command: /usr/bin/gunicorn fileshiffty.wsgi:application -w 2 -b :8000
nginx:
  restart: always
  build: ./nginx/
  ports:
    - "80:80"
  volumes_from:
    - web
  links:
    - web:web
postgres:
  restart: always
 image: postgres:latest
  volumes_from:
    - data
  volumes:
    - ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
    - ./backups/postgresql:/backup
  env_file:
    - env
  expose:
    - "5432"
redis:
  restart: always
  image: redis:latest
  expose:
    - "6379"
worker:
    build: ./web/
    working_dir: /data/web/fileshiffty
    command: bash -c "celery -A fileshiffty worker --loglevel=DEBUG"
    volumes:
      - ./web:/data/web
    links:
      - postgres:postgres
      - redis:redis
      - web:web
data:
  restart: always
  image: alpine
  volumes:
    - /var/lib/postgresql
  command: "true"

你尝试在命令的非工作实例中使用文件的绝对路径了吗? - JacobIRR
返回代码是什么? - Matt
@Matt,返回代码为0。 - alpha787
你是否将Django的上传文件夹挂载到Celery容器中?你说你有两个容器,这意味着有两个独立的文件系统,你必须以某种方式将它们链接起来... - Mazel Tov
你配置Celery时使用了哪种并发类型?能否请您展示一下Celery任务的代码? - DejanLekic
显示剩余9条评论
2个回答

1
检查您编写代码的Python版本和构建容器所使用的版本是否相同。 我遇到了完全相同的问题。我在我的代码中使用subprocess.call()在命令行上执行某些操作。我的代码在本地机器上运行得非常好,但当尝试在docker容器内运行时,在subprocess.call()处失败了。然而,奇怪的是,如果我在交互式Python shell中明确编写subprocess.call(),它会在docker中运行。我甚至尝试过用os.system()进行实验。同样的问题。
最后,当我使python版本相同时(最初开发版本为3.7.3,docker容器为3.5),问题立即得到解决。 希望对你也有帮助!
此外,如果有人能够为我提供更多技术见解,那将是很棒的。

0

可能的原因有几个:

  1. 只有在多个用户调用您的 Web API 并调用 libreoffice 时才会发生这种情况吗?如果是这样,您需要确保每个并发的 libreoffice 进程都有自己独立的用户安装目录。您可以使用 libreoffice -env:UserInstallation=file:///tmp/test 设置自定义目录。

  2. 如果您的模型是预先启动 libreoffice 进程,以便稍后的 libreoffice 进程只需将请求转发给已经启动的工作进程,那么您使用的 LibreOffice 版本是什么?例如,6.1 系列存在一个 bug,我们没有等待转换结果,请参见 https://gerrit.libreoffice.org/#/c/66168/ 进行修复。(关于对话框具有版本字符串和精确的 git 哈希值。因此,6.1.5 已经修复了此问题,但 6.1.4 没有。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接