Eine Geschichte über das Cross-Kompilieren eines Python-Pakets für AWS Lambda und das Bereitstellen ohne Server

Ich würde gerne wissen, ob es einen intelligenteren Weg gibt.

Auslösen

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.

Versuchen Sie zunächst, die Bereitstellung so wie sie ist durchzuführen

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.

Versuchen Sie es mit dockerizePip aus serverless-python-Anforderungen

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.

Cross-Compile mit Lambci / Lambda

[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.

Verwenden Sie unterschiedliche Pakete zum Laden entsprechend der Ausführungsumgebung

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.

Zusammenfassung

Ist es nicht so?

Recommended Posts

Eine Geschichte über das Cross-Kompilieren eines Python-Pakets für AWS Lambda und das Bereitstellen ohne Server
Über "Lamvery", ein Bereitstellungs- und Verwaltungstool für AWS Lambda
Eine Geschichte über Python Pop und Append
Eine Geschichte über das Ändern von Python und das Hinzufügen von Funktionen
Erstellen Sie mit dem Serverless Framework eine lokale Entwicklungsumgebung für Lambda + Python
[Python] Ich habe eine REST-API mit AWS API Gateway und Lambda geschrieben.
[AWS] Erstellen Sie mit CodeStar eine Python Lambda-Umgebung und führen Sie Hello World aus
[AWS lambda] Stellen Sie mit lambda verschiedene Bibliotheken bereit (generieren Sie eine Zip-Datei mit einem Kennwort und laden Sie sie auf s3 hoch) @ Python
Berühren Sie AWS mit Serverless Framework und Python
Führen Sie regelmäßig Python-Programme auf AWS Lambda aus
Eine Geschichte, die von Go's globalen Variablen und ihrem Umfang abhängig ist
Eine Geschichte über das Ausführen von Python auf PHP auf Heroku
Schreiben wir ein Python-Programm und führen es aus
Amazon API Gateway und AWS Lambda Python-Version
[Für Python] Erstellen Sie schnell eine Upload-Datei in AWS Lambda Layer
ImportError beim Versuch, das gcloud-Paket mit der AWS Lambda Python-Version zu verwenden
Stellen Sie mit AWS Lambda Python eine Verbindung zu s3 her
Eine Geschichte über das Cross-Kompilieren eines Python-Pakets für AWS Lambda und das Bereitstellen ohne Server
[AWS / Lambda] Laden einer externen Python-Bibliothek
Zusammenfassung des Studiums von Python zur Verwendung von AWS Lambda
Verwendung von pip, einem Paketverwaltungssystem, das für die Verwendung von Python unverzichtbar ist
Versuchen Sie, Schedule auszuführen, um Instanzen in AWS Lambda (Python) zu starten und zu stoppen.
Erstellen Sie mit Streamlit schnell ein Python-Datenanalyse-Dashboard und stellen Sie es in AWS bereit
Dynamische HTML-Seiten mit AWS Lambda und Python
Schreiben Sie über das Erstellen einer Python-Umgebung zum Schreiben von Qiita Qiita
Erstellen einer R- und Python Docker-Arbeitsumgebung
Die Geschichte, mit Python eine Hanon-ähnliche Partitur zu machen
Eine Geschichte über das Ausprobieren eines (Golang +) Python-Monorepo mit Bazel
Eine Geschichte über Kindergärten, Kindergärten und Kindergärten
Unterstützung für Python 2.7-Laufzeit auf AWS Lambda (ab 2020.1)
AWS Lambda unterstützt jetzt Python, also habe ich es versucht
Informationen zum Erstellen und Ändern von benutzerdefinierten Designs für Python IDLE
Machen Sie mit AWS Lambda und Python gewöhnliche Tweets flottenartig
Eine Geschichte, die es einfach macht, den Wohnbereich mit Elasticsearch und Python abzuschätzen
Über Python für Schleife
Pythons Lambda-Ausdruck ...
Über Python für ~ (Bereich)
Eine Geschichte darüber, wie man einen relativen Pfad in Python angibt.
Verknüpfen Sie Python Enum mit einer Funktion, um es aufrufbar zu machen
[Python] Erstellen Sie eine Datums- und Zeitliste für einen bestimmten Zeitraum
Installationsverfahren für Python und Ansible mit einer bestimmten Version
Holen Sie sich Python-Webseite, Zeichenkodierung und Anzeige
Wie erstelle ich ein Python-Paket (geschrieben für Praktikanten)
Eine Geschichte über einen Amateur, der mit Python (Kivy) einen Blockbruch macht ②
Eine Geschichte über einen Amateur, der mit Python (Kivy) einen Blockbruch macht ①
Bibliothek zur Angabe eines Nameservers in Python und Dig
Eine Geschichte über den Versuch, private Variablen in Python zu implementieren.
Site-Überwachung und Alarmbenachrichtigung mit AWS Lambda + Python + Slack
Eine Geschichte über einen Python-Anfänger, der mit dem No-Modul'http.server 'feststeckt.
Eine Geschichte über alles von der Datenerfassung über die KI-Entwicklung bis hin zur Veröffentlichung von Webanwendungen in Python (3. KI-Entwicklung)