Serverless Framework(v1.x) でPythonの追加パッケージを使う

  • 6
    いいね
  • 0
    コメント

Serverless(2)アドベントカレンダー17日目の記事です。
正直大したネタではないですが…(^_^;)
Serverless Framework(v1.x)でPythonの情報が少なくて自分でも悩んだため、こんなネタにしてみました。
(12月17日AM6:17追記)
別の件もあってインプットデータをCSVからJSONに変更しました。

背景

もともとうちの「IoTかんたんパック」では選択できるメッセージブローカーがMQTTのものしかなくてHTTPSに対応しないといけなくなったのがきっかけです。
(AWS IoTのRESTでもpublishできるんだけど認証が特殊すぎて今回は対象のデバイスがマイコンチップのためできるだけシンプルなAPIにしないといけなかったというか…^^;)

前回はServerless Framework(v1.1)でサンプルをそのままAPI Gatewayで動かしてみました。
Serverless Frameworkを使ってみた

今回はWebAPIにPUTされたCSVデータをMySQLにInsertするAPIを作ってみたいと思います。

Serverless Framework をつかったWebAPI構築手順

Serverless Framework のバージョンアップ

いつのまにやらv1.3にアップデートされていたので前回作成した環境をバージョンアップします。

% npm install -g serverless

バージョンの確認

% sls --version
1.3.0

プロジェクト作成

プロジェクトのディレクトリを作成して初期化

% mkdir iot-api
% cd iot-api
% sls create --template aws-python --name iot-api

PythonのMySQLライブラリ追加

lambdaのPythonにMySQLドライバを入れないといけないんだけど…
マニュアル見たらPythonの場合はpip使えと書いてあるので、普通にpipでmysql-pythonをインストールしたがうまくいかない。
どうやらプロジェクトのディレクトリに置いておけばそのままlambdaにアップロードするzipに入れてくれるみたいなので以下の手順でプロジェクトディレクトリにインストール。

% pip install mysql-python -t .

Shared Objectをカレントディレクトリにコピー

% cp /usr/lib64/mysql/libmysqlclient.so.18 .

serverless.yml の編集

serverless.ymlを以下のように編集。
今回はlambdaからRDSのMySQLにアクセスするためVPCの設定も追加
【参考】
https://serverless.com/framework/docs/providers/aws/guide/functions/
http://dev.classmethod.jp/etc/serverless-framework-lambda-function-run-in-vpc/

serverless.yml
service: iot-api
provider:
  name: aws
  runtime: python2.7
  vpc:
   securityGroupIds:
     - sg-xxxxxxxx ←セキュリティグループID
   subnetIds:
     - subnet-xxxxxxxx ←サブネットID
     - subnet-xxxxxxxx ←サブネットID
  stage: dev
  region: ap-northeast-1
  iamRoleStatements:
  - Effect: "Allow"
    Action:
      - "ec2:CreateNetworkInterface"
      - "ec2:DescribeNetworkInterfaces"
      - "ec2:DeleteNetworkInterface"
    Resource:
      - "*"
functions:
  iotput:
    handler: handler.iotput
    events:
      - http:
          path: iotput
          method: put

Pythonコード

実際に動かすコードはこちら
デモ用なので引数のチェックとかまったくやってません(^_^;)

handler.py
# -*- coding: utf-8 -*-
import MySQLdb,json

HOST = "接続するRDSのホスト名"
DBNAME = "DB名"
DBUSER = "DBユーザ名"
PASSWD = "パスワード"
CHARSET = "utf8"

def iotput(event, context):

  # MySQL Connect
    connect = MySQLdb.connect(host=HOST, db=DBNAME, user=DBUSER, passwd=PASSWD, charset=CHARSET)
    connect.cursorclass = MySQLdb.cursors.DictCursor
    cursor = connect.cursor()

  # BODY Data split for CSV
  #  data1 = event['body'].split(",")
  # BODY Data split for JSON
    data1 = json.loads(event['body'])
    data1[0] = data1['data1']
    data1[1] = data1['data2']
    data1[2] = data1['data3']

  # MySQL Data insert
    cursor.execute("insert into sensor01(data1,data2,data3) values(%s,%s,%s)",
        (data1[0],data1[1],data1[2]))
    connect.commit()
    cursor.close()
    connect.close()

    body = {
        "message": "input data is %s %s %s" % (data1[0],data1[1],data1[2]),
    }

    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response

デプロイ

% sls deploy
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3 (916.94 KB)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............
Serverless: Stack update finished...

Service Information
service: iot-api
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  PUT - https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/iotput
functions:
  iot-api-dev-iotput: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxxx:function:iot-api-dev-iotput

テスト

別のマシンからcurlでテストしてみる。

% curl -X PUT  -d '{"data1":"10","data2":"20","data3":"40"}' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/iotput
{"message": "input data is 10 20 40"}
% curl -X PUT  -d '{"data1":"1.1","data2":"5.4","data3":"2.7"}' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/iotput
{"message": "input data is 1.1 5.4 2.7"}

結果確認

mysql> select * from sensor01;
+-------+-------+-------+
| data1 | data2 | data3 |
+-------+-------+-------+
|    10 |    20 |    40 |
|   1.1 |   5.4 |   2.7 |
+-------+-------+-------+
2 rows in set (0.01 sec)