AWSを使い始めたらServerlessなLambda関数を作成してみたいですよね。本文書ではAWSでのLambda関数の作成を下記の3つの方法を説明しています。

  • AWS Management Console
  • AWS CLI
  • AWS SDK

Python、Java、Node.js、Rubyなどを利用してLambda関数を作成することができますが本文書ではPythonを利用しています。

3つの方法では作成済みのEC2のインスタンスを起動を行うLambda関数を作成します。

AWS Management Consoleを使った作成手順

GUIを利用して直感的に作成することができるのでAWS入門者にとって最も理解しやすい方法がAWS AWSのManagement Consoleを利用した方法です。

Management Consoleにログイン後、サービスからLambdaを検索して選択します。

メニューからLambdaを選択
メニューからLambdaを選択

AWS Lamdbaのページが表示されるので”関数の作成”ボタンをクリックします。

AWS Lamdbaのトップページ
AWS Lamdbaのトップページ

関数の作成画面が表示されるので”一から作成”を選択して関数名に任意の名前を設定することができます。ここではECインスタンスを起動するのでstartEC2Instanceという名前にしています。次にLambdaを実行するランタイムを選択する必要があります。ランタイムにはPythonを選択します。PythonをLamdbaで利用する際はこちらで情報を確認することができます。https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-python.html

関数の作成画面
関数の作成画面

デフォルトの実行ロールの変更で作成する関数のアクセス権限を定義するロールを選択する必要があります。ここではEC2のインスタンスの起動を行うため、Lambda関数がインスタンスを起動する権限を持つ必要があります。

新たにロールを作成して選択するために”既存のロールを使用する”を選択します。カスタムロールを作成するので”IAM コンソール”のリンクをクリックします。

実行ロールの変更
実行ロールの変更

ロールの作成画面が表示されます。信頼されたエンティティタイプではAWSのサービスを選択します。

ロールの作成画面
ロールの作成画面

ユースケースではサービスまたはユースケースから選択を行ってください。選択を行わないと次の画面に進むことはできません。ここではLamdbaを選択して”次へ”ボタンをクリックします。

ユースケースの選択
ユースケースの選択

許可ポリシーの選択画面が表示されるのでAmazonEC2FullAccessを選択するためにec2fuを検索バーに入力します。

AmazonEC2FullAccessが表示されるので選択して”次へ “ボタンをクリックします。

許可ポリシーでAmazonEC2FullAccessを選択
許可ポリシーでAmazonEC2FullAccessを選択

ロール名の設定画面が表示されるので任意のロール名と説明を入力してください。ここではロール名に”lamdb-ec2-full”という名前をつけています。

ロール名の設定
ロール名の設定

スクロールして”ロールを作成”ボタンをクリックしてください。

ロール作成ボタンをクリック
ロール作成ボタンをクリック

作成後はLamdbaのアクセス権限の既存のロールの再読み込みボタンをクリックすることで作成したロールが選択できるようになります。選択後は”関数の作成”ボタンをクリックしてください。

作成したロールの選択
作成したロールの選択

作成が完了すると以下の画面が表示されます。

作成した関数の概要画面
作成した関数の概要画面

コードソースには実行すると”Hello from Lamdba!”を戻すテスト動作確認用のコードが記述されていますがEC2を起動するコードに変更します。EC2インスタンスを作成済みでない場合はコードを変更しないまま進めてください。

EC2起動用のコードに変更
EC2起動用のコードに変更

instancesの配列にはi-から始まる作成済みのEC2のインスタンスIDを設定してください。


import boto3
region = 'ap-northeast-1'
instances = ['i-から始まるインスタンスID']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started your instances: ' + str(instances))

動作確認を行うためにテストイベントの設定を行います新しいイベントを作成を選択して任意の名前のイベント名を設定してください。下のイベントJSONなどはそのままで”保存”ボタンをクリックしてください。

テストイベントの作成
テストイベントの作成

設定が完了してテストを実行するとするとExcecution resultタブが追加されインスタンスが起動したことが確認できます。

テストの実行と結果
テストの実行と結果

statusCodeも200が戻されているのでEC2のインスタンスのステータスを確認すると実行中であることが確認できるはずです。

Management Consoleを利用することでLambda関数を作成できることが確認できました。

AWS CLIを使った作成手順

AWS CLIを使ってLambda関数の作成方法について確認していきます。IAMユーザを利用してAWS CLIを実行しますがLambda関数に対する権限がないと”An error occurred (AccessDeniedException) when calling the CreateFunction operation”といったメッセージが表示されLamdba関数を作成するコマンドを実行することができません。そのためAWS CLIコマンドを実行するIAMユーザに対して適切な権限を付与する必要があります。

IAMユーザへアタッチしたポリシー

本文書ではコマンドを実行するIAMユーザにはAWSLambda_FullAccessポリシーをアタッチしています。

アタッチしたAWSLambda_FullAccessポリシー
アタッチしたAWSLambda_FullAccessポリシー

Lamdba関数が実行に必要なロールについて

実行に必要なロールはAWS CLIでも作成することができますがManagement Consoleによって既にEC2インスタンスを作成するためのロール(lamdb-ec2-full)を作成しているので作成したロールを利用してLambda関数を作成します。

コードの作成

任意の名前のディレクトリを作成し、作成したディレクトリの中にtest.pyファイルを作成して以下のコードを記述します。Lambda関数が実行するコードの内容はManagement Consoleの時に利用したコードと同じ内容です。instancesには各自の環境に合わせたインスタンスIDを指定してください。


import boto3
region = 'ap-northeast-1'
instances = ['i-から始まるインスタンスID']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started your instances: ' + str(instances))

作成したtest.pyファイルをzipファイルにします。実行後は実行ディレクトリの中にtest.zipというファイルが作成されます。


 % zip test.zip test.py

Lambda関数の作成

”aws lambda create-function”コマンドを利用してLambda関数を作成します。コマンドには下記で利用するオプション以外にもさまざまなものがあります。詳細についてはコマンドリファレンスから確認することができます。


 % aws lambda create-function --function-name startEC2Instance_cli --zip-file fileb://test.zip --handler test.lambda_handler --runtime python3.12 --role arn:aws:iam::900000000000:role/Lamdb-ec2-full
{
    "FunctionName": "startEC2Instance_cli",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:900000000000:function:startEC2Instance_cli",
    "Runtime": "python3.12",
    "Role": "arn:aws:iam::900000000000:role/Lamdb-ec2-full",
    "Handler": "test.lambda_handler",
    "CodeSize": 340,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
//略

実行したコマンドのオプションについて説明を行います。–function-nameには関数の名前を指定します。ここでは関数名はstartEC2Instance_cliとしています。–zip-fileには作成したzipファイルを指定しますが指定する際はfileb://の後にファイル名と指定します。–handlerにはファイル名(test.py)と関数名のlambda_handlerを指定しています。–runtimeにはpython3.12を利用するためpython3.12を指定します。–roleには関数が実行する際に必要となるロールの名前は”lamdb-ec2-full”ですが、ARN(Amazon Resource Name)で指定します。ARNはManagement Consoleのロールから確認することができます。

実行後に作成したLambda関数を確認したい場合には”aws lambda list-functions”コマンドを利用することができます。


 % aws lambda list-functions
{
    "Functions": [
        {
         "FunctionName": "startEC2Instance_cli",
         "FunctionArn": "arn:aws:lambda:ap-northeast-1:900000000000:function:startEC2Instance_cli",
         "Runtime": "python3.12",
         "Role": "arn:aws:iam::900000000000:role/Lamdb-ec2-full",
         "Handler": "test.lambda_handler",
         "CodeSize": 340,
         "Description": "",
         "Timeout": 3,
         "MemorySize": 128,
//略

Management Consoleからでも作成したLambda関数を確認することができます。

Lambda関数の実行

作成したLambda関数は”aws lambda invoke”コマンドで実行することができます。response.jsonはoutfileでコマンドを実行するために必須な設定値で任意の名前をつけることができます。


 % aws lambda invoke --function-name startEC2Instance_cli response.json 
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

–function-nameには作成したLambda関数の名前を指定します。response.jsonファイルには関数が戻す内容が保存されますが実行後にresponse.jsonファイルを見るとnullが記述されています。関数の返却値がない場合はnullとなります。

関数の実行はStatusCodeの200が戻りEC2インスタンスの起動も行われています。

コードの更新方法

response.jsonファイルはprint関数の実行した結果は保存されないのでprint関数からreturnにコードを更新します。返却値はJSONが必須なわけではありませんが関数から戻された値を保存するファイルをresponse.jsonとしているのでJSONとして戻しています。


import boto3
region = 'ap-northeast-1'
instances = ['i-から始まるインスタンスID']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    return { message : 'started your instances: ' + str(instances)}

test.pyファイルを更新したら再度zipコマンドを実行してzipファイルを作成します。


 % zip test.zip test.py

更新したコードは”aws lambda update-function-code”コマンドを実行して反映させます。


%  aws lambda update-function-code --function-name startEC2Instance_cli --zip-file fileb://test.zip
{
    "FunctionName": "startEC2Instance_cli",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:900000000000:function:startEC2Instance_cli",
    "Runtime": "python3.12",
    "Role": "arn:aws:iam::900000000000:role/Lamdb-ec2-full",
    "Handler": "test.lambda_handler",
    "CodeSize": 340,
    "Description": ""
 
//略

反映後にinvokeコマンドを実行するとresponse.jsonファイルはnullではなくreturnした内容が保存されるようになります。


{"message": "started your instances: ['i-0977f1f925c671c15']"}

AWS SDKを使った作成手順

Python用のAWSのSDKとしてboto3を利用します。boto3をpipを利用してインストールするために仮想環境を構築します。

AWS CLIを利用した時に作成したコードのzipファイルを利用するためコードのzipファイルを保存したディレクトリ下で”python3 -m venv env”コマンドを実行します。


 % python3 -m venv env
仮想環境作成後、有効化するためにmacOSではsource env/bin/activateを実行します。実行するとコマンドのプロンプトの前に(env)が表示されます。

 % source env/bin/activate

boto3のパッケージのインストールを行います。


(env) % pip install boto3

boto3を利用したLambda関数を作成するためのコードを記述するためにtest2.pyファイルを作成して以下のコードを記述します。関数名はstartEC2Instance_sdkとしています。残りの設定についてはAWS CLIで設定した内容と同じです。


import boto3

lambda_client = boto3.client('lambda')

function_name = 'startEC2Instance_sdk'
runtime = 'python3.12'
role_arn = 'arn:aws:iam::9000000000:role/Lamdb-ec2-full'
handler = 'test.handler'
zip_file_path = 'test.zip'

response = lambda_client.create_function(
    FunctionName=function_name,
    Runtime=runtime,
    Role=role_arn,
    Handler=handler,
    Code={
        'ZipFile': open(zip_file_path, 'rb').read()
    }
)

print(response)

test.zipファイルはAWS CLIでLambda関数を利用した時に作成したtest.pyファイルをzip化したものです。


import boto3
region = 'ap-northeast-1'
instances = ['i-XXXXXXXXXXXXXXXX']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    return {
        'message' : 'started your instances: ' + str(instances)
    }

実行は”python3 test2.py”で実行します。


% python3 test2.py
{'ResponseMetadata': {'RequestId': 'b8dbc4de-0a4c-46c6-b93a-41e17e1d19e7', 'HTTPStatusCode': 201, 'HTTPHeaders': {'date': 'Tue, 13 Feb 2024 12:13:07 GMT', 'content-type': 'application/json', 'content-length': '1337', 'connection': 'keep-alive', 'x-amzn-requestid': 'b8dbc4de-0a4c-46c6-b93a-41e17e1d19e7'}, 'RetryAttempts': 0}, 'FunctionName': 'startEC2Instance_sdk', 'FunctionArn': //略

認証情報

test2.pyファイルを再度確認しているとAWSへの接続に必要なキー等など認証情報設定していないのになぜ実行できるのだろうかと疑問を持った人はいませんか?

AWS CLIをインストールした後に”aws configure”を実行しているとユーザのホームディレクトリ直下に.awsディレクトリが作成されその下にcredentials, configファイルが存在します。そのファイルがあるためtest2.pyで認証情報を設定していなくてもそのファイルから認証情報を取得して接続時に利用します。

.awsディレクトリが存在しない場合でもboto3.clientの引数に認証情報を指定することもできます。


import boto3

client = boto3.client(
    'lambda',
    aws_access_key_id=ACCESS_KEY,
    aws_secret_access_key=SECRET_KEY
)

環境変数を設定しておくことでも認証情報の設定は可能です。


AWS_ACCESS_KEY_ID - The access key for your AWS account.
AWS_SECRET_ACCESS_KEY - The secret key for your AWS account.

まとめ

ここまでの動作確認で3つの方法を利用してLambda関数を作成することができました。各自にあった方法でぜひLambda関数を作成してみてください。