web-dev-qa-db-ja.com

python awsラムダ関数内からバイナリを実行できません

このツールをラムダ関数内で実行しようとしています: https://github.com/nicolas-f/7DTD-leaflet

このツールは、AWSラムダコンテナで利用できないイメージングライブラリに依存するPillowに依存しています。これを回避するために、pyinstallerを実行して、うまくいけば実行できるバイナリを作成しました。このファイルの名前はmap_readerで、ラムダ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)

そして、2番目のsubprocess.Popen呼び出しで発生するエラーは次のとおりです。

<subprocess.Popen object at 0x7f08fa100d10>
[Errno 13] Permission denied: OSError

どうすればこれを正しく実行できますか?

9
stevepkr84

あなたは問題が実際に何であるかについて誤解されているかもしれません。

最初のポペンがうまく走ったとは思いません。標準エラーでメッセージをダンプしただけで、表示されていないと思います。それはおそらくそれを言っている

chmod: map_reader: No such file or directory

これらの2のいずれかを試すことができることをお勧めします:

  1. Map_readerをパッケージから/ tmpに抽出します。次に、/tmp/map_readerで参照します。
  2. 記事で次のように述べたAWSLambdaのゼネラルマネージャーであるTimWagnerの推奨に従って実行してください AWS Lambdaでの任意の実行可能ファイルの実行

独自の実行可能ファイルを含めるのは簡単です。アップロードするZipファイルにパッケージ化し、Node.jsまたは以前に開始した他のプロセスから呼び出すときに参照します(作成したZipファイル内の相対パスを含む)。必ず関数コードの先頭に以下を含めてください

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_readerbeforeパッケージを作成してアップロードすることも検討してください(提案されているように この他の質問で )。

6
Jeshan Babooa

私はこれに少し遅れていることを知っていますが、これを行うためのより一般的な方法が必要な場合(たとえば、バイナリがたくさんあり、すべてを使用しない可能性がある場合)、これは私がそれを行う方法です提供すべてのバイナリを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)
5
zoubida13

ここには2つの問題がありました。まず、Jeshanの回答によると、適切にアクセスする前に、バイナリを/ tmpに移動する必要がありました。

もう1つの問題は、ubuntuでpyinstallerを実行して、単一のファイルを作成することでした。ラムダコンテナが実行されるのと同じアーキテクチャでコンパイルすることを確認することについて、他の場所でいくつかのコメントを見ました。そのため、Amazon LinuxAMIに基づいてec2でpyinstallerを実行しました。出力は複数の.osファイルであり、tmpに移動すると、期待どおりに機能しました。

2
stevepkr84
copyfile('/var/task/yourbinary', '/tmp/yourbinary')
os.chmod('/tmp/yourbinary', 0555)

バイナリを/tmpに移動し、実行可能にすることでうまくいきました

1
Carlos Rendon

/tmpファイルをコピーする必要はありません。 ld-linux を使用して、実行可能とマークされていないファイルを含む任意のファイルを実行できます。

したがって、AWS Lambdaで実行不可能ファイルを実行するには、次のコマンドを使用します。

/lib64/ld-linux-x86-64.so.2 /opt/map_reader

P.S. map_readerバイナリまたはその他の静的ファイルをLambdaレイヤー、つまり/optフォルダーに追加する方が理にかなっています。

0
supersan