[DOCKER] Une histoire de compilation croisée d'un package Python pour AWS Lambda et de son déploiement sans serveur

J'aimerais savoir s'il existe un moyen plus intelligent.

Déclencheur

J'ai importé mysqlclient pour me connecter à RDS (mysql / aurora) depuis AWS Lambda. Cela fonctionnait localement, je l'ai donc déployé avec sans serveur. Lorsque je teste l'exécuter à partir de la console de gestion AWS, cela ne fonctionne pas.

Apparemment, mysqlclient contient du code natif, ce qui provoque une erreur lors de la tentative d'exécuter une image construite sur un Mac sous Linux.

C'est une histoire que j'ai essayé diverses choses pour résoudre ce domaine.

Essayez d'abord de déployer tel quel

En passant, le paquet externe de python est géré par serverless-python-requirements.

--Référence: Gestion des modules externes à l'aide du plug-in Serverless Framework

Mon service comme ça

ore-service
├── handler.py
├── requirements.py
├── requirements.txt
└── serverless.yml

Supposons que le contenu soit comme ça.

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 *DE D'une manière ou d'une autre ~")

    ....(Abréviation)

Erreur lors de la tentative de test d'exécution d'AWS Lambda à partir de la console AWS avec sls deploy. La sortie du journal a la sortie suivante.

Unable to import module 'handler': /var/task/_mysql.so: invalid ELF header

Oh je vois. J'essaye d'exécuter _mysql.so construit sur un Mac sous Linux.

Essayez d'utiliser dockerizePip à partir des exigences serverless-python

serverless-python-requirements a une option appelée dockerizePip, et si elle est définie sur true, elle effectuera une compilation croisée à l'aide de l'image docker-lambda. Je vais l'essayer immédiatement.

serverless.yml ressemble à ce qui suit.

serverless.yml


...(Abréviation)

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true

...(Abréviation)

Donc, malheureusement, j'ai eu une erreur lors du déploiement.

$ 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/

Cela semble être dû au fait que python-devel et mysql-devel nécessaires pour construire mysqlclient ne sont pas dans l'image docker.

Compilation croisée avec lambci / lambda

[Source] des exigences de Python sans serveur (https://github.com/UnitedIncome/serverless-python-requirements/blob/master/index.js) avec la baisse de tension, "Dois-je construire avec EC2?" Quand je l'ai regardé, je pouvais comprendre ce que je faisais. C'est comme démarrer le conteneur et faire l'installation de pip.

Ensuite, vous pouvez démarrer le conteneur vous-même, entrer avec bash et installer les bibliothèques nécessaires. Cela ressemble à ce qui suit.

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

Montez / var / task du conteneur sur le courant local. Cette zone est un pakuri complet du traitement autour de installRequirements () de la source que j'ai vu plus tôt.

Ensuite, installez les bibliothèques et pip. J'ai également besoin de libmysqlclient.so.18, alors copiez-le.

serverless télécharge les fichiers et les dossiers à l'emplacement de serverless.yml sous forme de zip, afin que vous puissiez déployer sls tel quel.

(Supprimez le dockerizePip: true qui a été ajouté à serverless.yml plus tôt)

Maintenant, le mysqlclient construit pour linux est chargé depuis lambda et vous pouvez accéder en toute sécurité au RDS.

Utilisez différents packages pour charger en fonction de l'environnement d'exécution

Un problème est survenu ici. Je ne peux pas exécuter localement car j'ai l'image linux mysqlclient localement.

$ 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

Par conséquent, il est possible de changer le binaire de chargement mysqlclient. La stratégie consiste à placer linux ELF sous ./third-party/ et à le charger en premier si l'environnement d'exécution est autre que mac. La racine du projet ne sera pas sale avec les dossiers de packages externes.

La structure des répertoires est la suivante.

ore-service
├── third-party
│   ├── MySQLdb
│   ├── _mysql.so
│   ├── libmysqlclient.so.18
│ └── Autres fichiers divers pour linux
├── handler.py
├── requirements.py
├── requirements.txt
└── serverless.yml

Compilez comme suit. (Je viens de définir le point de montage sur tiers /)

$ mkdir third-party
$ cd $_

$ docker run -it --rm -v "$PWD"/third-party/:/var/task "lambci/lambda:build-python2.7" bash

(comme ci-dessus)

Ensuite, python détermine le système d'exploitation et change la destination de chargement. Insérez un tiers au début de sys.path, et python ne semble pas avoir de paramètres de type LD_LIBRARY_PATH, donc je chargerai directement libmysqlclient.so.18.

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")

C'est boueux, mais j'ai réussi à atteindre mon objectif.

Après cela, si vous créez le répertoire tiers .gitignore et organisez le processus de compilation croisée dans un Dockerfile, cela conviendra pour la gestion de la configuration.

Résumé

N'est-ce pas comme ça?

Recommended Posts

Une histoire de compilation croisée d'un package Python pour AWS Lambda et de son déploiement sans serveur
À propos de «Lamvery», un outil de déploiement et de gestion pour AWS Lambda
Une histoire sur Python pop and append
Une histoire sur la modification de Python et l'ajout de fonctions
Créer un environnement de développement local pour Lambda + Python à l'aide de Serverless Framework
[Python] J'ai écrit une API REST en utilisant AWS API Gateway et Lambda.
[AWS] Créez un environnement Python Lambda avec CodeStar et faites Hello World
[AWS lambda] Déployer, y compris diverses bibliothèques avec lambda (générer un zip avec un mot de passe et le télécharger vers s3) @ Python
Touchez AWS avec Serverless Framework et Python
Exécutez régulièrement des programmes Python sur AWS Lambda
Une histoire accro aux variables globales et à la portée de Go
Une histoire sur l'exécution de Python sur PHP sur Heroku
Écrivons un programme Python et exécutons-le
Version Amazon API Gateway et AWS Lambda Python
[Pour Python] Créez rapidement un fichier de téléchargement vers AWS Lambda Layer
ImportError lors de la tentative d'utilisation du package gcloud avec la version AWS Lambda Python
Connectez-vous à s3 avec AWS Lambda Python
Une histoire de compilation croisée d'un package Python pour AWS Lambda et de son déploiement sans serveur
[AWS / Lambda] Comment charger une bibliothèque externe Python
Résumé de l'étude de Python pour utiliser AWS Lambda
Comment utiliser pip, un système de gestion de paquets indispensable pour utiliser Python
Essayez d'exécuter Schedule pour démarrer et arrêter des instances dans AWS Lambda (Python)
Créez rapidement un tableau de bord d'analyse de données Python avec Streamlit et déployez-le sur AWS
Pages HTML dynamiques créées avec AWS Lambda et Python
Écrire sur la création d'un environnement Python pour l'écriture de Qiita Qiita
Création d'un environnement de travail Docker R et Python
L'histoire de la création d'une partition de type Hanon avec Python
Une histoire d'essayer un monorepo (Golang +) Python avec Bazel
Histoire autour de la maternelle, de l'école maternelle, du jardin d'enfants
Prise en charge de l'environnement d'exécution Python 2.7 sur AWS Lambda (à partir de 2020.1)
AWS Lambda prend désormais en charge Python, je l'ai donc essayé
À propos de la création et de la modification de thèmes personnalisés pour Python IDLE
Créez des tweets ordinaires comme une flotte avec AWS Lambda et Python
Une histoire qui facilite l'estimation de la surface habitable à l'aide d'Elasticsearch et de Python
À propos de Python for loop
expression lambda de python ...
À propos de Python, pour ~ (plage)
Une histoire sur la façon de spécifier un chemin relatif en python.
Associez Python Enum à une fonction pour la rendre appelable
[Python] Créer une liste de dates et d'heures pour une période spécifiée
Procédure d'installation pour Python et Ansible avec une version spécifique
Obtenez la page Web Python, encodez et affichez les caractères
Comment créer un package Python (écrit pour un stagiaire)
Une histoire sur un amateur faisant une rupture de bloc avec python (kivy) ②
Une histoire sur un amateur faisant une rupture de bloc avec python (kivy) ①
Bibliothèque pour spécifier un serveur de noms en python et dig
Une histoire sur la tentative d'implémentation de variables privées en Python.
Surveillance du site et notification d'alerte avec AWS Lambda + Python + Slack
Une histoire à propos d'un débutant en python coincé avec aucun module nommé'ttp.server '
Une histoire sur tout, de la collecte de données au développement d'IA et à la publication d'applications Web en Python (3. développement d'IA)