AWS LambdaでSeleniumとActiveRecordを扱う

気付いたらもう9月ですね。 最近、AWS Lambdaでいろいろと遊ぶ機会があったのでメモとして残します。 はじめに とあるセキュリティゲームの運営用に、SeleniumでWebスクレイピングをやっているRubyのスクリプトをEC2で運用していたのですが、Headless Chromeを扱うため大量に起動するとメモリ食っちゃうし、スケールしようにもEC2インスタンスのAutoScaling組むのもちょっとなあ。とか、インスタンスの起動まで待ってられないからある程度多めにインスタンスを実行したりするのも余分にコストが。。。 1実行に15分もかからないスクリプトだし、ということでLambdaに移行することにしました。 Lambda Layerについて Headless Chromeを扱う場合、単純にFunctionのデプロイパッケージにバイナリを含めると50MBを超えてしまうため、Lambdaのクォータ(制限)にかかります。 今ではLambda Layerという仕組みができていてFunctionとは別に、Functionの実行に必要なライブラリやバイナリファイルをデプロイパッケージとして作成できます。それをアップロードし、Layerとして追加することでコンテナ内の/optとして展開されます。ただし、Layerの展開後のサイズが250MBに収まっている必要があります。 デプロイパッケージの作成 Layerに追加するためのデプロイパッケージを作成します。 ここでは、Layerの再利用性を考慮し、3つのパッケージに分割します。 Headless Chrome font Ruby Gems Headless Chromeのデプロイパッケージ作成 serverless chromeとchromedriverを用意。serverless-chromeとchroomedriverのバージョンは合わせる感じで、chromedriverは chromedriver_linux64.zip をダウンロード。 https://github.com/adieuadieu/serverless-chrome/releases https://chromedriver.storage.googleapis.com/index.html ディレクトリは以下のような感じで作成し、zipで圧縮する。 bin ├── chromedriver └── headless-chromium zip -r headless-chrome.zip bin .fontsのデプロイパッケージ作成 日本語用フォントがインストールされてないと、日本語のページを表示した場合に文字化けしてしまうためフォントパッケージを作成します。 wget https://ipafont.ipa.go.jp/IPAexfont/IPAexfont00201.zip unzip IPAexfont00201.zip mkdir .fonts cp IPAexfont00201/*.ttf .fonts zip -r .fonts.zip .fonts Ruby Gemsパッケージの作成 ActiveRecordなり、rubyでseleniumを扱うためにいろいろとライブラリが必要なのでパッケージを作成します。 ActiveRecordがmysql2を使用するため、mysql2のライブラリもまとめてパッケージにする必要があります。 作成方法は以下が参考になります。 AWS LambdaからRuby + Mysql2でAmazon RDSにつないでみた Using Mysql2 gem in AWS Lambda for Ruby - Medium 上記参考資料からの変更点は、Gemfileのみ。以下のGemfileを作成しました。 »

AlexaのプロアクティブイベントAPIを使ってみる

Alexaを買ったのはちょうど一年前くらい。 Alexaにいろいろ通知ができないかといろいろ模索してた時期があって、 そのときは通知用のAPIがβ版になっていてAmazonに申請しないと使えなかったのですが、最近調べたらプロアクティブイベントAPIなるものが出てるらしく遊んでみた。 https://twitter.com/328__/status/1112307063672061953 プロアクティブイベントAPI - amazon alexa プロアクティブイベントAPIとは? 一言で言うとサーバ側からAlexaにPUSH通知を行うことができるAPIです。 Alexaは基本的にユーザがEchoに呼びかけてサーバから結果を取得するいわば「フェッチ型」です。 このプロアクティブイベントAPIを利用すると、ユーザがEchoに呼びかけなくてもサーバ側から通知を送ってくれる「プッシュ型」の処理が作れるわけです。 とはいっても、このAPIだけでは好きな言葉をベラベラ喋らせれることはできなくて、ある定型文に沿って喋らせることができるだけです。 それと、「Alexa, 通知は何?」って聞かないと結果は返してくれません。 ※ 聞かなくても勝手に返してくれる方法があれば誰か教えてください 使ってみる https://github.com/328/alexa-proactive-api-test 1. ツールのインストール https://serverless.com https://developer.amazon.com/ja/docs/smapi/ask-cli-command-reference.html 2. AlexaDeveloperコンソールからスキルを作成 LambdaのトリガーにスキルIDが必要になるのでこちらを控えておく。 スキルIDはAlexaスキルのアプリ名の下に「スキルIDの表示」というボタンがあるのでそこを押下すると表示される。 3. ServerlessFrameworkで空のLambdaを作成 https://github.com/328/alexa-proactive-api-test/blob/master/lambda/subscribe-event-lambda/serverless.yml#L16 ↑の __SKILLID__ 部分を手順2で控えたスキルIDに差し替えて # sls deploy でデプロイを実行する。LambdaのARNを控える。 4. askコマンドでプロジェクトをデプロイを実行 uri内の __LAMBDA_ENDPOINT__ を手順3で控えたARNに変更する。 https://github.com/328/alexa-proactive-api-test/blob/master/skill.json configのskillIdを記載 https://github.com/328/alexa-proactive-api-test/blob/master/.ask/config#L4 ask deploy でデプロイを実行します。 5. Alexaコンソールから通知の許可を実行 https://alexa.amazon.co.jp にアクセスします。 「有効なスキル→作成したアプリをクリック→設定→アクセス権を管理→Alexaの通知をON→アクセス権を保存」で通知を許可します。 これやってなくてハマってしまった…^^; 6. クライアントIDとクライアントシークレットを控える alexa developer consoleから「アプリ→アクセス権限→Alexaスキルメッセージング」からクライアントIDとクライアントシークレットの2つを控える 7. userIdの取得 Alexaでスキルを動作させて、LambdaのコンソールからuserIdを取得 8. プロアクティブイベントAPIを実行 https://github. »

GCPインスタンスのスナップショットを定期的に取得する

GCPインスタンスのスナップショットを定期取得・削除してみる GCPで動作するインスタンスのスナップショットはGCPのコンソールからポチポチやると 簡単に取れたり不要なものを削除したりできるのだけれど、毎日コンソールを開けて手でポチポチやるのは大変なので自動化する。 その時のメモ。 ServerlessFrameworkでは、GoogleCloudFunctionも対応してるのでこれでいけるんじゃないかと思ったのだがeventがhttpしか選択できず cron的な使い方ができないので断念。。。 Google Function Events - Serverless.com 楽に実装できそうなLambdaに逃げることに。 GCPを操作するライブラリはNodeJSで書かれたgoogle-cloud-nodeを使用しました。 GoogleCloudPlatform/google-cloud-node - Github 下記のドキュメントにサンプルコードがあるのでそれを利用してます。 スナップショットの作成 https://googlecloudplatform.github.io/google-cloud-node/#/docs/compute/0.7.1/compute/disk?method=createSnapshot スナップショットの削除 https://googlecloudplatform.github.io/google-cloud-node/#/docs/compute/0.7.1/compute/snapshot?method=delete 実際に書いたコード 328/gcp-backup-cron - Github 1つのプロジェクトだけで利用するのではなく、複数のプロジェクトにも使い回しができるよう プロジェクト情報やインスタンス名は全て環境変数(serverless.yml)に記載するように気を使ってます。 インスタンスのスナップショットはポンポン消しちゃって大丈夫なのかなって疑問に思ってたんですが、 削除時に依存関係のあるデータは全て次のスナップショットに移動されるそうです。 スナップショットを削除する - GoogleCloudPlatform »

Github PullRequestのOpen/CloseのみをSlackに通知する

ChatOps系で使い古されたネタです。 Slackには元々Github Integrationがあるんですが、 無料で利用してると1チームで使用できるIntegrationには限りがあるのと Integrationを別で流用したかったので、その練習もかねて PullRequestのOpen CloseのみをSlackに通知したくて、ServerlessFrameworkでコードを組みました。 アーキテクチャ GithubからAPIGatewayのendpointに対してメッセージを投げて、 LambdaでメッセージをparseしてSlackにメッセージを投下するという感じです。 実際に作ったもの github-pr-notification/328 - github 実際にこんな感じで使えます。 作る上で困ったこと GithubからLambdaにpayloadを持ってくる時にpayload={ "message" : "test messages"}とJSONっぽいただの文字列が降ってくるんですが、ここをどうするかで少し悩んでました。結局、slice(8)で最初の文字列をそぎ落としてJSON.parseしました。 とりあえず、sliceするか正規表現でマッチかけてごにょごにょするかしか今のところは思いつかないですが、他に良い方法があったら誰か教えてくださいm(_ _)m おわりに APIGatewayやLambdaを結構使ってきましたが、そろそろDynamoDBとの連携もやってみたいなと思ったり。 CodeBuildで遊んだりもしてるのでそろそろ記事を投下しようと思います。 おしまい。 »

Lineトークにアップした画像をS3に保存する

先日はRekognitionを利用して飯テロ禁止botを作成しましたが、 今回はLINEにアップした画像をS3に保存するbotを作ってみました。 Lineトークにアップされた画像は2週間でLineサーバから削除されるため、 後でダウンロードしようと思った時に有効期限が切れてしまってもう1度アップし直してもらう… なんてことがありました。 アルバムに置いてれば保存期間は無期限なんですが やはりトーク内に画像貼り付ける方が楽ですからね。 そんなこんなで、S3に置いて永続化できるといいなぁと思った次第です。 アーキテクチャ 基本構成は前回のものと同じですが、RekognitionがS3に置き換わっています。 実際に作ってみた コードはGithubに置いてます。 https://github.com/328/serverless-practice/tree/master/linebot-s3 serverless.yml LambdaにはS3の書き込み権限を付与します。(めんどくさいのでフルアクセスにしてるのは申し訳ない) 環境変数はLine developerからとってくる handler.js 保存するファイル名をどうしようかなぁちょっとばかり悩んでたんですが 「画像をMD5関数に突っ込んでハッシュ値を得る。そのハッシュ値をファイル名として利用する。」 としました。 メリットとして 同じ画像が既に上がっていた場合は上書き保存される。 同じ画像はリストに出てこなくなるので一種の重複排除機能として利用できる。 もちろん問題点はあって 「ハッシュ値は衝突する可能性がある」 ということで この辺りを改善するには ハッシュ値 + タイムスタンプ でファイル名とする 既に同じファイル名のものがS3上にあるか検索し、あればMD5とは別のもので再計算する くらいでしょうか。 実際に大量のファイルを保存する場合にはこの辺りも考慮にいれないといけなかったり。 あとは他のアルゴリズムを使うと計算量が多くなる可能性があったり その分Lambdaの実行時間が長くなってしまう可能性もある(要検証)。 個人で利用する分にはこれくらいのもので良いし、 違う画像でMD5が一致した場合には画像が消えてしまいますが、 その辺は許容します。 という感じでLinebotを作ってみました。 先日のRekognitionと組み合わせれば画像を仕分けしつつ保存できそうですね。 もう少し時間を作って他のLINE APIも触ってみようかなと思います。 »

飯テロ禁止botをLINE + AWS Rekognitionで実装する

先週、JAWS-UG沖縄 画像認識サービスを使ってみようハンズオン / もくもく勉強会 2017年7月に参加してきました。 AWSの画像認識サービス(Rekognition)を使って感情ランキングアプリを作るハンズオンをやっておりました。 JAWS-UG青森で開催されたハンズオンの再演で、感情ランキングアプリを作りました。 Rekognition使って何か作れないかなあと考えてたら そういやパリピ共がよくご飯の時間に美味そうなご飯の写真をうpしてくるので それを撃退できるbotが作れたらいいなと思ってちょっと頑張ってみました。 ちょっとググってみたら似たようなことを既に実施してる人がいたのでこれを元にちょいっと変更したらできそうな感じ Amazon Rekognition × LINE Botを試してみた - Qiita 実際に作ったもの 下記の画像を見てもらえればわかる通りご飯画像を投げるとアラートメッセージが飛んできます。 アーキテクチャ Line DeveloperのサイトにWEBHOOK_URLを登録する項目があるので、そこにAPIGatewayのURLを登録する。 Linebotへの個別, もしくはLinebotが属するグループに対して発言なり画像を送信するとアップロードするとWebhook URLにイベントが通知されてAPIGatewayを経由して、Lambdaが処理を行う。 そのイベントが画像であればLambdaを介してRekognitionで解析をかける。 それがご飯であればアラートを上げるようにします。 Rekognition自体は日本のリージョンで展開されてないサービスですので、バージニア北部等のリージョンで利用します。 APIGateway, Lambdaもそれに合わせて今回はバージニア北部のリージョンで利用します。 Rekognition Rekognitionに画像を投げると下記のような感じでラベル付けをしてくれます。 { "Labels": [ { "Name": "Bowl", "Confidence": 97.36100769042969 }, { "Name": "Dish", "Confidence": 69.66221618652344 }, { "Name": "Food", "Confidence": 69.66221618652344 } ] } 今回のお題は「ご飯の画像であればアラートを上げる」ですので、 LabelsのNameのValueがFoodでConfidenceのvalueがある一定以上であればメッセージを出力できればOKです。 Line -> APIGateway 一部マスク・省略してますが、LINEからAPIGatewayに入ってくるパラメータはこんな感じです. { resource: '/', path: '/', httpMethod: 'POST', headers: { Accept: '*/*', 'Content-Type': 'application/json;charset=UTF-8', Host: '********. »

Serverless Frameworkを触ってみた + 環境変数のアップロードまでやってみる

最近はあちこちでサーバーレスってTwitterのTLでよく聞くようになってて興味を持っています。 そういや、 今年の8月にもJAWS-UG沖縄 真夏の熱すぎるサーバレス祭り! - Doorkeeperに参加したのだれど、 その時のブログを書くの忘れてたのを今気づいた。 (過去記事漁ってみたら無かったからきっと書いてない…) ↑の勉強会に参加したときにServerless Frameworkの存在を初めて知りました。 と前置きはこのくらいにして Serverless Frameworkをちょっと触ってみたときのログを書いておきます。 最近、AWSのLambdaさんが環境変数使えるようになったのと、 Serverless Frameworkが環境変数のアップロードに対応したのでそこまでがんばってみました。 Serverless Frameworkの導入から実行まで 下記は割愛します。 npmのインストール awsのアクセスキー取得と登録 serverless frameworkのインストールは公式のドキュメントに書いてある通り $ npm install -g serverless で、プロジェクト作る時は $ serverless create --template aws-nodejs --path my-service でいけた。 後、ローカルで実行したかったのでserverless-run-function-pluginも入れておく。 $ npm install -g serverless-run-function-plugin my-serviceディレクトリに移動して/handler.jsの中身をちょちょいと書き換えて module.exports.hello = (event, context, callback) => { console.log("テストメッセージ"); }; 実行します。 $ serverless run -f hello すると、テストメッセージが表示される。 環境変数のアップロードまでやってみる ただアップロードするだけじゃ面白くないので 実際に環境変数が呼ばれて動くところまで確認してみます。 1分に1度Slackにメッセージをポストする感じのLambda Functionを作ってみます。 (1分に1度もポストされるとすごいうっとおしいので注意…w) プロジェクトを新しく作成します。 $ serverless create --template aws-nodejs --path slack-post $ cd slack-post ソースはgistに上げて起きました。 »