今回のお題
PythonでSSH経由のMySQLアクセスをして、WordPressの投稿情報を取得する
こちらを元に作成したLambda関数をデプロイし、
AWSのLambdaからLambdaを呼んで、Slackにメッセージを送信する
このような形で、RequestとResponseでデータをやりとりするように改造して見ました。
しかし、その際に下記の2点が課題になりました。
- サイズが大きいとソースが見れない・・・
**このようなエラーが表示されます。今回はこれを解消するための手順を備忘録として記載します。**
原因
使用している「sshtunnel」のパッケージが原因でした。
どうやらpipでインストールする際に、バイナリファイルを生成しておりますが、私の開発環境がMacOSのため、Amazon Linux環境でのバイナリ形式と異なり正常に読み取れないようです。
パッケージをデプロイし実行した結果、エラーにinvalid ELF headerと出力される場合は、Amazon linux上でデプロイパッケージを作成する必要があるようです。
解消法(2017/11/27時点)
- ユーザに必要なアクセス権限を付与する
- IAMからアクセスキーと、シークレットアクセスキーを取得する。
- EC2を作成し、Amazon Linuxのインスタンスを立ち上げる。
- lambda-uploaderを入れる
- Lambdaにアップロード
となります。方法はいくつかあると思いますが、シンプルそうなので、EC2で環境を整えて、lambda-uploderを使用してLambdaにデプロイします。
MaxOS内にvirtualenvを導入し、python-lambda-localを入れて見ましたがダメでした・・・
やはりバイナリファイルを生成する場合のOSを同一にしなければいけないようです。。。
ユーザロールを設定する
実行するユーザのロールに必要なポリシーをアタッチします。
ちゃんと調べたわけでなくすみませんが、自分は下記でいけました。
- AmazonEC2FullAccess
- AWSLambdaFullAccess
- IAMFullAccess
- AmazonVPCFullAccess
ポリシーをアタッチする
IAM>ユーザで、対象のユーザを選択します。
アクセス権限の追加ボタンを押下します。
必要なポリシーを選択し、次のステップ:確認ボタンを押下します。
アクセスキーを取得する
デプロイする実行するユーザのアクセスキーIDとシークレットアクセスキーが必要になるので、下記の画面から確認しメモをしておきます。
IAM>ユーザ>概要の認証情報をクリックします。
アクセスキーとシークレットキーをメモします。CSV保存だけして、あとで削除するもの有りです。
EC2を作成する。
無料枠でEC2を作成します。作成する際のOSはAmazon Linuxを設定してください
デフォルトで、Python2.7系が入っているようなので今回はそちらを使用します。
Python3系で環境を作りたい場合は、下記のAWSのドキュメントを参考にコマンド入力していきます。
AWSのドキュメント
作成したら、ssh経由で接続し、以下のコマンドを入れていきます。
lambda-uploaderを導入する
lambdaへのアップロードを行ってくれるパッケージです。こちらを導入し、デプロイを行いたいと思います。
lambda-uploaderを入れるコマンド
$ pip install lambda-uploader
アクセスキーを設定する
aws configureを入力し、AWSの設定を行います。
$ aws configure
$ AWS Access Key ID:"取得したアクセスキーを入力しエンター"
$ AWS Secret Access Key:"取得したシークレットキーを入力しエンター"
$ Default region name: ap-northeast-1(東京の場合)
$ Default output format [None]: (何も入力せずにエンター)
lambda-uploaderを使用するためのファイルを作成する。
下記の4つが必要のようで、全て同一ディレクトリに配置します。
- requirements.txt
- lambda.json
- XXXXX.py(実行する処理を記載したPythonファイル)
- event.json(必要なら)
1は、使用するパッケージの内容を羅列したもの。
2は、lambdaにデプロイする際の情報の定義
3は、登録するpythonのソース
4は、イベント定義です。
今回は特にイベントを設定しないので、1〜3を順番に設定していきます。
下記では、必要なものだけを抜粋してますが定義ファイルなどはgitを参照願います。
https://github.com/rackerlabs/lambda-uploader
1. インストールするパッケージの定義を行う
適当な作業ディレクトリを作成し移動します。
下記のコマンドを叩いて、ファイルを作成し中身をpipでインストールするパッケージを定義します。
$ mkdir ~/python-deploy
$ cd ~/python-deploy
$ touch requirements.txt
$ echo PyMySQL >> requirements.txt
$ echo sshtunnel >> requirements.txt
$ cat requirements.txt
PyMySQL
sshtunnel
今回はSSHTunnelとMySQLが必要なので、この2つを定義しました。
他にもrequestsなど、必要に応じて記載します。
2. Lambdaアップロード用の定義ファイルを作成する。
デプロイ時の設定が必要ですが、その際にロールを設定する場面が出てきます。
適用するロールを開き、arnの内容を確認しておきます。
あとでLambdaの画面から変更できるので、デフォルトで用意されている「lambda-basic-exetcution」をとりあえず設定します。
先ほどと同階層のディレクトリに、lambda.jsonを作成し、中身を記載します。
$ touch lambda.json
$ vi lambda.json
記載内容はこのような形になります。
{
"name": "lambdaに設定する名前",
"description": "lambdaの説明",
"runtime": "使用するランタイム",
"region": "リージョン(東京ならap-northeast-1)",
"handler": "Pythonのファイル名.実行関数名(lambda.handlerみたいに記載)",
"role": "arn:aws:iam::アカウントID:role/ロール名",
"timeout": タイムアウト値(数値:300が最大値),
"memory": 使用メモリ(数値)
}
仮で書くと下記のような形になると思います。
{
"name": "lambda-upload-test",
"description": "lambda uploaderからのデプロイテスト",
"runtime": "python2.7",
"region": "ap-northeast-1",
"handler": "ssh.ssh_test",
"role": "arn:aws:iam::000000000000:role/lambda-basic-exetcution",
"timeout": 300,
"memory": 128
}
3. 実行ファイルを定義
lambda.jsonに記載したファイル名を記載しますので、下記のようなファイルができると思います。
SSH接続してMySQL接続は、下記を参照。
PythonでSSH経由のMySQLアクセスをして、WordPressの投稿情報を取得する
LambdaのRequestとResponseの利用方法は、下記を参照。
AWSのLambdaからLambdaを呼んで、Slackにメッセージを送信する
# -*- coding: utf-8 -*-
from sshtunnel import SSHTunnelForwarder
# モジュール読み込み
import pymysql.cursors
def ssh_test(event, date):
is_write = is_wordpress_write(event["id"], event["date"])
return {"ret": is_write}
def is_wordpress_write(id, date):
# SSH関連の設定
with SSHTunnelForwarder(
("SSH接続先ホスト名", SSH接続ポート),
ssh_host_key="SSHホストキー(使用しないならNone)",
ssh_pkey="SSHファイルの鍵のパス",
ssh_username="接続ユーザ名(使用しないならNone)",
ssh_password="接続パスワード or 鍵ファイルのパスフレーズ(使用しないならNone)",
remote_bind_address=("127.0.0.1(ローカルホストとしてMySQLに接続するので)", MySQLのポート)
) as ssh:
# MySQLに接続する
conn = pymysql.connect(host='127.0.0.1(localhostなので)',
user='ユーザ名',
password='パスワード',
db='DB名',
charset='utf8',
cursorclass=pymysql.cursors.DictCursor)
# select
# SQLを実行する
cursor = conn.cursor()
# select
# SQLを実行する
with connection.cursor() as cursor:
sql = "select count(id) as count " \
" from " \
" wp_posts " \
" where " \
" post_author = %s " \
" and " \
" post_date > %s " \
" and " \
" post_status = 'publish' " \
" and " \
" post_type = 'post' "
cursor.execute(sql, (id, date))
# Select結果を取り出す
rets = cursor.fetchall()
is_write = False
for r in rets:
if r["count"] >= 1:
is_write = True
# cursorクローズ
cursor.close
# MySQLから切断する
connection.close()
return is_write
接続情報は、直書きしたくないので、KMSを利用して暗号化したテキストを定数に置いたり、
環境変数に定義したりしてください。使用する際に複合化します。
あとはRequestで検索条件をもらい、Responseで結果を返すものにしました。
Lambdaの環境変数をKMSで暗号化して、Pythonで複合化する
デプロイを実行する。
上記で作成したファイルを格納したディレクトリに移動し、コマンドを実行します。
$ cd ~/python-deploy
$ lambda-uploader
λ Building Package
λ Uploading Package
λ Fin
と表示されれば無事にアップロード完了です。
もしエラーが起きる場合は、定義ミスか、ファイルサイズの容量(最大10MB)、asw configureの設定や、実行ユーザの権限のどれかだと思います。
Lambdaを確認する
テスト実行する
結果も無事に取得できました。以上