ようへいの日々精進XP

よかろうもん

2018 年 12 月 07 日 (金)

ジョギング

  • お休み

東京出張 3 日目

  • 職場の部署忘年会
  • こんなに大勢で呑むのは本当に久しぶりで楽しかった
  • 普段話せてない人とかといろいろと喋れたはず (酔っててあまり覚えていない) なので良かった
  • 二次会まで参加して, その後, 西尾さんと新橋のガード下で呑む, 西尾さんとも久しぶりに会ったのでとても楽しかった

西尾さん, 一緒に仕事をしている時よりもすごく痩せていたし, 色々と話していて技術的な経験も積んでだいぶ立派になったなあ. 自分も負けないようにこれかも頑張りたい.

2018 年 12 月 06 日 (木)

ジョギング

  • お休み

東京出張 2 日目

  • 久しぶりに福田先生夫妻と飯田橋で呑む
  • 高校時代から体のメンテナンスをして頂いていて, 摂食障害で死にそうになっている時にも色々とお世話になった大恩人夫妻
  • 一念発起して上京して東京の暮らしがとても楽しいとおっしゃっていたのがとても印象的だった

ギョームにて

  • イケるだろって思ったことが全くうまくいかずに大変な思いをした
  • 慢心は良くない, 1 つ 1 つ, ちゃんと確認することが何よりも正義ということを実感した

Backlog Wiki をオフラインでも管理したいと思ったので daimyo を作ってみました

これは

adventar.org

Backlog Advent Calendar 2018 の第 7 日目の記事です.

qiita.com

初老丸アドベントカレンダー 2018 の第 7 日目の記事です.

本当は

furikake について書こうと思っていたのですが, たまたま出張で飛行機に乗ることがあり, インターネットが使えない, もしくは遅くて使い物にならない環境でも Backlog Wiki を更新したいなあと思ったので, 出張先のホテルでザクッと作ってみた daimyo というツールについて紹介させて頂きます.

github.com

ちなみに, 好きなエディタで Wiki を書きたいという方にもピッタリなのではと考えています. 残念ながら Markdownプレビュー機能は備わっていませんが, 別のプレビューツールと組み合わせて快適な Wiki 編集環境を築けるのではないかと思います.

daimyo = 大名

daimyo は

Backlog の Wiki をローカルマシンのダウンロードしてきて, ローカルマシン上の好きなエディタで更新し, 更新内容をアップロードする際に簡単な差分チェックを行い, 更新をアップロードするツールです. daimyo という名前はヌーラボさんの福岡オフィスがたしか福岡市中央区大名にあったよなあと思って付けました. すいません.

daimyo の使い方

daimyo のインストールについては, README.md をご一読ください. 以下, 既に daimyo がインストールされている前提で書かせて頂きます.

.daimyo.yml の作成

.daimyo.yml に Backlog のスペースキー, Backlog API キーを設定します.

space_id: 'your-space-name'
top_level_domain: 'jp'
api_key: 'your-api-key'

プロジェクトの Wiki 一覧を出力する

以下を実行してプロジェクトの wiki 一覧を出力することが出来ます.

bundle exec daimyo list --project-id=your-backlog-project

以下のように出力されます.

+--------+--------------------------------------------+----------------------+----------------------+
| ID     | Name                                       | Created              | Updated              |
+--------+--------------------------------------------+----------------------+----------------------+
| xxxxx1 | Home                                       | 2017-05-15T05:51:52Z | 2018-12-07T03:02:03Z |
| xxxxx2 | Lambda 送信テスト                          | 2018-11-16T10:01:24Z | 2018-12-07T02:47:20Z |
| xxxxx3 | ディレクトリ/サブディレクトリ/うぃきうぃき | 2018-12-07T03:30:57Z | 2018-12-07T03:30:57Z |
+--------+--------------------------------------------+----------------------+----------------------+

プロジェクト単位での Wiki の書き出す

以下を実行してプロジェクト単位で wiki を export します.

bundle exec daimyo export --project-id=your-backlog-project

一応, Wiki の階層構造がそのままディレクトリ構造になるようにしています.

$ tree your-space -N
your-space
└── YOUR-PJ
    ├── xxxxx1_Home.md
    ├── xxxxx2_Lambda 送信テスト.md
    └── ディレクトリ
        └── サブディレクトリ
            └── xxxxx3_うぃきうぃき.md

3 directories, 5 files

Wiki を更新する

ローカルマシン上で Wiki を修正したら, 以下を実行して変更の差分を確認します.

bundle exec daimyo publish --project-id=YOUR-PJ --dry-run

以下のように差分を確認出来ます.

$ c --dry-run
your-space/YOUR-PJ/ディレクトリ/サブディレクトリ/xxxxx3_うぃきうぃき.md
 # ディレクトリ/サブディレクトリ/うぃきうぃき
+
+## テスト
+
+* テスト

インターネットがつながる環境になったら, 以下を実行して Wiki を更新します.

bundle exec daimyo publish --project-id=YOUR-PJ

いい感じです.

f:id:inokara:20181207125518p:plain

Wiki を更新したら, 改めて export を実行してローカルマシン上の Wiki ファイル (Markdown) を更新するようにしましょう.

色々とやりたい

出張先のホテルでザクッと作った daimyo ですが, まだまだ色々と課題があります.

  • 差分比較の比較元について, ローカルだけではなく, Wiki と直接比較出来るようにしたい
  • 複数のスペース, 複数のプロジェクトを跨いで管理出来るようにしたい
  • とにかくコードが汚いので...直すぞ!

ということで

ということで, 飛行機等の長距離移動の際, インターネット環境が無いような場所でも Wiki が更新出来るようになって自分は嬉しいのですが, もし, よろしければ, daimyo をお試し頂きフィードバックをいただけると嬉しいです.

ありがとうございました.

2018 年 12 月 05 日 (水)

ジョギング

  • お休み
  • だいぶん走っていない感, 今日から出張なので皇居の周りを一回は走りたいと思っている

東京出張

  • 久しぶりの東京出張
  • チームメンバーとワイワイ話しをしながら仕事が久しぶりで楽しかったけど疲れた

夕飯

  • チームメンバーと焼鳥, 東京でもこんなに美味しい焼き鳥が食べれるのかと感動
  • 焼き鳥の後は新橋駅前の焼酎バーで安田というとてもフルーティーな焼酎を呑む

面白いなあ

  • もうすぐ一区切りつきそうなタイミングで色々と課題が降ってくる
  • 自分ってなにか持ってるのかなって思ってしまった (笑...というか, 笑うしかないので, 明日は走ろうと思う

2018 年 12 月 04 日 (火)

ジョギング

  • 引き続き, 左足首周りの痛み, 右足甲の痛みがあったのでお休み
  • いつまでこの痛みが続くのかな..., ほんと, いつまで続くのかな...

日課

  • 筋トレも早くやりたい, 特に懸垂は効果てきめんだったので...

お休み

  • お仕事お休みを頂いて, 銀行の住所変更や解約手続きなど
  • 家事したり, 結構バタバタしてて結局何していたんだかという一日だった
  • 奥さんが仕事から帰ってくるなり, 諸々の進捗が思ったほど悪かったらしく罵倒された...ごめんなさい

明日から

  • 東京出張

2018 年 12 月 03 日 (月)

ジョギング

  • 引き続き, 左足首周りの痛み, 右足甲の痛みがあったのでお休み
  • いつまでこの痛みが続くのかな...

日課

  • 実はまだあばらが痛い, 特に寝起きで体勢を変える際に痛みが走る

湯豆腐

  • 佐賀出身の女性と結婚し弟参号から湯豆腐セットのお歳暮が届いていたので, 早速, 湯豆腐してみた
  • 一見, 木綿豆腐なんだけど, 添付の調味液と一緒に煮込むととろとろのいい感じになってとても美味しかった...ので 3 パック一気食いしてしまった

2018 年 12 月 02 日 (日)

ジョギング

  • 左足首周りの痛み, 右足甲の痛みがあったのでお休み

日課

  • 実はまだあばらが痛い, 特に寝起きで体勢を変える際に痛みが走る

福岡国際マラソン

www.fukuoka-marathon.com

  • 珍しくスタートから応援
  • 日本が世界に追いついてきたんじゃないかと思えるようなレース展開で福岡の街を服部勇馬が駆け抜けた感じで良いレースだった
  • 30 キロ以降を 1 キロ 3 分を切って走っていたのには震えが来るくらい興奮した

furikake-serverless

せっかく AWS Lambda が Ruby ランタイムをサポートしたので, furikake を Lambda 上で動かせるようにしてみた.

github.com

furikake 側の修正範囲が意外に小さくて良かった. ギョームに利用していきたい.

コロッケ

実家から沢山送られてきたじゃがいもで奥さんがコロッケを作ってくれた. サッと作った割にはとても美味しくて 5 個くらい食べてしまった.

furikake-serverless を作った 〜 今夜は炊き込みご飯なので furikake は要らない 〜

これは

qiita.com

初老丸 Advent Calendar 2018 第 13 日目の記事になる予定です.

tl;dr

AWS Lambda のランタイムとして Ruby がサポートされました. 待ちに待っていた方, もう待ちくたびれた方, 悲喜こもごもだと思います.

aws.amazon.com

さて, 早速ではありますが, Lambda 上で動かしてみたいと思っていた furikake について, Lambda 上で実行出来るようにしてみましたので, 紹介させていただきます.

github.com

ちなみに, furikake を Lambda で動かすのは単なる興味からだけではなく, 以下のようなメリットがあると考えている為です.

  • 実行環境 (サーバーや個人端末) が不要
  • CloudWatch Events と組み合わせて定期実行することにより, Backlog Wiki 上の情報を新鮮に保つことが出来る

EC2 インスタンスのバックアップスクリプト等も Lambda を利用して取得していたりますので, ドキュメントについても同じように Lambda を利用して常に最新の状態に保つことが出来るのではと考えています. (同じようなアプローチで Fargate のスケジュールタスクを利用する方法もあると思いますが, そちらは別の機会に試してみたいと思います.)

furikake-serverless チュートリアル

必要なもの (準備しておくもの)

direnv も利用出来るようにしておくとより良いと思います.

セットアップ

sam で利用する S3 バケットを作成する

aws s3 mb s3://your-sam-s3-bucket

git clone

git clone https://github.com/inokappa/furikake-serverless.git

event.json の修正

event.sample.json を修正して event.json を作成します.

{
  "resources": {
    "aws": [
      "alb",
      "clb",
      "directory_service",
      "ec2",
      "elasticsearch_service",
      "kinesis",
      "lambda",
      "rds",
      "security_group",
      "vpc",
      "vpc_endpoint"
    ]
  },
  "backlog": {
    "projects": [
      {
        "space_id": "example",
        "top_level_domain": "jp",
        "wiki_id": "1234567",
        "wiki_name": "Lambda 送信テスト",
        "header": "# Test Header\n[toc]\n## Sub Header\n",
        "footer": "## Test Footer\n### Sub Footer"
      }
    ]
  }
}

resources.aws 以下のリソース名を必要に応じて, space_id 等を環境に応じて修正します. これは furikake の .furikake.yml と同じ内容になっていて, 単に YAMLJSON の違いです.

sam の template.yml の生成

KMS を利用して Backlog の API キーを暗号化しますので, make template を実行して template.yaml を生成します.

$ make template

以下のように出力されるので, KMS の Key ID を API キー, 実行間隔 (任意なので, 何も指定しない場合には Enter を押下), タイムゾーン (任意なので, 何も指定しない場合には Enter を押下) を入力します.

$ make template
KMS の Key ID を入力してください:
xxxxxxxx-xxx-xxxx-xxxx-xxxxxxxx
API キーを入力してください:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
実行間隔を分で入力してください (デフォルト 60):

タイムゾーンを入力してください (デフォルト Asia/Tokyo):

template.yaml created.

上記のように出力されると, 正常に template.yaml が生成されていると思います. 念の為, template.yaml の中身を確認してみます.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'furikake-serverless'

Resources:
  FurikakeServerless:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./src
      Handler: lambda.run
      Runtime: ruby2.5
      Timeout: 900
      Policies:
        - ReadOnlyAccess
        - KMSDecryptPolicy:
            KeyId: xxxxxxxx-xxx-xxxx-xxxx-xxxxxxxx
      Environment:
        Variables:
          ENCRYPTED_BACKLOG_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      Events:
        FurikakeSchedule:
          Type: Schedule
          Properties:
            Schedule: rate(60 minutes)
            Input: '{
  "resources": {
    "aws": [
      "alb",
...

Outputs:
  FurikakeServerless:
    Description: Serverless Furikake Lambda Function ARN.
    Value:
      Fn::GetAtt:
      - FurikakeServerless
      - Arn

CloudWatch Events で 60 分毎に Lambda 関数が起動するように設定されています.

...
      Events:
        FurikakeSchedule:
          Type: Schedule
          Properties:
            Schedule: rate(60 minutes)
...

Schedule: の値を修正することで任意の時間で Lambda 関数が起動するようにカスタマイズが可能です.

デプロイ

make packagemake deploy を実行して, Lambda 関数をデプロイします.

# packaged-template.yaml を生成して, 各種ファイルを S3 にアップロードする
make package _BUCKET_NAME=your-sam-s3-bucket

make package を実行した後, packaged-template.yaml が生成されていることを確認します.

# Lambda 関数をデプロイ
make deploy

以下のように出力されることを確認します.

$ make deploy

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - FurikakeServerless

デプロイが完了したらしばらく待ちましょう...デフォルトで 1 時間後.

しばらく放置しておくと

下図のように, 定期的に wiki が更新されていることを確認することが出来ると思います.

f:id:inokara:20181202090256j:plain

いい感じです.

以上

いよいよ Ruby が Lamda 上で動くということで, furikake を Lambda で動かせるようにしてみました. まだ色々と課題はありそうですが, furikake を作ったモチベーションの一つである, ドキュメントの鮮度を常に最新に保つ, しかもお手軽に...がこれで叶ったような気がしています. また, 他にも Lambda で動かしてみたい gem があるので, 引き続き, 試行錯誤してみようかなと思います.

2018 年 12 月 01 日 (土)

ジョギング

  • 山王公園往復
  • 左足首周りの痛み, 右足甲の痛み...満身創痍感
  • 超スローペースで走ったけど, 明日は休む

日課

  • あばらの状態も良くなってきたので, 走れないのを筋トレでカバーしようとかなと考えている

奥さん

  • 2 泊 3 日の出張から帰ってきた
  • 仕事自体は疲れたけど, ちょっと体力に自信が付いたとのことで良かった

  • 利尻昆布で出汁を取ったけど...なんかイマイチだった

furikake-serverless

とりあえず作ってみた.

github.com

続・日本で 128 番目くらいに Ruby で AWS Lambda を試したメモ 〜俺のライブラリを Lambda で動かしたいけど...〜

追記

追記 (3) aws-sdk 以外の gem だけをロードする場合ってどうなのか

検証コード

以下のように furikake で利用する aws-sdk を除いて, 依存している gem を require してみます.

require 'benchmark'

def run(event:, context:)
  Benchmark.bm(10) do |r|
    r.report 'require gems' do
      require 'thor'
      require 'markdown-tables'
      require 'backlog_kit'
    end
  end
end

run(event: {}, context: {})

結果

# On macOS (Ruby 2.5.1)
$ bundle exec ruby lambda.rb
                 user     system      total        real
require gems  0.091279   0.049211   0.140490 (  0.387624)

$ bundle exec ruby lambda.rb
                 user     system      total        real
require gems  0.091667   0.041068   0.132735 (  0.133426)

$ bundle exec ruby lambda.rb
                 user     system      total        real
require gems  0.087537   0.043253   0.130790 (  0.132725)

# On Docker Container (lambci/lambda:build-ruby2.5)
bash-4.2# ruby lambda.rb
                 user     system      total        real
require gems  0.060000   0.310000   0.370000 (  1.752973)

bash-4.2# ruby lambda.rb
                 user     system      total        real
require gems  0.060000   0.190000   0.250000 (  1.729625)

bash-4.2# ruby lambda.rb
                 user     system      total        real
require gems  0.140000   0.120000   0.260000 (  1.668639)

# On Lambda
                 user     system      total        real
require gems  0.000016   0.000006   0.000022 (  0.000020)

                 user     system      total        real
require gems  0.000021   0.000008   0.000029 (  0.000026)

                 user     system      total        real
require gems  0.000030   0.000011   0.000041 (  0.000037)

Lambda での処理時間が圧倒的に高速で優秀だと思います. 全く aws-sdk に依存しない gem を利用する場合にはロードに要する時間はとても短いことを確認しました.

見解

これらの結果から, 以下のようなことが言えそうです.

  • サードパーティ製の gem において, aws-sdk に依存している gem を Lambda で利用する場合, 関数の初回起動時だけ gem のロードに時間が掛かる可能性がる (furikake はまさにそうで, furikake 自身が aws-sdk に依存している)

追記 (2) Ruby ランタイムに組み込まれている gem の一覧

以下, Ruby ランタイムに事前に組み込まれている gem の一覧です. aws-sdk は予め組み込まれていました (そりゃそうだ...).

codestar (1.7.0)
aws-sdk-cognitoidentity (1.5.0)
aws-sdk-cognitoidentityprovider (1.10.0)
aws-sdk-cognitosync (1.5.0)
aws-sdk-comprehend (1.8.0)
aws-sdk-configservice (1.19.0)
aws-sdk-connect (1.8.0)
aws-sdk-core (3.37.0)
aws-sdk-costandusagereportservice (1.5.0)
aws-sdk-costexplorer (1.12.0)
aws-sdk-databasemigrationservice (1.13.0)
aws-sdk-datapipeline (1.5.0)
aws-sdk-dax (1.7.0)
aws-sdk-devicefarm (1.12.0)
aws-sdk-directconnect (1.8.0)
aws-sdk-directoryservice (1.10.0)
aws-sdk-dlm (1.6.0)
aws-sdk-dynamodb (1.16.0)
aws-sdk-dynamodbstreams (1.5.0)
aws-sdk-ec2 (1.56.0)
aws-sdk-ecr (1.8.0)
aws-sdk-ecs (1.22.0)
aws-sdk-efs (1.6.0)
aws-sdk-eks (1.7.0)
aws-sdk-elasticache (1.9.0)
aws-sdk-elasticbeanstalk (1.13.0)
aws-sdk-elasticloadbalancing (1.7.0)
aws-sdk-elasticloadbalancingv2 (1.16.0)
aws-sdk-elasticsearchservice (1.14.0)
aws-sdk-elastictranscoder (1.6.0)
aws-sdk-emr (1.7.0)
aws-sdk-firehose (1.8.0)
aws-sdk-fms (1.6.0)
aws-sdk-gamelift (1.9.0)
aws-sdk-glacier (1.13.0)
aws-sdk-glue (1.20.0)
aws-sdk-greengrass (1.10.0)
aws-sdk-guardduty (1.10.0)
aws-sdk-health (1.7.0)
aws-sdk-iam (1.10.0)
aws-sdk-importexport (1.5.0)
aws-sdk-inspector (1.11.0)
aws-sdk-iot (1.18.0)
aws-sdk-iot1clickdevicesservice (1.5.0)
aws-sdk-iot1clickprojects (1.5.0)
aws-sdk-iotanalytics (1.9.0)
aws-sdk-iotdataplane (1.5.0)
aws-sdk-iotjobsdataplane (1.6.0)
aws-sdk-kinesis (1.8.0)
aws-sdk-kinesisanalytics (1.7.0)
aws-sdk-kinesisvideo (1.6.0)
aws-sdk-kinesisvideoarchivedmedia (1.6.0)
aws-sdk-kinesisvideomedia (1.5.0)
aws-sdk-kms (1.11.0)
aws-sdk-lambda (1.13.0)
aws-sdk-lambdapreview (1.5.0)
aws-sdk-lex (1.8.0)
aws-sdk-lexmodelbuildingservice (1.11.0)
aws-sdk-lightsail (1.10.0)
aws-sdk-machinelearning (1.5.0)
aws-sdk-macie (1.5.0)
aws-sdk-marketplacecommerceanalytics (1.5.0)
aws-sdk-marketplaceentitlementservice (1.5.0)
aws-sdk-marketplacemetering (1.5.0)
aws-sdk-mediaconvert (1.16.0)
aws-sdk-medialive (1.15.0)
aws-sdk-mediapackage (1.9.0)
aws-sdk-mediastore (1.6.0)
aws-sdk-mediastoredata (1.7.0)
aws-sdk-mediatailor (1.6.0)
aws-sdk-migrationhub (1.7.0)
aws-sdk-mobile (1.5.0)
aws-sdk-mq (1.7.0)
aws-sdk-mturk (1.8.0)
aws-sdk-neptune (1.6.0)
aws-sdk-opsworks (1.8.0)
aws-sdk-opsworkscm (1.9.0)
aws-sdk-organizations (1.15.0)
aws-sdk-pi (1.5.0)
aws-sdk-pinpoint (1.12.0)
aws-sdk-pinpointemail (1.0.0)
aws-sdk-polly (1.13.0)
aws-sdk-pricing (1.5.0)
aws-sdk-rds (1.36.0)
aws-sdk-redshift (1.13.0)
aws-sdk-rekognition (1.14.0)
aws-sdk-resourcegroups (1.7.0)
aws-sdk-resourcegroupstaggingapi (1.5.0)
aws-sdk-resources (3.27.0)
aws-sdk-route53 (1.15.0)
aws-sdk-route53domains (1.7.0)
aws-sdk-s3 (1.23.1)
aws-sdk-sagemaker (1.22.0)
aws-sdk-sagemakerruntime (1.6.0)
aws-sdk-secretsmanager (1.19.0)
aws-sdk-serverlessapplicationrepository (1.9.0)
aws-sdk-servicecatalog (1.12.0)
aws-sdk-servicediscovery (1.7.0)
aws-sdk-ses (1.13.0)
aws-sdk-shield (1.8.0)
aws-sdk-signer (1.4.0)
aws-sdk-simpledb (1.5.0)
aws-sdk-sms (1.5.0)
aws-sdk-snowball (1.9.0)
aws-sdk-sns (1.7.0)
aws-sdk-sqs (1.9.0)
aws-sdk-ssm (1.32.0)
aws-sdk-states (1.7.0)
aws-sdk-storagegateway (1.12.0)
aws-sdk-support (1.5.0)
aws-sdk-swf (1.5.0)
aws-sdk-transcribeservice (1.10.0)
aws-sdk-translate (1.6.0)
aws-sdk-waf (1.10.0)
aws-sdk-wafregional (1.11.0)
aws-sdk-workdocs (1.6.0)
aws-sdk-workmail (1.6.0)
aws-sdk-workspaces (1.8.0)
aws-sdk-xray (1.8.0)
aws-sigv2 (1.0.1)
aws-sigv4 (1.0.3)
bigdecimal (default: 1.3.4)
bundler (1.17.1)
cmath (default: 1.0.0)
csv (default: 1.0.0)
date (default: 1.0.0)
dbm (default: 1.0.0)
etc (default: 1.0.0)
fcntl (default: 1.0.0)
fiddle (default: 1.0.0)
fileutils (default: 1.0.2)
gdbm (default: 2.0.0)
io-console (default: 0.4.6)
ipaddr (default: 1.2.0)
jmespath (1.4.0)
json (default: 2.1.0)
openssl (default: 2.1.2)
psych (default: 3.0.2)
rdoc (default: 6.0.1)
scanf (default: 1.0.0)
sdbm (default: 1.0.0)
stringio (default: 0.0.1)
strscan (default: 1.0.0)
webrick (default: 1.4.2)
zlib (default: 1.0.0)

追記 (1) Ruby ランタイムの gem environment

以下のようになっていました.

RubyGems Environment:
  - RUBYGEMS VERSION: 2.7.6
  - RUBY VERSION: 2.5.3 (2018-10-18 patchlevel 105) [x86_64-linux]
  - INSTALLATION DIRECTORY: /var/runtime
  - USER INSTALLATION DIRECTORY: /.gem/ruby/2.5.0
  - RUBY EXECUTABLE: /var/lang/bin/ruby
  - EXECUTABLE DIRECTORY: /var/runtime/bin
  - SPEC CACHE DIRECTORY: /.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /var/lang/etc
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86_64-linux
  - GEM PATHS:
     - /var/runtime
     - /var/task/vendor/bundle/ruby/2.5.0
     - /opt/ruby/gems/2.5.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /var/lang/bin
     - /var/lang/bin
     - /usr/local/bin
     - /usr/bin/
     - /bin
     - /opt/bin

これは

qiita.com

俺でもわかるシリーズ Advent Calendar 2018 第 8 日目の記事になる予定です.

qiita.com

初老丸 Advent Calendar 2018 第 12 日目の記事になる予定です.

tl;dr

昨日, 以下のような記事を書きました.

qiita.com

RubyAWS Lambda 上で動くなんてすごいなあと興奮していたのもつかの間, 自分で作ったライブラリが動くかなあと試そうとして躓いた (今も躓いている) ので, メモっておきます.

あれ, 関数の起動が遅いよ...これ

furikake を Lambda で

以下のような issue を立てて, furikake を Lambda 上で動かしてみようとしました.

github.com

以下のようなエントリーポイントになるコードを書いて sam でローカルテストを実行するところまで漕ぎ着けました.

require 'furikake'

def run(event:, context:)
  report = Furikake::Report.new
  report.show
end

以下, 実際の実行例です. 関数のタイムアウト自体は 60 秒に設定しています.

$ echo '{"test":"dayo"}' | sam local invoke ServerlessFurikake
2018-12-01 07:26:47 Reading invoke payload from stdin (you can also pass it from file with --event)
2018-12-01 07:26:47 Found credentials in shared credentials file: ~/.aws/credentials
2018-12-01 07:26:47 Invoking lambda.run (ruby2.5)

Fetching lambci/lambda:ruby2.5 Docker container image......
2018-12-01 07:26:49 Mounting /path/to/serverless-furikake as /var/task:ro inside runtime container
2018-12-01 07:27:50 Function 'ServerlessFurikake' timed out after 60 seconds

あれ...なんでや...タイムアウトしてしまいました.

何が起きているのか

gem のロードが遅くない??

furikake は aws-sdk 等の幾つかの gem に依存しているのですが, これらの gem のロードが遅いんじゃないかな...という仮説を立ててみました. ほんとにそれくらいしか思いつかなかったので. ということで, ローカル環境と sam invoke local で実行する Docker コンテナ環境, Lambda 環境の三環境で gem の読み込み速度の比較をしてみたいと思います.

検証環境

sam は local invoke する際に Docker コンテナを起動して, そのコンテナ上で関数を実行しているので, そのコンテナ上でデバッグしてみたいと思います.

尚, 利用する Docker イメージは以下のイメージです.

github.com

また, Docker を動かしている環境は以下の通りです.

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.13.6
BuildVersion:   17G65

$ ruby --version
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]

ハードウェア的には以下の通りです.

2018 年でも快適に利用出来る環境だと思います.

で, 一旦, furikake から離れて, シンプルな検証用のコードを書いて検証してみます.

require 'benchmark'

def run(event:, context:)
  Benchmark.bm(10) do |r|
    r.report 'require aws-sdk' do
      require 'aws-sdk'
    end
  end
end

run(event: {}, context: {})

gem は bundle init で Gemfile を生成して以下のように記載して bundle install --path vendor/bundle と実行してインストールしました.

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'aws-sdk'

以下のようなディレクトリ, ファイル構成となります.

$ tree . -L 2
.
├── Gemfile
├── Gemfile.lock
├── lambda.rb
├── template.yaml
└── vendor
    └── bundle

2 directories, 4 files

ローカル環境

以下のように, real で 1.5 秒程度掛かっていますが, 2 回目以降は 0.5 秒程度となり, 個人的に違和感はありません.

$ bundle exec ruby lambda.rb
                 user     system      total        real
require aws-sdk  0.327319   0.268804   0.596123 (  1.496711)
$ bundle exec ruby lambda.rb
                 user     system      total        real
require aws-sdk  0.296917   0.187150   0.484067 (  0.489871)
$ bundle exec ruby lambda.rb
                 user     system      total        real
require aws-sdk  0.299350   0.188319   0.487669 (  0.494612)

sam の local invoke で利用する Docker 環境

以下のようにコンテナを起動します.

$ docker run -t -i --rm -v "$PWD":/var/task lambci/lambda:build-ruby2.5 /bin/bash

以下のように 100 秒以上掛かるようになりました.

bash-4.2# ruby lambda.rb && ruby lambda.rb && ruby lambda.rb
                 user     system      total        real
require aws-sdk 27.580000   8.450000  36.030000 (119.208587)
                 user     system      total        real
require aws-sdk 25.780000   9.320000  35.100000 (105.250906)
                 user     system      total        real
require aws-sdk 24.730000   9.860000  34.590000 (102.976592)

あれ.

Lambda 環境 (sam でデプロイ)

sam を使ってデプロイしてマネジメントコンソールで確認します. タイムアウトは最大の 15 分に設定しています.

                 user     system      total        real
require aws-sdk 17.486155   1.504303  18.990458 (232.400251)
                 user     system      total        real
require aws-sdk  0.000095   0.000008   0.000103 (  0.000101)
                 user     system      total        real
require aws-sdk  0.000026   0.000002   0.000028 (  0.000025)
                 user     system      total        real
require aws-sdk  0.000026   0.000002   0.000028 (  0.000025)

初回が鬼のように時間が掛かっています. 2 回目以降は 1 回目が嘘のように速くなっていて, むしろローカル環境で実行するよりも速くなっています. どのような仕組みになっているかは分かりかねますが, gem がキャッシュに載っているんだと思います... きっと.

エントリーポイントになるコードを修正して, デプロイし直したところ, キャッシュを含む環境が破棄されて新しい環境に展開される為, 初回起動と同じくらいの起動時間を要してしまいました.

                 user     system      total        real
require aws-sdk 18.216496   1.705607  19.922103 (243.839962)
Hello.
                 user     system      total        real
require aws-sdk  0.000100   0.000010   0.000110 (  0.000107)
Hello.

なぜか, 初回起動時だけ 2 回 require 'aws-sdk' が実行されているのは...すいません. コードの問題だとおもいます.

Lambda 環境 (手動で Lambda 関数を作成)

マネジメントコンソールにて手動で Lambda 関数を作って, コードを貼り付けてテストしてみます.

                 user     system      total        real
require aws-sdk  0.264964   0.043559   0.308523 (  3.765794)
                 user     system      total        real
require aws-sdk  0.000027   0.000004   0.000031 (  0.000027)
                 user     system      total        real
require aws-sdk  0.000024   0.000004   0.000028 (  0.000026)

初回起動時は 3 秒ほど掛かっていますが, 2 回目以降は一瞬です. Ruby ランタイムには既に aws-sdk が利用可能な状態で組み込まれているようですので, 単純に aws-sdk だけを利用する Lambda 関数を実行する場合には, この程度の起動時間を要すると考えておくと良さそうです.

結果のまとめ

  • Lambda 環境では初めて関数を起動する際, サードパーティ製 gem のロードに時間を要する場合があるので気長に待つ (タイムアウトは長めに設定しておく必要がある)
  • 2 回目以降の実行は爆速, コードを変更してデプロイし直すと環境は破棄されて gem を再ロードしてしまうので...起動は遅くなる
  • sam を使ってローカル実行する場合には, 毎回 gem をロードしてしまうので注意 (そんなもんだと割り切るしかないのかな...)

以上

初回起動時間にさえ注意すれば, 多くの Ruby ライブラリを Lambda 上で動かすことができそうです!

ということで, furikake を動かせそうな気がしてきました.