无法在 Docker 容器内的 Celery Worker 中获取 Bash 脚本输出
Cannot get Bash script output in Celery Worker inside Docker Container
对于这个问题,我真的很紧张。最近我开始研究远程代码执行服务。
该服务向 Celery worker 发送以下负载:
{
"language": "python",
"code": "print('Hello World!')"
}
服务期望接收回代码的输出。
Celery worker 在 docker 容器中运行,具有以下 Dockerfile:
FROM python:3.9-slim-buster
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONBUFFERED 1
RUN mkdir /worker
WORKDIR /worker
COPY requirements.txt /worker/
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install -r /worker/requirements.txt
COPY . /worker/
对于服务和工作人员,我正在使用 docker-compose 文件:
version: "3"
services:
rabbit:
image: rabbitmq:latest
ports:
- "5672:5672"
api:
build: app/
command: uvicorn remote_coding_compilation_engine.main:app --host 0.0.0.0 --reload
volumes:
- ./app:/app
ports:
- "8000:8000"
worker:
build: worker/
command: watchmedo auto-restart --directory=./ --pattern=*.py --recursive -- celery --app=worker.celery_app worker -c 2 --loglevel=INFO
#celery --app=worker.celery_app worker -c 2 --loglevel=INFO
volumes:
- ./worker:/worker
depends_on:
- api
- rabbit
flower:
image: mher/flower
command: ["flower", "--broker=pyamqp://guest@rabbit//", "--port=8888"]
ports:
- "8888:8888"
depends_on:
- api
- rabbit
- worker
worker用payload中给出的代码创建一个.py文件,然后运行一个bash脚本来执行代码,代码输出应该是自动的从 python 重定向到 out_file。但是我无法获得 bash 脚本的输出。
这是 bash 脚本:
#!/bin/bash
if [ $# -lt 1 ]
then
echo "No code running command provided!"
else
eval $@
fi
我将以下参数传递给此脚本:python path_to_file
这是运行 bash 脚本的工作代码:
def execute_code(cls, command: str, out_file_path: str) -> None:
"""
Function which execudes the given command and outputs the result in the given out_file_path
@param command: command to be executed
@param out_file_path: path to the output file
@return None
@raise: FileNotFoundError if the command does not exist
@raise: IOError if the output file cannot be created
@raise: CalledProcessError if the command fails to be executed
"""
try:
logging.info(f"Creating output file: {out_file_path}")
with open(out_file_path, "w+") as out_file_desc:
logging.info(f"Creating process with command: {command} and output_file: {out_file_path}")
os.chmod(cls.EXECUTE_CODE_SCRIPT_PATH, 0o755)
rc = subprocess.call(command, shell=True, stdout=out_file_desc, stderr=out_file_desc)
logging.info(f"Commandmd: {command.split()}")
logging.info(f"Return Code: {rc}")
logging.info(f"OutFile Content: {out_file_desc.read()}")
if rc != 0:
logging.debug(f"Command execution was errored: {out_file_desc.read()}")
raise subprocess.CalledProcessError(rc, command)
except FileNotFoundError as fnf:
logging.error(
f"Command not found: {command}"
)
raise fnf
except IOError as ioe:
logging.error(
f"Could not create output file: {out_file_path}"
)
raise ioe
except subprocess.CalledProcessError as cpe:
logging.error(
f"Process exited with error: {cpe.output}"
)
raise cpe
Obs1。 subprocess.call
中执行的命令格式为/worker/execute_code/code_execute.sh python /worker/tmp/in_files/some_file_name.py
观察2。我确定脚本会运行命令,因为例如,如果我更改包含要执行的代码的文件夹的路径,我会收到“FileNotFound”错误。
观察3。如果我使用字面上的 python <> 而不是“$@”,我可以看到 bash 脚本
的输出
Obs4。 运行 实体对输出文件具有读写访问权限。即使我使用默认的 stdout
,我也无法获得脚本的输出
我尝试过的:
- 首先我不想使用 bash 脚本,我想使用 subprocess.run,但我还是无法获得输出
- 如果我使用终端调用脚本,我会得到代码输出
任何帮助将不胜感激,谢谢!
我相信您最初的直觉是正确的,根本不必维护 bash 文件。如果我正确理解您要执行的操作(执行命令,将输出写入文件),则无需维护 bash 脚本或将命令写入输入文件以开头:
def execute_code(command="print('Hello World')", out_file_path='/home/geo/result.txt'):
with open(out_file_path, 'w+') as f:
subprocess.Popen(["python", "-c", command], stdout=f)
您应该会在 result.txt
中看到输出。
对于这个问题,我真的很紧张。最近我开始研究远程代码执行服务。
该服务向 Celery worker 发送以下负载:
{
"language": "python",
"code": "print('Hello World!')"
}
服务期望接收回代码的输出。
Celery worker 在 docker 容器中运行,具有以下 Dockerfile:
FROM python:3.9-slim-buster
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONBUFFERED 1
RUN mkdir /worker
WORKDIR /worker
COPY requirements.txt /worker/
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install -r /worker/requirements.txt
COPY . /worker/
对于服务和工作人员,我正在使用 docker-compose 文件:
version: "3"
services:
rabbit:
image: rabbitmq:latest
ports:
- "5672:5672"
api:
build: app/
command: uvicorn remote_coding_compilation_engine.main:app --host 0.0.0.0 --reload
volumes:
- ./app:/app
ports:
- "8000:8000"
worker:
build: worker/
command: watchmedo auto-restart --directory=./ --pattern=*.py --recursive -- celery --app=worker.celery_app worker -c 2 --loglevel=INFO
#celery --app=worker.celery_app worker -c 2 --loglevel=INFO
volumes:
- ./worker:/worker
depends_on:
- api
- rabbit
flower:
image: mher/flower
command: ["flower", "--broker=pyamqp://guest@rabbit//", "--port=8888"]
ports:
- "8888:8888"
depends_on:
- api
- rabbit
- worker
worker用payload中给出的代码创建一个.py文件,然后运行一个bash脚本来执行代码,代码输出应该是自动的从 python 重定向到 out_file。但是我无法获得 bash 脚本的输出。
这是 bash 脚本:
#!/bin/bash
if [ $# -lt 1 ]
then
echo "No code running command provided!"
else
eval $@
fi
我将以下参数传递给此脚本:python path_to_file
这是运行 bash 脚本的工作代码:
def execute_code(cls, command: str, out_file_path: str) -> None:
"""
Function which execudes the given command and outputs the result in the given out_file_path
@param command: command to be executed
@param out_file_path: path to the output file
@return None
@raise: FileNotFoundError if the command does not exist
@raise: IOError if the output file cannot be created
@raise: CalledProcessError if the command fails to be executed
"""
try:
logging.info(f"Creating output file: {out_file_path}")
with open(out_file_path, "w+") as out_file_desc:
logging.info(f"Creating process with command: {command} and output_file: {out_file_path}")
os.chmod(cls.EXECUTE_CODE_SCRIPT_PATH, 0o755)
rc = subprocess.call(command, shell=True, stdout=out_file_desc, stderr=out_file_desc)
logging.info(f"Commandmd: {command.split()}")
logging.info(f"Return Code: {rc}")
logging.info(f"OutFile Content: {out_file_desc.read()}")
if rc != 0:
logging.debug(f"Command execution was errored: {out_file_desc.read()}")
raise subprocess.CalledProcessError(rc, command)
except FileNotFoundError as fnf:
logging.error(
f"Command not found: {command}"
)
raise fnf
except IOError as ioe:
logging.error(
f"Could not create output file: {out_file_path}"
)
raise ioe
except subprocess.CalledProcessError as cpe:
logging.error(
f"Process exited with error: {cpe.output}"
)
raise cpe
Obs1。 subprocess.call
中执行的命令格式为/worker/execute_code/code_execute.sh python /worker/tmp/in_files/some_file_name.py
观察2。我确定脚本会运行命令,因为例如,如果我更改包含要执行的代码的文件夹的路径,我会收到“FileNotFound”错误。
观察3。如果我使用字面上的 python <
Obs4。 运行 实体对输出文件具有读写访问权限。即使我使用默认的 stdout
,我也无法获得脚本的输出我尝试过的:
- 首先我不想使用 bash 脚本,我想使用 subprocess.run,但我还是无法获得输出
- 如果我使用终端调用脚本,我会得到代码输出
任何帮助将不胜感激,谢谢!
我相信您最初的直觉是正确的,根本不必维护 bash 文件。如果我正确理解您要执行的操作(执行命令,将输出写入文件),则无需维护 bash 脚本或将命令写入输入文件以开头:
def execute_code(command="print('Hello World')", out_file_path='/home/geo/result.txt'):
with open(out_file_path, 'w+') as f:
subprocess.Popen(["python", "-c", command], stdout=f)
您应该会在 result.txt
中看到输出。