AWSのLambdaファンクションの作成、実行、削除をコマンドラインから操作する

2019-03-23Amazon,AWS,Bash,Linux

S3にファイルがアップロードされたことを検知して、処理を行うような仕組みを作り必要がありました。

処理の部分のロジックはまだ未決定事項が多いため、とりあえずは
Lambdaファンクション呼び出しからCloudWatchLogへログを吐き出すところまでの仕組みを作成してみることにしました。

※作成したLambdaファンクションをS3へのファイルアップロードのつなぎこみは次回調査

aws-cli (AWSコマンドの利用可能な環境づくり)

AWSコマンドを使うための環境をDockerを使って構築(Mac/Linux/WindowsでもPythonなしで動くよ) | ゲンゾウ用ポストイット で環境構築済み。

AWS Lambdaファンクションの作成

AWS Lambda については以下の記事がわかりやすかった。

Lambda作成にあたってやらないといけないことは以下の2つ。

  1. Lambdaファンクションの実行ロールを作成する
  2. Lambdaファンクションを作成する

実行ロールの作成

まずは初期ポリシーファイルを作成します。
Lambdaファンクションの実行に関するフル権限を与えました。

# ファイル名は何でも良い
$ cat <<EOF >logging-function-role-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

作成したポリシーファイルを元に、ロールを作成。

--role-name オプションに今回作成するロール名を指定します。
--assume-role-policy-document オプションに先ほど作成したポリシーファイルを指定します。 file:// プロトコルの指定は必須。これなしだとエラーになってしまうので注意しましょう。

$ aws iam create-role \
  --role-name logging-function-role \
  --assume-role-policy-document file://logging-function-role-policy.json

{
  "Role": {
    "Path": "/",
    "RoleName": "logging-function-role",
    "RoleId": "AROAI5BO3KLUTIOT4H4A4",
    "Arn": "arn:aws:iam::642942901536:role/logging-function-role",
    "CreateDate": "2019-02-25T03:49:50Z",
    "AssumeRolePolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }
  }
}

実行時に出力されたJSONメッセージのうち、 Arn の部分 ( arn:aws:iam::642942901536:role/logging-function-role ) は後々必要となるためメモしておきます

実行結果を CloudWatch Log として保存したいので、以下の既存ポリシーを追加で付与します。

# arn:aws:iam::aws:policy/CloudWatchLogsFullAccess が "CloudWatchLogsFullAccess" のリソース識別子を新たしている
$ aws iam attach-role-policy \
  --role-name logging-function-role \
  --policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess

関数を作成

CloudWatch Logs にログを記録するLambdaファンクションのサンプルコードがあったので、そちらを流用させてもらいましょう。

例) index.js

$ cat <<EOF >index.js
console.log('Loading function');

exports.handler = function(event, context, callback) {
    console.log('value1 =', event.key1);
    console.log('value2 =', event.key2);
    console.log('value3 =', event.key3);
    callback(null, "Success");
};
EOF

このjsファイルを使ってLambdaファンクションを作成。

# 【重要!】jsファイルには忘れずに読み取り可能権限を付与しておく
$ chmod 644 index.js

# デプロイパッケージを作成します。
$ zip function.zip index.js

# create-function コマンドを使用して Lambda 関数を作成します。
$ aws lambda create-function \
  --function-name logging-function \
  --zip-file fileb://function.zip \
  --handler index.handler \
  --runtime nodejs8.10 \
  --role "arn:aws:iam::642942901536:role/logging-function-role"

{
  "FunctionName": "logging-function",
  "FunctionArn": "arn:aws:lambda:ap-northeast-1:642942901536:function:logging-function",
  "Runtime": "nodejs8.10",
  "Role": "arn:aws:iam::642942901536:role/logging-function-role",
  "Handler": "index.handler",
  "CodeSize": 307,
  "Description": "",
  "Timeout": 3,
  "MemorySize": 128,
  "LastModified": "2019-02-25T03:50:50.928+0000",
  "CodeSha256": "XXvquA+6ckcnnRiKe5T6uov/yBXFIqDZTULBJ9TPfvw=",
  "Version": "$LATEST",
  "TracingConfig": {
    "Mode": "PassThrough"
  },
  "RevisionId": "ab7440f3-1443-4e73-b2f6-10bd85b6e0c2"
}

実行してみる

コマンドラインから実行してみます。(通常通り、マネージメントコンソールページから実行してもよいか、コマンドラインの世界が好きなので。)

$ aws lambda invoke \
  --function-name logging-function \
  --log-type Tail \
  --payload '{"key1":"value1", "key2":"value2", "key3":"value3"}' \
  outputfile.txt

{
    "StatusCode": 200,
    "LogResult": "U1RBUlQgUmVxdWVzdElkOiAxNWQzOTE2NC1mMjJjLTQxNDMtYjI3OS0zZWM1YjcyMThmNTggVmVyc2lvbjogJExBVEVTVAoyMDE5LTAyLTI1VDAzOjU5OjE0LjM5NloJMTVkMzkxNjQtZjIyYy00MTQzLWIyNzktM2VjNWI3MjE4ZjU4CXZhbHVlMSA9IHZhbHVlMQoyMDE5LTAyLTI1VDAzOjU5OjE0LjM5NloJMTVkMzkxNjQtZjIyYy00MTQzLWIyNzktM2VjNWI3MjE4ZjU4CXZhbHVlMiA9IHZhbHVlMgoyMDE5LTAyLTI1VDAzOjU5OjE0LjM5NloJMTVkMzkxNjQtZjIyYy00MTQzLWIyNzktM2VjNWI3MjE4ZjU4CXZhbHVlMyA9IHZhbHVlMwpFTkQgUmVxdWVzdElkOiAxNWQzOTE2NC1mMjJjLTQxNDMtYjI3OS0zZWM1YjcyMThmNTgKUkVQT1JUIFJlcXVlc3RJZDogMTVkMzkxNjQtZjIyYy00MTQzLWIyNzktM2VjNWI3MjE4ZjU4CUR1cmF0aW9uOiAwLjQwIG1zCUJpbGxlZCBEdXJhdGlvbjogMTAwIG1zIAlNZW1vcnkgU2l6ZTogMTI4IE1CCU1heCBNZW1vcnkgVXNlZDogNzIgTUIJCg==",
    "ExecutedVersion": "$LATEST"
}

# 実行結果ファイルの中身を確認
$ cat outputfile.txt
"Success"

正常に動作している用に見える。

※(余談)僕は、初回に index.js の読み取り可能権限の付与をしておらず、 index.js の権限がないよ!と起こられてしまった。
ハマった人は chmod の実行をお忘れなく。

# ワンライナーJSONはみにくいので `jq` でフォーマット
$ cat outputfile.txt | jq .
{
  "errorMessage": "EACCES: permission denied, open '/var/task/index.js'",
  "errorType": "Error",
  "stackTrace": [
    "Object.fs.readFileSync (fs.js:551:33)",
    "Object.Module._extensions..js (module.js:662:20)",
    "Module.load (module.js:565:32)",
    "tryModuleLoad (module.js:505:12)",
    "Function.Module._load (module.js:497:3)",
    "Module.require (module.js:596:17)",
    "require (internal/module.js:11:18)"
  ]
}

CloudWatchLogが正しく書き出されているかを確認

以下のページにログインしてみて、ログが出力されているかを確認してみたところ、無事書き出しされていました。

https://ap-northeast-1.console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#logs:


ゴミ掃除

検証が終わったらゴミ掃除。

# Lambdaファンクションの削除
$ aws lambda delete-function --function-name logging-function

# IAMロールの削除
$ aws iam detach-role-policy \
  --role-name logging-function-role \
  --policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess

$ aws iam delete-role \
  --role-name logging-function-role

ひとこと

次回 はようやくS3へファイルをアップロードした際のイベントとLambdaを紐付ける設定をしてみます。

2019-03-23Amazon,AWS,Bash,Linux