SakuraWi - BLog

WEBエンジニア。聴いたお話をまとめておく倉庫的な。スタックストックスタック!

AWS lambdaを使って一定時間ごとにrubyを動かしたい


AWS Lambdaの奮闘記です。

初めて触るAWS Lambdaちゃんに苦戦した様子の備忘録。

やりたいこと

AWS LambdaでRubyを動かして、そこからスクレイピング、Google spread sheetにpostして表にデータ挿入

詰まったポイント感

  • SAMって何?とっとこSAM太郎?
  • chrome driver動かなさすぎワロタ
  • pythonの記事ばっかやん!!
  • IAMのポリシーって何

など。

環境なのかわからないけど動かないってケースが多くて結構ハマってました。

ざっくりはじめに見た記事

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-ruby.html

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install-mac.html

https://qiita.com/Y_uuu/items/85c86df8773f7c225521

AWS IAM ロールを追加

AWS IAMとは?

めちゃ簡単に言うとユーザ管理です。
セキュリティリスクなどを考えると、ユーザには最低限の権限を与えて管理するのが望ましいです。

そのためのサービスですね。

AWS IAM ポリシー

ポリシーってやつが権限ですね。

サービスごとに権限がつけられたりするわけです。

業務委託の人とか権限わけたいですよね、そういうイメージ。

ひとまず、ロールを追加をぽちぽち。 権限については、使いたいサービスのFullAccessでひとまずOKだと思いますが、参考記事があるならそれ通りでよいと思います。

ルートユーザを利用するのは危険なので、避けましょう。

SAM

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/what-is-sam.html

サーバーアプリケーションモデルです。

今のところの理解は、サーバレスで動かしたいための一式をコードで管理しちゃおうってやつです。

build叩いて 実行も deployもコマンドひとつでできるようになる感じです。 dockerのコンテナでの実行を超楽にまとめてくれてる。すげえよとっとこSAM太郎。

SAMをインストール

dockerなどはすでにはいっているので、sam cliをインストール。

dockerが入ってない人はインストールしましょう。(手順は書いてほしい気持ちはわかるんですが、省略します...)

ruby のversionは記事では2.5だったが、AWSもruby 2.7に対応しているようなので、2.7で入れてみる。 -> あとでやっぱ2.5にしました。

ローカルのrubyの環境整備

2.5.0とかに合わせたかったので、環境を整備。

手元のruby-buildとかが古かったので、更新。

brew update && brew upgrade ruby-build

2.7.0が rbenv install --listとかしても-devだったりしていた。

2.6.6
2.7.0-dev
2.7.0-preview1
2.7.0-preview2
2.7.0-preview3
2.7.0-rc1
2.7.0-rc2
2.7.0
2.7.1
2.8.0-dev

更新するとちゃんとでてくれる。

ということでinstall rbenv install 2.7.0

rubyの安定板とかはこちらをチェックしましょう。

https://www.ruby-lang.org/ja/downloads/

sam buildすると

Building resource 'HelloWorldFunction'
Running RubyBundlerBuilder:CopySource
Running RubyBundlerBuilder:RubyBundle
Running RubyBundlerBuilder:RubyBundleDeployment

Build Succeeded

いけました。

進める

samの実行自体は以下コマンドでできるみたいですね。

sam local invoke HelloWorldFunction

--event event.json をつけるとエラったので、一旦なし。

Invoking app.lambda_handler (ruby2.7)

Fetching lambci/lambda:ruby2.7 Docker container image................................................................................................................................................
Mounting /Users/sakuraikota/workspace/room_post_sam/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: 74af0a77-3cfa-16a5-c78d-443dee1cd773 Version: $LATEST
END RequestId: 74af0a77-3cfa-16a5-c78d-443dee1cd773
REPORT RequestId: 74af0a77-3cfa-16a5-c78d-443dee1cd773  Init Duration: 255.71 ms    Duration: 5.67 ms   Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 23 MB

{"statusCode":200,"body":"{\"message\":\"Hello World!\"}"}

いけたっぽい?

ファイルの修正したあとは、build。 実行には sam local invoke HelloWorldFunction でいけるようです。

deployもCLIから行えるようで、めちゃ便利だ...!

スクレイピングする際

そのサイトがクロールしても問題ないか、みてあげたほうがいいみたい。

gem 'robotex'

という便利なものがあるみたい。

https://qiita.com/hikao/items/a9864845922a24036660#%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%A9%E3%81%AE%E3%81%8A%E4%BD%9C%E6%B3%95

lambdaがタイムアウトする

Function 'HelloWorldFunction' timed out after 3 seconds

template.yaml のtimeoutの値を増やす。

invokeって強そう

強そうに思える単語ですが、 呼び出すっていう意味です。

そのままですね

chrome driverを先にlambda layersにあげる必要がありそう

何より重たいものっぽく、layersにあげておくとcodeと分離できて軽くなるしよいみたい。

pythonの記事がおおい...

gem 'webdrivers', '~> 3.0'

3.0の方が安定して動いてる、みたいな記事もありました。

Selenium::WebDriver::Chrome.driver_path

driverのpathを指定する。

dir内で完結したい、参照先を配下にしたい。

Selenium::WebDriver::Chrome.driver_path="/layer/bin/chromedriver"

このpathの指定、chromedriverのverなのか、binaryがおかしいのかわかりませんが動きませんでした。。。

ここらへんでsamでやるのは中断。

chrome driver

curl -SL https://chromedriver.storage.googleapis.com/83.0.4103.14/chromedriver_linux64.zip > chromedriver.zip

chrome driver どうもversionがserver-less chromiumとかと合わせないと動作しないケースが多いみたいです。

server-less chromium

うーん、最新版がどれだw

これしかでてこない。。。

curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-37/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip

sam deploy --guided

権限がない、とはじかれる。

AWS iamでユーザ作る

ルートユーザじゃなくて、ユーザ作ってそこで管理してねってことなので、 適当に管理権限つけて作成、設定。

https://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html

rubyだと解決に至らず。

Error raised from handler method
{
  "errorMessage": "not a file: \"../layer/bin/chromedriver\"",
  "errorType": "Function<Selenium::WebDriver::Error::WebDriverError>",
  "stackTrace": [
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-3.142.7/lib/selenium/webdriver/common/platform.rb:136:in `assert_file'",

どうも、binaryのchrome driverが読み込めてないと思うんですが,動きません。

くじけそう

https://dev.to/mknycha/serverless-web-scraper-in-ruby-tutorial-50hg

以下からは上記のサイトの手順でやってみたら動きました。

これを試す。samじゃないけど。とにかく動かそう...

bundle install --deployment とかして、いれても requireする cannot load such file -- selenium-webdriver

えええ。

vendor/bundle 配下を眺めていると、 あ、rubyが2.6.0ではいっている...

vendor/bundle/ruby/2.6.0/gems/selenium-webdriver-3.142.7/selenium-webdriver.gemspec

rbenvですぐさま 2.5.0に整え。

なんとか動いた...

sam利用はできてないけど、ひとまず動いた。

dockerを通して動作を確認。

docker run --rm -v "$PWD":/var/task --mount type=tmpfs,target=/dev/shm,readonly=true lambci/lambda:ruby2.5 lambda_function.lambda_handler

んーと、localでぱっと試せないんだっけか。

ひとまずdeploy、実行できた

実行はできた!

timezoneの設定は、環境変数に TZ, Asia/Tokyoを追加。

実行時間のtimeoutも、 メモリ : 512MB タイムアウト時間: 1分 で設定。

lambdaをちょこっと使うくらいなら無料枠からはみ出さない。

公式サイトで料金計算はできるようになっているので、気になる人は計算してみよう。

リポジトリに追加

binaryファイルとか重たいので、適度に gitignoreしてあげてpushするとよさそう。

一定時間ごとに実行させる

トリガーを追加。

cloud watchを追加。

cronの設定でめちゃはじかれたw ぐぐったらでてきますが、こんな感じにしました。

時差があるので、9時間ひいて。

cron(0 20 * * ? *)

朝5時に実行させます。

google spread sheetへの書き込み

https://qiita.com/takatama/items/e5cb83012d14c0094a79

こちらの記事を参考に、10秒で作れました

まとめ

lambdaの使い方、aws CLI, IAM, ポリシー

とにもかくにも触ってみてわかることってめちゃありますね。

rubyとかbunlderとか環境のこともまた再認識できて、良い機会になりました。