无法从 python aws lambda 函数中 运行 二进制文件
Can't run binary from within python aws lambda function
我正在尝试 运行 在 lambda 函数中使用此工具:https://github.com/nicolas-f/7DTD-leaflet
该工具依赖于 Pillow,它依赖于 AWS lambda 容器中不可用的映像库。为了尝试解决这个问题,我使用 运行 pyinstaller 创建了一个我希望可以执行的二进制文件。此文件名为 map_reader
,位于 lambda zip 包的顶层。
下面是我用来尝试 运行 工具的代码:
command = 'chmod 755 map_reader'
args = shlex.split(command)
print subprocess.Popen(args)
command = './map_reader -g "{}" -t "{}"'.format('/tmp/mapFiles', '/tmp/tiles')
args = shlex.split(command)
print subprocess.Popen(args)
这是在第二次 subprocess.Popen
调用时发生的错误:
<subprocess.Popen object at 0x7f08fa100d10>
[Errno 13] Permission denied: OSError
我怎样才能 运行 正确?
您可能被误导了问题的实质。
我认为第一个 Popen 运行 没有成功。我认为它只是在标准错误中转储了一条消息,而您没有看到它。大概是说
chmod: map_reader: No such file or directory
我建议您可以尝试以下两个之一:
- 从包中提取 map_reader 到 /tmp。然后用
/tmp/map_reader
. 引用它
- 按照 AWS Lambda 总经理 Tim Wagner 的建议进行,他在文章 Running Arbitrary Executables in AWS Lambda 中说了以下内容:
Including your own executables is easy; just package them in the ZIP file you upload, and then reference them (including the relative path within the ZIP file you created) when you call them from Node.js or from other processes that you’ve previously started. Ensure that you include the following at the start of your function code:
process.env[‘PATH’] = process.env[‘PATH’] + ‘:’ + process.env[‘LAMBDA_TASK_ROOT’]
上面的代码是针对Node JS的,但是对于Python,就像下面这样
import os
os.environ['PATH']
这应该使命令 command = './map_reader <arguments>
起作用。
如果它们仍然不起作用,您还可以考虑 运行 chmod 755 map_reader
在 创建包并上传它之前(按照建议 in this other question).
这里有两个问题。首先,根据 Jeshan 的回答,我必须将二进制文件移动到 /tmp 才能正确访问它。
另一个问题是我在 ubuntu 上 运行 pyinstaller 创建了一个文件。我在别处看到一些关于确保在与 lambda 容器运行相同的架构上编译的评论。因此,我 运行 ec2 上的 pyinstaller 基于 Amazon Linux AMI。输出是多个 .os 文件,当移动到 tmp 时,它们按预期工作。
copyfile('/var/task/yourbinary', '/tmp/yourbinary')
os.chmod('/tmp/yourbinary', 0555)
将二进制文件移动到 /tmp
并使其可执行对我有用
我知道我来晚了一点,但如果你想要一种更通用的方法来做到这一点(例如,如果你有很多二进制文件并且可能不会全部使用它们),我就是这样做的, 假设您将所有二进制文件放在 py 文件旁边的 bin 文件夹中,并将所有库放在 lib 文件夹中 :
import shutil
import time
import os
import subprocess
LAMBDA_TASK_ROOT = os.environ.get('LAMBDA_TASK_ROOT', os.path.dirname(os.path.abspath(__file__)))
CURR_BIN_DIR = os.path.join(LAMBDA_TASK_ROOT, 'bin')
LIB_DIR = os.path.join(LAMBDA_TASK_ROOT, 'lib')
### In order to get permissions right, we have to copy them to /tmp
BIN_DIR = '/tmp/bin'
# This is necessary as we don't have permissions in /var/tasks/bin where the lambda function is running
def _init_bin(executable_name):
start = time.clock()
if not os.path.exists(BIN_DIR):
print("Creating bin folder")
os.makedirs(BIN_DIR)
print("Copying binaries for "+executable_name+" in /tmp/bin")
currfile = os.path.join(CURR_BIN_DIR, executable_name)
newfile = os.path.join(BIN_DIR, executable_name)
shutil.copy2(currfile, newfile)
print("Giving new binaries permissions for lambda")
os.chmod(newfile, 0775)
elapsed = (time.clock() - start)
print(executable_name+" ready in "+str(elapsed)+'s.')
# then if you're going to call a binary in a cmd, for instance pdftotext :
_init_bin('pdftotext')
cmdline = [os.path.join(BIN_DIR, 'pdftotext'), '-nopgbrk', '/tmp/test.pdf']
subprocess.check_call(cmdline, shell=False, stderr=subprocess.STDOUT)
不需要复制文件/tmp
。您可以只使用 ld-linux 来执行任何文件,包括那些未标记为可执行的文件。
因此,对于 运行 AWS Lambda 上的不可执行文件,您使用以下命令:
/lib64/ld-linux-x86-64.so.2 /opt/map_reader
P.S。在 Lambda 层中添加 map_reader
二进制文件或任何其他静态文件会更有意义,因此添加 /opt
文件夹。
Like the docs mention for Node.js,您需要更新 $PATH
,否则在尝试 运行 您添加到 Lambda 根目录的可执行文件时,您将得到 command not found
包裹。在 Node.js 中,即:
process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT']
现在,同样的事情 在 Python:
import os
# Make the path stored in $LAMBDA_TASK_ROOT available to $PATH, so that we
# can run the executables we added at the root of our package.
os.environ["PATH"] += os.pathsep + os.environ['LAMBDA_TASK_ROOT']
使用 Python 3.8.
测试正常
(作为奖励,这里还有一些 env variables used by Lambda。)
我正在尝试 运行 在 lambda 函数中使用此工具:https://github.com/nicolas-f/7DTD-leaflet
该工具依赖于 Pillow,它依赖于 AWS lambda 容器中不可用的映像库。为了尝试解决这个问题,我使用 运行 pyinstaller 创建了一个我希望可以执行的二进制文件。此文件名为 map_reader
,位于 lambda zip 包的顶层。
下面是我用来尝试 运行 工具的代码:
command = 'chmod 755 map_reader'
args = shlex.split(command)
print subprocess.Popen(args)
command = './map_reader -g "{}" -t "{}"'.format('/tmp/mapFiles', '/tmp/tiles')
args = shlex.split(command)
print subprocess.Popen(args)
这是在第二次 subprocess.Popen
调用时发生的错误:
<subprocess.Popen object at 0x7f08fa100d10>
[Errno 13] Permission denied: OSError
我怎样才能 运行 正确?
您可能被误导了问题的实质。
我认为第一个 Popen 运行 没有成功。我认为它只是在标准错误中转储了一条消息,而您没有看到它。大概是说
chmod: map_reader: No such file or directory
我建议您可以尝试以下两个之一:
- 从包中提取 map_reader 到 /tmp。然后用
/tmp/map_reader
. 引用它
- 按照 AWS Lambda 总经理 Tim Wagner 的建议进行,他在文章 Running Arbitrary Executables in AWS Lambda 中说了以下内容:
Including your own executables is easy; just package them in the ZIP file you upload, and then reference them (including the relative path within the ZIP file you created) when you call them from Node.js or from other processes that you’ve previously started. Ensure that you include the following at the start of your function code:
process.env[‘PATH’] = process.env[‘PATH’] + ‘:’ + process.env[‘LAMBDA_TASK_ROOT’]
上面的代码是针对Node JS的,但是对于Python,就像下面这样
import os
os.environ['PATH']
这应该使命令 command = './map_reader <arguments>
起作用。
如果它们仍然不起作用,您还可以考虑 运行 chmod 755 map_reader
在 创建包并上传它之前(按照建议 in this other question).
这里有两个问题。首先,根据 Jeshan 的回答,我必须将二进制文件移动到 /tmp 才能正确访问它。
另一个问题是我在 ubuntu 上 运行 pyinstaller 创建了一个文件。我在别处看到一些关于确保在与 lambda 容器运行相同的架构上编译的评论。因此,我 运行 ec2 上的 pyinstaller 基于 Amazon Linux AMI。输出是多个 .os 文件,当移动到 tmp 时,它们按预期工作。
copyfile('/var/task/yourbinary', '/tmp/yourbinary')
os.chmod('/tmp/yourbinary', 0555)
将二进制文件移动到 /tmp
并使其可执行对我有用
我知道我来晚了一点,但如果你想要一种更通用的方法来做到这一点(例如,如果你有很多二进制文件并且可能不会全部使用它们),我就是这样做的, 假设您将所有二进制文件放在 py 文件旁边的 bin 文件夹中,并将所有库放在 lib 文件夹中 :
import shutil
import time
import os
import subprocess
LAMBDA_TASK_ROOT = os.environ.get('LAMBDA_TASK_ROOT', os.path.dirname(os.path.abspath(__file__)))
CURR_BIN_DIR = os.path.join(LAMBDA_TASK_ROOT, 'bin')
LIB_DIR = os.path.join(LAMBDA_TASK_ROOT, 'lib')
### In order to get permissions right, we have to copy them to /tmp
BIN_DIR = '/tmp/bin'
# This is necessary as we don't have permissions in /var/tasks/bin where the lambda function is running
def _init_bin(executable_name):
start = time.clock()
if not os.path.exists(BIN_DIR):
print("Creating bin folder")
os.makedirs(BIN_DIR)
print("Copying binaries for "+executable_name+" in /tmp/bin")
currfile = os.path.join(CURR_BIN_DIR, executable_name)
newfile = os.path.join(BIN_DIR, executable_name)
shutil.copy2(currfile, newfile)
print("Giving new binaries permissions for lambda")
os.chmod(newfile, 0775)
elapsed = (time.clock() - start)
print(executable_name+" ready in "+str(elapsed)+'s.')
# then if you're going to call a binary in a cmd, for instance pdftotext :
_init_bin('pdftotext')
cmdline = [os.path.join(BIN_DIR, 'pdftotext'), '-nopgbrk', '/tmp/test.pdf']
subprocess.check_call(cmdline, shell=False, stderr=subprocess.STDOUT)
不需要复制文件/tmp
。您可以只使用 ld-linux 来执行任何文件,包括那些未标记为可执行的文件。
因此,对于 运行 AWS Lambda 上的不可执行文件,您使用以下命令:
/lib64/ld-linux-x86-64.so.2 /opt/map_reader
P.S。在 Lambda 层中添加 map_reader
二进制文件或任何其他静态文件会更有意义,因此添加 /opt
文件夹。
Like the docs mention for Node.js,您需要更新 $PATH
,否则在尝试 运行 您添加到 Lambda 根目录的可执行文件时,您将得到 command not found
包裹。在 Node.js 中,即:
process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT']
现在,同样的事情 在 Python:
import os
# Make the path stored in $LAMBDA_TASK_ROOT available to $PATH, so that we
# can run the executables we added at the root of our package.
os.environ["PATH"] += os.pathsep + os.environ['LAMBDA_TASK_ROOT']
使用 Python 3.8.
测试正常(作为奖励,这里还有一些 env variables used by Lambda。)