この記事はシスコシステムズ有志による Cisco Systems Japan Advent Calendar 2020 (2枚目) の 3 日目として投稿しています。
2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2
はじめに
2020年10月にプレビューとなった AWS Lambda Extensions により,コード変更なしに Lambda 関数の AppDynamics での監視が可能となりました。
AWS Lambda Extensions(プレビュー)を構築する
[Step-by-Step Guide: Enhancing Lambda Performance Monitoring with AppDynamics]
(https://www.appdynamics.com/blog/product/enhancing-lambda-performance-monitoring/)
これまでは,AppDynamics Tracer SDK を用いるため Lambda 関数のコード変更が必要でしたが, AppDynamics Extension Layer を追加することによりコード変更なしでモニタリング可能となりました。
本記事では,AWS SAM CLI を用いて Lambda 関数のテスト/デプロイ, AppDynamics による性能監視を試してみます。
AppDynamics Lambda Extension 利用前提条件
- Node.js 10+, Python 3.6+ で書かれた Lambda 関数がインストゥルメント可能
- Serverless APM for AWS Lambda subscription へサブスクライブ済み
- AppDynamics SaaS Controller : バージョン 4.5.11 以降が利用可能
利用可能な AWS リージョン
- ap-northeast-1 (東京)
- ap-northeast-2 (ソウル)
- ap-south-1
- ap-southeast-1
- ap-southeast-2
- eu-central-1
- eu-north-1
- eu-west-1
- eu-west-2
- eu-west-3
- ca-central-1
- sa-east-1
- us-east-1
- us-east-2
- us-west-1
インストゥルメント手順公式ドキュメント
2020年12月時点で英語版のみとなりますが,Extension を用いた Lambda 関数のインストゥルメント手順の公式ドキュメントはこちらになります。
[Use the AppDynamics AWS Lambda Extension to Instrument Serverless APM at Runtime]
(https://docs.appdynamics.com/display/PRO45/Use+the+AppDynamics+AWS+Lambda+Extension+to+Instrument+Serverless+APM+at+Runtime)
Serverless APM for AWS Lambda subscription へサブスクライブ
Serverless APM for AWS Lambda subscription から Continue to Subscribe をクリックし,
次の画面で Subscribe をクリック,
次に Set Up Your Account をクリックします。
最後に AppDynamics SaaS コントローラURL, コントローラアクセスキーを入力します。
サブスクリプションの確認は AWS Marketplace > Manage subscriptions から行うことができます。
AWS SAM CLI による Lambda 関数のデプロイと AppDynamics Extension インストゥルメント
今回は AWS マネジメントコンソールを極力用いず,AWS SAM CLI を用いて監視対象の Lambda 関数のデプロイを行ってみます。AWS SAM CLI のインストールをされていない方は以下のリンクからご自分の利用環境に合わせてインストールを事前に行ってください。
template.yaml の編集
SAM のテンプレートを編集し,Layers に 以下のように ARN, arn:aws:lambda:ap-northeast-1:716333212585:layer:appdynamics-lambda-extension:9
を設定します(東京リージョンの場合)。利用リージョンが異なる場合は ap-northeast-1 を適宜変更してください。
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: AppDynamics Lambda extension
Resources:
Function:
Type: 'AWS::Serverless::Function'
Properties:
Handler: lambda_function.lambda_handler
Runtime: python3.8
CodeUri: code
Handler: app.lambda_handler
MemorySize: 128
Timeout: 3
Environment:
Variables:
APPDYNAMICS_CONTROLLER_HOST: your-account.saas.appdynamics.com
APPDYNAMICS_SERVERLESS_API_ENDPOINT: 'https://syd-sls-agent-api.saas.appdynamics.com'
APPDYNAMICS_ACCOUNT_NAME: your-account
APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY: your-access-key
APPDYNAMICS_APPLICATION_NAME: your-application
APPDYNAMICS_TIER_NAME: your-tier
AWS_LAMBDA_EXEC_WRAPPER: /opt/appdynamics-extension-script
Layers:
- >-
arn:aws:lambda:ap-northeast-1:716333212585:layer:appdynamics-lambda-extension:9
各環境変数はご利用の AppDynamics コントローラへのアクセス情報,アプリケーション名,Tier名に適宜置き換えてください。なお,アクセスキーは SaaS コントローラ の右上の歯車アイコン - License - Account で確認することができます。
サンプル Python コード
今回は以下の非常にシンプルなサンプルコードを用います。ifconfig.io に GET リクエストを送り,グローバル IP アドレスを取得します。
import urllib.request
def lambda_handler(event, context):
url = 'https://ifconfig.io/'
req = urllib.request.Request(url)
req.add_header("User-Agent", 'curl')
with urllib.request.urlopen(req) as res:
body = res.read()
return {
'statusCode': 200,
'body': body.decode().strip()
}
このスクリプトは code/app.py
として保存しておきます。
ビルド
今回は Python 3.8 Runtime を用いますが,ローカル環境で 正常に SAM から Python 3.8 を実行できない場合は,sam build -u
でDocker コンテナを利用することにより抽象化/仮想化することができます。
$ sam build -u
Starting Build inside a container
Building codeuri: code runtime: python3.8 metadata: {} functions: ['SampleFunction']
Fetching amazon/aws-sam-cli-build-image-python3.8 Docker container image......
Mounting /Users/foo/sample_app/code as /tmp/samcli/source:ro,delegated inside runtime container
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
ローカルテスト実行
sam local invoke
でローカルテストを実行することができます。
$ sam local invoke
Invoking app.lambda_handler (python3.8)
arn:aws:lambda:ap-northeast-1:716333212585:layer:appdynamics-lambda-extension:9 is already cached. Skipping download
Skip pulling image and use local one: samcli/lambda:python3.8-f00964ae55accef74c51e9ff8.
Mounting /Users/foo/sample_app/.aws-sam/build/SampleFunction as /var/task:ro,delegated inside runtime container
[Appdynamics wrapper script] AWS_Execution_Env is
[Appdynamics wrapper script] not supported, running lambda with default arguments
START RequestId: db5cd0c4-3cf3-10a1-8fde-bf6711cc3df0 Version: $LATEST
END RequestId: db5cd0c4-3cf3-10a1-8fde-bf6711cc3df0
REPORT RequestId: db5cd0c4-3cf3-10a1-8fde-bf6711cc3df0 Init Duration: 241.18 ms Duration: 371.69 ms Billed Duration: 400 ms Memory Size: 128 MB Max Memory Used: 27 MB
{"statusCode":200,"body":"xx.xxx.xxx.xxx"}
Lambda 関数,AppDynamics Extension Layer のデプロイ
正常にグローバル IP アドレスを取得可能なことが確認できたら,sam deploy --guided
で自動デプロイを行うことができます。
$ sam deploy --guided
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Found
Reading default arguments : Success
Setting default arguments for 'sam deploy'
=========================================
Stack Name [Python]:
AWS Region [ap-northeast-1]:
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [Y/n]: y
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: y
Save arguments to configuration file [Y/n]: y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
Looking for resources needed for deployment: Found!
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxx
A different default S3 bucket can be set in samconfig.toml
Saved arguments to config file
Running 'sam deploy' for future deployments will use the parameters saved above.
The above parameters can be changed by modifying samconfig.toml
Learn more about samconfig.toml syntax at
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
Deploying with following values
===============================
Stack name : Python
Region : ap-northeast-1
Confirm changeset : True
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxx
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Signing Profiles : {}
Initiating deployment
=====================
Waiting for changeset to be created..
CloudFormation stack changeset
-------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-------------------------------------------------------------------------------------------------------------------------------------
+ Add SampleFunctionRole AWS::IAM::Role N/A
+ Add SampleFunction AWS::Lambda::Function N/A
-------------------------------------------------------------------------------------------------------------------------------------
Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:679382613873:changeSet/samcli-deploy1606793756/cda913e6-946d-4713-b0b2-71c816716825
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
2020-12-01 12:36:12 - Waiting for stack create/update to complete
CloudFormation events from changeset
-------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS AWS::IAM::Role SampleFunctionRole -
CREATE_IN_PROGRESS AWS::IAM::Role SampleFunctionRole Resource creation Initiated
CREATE_COMPLETE AWS::IAM::Role SampleFunctionRole -
CREATE_IN_PROGRESS AWS::Lambda::Function SampleFunction -
CREATE_IN_PROGRESS AWS::Lambda::Function SampleFunction Resource creation Initiated
CREATE_COMPLETE AWS::Lambda::Function SampleFunction -
CREATE_COMPLETE AWS::CloudFormation::Stack Python -
-------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - Python in ap-northeast-1
AWS CLI によるLambda 関数の実行
aws lambda list-functions --query Functions[].FunctionName
を実行することにより,デプロイされている Lambda 関数のリストを取得することができます。
$ aws lambda list-functions --query Functions[].FunctionName
[
"Python-Function-123456ABCDEF"
]
次に,以下のように aws lambda invoke
により,コマンドラインから Lambda 関数を実行することが可能です。
$ aws lambda invoke --function-name Python-Function-123456ABCDEF /dev/stdout
{"statusCode": 200, "body": "xx.xxx.xxx.xxx"}
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
ログの確認
sam logs
コマンドで Lambda 関数のログを確認します。
sam logs -n Python-Function-123456ABCDEF
...
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:41.708000 START RequestId: e0db5107-9048-45b6-a2d6-c9e586417891 Version: $LATEST
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:41.715000 2020-12-01 04:28:41,715 AppDynamics - transaction_service.py [INFO]: Starting the business transaction.
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:42.095000 2020-12-01 04:28:42,094 AppDynamics - transaction_service.py [INFO]: Stopping the business transaction.
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:42.095000 2020-12-01 04:28:42,095 AppDynamics - event_service.py [INFO]: Total number of items in the events queue are 4
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:42.095000 2020-12-01 04:28:42,095 AppDynamics - event_service.py [INFO]: Successfully scheduled the sending of events to downstream
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:42.754000 2020-12-01 04:28:42,754 AppDynamics - http_service.py [INFO]: HTTP post request was successful for url https://syd-sls-agent-api.saas.appdynamics.com/v1/events
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:42.756000 END RequestId: e0db5107-9048-45b6-a2d6-c9e586417891
2020/12/01/[$LATEST]6e06e51410a146fab5b645091d7ce510 2020-12-01T04:28:42.756000 REPORT RequestId: e0db5107-9048-45b6-a2d6-c9e586417891 Duration: 1041.72 ms Billed Duration: 1042 ms Memory Size: 128 MB Max Memory Used: 81 MB
AppDynamics - http_service.py [INFO]: HTTP post request was successful for url https://syd-sls-agent-api.saas.appdynamics.com/v1/events
を含む行が確認でき,正常にメトリックが AppDynamics SaaS プラットフォームに送信されていることが確認できます。
Application Flow Map の確認
AppDynamics SaaS コントローラで template.yaml の APPDYNAMICS_APPLICATION_NAME で指定したアプリケーションの Application Flow Map を確認すると,以下のように Lambda 関数(Python) Tier からリモートサービスとして,ifconfig.io がコールされていることが確認できました。
Lambda 関数,S3 バケット, CloudFormation スタックの削除
以下のコマンドで SAM により作成した Lambda 関数,S3 バケット, CloudFormation スタックを削除することができます(Python: CloudFormation スタック名)。
aws cloudformation delete-stack --stack-name Python
まとめ
今回は AWS SAM CLI を用い,2020年10月に導入された AppDynamics Lambda Extension で性能監視を行う Python で書かれた Lambda 関数のデプロイ,テストを実施しました。
Extension Layer により,従来必要であった Lambda 関数のコード変更が不要となり,より利便性が高くなったと考えます。