Ich würde gerne wissen, ob es einen intelligenteren Weg gibt.
Ich habe mysqlclient importiert, um eine Verbindung zu RDS (mysql / aurora) von AWS Lambda herzustellen. Es hat lokal funktioniert, also habe ich es mit serverless bereitgestellt. Wenn ich es über die AWS-Verwaltungskonsole teste, funktioniert es nicht.
Anscheinend enthält mysqlclient nativen Code, der beim Versuch, ein auf einem Mac unter Linux erstelltes Image auszuführen, einen Fehler verursacht.
Es ist eine Geschichte, dass ich verschiedene Dinge versucht habe, um diesen Bereich zu lösen.
Das externe Python-Paket wird übrigens von [Serverless-Python-Anforderungen] verwaltet (https://github.com/UnitedIncome/serverless-python-requirements).
--Referenz: Verwaltung externer Module mit dem Serverless Framework-Plug-In
Mein Service gefällt so
ore-service
├── handler.py
├── requirements.py
├── requirements.txt
└── serverless.yml
Angenommen, der Inhalt ist so.
requirements.txt
mysqlclient
handler.py
#!/use/bin/env python
# -*- coding: utf-8 -*-
import requirements
import MySQLdb
def lambda_handler(event, context):
con = MySQLdb.connect(host='〜', db='〜', user='〜', passwd='〜', charset='utf8')
cur = con.cursor()
cur.execute("SELECT *VON Irgendwie ~")
....(Abkürzung)
Fehler beim Versuch, AWS Lambda über die AWS-Konsole mit sls deploy zu testen. Die Protokollausgabe hat die folgende Ausgabe.
Unable to import module 'handler': /var/task/_mysql.so: invalid ELF header
Oh, ich verstehe. Ich versuche, _mysql.so auf einem Mac unter Linux auszuführen.
Für serverless-python-Anforderungen gibt es eine Option namens dockerizePip. Wenn diese Option auf true gesetzt ist, wird sie mithilfe des Images docker-lambda crosskompiliert. Ich werde es sofort versuchen.
serverless.yml sieht wie folgt aus.
serverless.yml
...(Abkürzung)
plugins:
- serverless-python-requirements
custom:
pythonRequirements:
dockerizePip: true
...(Abkürzung)
Leider habe ich beim Bereitstellen einen Fehler erhalten.
$ sls deploy
Serverless: Installing required Python packages...
Error --------------------------------------------------
Command "python setup.py egg_info" failed with error
code 1 in /tmp/pip-build-4MzA_g/mysqlclient/
Dies scheint daran zu liegen, dass die zum Erstellen von mysqlclient erforderliche Python-Entwicklung und MySQL-Entwicklung nicht im Docker-Image enthalten sind.
[Quelle] der Serverless-Python-Anforderungen (https://github.com/UnitedIncome/serverless-python-requirements/blob/master/index.js) Wenn ich es mir ansah, konnte ich verstehen, was ich tat. Es ist so, als würde man den Container starten und die Pip-Installation durchführen.
Dann können Sie den Container selbst starten, mit bash eingeben und die erforderlichen Bibliotheken installieren. Es sieht wie folgt aus.
$ docker run -it --rm -v "$PWD":/var/task "lambci/lambda:build-python2.7" bash
bash-4.2# cd /var/task
bash-4.2# yum -y install python-devel mysql-devel
bash-4.2# pip install mysqlclient -t .
bash-4.2# cp /usr/lib64/mysql/libmysqlclient.so.18 .
Hängen Sie / var / task des Containers an den lokalen Strom an. Dieser Bereich ist ein vollständiges Paket der Verarbeitung um installRequirements () der Quelle, die ich zuvor gesehen habe.
Installieren Sie dann die erforderlichen Bibliotheken und Pip. Ich brauche auch libmysqlclient.so.18, also kopiere es.
serverless lädt die Dateien und Ordner am Speicherort von serverless.yml als Zip hoch, sodass Sie sls so bereitstellen können, wie es ist.
(Löschen Sie dockerizePip: true, das zuvor zu serverless.yml hinzugefügt wurde.)
Jetzt wird der für Linux erstellte mysqlclient aus Lambda geladen und Sie können sicher auf das RDS zugreifen.
Hier ist ein Problem aufgetreten. Ich kann nicht lokal ausgeführt werden, da ich das Linux-Image mysqlclient lokal habe.
$ python handler.py
Traceback (most recent call last):
File "handler.py", line 18, in <module>
import MySQLdb
File "./MySQLdb/__init__.py", line 19, in <module>
import _mysql
ImportError: dlopen(./_mysql.so, 2): no suitable image found. Did find:
./_mysql.so: unknown file type, first eight bytes: 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00
Daher ist es möglich, die ladende mysqlclient-Binärdatei zu wechseln. Die Strategie besteht darin, Linux ELF unter ./third-party/ zu platzieren und es zuerst zu laden, wenn die Ausführungsumgebung nicht Mac ist. Das Projektstammverzeichnis wird mit externen Paketordnern nicht verschmutzt.
Die Verzeichnisstruktur ist wie folgt.
ore-service
├── third-party
│ ├── MySQLdb
│ ├── _mysql.so
│ ├── libmysqlclient.so.18
│ └ Andere verschiedene verschiedene Dateien für Linux
├── handler.py
├── requirements.py
├── requirements.txt
└── serverless.yml
Kompilieren Sie wie folgt. (Ich habe gerade den Mount-Punkt auf Drittanbieter gesetzt /)
$ mkdir third-party
$ cd $_
$ docker run -it --rm -v "$PWD"/third-party/:/var/task "lambci/lambda:build-python2.7" bash
(das gleiche wie oben)
Dann bestimmt Python das Betriebssystem und wechselt das Ladeziel. Fügen Sie am Anfang von sys.path einen Drittanbieter ein, und Python scheint keine LD_LIBRARY_PATH-ähnlichen Einstellungen zu haben. Daher lade ich libmysqlclient.so.18 direkt.
handler.py
import platform
if platform.system() != "Darwin":
import sys
import ctypes
sys.path.insert(0, './third-party/')
ctypes.CDLL("./third-party/libmysqlclient.so.18")
Es ist schlammig, aber ich habe mein Ziel erreicht.
Wenn Sie danach das Drittanbieterverzeichnis .gitignore erstellen und den Cross-Compilation-Prozess in einer Docker-Datei organisieren, ist die Konfigurationsverwaltung in Ordnung.
Ist es nicht so?
Recommended Posts