BioErrorLog Tech Blog

試行錯誤の記録

Athena経由でpandas DataFrameを作成する

Amazon Athena経由でpandas DataFrameを作成するやり方をまとめます。

はじめに

こんにちは、@bioerrorlogです。

Amazon Athenaクエリ経由でpandas DataFrameを作成したい、としたらどのようなやり方があるでしょうか。 

例えばいちばん愚直にやろうとすれば、boto3でAthenaクエリを発行し、クエリ結果からデータを取得して、上手いことpandasに読み込ませる...とかでしょうか。 そんな複雑なことやりたくないなぁと思って調べてみても、stackoverflowの上位answerでも似たような解決策が示されています。

しかしもう少し調べると、awswranglerを使えばかなりスッキリ書けることを知りました。

今回は、awswranglerを使ってAthena経由でpandas DataFrameを作成するやり方をメモします。


※追記:awswranglerはAWS SDK for pandasに改名されました(使い方は特に変わってない模様です)。

awswrangler (AWS SDK for pandas)とは

awswranglerは、AWSサービスとpandasを連携するツールです。

AWS公式(awslabs)が開発しており、Athenaだけでなく各AWSのDB系サービスとの連携もサポートしています。

Pandas on AWS. Easy integration with Athena, Glue, Redshift, Timestream, OpenSearch, Neptune, QuickSight, Chime, CloudWatchLogs, DynamoDB, EMR, SecretManager, PostgreSQL, MySQL, SQLServer and S3 (Parquet, CSV, JSON and EXCEL).

github.com

Athena経由でpandas DataFrameを作成する

このawswranglerを使えば、次のように簡単にAthenaのクエリ結果をそのままpandas DataFrameに読み込ませることができます。

import awswrangler as wr

df = wr.athena.read_sql_query(sql='SELECT * FROM "<table_name>"', database='<database_name>')

ちなみに上記のコードでは、Athena query resultの出力先を指定していません。 その場合はデフォルトでs3://aws-athena-query-results-ACCOUNT-REGION/にquery resultが出力されますが、任意のS3を指定したければs3_outputから指定することができます。

その他athena.read_sql_queryの各オプションはドキュメントをご覧ください

おわりに

今回は、awswranglerを使ってAthena経由でpandas DataFrameを作成するやり方をメモしました。

素のboto3で書くよりもずっとシンプルに書くことができるので、なかなか使い勝手が良いのではないでしょうか。 awslabs公式のツールであることも嬉しいポイントです。

以上、どなたかの参考になれば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

GitHub - aws/aws-sdk-pandas: Pandas on AWS - Easy integration with Athena, Glue, Redshift, Timestream, Neptune, OpenSearch, QuickSight, Chime, CloudWatchLogs, DynamoDB, EMR, SecretManager, PostgreSQL, MySQL, SQLServer and S3 (Parquet, CSV, JSON and EXCEL).

Quick Start — AWS SDK for pandas 2.17.0 documentation

awswrangler.athena.read_sql_query — AWS SDK for pandas 2.17.0 documentation

python - How to Create Dataframe from AWS Athena using Boto3 get_query_results method - Stack Overflow

boto3でエラーハンドリングする方法をまとめる | AWS SDK for Python

boto3でエラーハンドリングする方法を整理します。

はじめに

こんにちは、@bioerrorlogです。

boto3で発生するエラーをcatchしようとしたときに、少しハマったことがありました。

例えば以下のコードを実行すると、examplebucketという名前のS3バケットが既に存在しているため、BucketAlreadyExistsエラーが吐かれます。

import boto3


client = boto3.client('s3')
client.create_bucket(
    Bucket='examplebucket',
    CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-1',},
)
botocore.errorfactory.BucketAlreadyExists: An error occurred (BucketAlreadyExists) when calling the CreateBucket operation: The requested bucket name is not available.
The bucket namespace is shared by all users of the system. Please select a different name and try again.

では、このエラーをcatchするにはどうすればいいでしょうか。

エラーメッセージに従って愚直にbotocore.errorfactory.BucketAlreadyExistsをcatchする例外処理を書いてしまうと、上手く動きません。

import boto3
import botocore


client = boto3.client('s3')
try:
    client.create_bucket(
        Bucket='examplebucket',
        CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-1',},
    )
except botocore.errorfactory.BucketAlreadyExists as e:
    print(e)
AttributeError: module 'botocore.errorfactory' has no attribute 'BucketAlreadyExists'

今回は、このようなケースでboto3エラーをハンドリングする方法をまとめます。

boto3でエラーハンドリングする

boto3でエラーハンドリングするやり方は、大きく分けて2つあります。

  • client.exceptions
  • botocore.exceptions

client.exceptions

client.exceptionsを使えば、とてもシンプルに例外処理を書くことが出来ます。 宣言したboto3 clientから、client.exceptions.<エラー名>でcatchします。

import boto3


client = boto3.client('s3')
try:
    client.create_bucket(
        Bucket='examplebucket',
        CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-1',},
    )
except client.exceptions.BucketAlreadyExists as e:
    print(e.response['Error'])

なお、boto3 clientではなくresourceを宣言している場合はresource.meta.client.exceptions.<エラー名>でcatchできます。

import boto3


resource = boto3.resource('s3')
try:
    resource.create_bucket(
        Bucket='examplebucket',
        CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-1',},
    )
except resource.meta.client.exceptions.BucketAlreadyExists as e:
    print(e.response['Error'])

ただし、全てのエラーがこのやり方でcatch出来るわけではない、という点に注意が必要です。 対応できるエラーは、boto3ドキュメントの各APIごとに記載があります

一方、次に紹介するbotocore.exceptionsを使ったやり方では、全てのエラーをcatchできます。

botocore.exceptions

botocore.exceptionsを使う場合は少し冗長な書き方になってしまいますが、全ての例外を処理できるメリットがあります。

import botocore
import boto3


client = boto3.client('s3')
try:
    client.create_bucket(
        Bucket='examplebucket',
        CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-1',},
    )
except botocore.exceptions.ClientError as e:
    if e.response['Error']['Code'] == 'BucketAlreadyExists':
        print(e.response['Error'])
    else:
        raise e

botocore.exceptions.ClientErrorでエラーをcatchしたのち、エラーのresponse['Error']['Code']から対応を振り分けます。

コード量が少し多くなってしまうのでなるべくclient.exceptionsを使ったやり方で書きたいところですが、やむを得ない場合はこちらで実装しましょう。

コード例

では、いくつかboto3で例外処理をするコード例を書いてみます。 xxxAlreadyExists系エラーやNoSuchEntitiy系のエラーはcatchしたいケースが多いので、これら中心にメモします。


S3 create_bucketにおけるBucketAlreadyExistsエラーのハンドリング例

import boto3


client = boto3.client('s3')
try:
    client.create_bucket(
        Bucket='examplebucket',
        CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-1',},
    )
except client.exceptions.BucketAlreadyExists as e:
    print(f'S3 bucket already exists: {e.response["Error"]["BucketName"]}')


S3 get_objectにおけるNoSuchKeyエラーのハンドリング例

import boto3


client = boto3.client('s3')
try:
    client.get_object(
        Bucket='target-bucket-001',
        Key='no-such/ocject-key',
    )
except client.exceptions.NoSuchKey as e:
    print(f'No such key: {e.response["Error"]["Key"]}')


IAM get_roleにおけるNoSuchEntityExceptionエラーのハンドリング例

import boto3


client = boto3.client('iam')
try:
    client.get_role(
        RoleName='NoSuchRoleName'
    )
except client.exceptions.NoSuchEntityException as e:
    print(e.response['Error']['Message'])


Glue create_databaseにおけるAlreadyExistsExceptionエラーのハンドリング例

import boto3


client = boto3.client('glue')
try:
    client.create_database(
        DatabaseInput={
            'Name': 'test_db'
        }
    )
except client.exceptions.AlreadyExistsException as e:
    print(e.response['Error']['Message'])

おわりに

以上、boto3でエラーハンドリングする方法を整理しました。

上手にエラーハンドリングして、デバッグしやすいコードを心掛けたいものです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

Error handling — Boto3 Docs 1.26.14 documentation

python - Properly catch boto3 Errors - Stack Overflow

python - How to handle errors with boto3? - Stack Overflow

AWS Config advanced queyのスキーマ定義の記載場所と使い方をまとめる

AWS Config advanced queyで指定できるスキーマ定義 (カラム名/propertiesの一覧) がある場所と、使い方をまとめます。

はじめに

こんにちは、@bioerrorlogです。

AWS Config advanced queyは、AWS上のリソース状況をクエリベースで簡単に調べられる便利なサービスです。

クエリのテンプレートも豊富に用意されていて、例えば「ステータスが'ACTIVE'のDynamoDBテーブル」を調べるクエリがすぐに実行できたりします(下図)。


用意されたクエリテンプレートをそのまま使うならこれでよいのですが、自分でクエリを書きたいとなるとスキーマ定義(カラム定義/properties)を知る必要があります。

が、ドキュメント等を漁ってもこのスキーマ定義が見当たりませんでした。

今回はこのAWS Config advanced queyで使えるスキーマ定義の場所と使い方をメモします。

AWS Config advanced queyのスキーマ定義はどこにあるのか

場所

AWSのGitHubリポジトリにありました。 github.com

└── config
    ├── properties
    │   ├── AWS.properties.json
    │   └── resource-types
    │       ├── AWS::ACM::Certificate.properties.json
    │       ├── AWS::AutoScaling::AutoScalingGroup.properties.json
    ...     ...

リソースごとのスキーマ定義はresource-types配下に、全てのリソースのスキーマ定義がマージされたものがAWS.properties.jsonに記載されています。

各jsonファイルxxx.properties.jsonにはスキーマ定義(カラム名とデータ型)が記載されています。

{
  "...": "...",
  "sample.property.name": "string",
  "...": "...",
}

使用例

AWS::S3::Bucketのスキーマ定義をもとに、リージョンap-northeast-1、タグOwner=user-1のバケット名(resourceId)一覧を取得するクエリ例を示します。

・AWS::S3::Bucketのスキーマ定義:

{
  "...": "...",
  "awsRegion": "string",
  "...": "...",
  "resourceId": "string",
  "...": "...",
  "resourceType": "string",
  "...": "...",
  "tags.tag": "string",
  "...": "...",
}


・クエリ:

SELECT
  resourceId
WHERE
  resourceType = 'AWS::S3::Bucket'
  AND awsRegion = 'ap-northeast-1'
  AND tags.tag = 'Owner=user-1'

上記のクエリをAWS Config advanced queyで実行すると、該当のバケット名一覧が取得できます。

おわりに

以上、AWS Config advanced queyで指定できるスキーマ定義の記載場所と使い方をまとめました。

スキーマ定義の記載場所はドキュメントからは見つけることが出来ず、AWSのブログからリンクを辿って初めて見つけたものです。 (本当はドキュメントのどこかに記載があるのかもしれませんが、私は見つけられませんでした...)

どなたかの参考になれば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

GitHub - awslabs/aws-config-resource-schema: AWS Config resource schema define the properties and types of AWS Config resource configuration items (CIs). Resource CI schema are used by developers when performing advanced resource queries and when processing CI data.

Querying the Current Configuration State of AWS Resources - AWS Config

Query your resource configuration state using the advanced query feature of AWS Config | AWS Cloud Operations & Migrations Blog

boto3 clientのendpoint URLを確認する | AWS SDK for Python

作成済みboto3 clientのendpoint URLを確認する方法をまとめます。

はじめに

こんにちは、@bioerrorlogです。

boto3クライアントの宣言時には、endpoint URLを独自のURLに上書きすることが出来ます。

import boto3


client = boto3.client('s3', endpoint_url='http://my.endpoint:4566')

これはLocalStackなどを使う際に特に便利で、boto3がアクセスするエンドポイントを実際のAWSエンドポイントから独自のURLに振り向けることが出来ます。

しかし逆に、設定されているエンドポイントURLをclientから取得する方法はパッと思い浮かびませんでした。 もしそれが出来れば、デバッグ時に重宝しそうです。

今回は、作成済みboto3 clientから、設定されているendpoint URLを確認する方法まとめます。

環境

boto3 1.18.31 で動作確認してます。

boto3 clientのendpoint URLを確認する

作成したboto3 clientのendpoint URLを確認するには、(少なくとも)以下のふたつの方法があります。

  • client.meta.endpoint_url
  • client._endpoint.host

client.meta.endpoint_url

まず一つ目のやり方は、client.meta.endpoint_urlです。

import boto3


client = boto3.client('s3')
print(client.meta.endpoint_url)
# 出力例: https://s3.ap-northeast-1.amazonaws.com

client = boto3.client('s3', endpoint_url='http://localstack:4566')
print(client.meta.endpoint_url)
# 出力: http://localstack:4566

このようにboto3クライアントに設定されたendpoint URLを都度取得することが出来ます。

※ botocoreにおけるmeta.endpoint_url実装部分のソースコードはこちら: botocore/client.py at 6451ae1fad57f4453af97649e7ed9192b0f623be · boto/botocore · GitHub

client._endpoint.host

もう一つのやり方は、client._endpoint.hostです。

import boto3


client = boto3.client('s3')
print(client._endpoint.host)
# 出力例: https://s3.ap-northeast-1.amazonaws.com

client = boto3.client('s3', endpoint_url='http://localstack:4566')
print(client._endpoint.host)
# 出力: http://localstack:4566

client.meta.endpoint_urlと同様、boto3クライアントに設定されたendpoint URLを取得することが出来ます。

ただ、アンダースコアで始まる属性値_endpointに直接アクセスするのは憚られるので、client.meta.endpoint_urlでアクセスした方が自然に思います。

※ botocoreにおける_endpoint.host実装部分のソースコードはこちら: botocore/client.py at 6451ae1fad57f4453af97649e7ed9192b0f623be · boto/botocore · GitHub

おわりに

以上、boto3 clientのendpoint URLを確認する方法をまとめました。

なかなかboto3ドキュメントを漁っても該当のやり方を見つけることが出来ず、やり方を調べるのも一苦労でした。 (ネット上のコード例を探したうえで、boto3/botocoreソースコードを辿る必要がありました)

どなたかの参考になれば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

botocore/client.py at 6451ae1fad57f4453af97649e7ed9192b0f623be · boto/botocore · GitHub

botocore/client.py at 6451ae1fad57f4453af97649e7ed9192b0f623be · boto/botocore · GitHub

Add environment variable to override endpoint_url (#2099) by rwillmer · Pull Request #2746 · boto/boto3 · GitHub

django models - Upload to Amazon S3 using Boto3 and return public url - Stack Overflow

GitHub - localstack/localstack: 💻 A fully functional local AWS cloud stack. Develop and test your cloud & Serverless apps offline!

Fargateでエフェメラルストレージを拡張する

FargateのエフェメラルストレージをAWS CLIを用いて拡張する方法をまとめます。

はじめに

こんにちは、@bioerrorlogです。

先日のアップデートで、Fargateのエフェメラルストレージ機能が拡張されました。 20GBのエフェメラルストレージがデフォルト(無料)でアタッチされ、最大200GBまで拡張できるようになります。

Amazon ECS on AWS Fargate now allows you to configure the size of ephemeral storage for your Tasks

ただし、上のアナウンス記事にも書かれている通り、エフェメラルストレージの拡張を設定できるのは現時点でCopilot CLI, CloudFormation, AWS SDK, AWS CLIのみであり、マネジメントコンソール上からは設定できません。

You can configure the size of the ephemeral storage for your Amazon ECS Tasks running on AWS Fargate platform version 1.4.0 or higher in all regions where AWS Fargate is available using AWS Copilot CLI, CloudFormation, AWS SDK, and AWS CLI.


今回は、AWS CLIを用いてエフェメラルストレージを拡張する方法をメモします。

前提条件

Fargateのエフェメラルストレージを拡張するには、AWS CLIバージョンがv1, v2でそれぞれ以下を満たしている必要があります。 aws --versionでバージョンを確認してください。

  • v1: 1.19.61以上
  • v2: 2.2.1以上

※参考:
aws-cli/CHANGELOG.rst at v2 · aws/aws-cli · GitHub

Fargateでエフェメラルストレージを拡張する

エフェメラルストレージを拡張する方法としては以下の2つがあります。

  • Task Definition作成時に指定するやり方
  • Run Task時に指定する(上書きする)やり方

Task Definition作成時にエフェメラルストレージを指定する

Task Definition作成時にエフェメラルストレージ指定するregister-task-definitionコマンド例:

aws ecs register-task-definition \
  --family test-ephemeral-storage \
  --requires-compatibilities FARGATE \
  --network-mode awsvpc\
  --cpu 256 \
  --memory 512 \
  --ephemeral-storage "{\"sizeInGiB\":200}" \
  --execution-role-arn arn:aws:iam::123456789012:role/ecsTaskExecutionRole \
  --container-definitions "[{\"name\":\"df\",\"image\":\"public.ecr.aws/ubuntu/ubuntu:18.04\",\"command\":[\"df\",\"-h\"],\"essential\":true,\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/test-ephemeral-storage\",\"awslogs-region\":\"ap-northeast-1\",\"awslogs-stream-prefix\":\"ecs\"}}}]"

# Task Definition "test-ephemeral-storage:1"が作成される

--ephemeral-storage "{\"sizeInGiB\":integer}"オプションで、拡張するエフェメラルストレージを21~200(GiB)の範囲で指定できます。

作成したTask Definition (public.ecr.aws/ubuntu/ubuntu:18.04でcommanddf -hが実行される) からTaskを実行してディスクサイズを確認すると、

# Taskを実行
aws ecs run-task --launch-type FARGATE \
  --cluster test-cluster \
  --task-definition test-ephemeral-storage:1 \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-1234567]}"
# CloudWatch Logsに出力されたログ
Filesystem      Size  Used Avail Use% Mounted on
overlay         207G  9.4G  189G   5% /
tmpfs            64M     0   64M   0% /dev
shm             2.0G     0  2.0G   0% /dev/shm
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/xvdcz      207G  9.4G  189G   5% /etc/hosts
tmpfs           2.0G     0  2.0G   0% /proc/acpi
tmpfs           2.0G     0  2.0G   0% /sys/firmware
tmpfs           2.0G     0  2.0G   0% /proc/scsi

利用可能なディスクサイズが拡張されていることが確認できます。

Run Task時にエフェメラルストレージを指定する

次は、Task Definition作成時にはエフェメラルストレージを指定せず、Task実行時にエフェメラルストレージ設定を上書きしてみます。

# エフェメラルストレージを指定せずにTask Definitionを作成
aws ecs register-task-definition \
  --family test-ephemeral-storage \
  --requires-compatibilities FARGATE \
  --network-mode awsvpc\
  --cpu 256 \
  --memory 512 \
  --execution-role-arn arn:aws:iam::123456789012:role/ecsTaskExecutionRole \
  --container-definitions "[{\"name\":\"df\",\"image\":\"public.ecr.aws/ubuntu/ubuntu:18.04\",\"command\":[\"df\",\"-h\"],\"essential\":true,\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"/ecs/test-ephemeral-storage\",\"awslogs-region\":\"ap-northeast-1\",\"awslogs-stream-prefix\":\"ecs\"}}}]"

# Task Definition "test-ephemeral-storage:2"が作成される
# エフェメラルストレージを指定してTaskを実行
aws ecs run-task --launch-type FARGATE \
  --cluster test-cluster \
  --task-definition test-ephemeral-storage:2 \
  --overrides "{\"ephemeralStorage\":{\"sizeInGiB\":200}}" \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-1234567]}"

--overridesオプション内で"ephemeralStorage":{"sizeInGiB":integer}を指定することで、Task実行時にエフェメラルストレージを上書き設定することが出来ます。

CloudWatch Logsの出力を見ると、以下のようにディスク容量が拡張されていることが確認できます。

# CloudWatch Logsに出力されたログ
Filesystem      Size  Used Avail Use% Mounted on
overlay         207G  9.4G  189G   5% /
tmpfs            64M     0   64M   0% /dev
shm             2.0G     0  2.0G   0% /dev/shm
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/xvdcz      207G  9.4G  189G   5% /etc/hosts
tmpfs           2.0G     0  2.0G   0% /proc/acpi
tmpfs           2.0G     0  2.0G   0% /sys/firmware
tmpfs           2.0G     0  2.0G   0% /proc/scsi


ちなみにTask実行時にエフェメラルストレージを指定しなければ、デフォルトのまま20GBのエフェメラルストレージがアタッチされます。

# エフェメラルストレージを指定せずにTaskを実行
aws ecs run-task --launch-type FARGATE \
  --cluster test-cluster \
  --task-definition test-ephemeral-storage:2 \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-1234567]}"
# CloudWatch Logsに出力されたログ
# 20GBのエフェメラルストレージがアタッチされている
Filesystem      Size  Used Avail Use% Mounted on
overlay          30G  9.4G   19G  34% /
tmpfs            64M     0   64M   0% /dev
shm             2.0G     0  2.0G   0% /dev/shm
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/xvdcz       30G  9.4G   19G  34% /etc/hosts
tmpfs           2.0G     0  2.0G   0% /proc/acpi
tmpfs           2.0G     0  2.0G   0% /sys/firmware
tmpfs           2.0G     0  2.0G   0% /proc/scsi

おわりに

今回は、FargateのエフェメラルストレージをAWS CLIを用いて拡張する方法をまとめました。

ECS / Fargateはアップデートのたびにどんどん使いやすくなっています。 キャッチアップして使いこなしていきたいものです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

Amazon ECS on AWS Fargate now allows you to configure the size of ephemeral storage for your Tasks

Amazon ECS on AWS Fargate now enables customers to configure ephemeral storage up to 200GiB | Containers

Fargate task storage - Amazon Elastic Container Service

register-task-definition — AWS CLI 1.25.64 Command Reference

run-task — AWS CLI 1.25.58 Command Reference

aws-cli/CHANGELOG.rst at v2 · aws/aws-cli · GitHub

Lambdaコンソールでコードが読めない時の対処法 | too large to enable inline code editing

The deployment package of your Lambda function XXX is too large to enable inline code editing. However, you can still invoke your function.

Lambdaコンソールにて上記のエラーが出てコードが読めない時に、コードを取得する方法をメモします。

はじめに

こんにちは@bioerrorlogです。

Lambdaにサイズの大きいコードをアップロードすると、以下のエラーが出てコンソール上でコードが確認できなくなります。

The deployment package of your Lambda function XXX is too large to enable inline code editing. However, you can still invoke your function.

ドキュメントを確認すると、コードサイズが3MBを超えた場合にコンソール上でコードが確認できなくなることが分かります。

Deployment package (.zip file archive) size quota: 3 MB (console editor), 512 KB maximum for an individual file

依存パッケージごとzipにした場合など、3MBは超えてしまうことが多いでしょう。


自分で作成したコードであれば、Lambdaコンソール上でコードが見れなくてもソースを確認すればよいかもしれません。

しかし、例えばAWS Solutions Libraryを使ってLambdaがデプロイされた場合など、自分でコードを書いていない場合はコンソール上でコードが読めないと少し厄介です。

今回は、Lambdaコンソールでコードが確認できないときでも使える、コマンドでLambdaコードを取得する方法をメモします。

Lambdaコードを取得する

コマンドでLambdaコードを取得する

まず結論、以下のコマンドでLambdaコードが取得できます。

aws lambda get-function --function-name <function名> --query 'Code.Location' | xargs curl -o <出力ファイル名>

例えば、function_aという名前のLambdaのコードをcode.zipという名前で取得するには、以下のコマンドを実行します。

aws lambda get-function --function-name function_a --query 'Code.Location' | xargs curl -o code.zip

コマンド解説

ではコマンドの処理内容を見ていきます。

まずはじめに、AWS CLIのget-functionコマンドを実行してLambdaの情報を取得します。

aws lambda get-function --function-name <function名>

--queryオプションを使わずにget-functionコマンドでLambda情報全体を取得した場合、例えば以下のような出力が得られます。

{
    "Concurrency": {
        "ReservedConcurrentExecutions": 100
    },
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://awslambda-us-west-2-tasks.s3.us-west-2.amazonaws.com/snapshots/123456789012/my-function..."
    },
    "Configuration": {
        "TracingConfig": {
            "Mode": "PassThrough"
        },
        "Version": "$LATEST",
        "CodeSha256": "5tT2qgzYUHoqwR616pZ2dpkn/0J1FrzJmlKidWaaCgk=",
        "FunctionName": "my-function",
        "VpcConfig": {
            "SubnetIds": [],
            "VpcId": "",
            "SecurityGroupIds": []
        },
        "MemorySize": 128,
        "RevisionId": "28f0fb31-5c5c-43d3-8955-03e76c5c1075",
        "CodeSize": 304,
        "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:my-function",
        "Handler": "index.handler",
        "Role": "arn:aws:iam::123456789012:role/service-role/helloWorldPython-role-uy3l9qyq",
        "Timeout": 3,
        "LastModified": "2019-09-24T18:20:35.054+0000",
        "Runtime": "nodejs10.x",
        "Description": ""
    }
}

この出力結果のうち、Code内のLocationにてLambdaコードの配置場所が記されています。

--queryオプションを用いることで、このLambdaコードの配置場所Code.Locationのみを出力するようフィルタリングすることが出来ます。

aws lambda get-function --function-name <function名> --query 'Code.Location'


次に、得られたLambdaコード配置場所のURLをパイプ|xargsコマンドに渡し、curlコマンドを実行しています。

 | xargs curl -o <出力ファイル名>

xargsコマンドは、標準入力等から値を読み込んで別のコマンドを実行させることが出来るコマンドです。 Lambdaコード配置場所のURLをxargsコマンドでcurlコマンドに渡し、GETリクエストを送ります。

得られたレスポンスの内容(Lambdaコード)は、-oオプションで指定したファイル名で保存されます。


以上のようにして、Lambdaコードをコマンドで取得することが可能です。

おわりに

今回は、コマンドでLambdaコードを取得する方法をメモしました。

AWSマネジメントコンソールは手軽に利用できますが、要所要所で制約が気になることも多くあります。 APIやコマンドも上手く活用して、円滑なAWSライフを送りたいものです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

Lambda quotas - AWS Lambda

get-function — AWS CLI 1.25.2 Command Reference

How to check what code is currently running in your lambda when UI Console does not allow viewing or editing it - DEV Community

DeletionPolicyの変更が反映されないときの対処法 | CDK/CloudFormation

CDKやCloudFormationにて、変更したDeletionPolicy (RemovalPolicy)がStackに反映されない時の対処法を残します。

はじめに

おはよう。@bioerrorlogです。

先日、CDKで作成したリソースのDeleteionPolicyを変更してdeployした際に、その変更が実環境のStackに反映されないことがありました。

その原因と対処法をメモします。

DeletionPolicyの変更が反映されないときの対処法

起こったこと

まず、起こったことをおさらいします。

例えば以下のように、S3を定義したシンプルなCDKコードがあるとします(Pythonを例とします)。

from aws_cdk import (
    aws_s3 as s3,
    core
)


class SampleS3Stack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        s3_bucket = s3.Bucket(self, "TestBucket", bucket_name="deletion-policy-test-bucket")

app = core.App()
SampleS3Stack(app, "deletion-policy-test-stack")

app.synth()

上記のようにS3 BucketをCDK Constructのデフォルトで作成した場合、DeletionPolicyおよびUpdateReplacePolicyにはRetainが設定されます。

以下、生成されるCloudFormationテンプレート抜粋です。

Resources:
  TestBucket560B80BC:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: deletion-policy-test-bucket
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain

ここで、DeletionPolicy / UpdateReplacePolicyをDeleteに変更するには、以下のようにapply_removal_policy()を利用します。

from aws_cdk import (
    aws_s3 as s3,
    core
)


class SampleS3Stack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        s3_bucket = s3.Bucket(self, "TestBucket", bucket_name="deletion-policy-test-bucket")
        
        # DeletionPolicy / UpdateReplacePolicyを指定
        s3_bucket.apply_removal_policy(core.RemovalPolicy.DESTROY) 

app = core.App()
SampleS3Stack(app, "deletion-policy-test-stack")

app.synth()

上記のようにapply_removal_policy()を適用することで、生成されるCloudFormationテンプレートやcdk diffの結果には変更が反映されます。

# cdk synth
Resources:
  TestBucket560B80BC:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: deletion-policy-test-bucket
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
# cdk diff
Stack deletion-policy-test-stack
Resources
[~] AWS::S3::Bucket TestBucket TestBucket560B80BC 
 ├─ [~] DeletionPolicy
 │   ├─ [-] Retain
 │   └─ [+] Delete
 └─ [~] UpdateReplacePolicy
     ├─ [-] Retain
     └─ [+] Delete

しかし、上記変更後のCDKコードをデプロイしても、変更がStackに反映されませんでした。

以下のようにno changesと表示され、変更はデプロイされなかったのです。

# cdk deploy
deletion-policy-test-stack: deploying...
deletion-policy-test-stack: creating CloudFormation changeset...

 ✅  deletion-policy-test-stack (no changes)

原因

少し調べた結果、上記の振る舞いはCloudFormationの仕様であることが分かりました。

以下ドキュメント抜粋です。

You can't update the CreationPolicy, DeletionPolicy. or UpdatePolicy attribute by itself. You can update them only when you include changes that add, modify, or delete resources.

CreationPolicy/DeletionPolicy/UpdatePolicyのみでは変更を更新できないため、他のリソース情報と一緒に更新する必要がある、とのことです。

仕様としてイケてないとは思いますが、DeletionPolicyが更新できないこと自体は仕様として想定通りということですね。

対処法

では、どのようにしてDeletionPolicyを更新すればよいのか。

それ単体では更新できないことが仕様である以上、他のリソース情報と一緒に更新する他なさそうです。

例えば、metadataやTagの変更を同時に行えば、リソースそのものにはあまり影響を与えずにDeletionPolicyを更新することが出来ます。

ドキュメントにも以下のように、metadataの更新を一緒に行うことが言及されています。

For example, you can add or modify a metadata attribute of a resource.


例えば、以下のようにmetadataを変更して再デプロイすればDeletionPolicyの変更が反映されます。

from aws_cdk import (
    aws_s3 as s3,
    core
)


class SampleS3Stack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        s3_bucket = s3.Bucket(self, "TestBucket", bucket_name="deletion-policy-test-bucket")
        
        # DeletionPolicy / UpdateReplacePolicyを指定
        s3_bucket.apply_removal_policy(core.RemovalPolicy.DESTROY)
        
        # metadataを更新
        cfn_bucket = s3_bucket.node.default_child
        cfn_bucket.cfn_options.metadata = {
            "DeletionPolicyUpdated": "DESTROY"
        }

app = core.App()
SampleS3Stack(app, "deletion-policy-test-stack")

app.synth()

※Metadataの更新方法はドキュメントGitHub issueを参考にしています。 Metadataの上書き操作になるので注意が必要です(もともとあったmetadata aws:cdk:pathが上書きされる)。


また以下のようにTagを追加して再デプロイしても、DeletionPolicyの変更が反映されます。

from aws_cdk import (
    aws_s3 as s3,
    core
)


class SampleS3Stack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        s3_bucket = s3.Bucket(self, "TestBucket", bucket_name="deletion-policy-test-bucket")
        
        # DeletionPolicy / UpdateReplacePolicyを指定
        s3_bucket.apply_removal_policy(core.RemovalPolicy.DESTROY)
        
        # Tagを追加
        core.Tags.of(s3_bucket).add("DeletionPolicyUpdated", "DESTROY")

app = core.App()
SampleS3Stack(app, "deletion-policy-test-stack")

app.synth()

おわりに

今回は、CloudFormation/CDKにてDeletionPolicyの変更が反映されないときの対処法を書きました。

そもそもDeletionPolicy単体では更新できないのがCloudFormationの仕様、というのにはなかなか驚きました。

なるべくリソースそのものに影響のないTagやmetadataの更新を一緒に行うことを対処法として書きましたが、他にもっと適切なやり方があれば教えて頂けると嬉しいです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

[aws-events] `cdk diff` shows difference, but `cdk deploy` tells no changes · Issue #10219 · aws/aws-cdk · GitHub

Modifying a stack template - AWS CloudFormation

RemovalPolicy — AWS Cloud Development Kit 1.94.1 documentation

Escape hatches - AWS Cloud Development Kit (AWS CDK)

Identifiers - AWS Cloud Development Kit (AWS CDK)

Python: cfn_options.metadata cannot be mutated · Issue #6379 · aws/aws-cdk · GitHub

Add Support for adding Metadata to deal with 3rd party tools · Issue #8336 · aws/aws-cdk · GitHub

AWS CDKでTagを付与する

AWS CDKでTagを付与する方法の備忘録です。

はじめに

こんにちは、@bioerrorlogです。

CDKでリソースにTagを付与するとき、やり方を忘れてググり直すことがしばしばあります。

いちいち調べなくてもいいように、Tagの付与方法をメモします。

環境

今回は以下の環境で作業しました:
CDK version: 1.92.0
OS: Amazon Linux 2 (Cloud9)

CDKでTagを付与する

CDKでTagを付与するには、Tagsクラスを用いたやり方が推奨されています。

Tagging - AWS Cloud Development Kit (AWS CDK) v2

※他にはTagクラスを用いたやり方もありますが、非推奨となっています。

以下、Pythonを例にTag付与方法を見ていきます。

具体例

以下の形でTagを付与します。

Tags.of(SCOPE).add(key, value) 

SCOPEにはConstructやStackを指定し、tag, valueにはそれぞれタグのキーと値を指定します。

以下、具体例を挙げます。

Stack単位でTagを付与する

from aws_cdk import (
    aws_s3 as s3,
    core
)


class TagSampleStack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        s3_01 = s3.Bucket(self, "TagTestBucket01", bucket_name="tag-test-bucket-001")
        s3_02 = s3.Bucket(self, "TagTestBucket02", bucket_name="tag-test-bucket-002")


app = core.App()
tag_sample_stack = TagSampleStack(app, "tag-sample")

# Stackにタグを付与する
core.Tags.of(tag_sample_stack).add("Project", "TagTest")

app.synth()

このようにStackに対してTagを付与すると、Stackに含まれるリソースすべてに対してTagが付与されます。

上記のケースですと、Stackに含まれるふたつのS3バケットtag-test-bucket-001tag-test-bucket-002の両方にProject: TagTestのTagが付与されます。

Construct単位でTagを付与する

from aws_cdk import (
    aws_s3 as s3,
    core
)


class TagSampleStack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        s3_01 = s3.Bucket(self, "TagTestBucket01", bucket_name="tag-test-bucket-001")
        s3_02 = s3.Bucket(self, "TagTestBucket02", bucket_name="tag-test-bucket-002")

        # ConstructにTagを付与する
        core.Tags.of(s3_01).add("Project", "TagTest")


app = core.App()
tag_sample_stack = TagSampleStack(app, "tag-sample")

app.synth()

このように特定のConstructに対してTagを付与すると、対象のConstructに対してのみTagが付与されます。

上記のケースでは、S3バケットtag-test-bucket-001にのみProject: TagTestのTagが付与されます。

補足: 非推奨のTag付与方法

以下のようにTagクラスを用いてもTagを付与することはできますが、このやり方は非推奨となっています。

Tag.add(SCOPE, key, value)


コード例:

from aws_cdk import (
    aws_s3 as s3,
    core
)


class TagSampleStack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        s3_01 = s3.Bucket(self, "TagTestBucket01", bucket_name="tag-test-bucket-001")
        s3_02 = s3.Bucket(self, "TagTestBucket02", bucket_name="tag-test-bucket-002")


app = core.App()
tag_sample_stack = TagSampleStack(app, "tag-sample")

# Tagクラスを用いてTagを付与
core.Tag.add(tag_sample_stack, "Project", "TagTest")

app.synth()

上記のコードを実行すると、以下のようにTag.addの使用は非推奨との警告が表示され、代わりTags.of(scope).add(k,v)の使用を推奨されます。

[Warning at /tag-sample] The API @aws-cdk/core.Tag.add(scope,k,v) is deprecated: Use "Tags.of(scope).add(k,v)" instead. This API will be removed in the next major release

おわりに

今回は、CDKでのTagの付与方法をメモしました。

Pythonを例にやり方を書きましたが、他の言語でも基本同じやり方でTagを付与することが出来ます。

どなたかの参考になれば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

Tagging - AWS Cloud Development Kit (AWS CDK) v2

Tags — AWS Cloud Development Kit 1.170.1 documentation

Tag — AWS Cloud Development Kit 1.170.1 documentation

CI/CDとは何か | 定義を改めて整理する

CI/CDの定義と概念を改めて整理します。

はじめに

こんにちは、@bioerrorlogです。

開発を進める上で、CI/CDの仕組みを構築することはとても重要です。 開発者の体験の向上させ、本番プロダクトの実装サイクルを高速化できます。

しかし、CI/CDの概念を分かったつもりになっていても、CIやCDそれぞれの言葉の定義や違いを明確に解釈できているかは不安になりがちです。

今回は、CI/CDとは何か、その定義と概念を改めて整理し直します。

CI/CDとは

CI/CDとは、Continuous Integration/継続的インテグレーションと、Continuous Delivery/継続的デリバリーまたはContinuous Deployment/継続的デプロイを組み合わせたプロセスのことです。

CI/CDの全体像 | What is Continuous Integration? - AWSより

以降、この3つの概念の定義をそれぞれ見ていきます。

Continuous Integration/継続的インテグレーションとは

Continuous Integration (CI)/継続的インテグレーションとは、コード変更をメインのブランチに頻繁にマージすることです。 そのためには、前提としてビルドやテストの自動化が必要になります。


  • 書籍"Effective DevOps"での説明

    継続的インテグレーション(CI)は、開発者が書いた新しいコードとマスターブランチを頻繁に統合するプロセスだ。


  • What is Continuous Integration? - AWSでの説明

    Continuous integration is a DevOps software development practice where developers regularly merge their code changes into a central repository, after which automated builds and tests are run.


  • 継続的インテグレーション(CI)と継続的デリバリー(CD) - GitLabでの説明

    継続的インテグレーション (CI) は、チームメンバーが書いたコードを共有リポジトリに統合するために動作します。 開発者はマージ (プル) リクエストで新しいコードをチームメンバーと共有します。 このリクエストは、コードの変更を統合ブランチにマージする前に、新しいコードをビルド・テスト・検証するためのパイプラインを作成します。

Continuous Delivery/継続的デリバリーとは

Continuous Delivery (CD)/継続的デリバリーとは、コード変更を本番環境にデプロイ可能な状態にすることです。



  • What is Continuous Delivery? - AWSでの説明

    Continuous delivery is a software development practice where code changes are automatically prepared for a release to production. A pillar of modern application development, continuous delivery expands upon continuous integration by deploying all code changes to a testing environment and/or a production environment after the build stage.


  • What is CI/CD? - RedHatでの説明

    Continuous delivery usually means a developer’s changes to an application are automatically bug tested and uploaded to a repository (like GitHub or a container registry), where they can then be deployed to a live production environment by the operations team.


  • DevOps tech: Continuous delivery - Google Cloudでの説明

    Continuous delivery is the ability to release changes of all kinds on demand quickly, safely, and sustainably. Teams that practice continuous delivery well are able to release software and make changes to production in a low-risk way at any time—including during normal business hours—without impacting users.

Continuous Deployment/継続的デプロイとは

Continuous Deployment (CD)/継続的デプロイとは、コード変更を本番環境に自動デプロイすることです。


  • 書籍"Effective DevOps"での説明

    継続的デプロイ(同じくCDと呼ばれる)は、変更を本番環境にデプロイするプロセスのことだ。リスクを最小化するために、テストや結果検証の仕組みを用意する。継続的デリバリーでは新しい変更がデプロイ可能なことを保証するが、継続的デプロイでは本番環境に実際にデプロイする。


  • CI/CD concepts - GitLab Docsでの説明

    Continuous Deployment is another step beyond Continuous Integration, similar to Continuous Delivery. The difference is that instead of deploying your application manually, you set it to be deployed automatically.


  • Continuous deployment - Wikipediaでの説明

    Continuous deployment (CD) is a software engineering approach in which software functionalities are delivered frequently through automated deployments.


以上をまとめると、

  • ビルドやテストの自動化を踏まえて、コード変更をメインのブランチに頻繁にマージすることがContinuous Integration (CI)/継続的インテグレーション
  • さらに、コード変更を本番環境にデプロイ可能な状態にすることがContinuous Delivery (CD)/継続的デリバリー
  • さらに、自動でコード変更を本番環境にデプロイすることがContinuous Deployment (CD)/継続的デプロイ

と言えるでしょう。

CI/CDの流れ | What is CI/CD? - RedHatより

おわりに

今回は、CI/CDの各プロセスの定義を振り返りました。

継続的デリバリーと継続的デプロイの違いなどは、これまで何となくしか把握できていなかったと気付かされました。 言葉の定義が分かっただけでも、頭の中はスッキリするものです。

どなたかの参考になれば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

What is Continuous Integration? – Amazon Web Services

What is Continuous Delivery? – Amazon Web Services

Implement Continuous Integration and Continuous deployment using Azure DevOps | Microsoft Docs

DevOps tech: Continuous delivery  |  DevOps capabilities  |  Google Cloud

DevOps tech: Continuous integration  |  DevOps capabilities  |  Google Cloud

CI/CD concepts | GitLab

GitLabの継続的インテグレーションと継続的デリバリー | GitLab.JP

https://docs.github.com/en/actions/guides/about-continuous-integration

Continuous integration - CI - CircleCI

What is CI/CD?

CI/CD - Wikipedia

Continuous integration - Wikipedia

Continuous delivery - Wikipedia

Continuous deployment - Wikipedia

O'Reilly Japan - Effective DevOps

Session Managerで自動実行コマンドを設定する | AWS Systems Manager

Session Managerでセッション開始時の自動実行コマンド(shell profiles)を指定する方法と、その利用例を整理します。

はじめに

こんにちは、@bioerrorlogです。

AWS Systems Manager(SSM)のSession ManagerでEC2インスタンスに接続すると、カレントディレクトリが/usr/binだったり、デフォルトのshellがbashでなくBourne shellだったりと、少し不便なことがあります。

これら接続時のデフォルト設定を変更するために、セッション開始時の自動実行コマンド(shell profiles)を指定する方法を整理します。

環境

EC2インスタンス: Amazon Linux 2
SSM agent version: 3.0.655.0

Session Managerの自動実行コマンドを設定する

自動実行コマンド(shell profiles)の設定方法

最初に、自動実行コマンドの設定方法を確認します。

まず、Systems Managerのマネジメントコンソールから、"セッションマネージャー"を選択します。


次に、"設定"タブを選択し、"編集"ボタンをクリックします。


下の方にスクロールし、"Linux shell profile"の欄に任意のコマンドを入力します(Windowsインスタンスの場合は、その下の"Windows shell profile"の欄に入力します)。


これで、上記の欄に記入されたコマンドがセッション開始時に実行されます。

それでは、以下に利用例を挙げていきます。

利用例) デフォルトshellをbashにする

Session Manager接続時には、デフォルトのshellがbashでなくBourne shellになっています。 以下のように接続画面でsh-4.2$と表示されているのがそれです。

sh-4.2$

これをデフォルトでbashにするには、"Linux shell profile"にbashコマンドを設定しておきます。

bash

これで、以下のようにセッション開始時からbashが指定された状態になります。

[ssm-user@ip-172-31-14-102 bin]$

利用例) カレントディレクトリを変更する

セッション開始時のカレントディレクトリは、デフォルトで/usr/binになっています。

sh-4.2$ pwd
/usr/bin

これをあらかじめ変更させておくには、"Linux shell profile"でcdコマンドを設定しておきます。 例えばユーザーディレクトリをデフォルトのカレントディレクトリとするには、以下のようにコマンドを設定しておきます。

cd ~

これで、ユーザーディレクトリに移動した状態から作業を始めることが出来ます。

sh-4.2$ pwd
/home/ssm-user

利用例) ログインユーザーを変更する

Session Managerでは、デフォルトでユーザーssm-userとして接続されています。

sh-4.2$ whoami
ssm-user

このログインユーザをあらかじめ変更させるには、"Linux shell profile"でsuコマンドを設定します。 例えばrootとしてログインしたいのであれば、以下のように設定しておきます。

sudo su -

これで、rootユーザーとして作業を始めることが出来ます。

[root@ip-172-31-14-102 ~]# whoami
root


これら以外にも任意のコマンドを組み合わせて、接続時の状態を自由に設定することが出来ます。

おわりに

今回は、Session Managerで自動実行コマンド(shell profiles)を設定する方法をその利用例を整理しました。

Session Managerは接続時の状態に何かと不便なことがあるので、これを利用すれば少しでもフラストレーションを緩和することが出来ます。

どなたかの参考になれば幸いです。

[関連記事]
www.bioerrorlog.work

www.bioerrorlog.work

参考

Allow configurable shell profiles - AWS Systems Manager

Session Managerの"sh-4.2$"をbashに切り替える | AWS Systems Manager

Session Managerで表示される sh-4.2$の正体と、それをbashに切り替える方法の備忘録です。

はじめに

こんにちは、@bioerrorlogです。

AWS Systems Manager(SSM)のSession ManagerでEC2インスタンスに接続すると、最初に以下のような画面が表示されます。

sh-4.2$

何か、見慣れたLinuxターミナル画面とは違うなとずっと思っていました。

Linux EC2インスタンスで見慣れたshell画面は、例えば次のようなものです。

[ec2-user@ip-172-31-14-102 ~]$

今回は、このsh-4.2$の正体と、それを見慣れたbashに切り替える方法を整理します。

環境

EC2インスタンス: Amazon Linux 2
SSM agent version: 3.0.161.0

Session Managerの"sh-4.2$"をbashに切り替える

sh-4.2$の正体は何か

まずsh-4.2$の正体ですが、これはBourne shell (sh)と呼ばれるもので、普段使われるbashとは異なるものです。

Session ManagerでLinux EC2インスタンスに接続した際には、デフォルトでこのBourne shellが設定されています。

SSMドキュメントにも、以下のように記載があります。

By default, sessions on EC2 instances for Linux start using the Bourne shell (sh).

このBourne shellをbashに切り替えてあげれば、見慣れた形で作業が出来そうです。

bashに切り替える方法

ではどうやってbashに切り替えるのか?

やり方は簡単で、bashとコマンドに打てばbashに切り替わります。

sh-4.2$ bash
[ssm-user@ip-172-31-14-102 bin]$

これで、bashで実行できるようになりました。


逆にBourne shellに戻すには、shと打ちます。

[ssm-user@ip-172-31-14-102 bin]$ sh
sh-4.2$

おわりに

以上、Session Managerで表示される sh-4.2$の正体と、それをbashに切り替える方法をメモしました。

これまではBourne shellの存在を知らないままモヤモヤしていましたが、Bourne shellとbash shellの切り替えを知ってスッキリしました。

誰かの役に立てば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

Allow configurable shell profiles - AWS Systems Manager

bash - Linux difference between root shell "#" and "sh-4.2 #" - Stack Overflow

How to use common workflows on Amazon SageMaker notebook instances | AWS Machine Learning Blog

Bourne shell - Wikipedia

bash(1) - Linux manual page

Lambdaのboto3バージョンを確認する | AWS SDK for Python

Lambdaのboto3/botocoreバージョンを確認する方法の備忘録です。

はじめに

こんにちは、@bioerrorlogです。

Lambdaからboto3を用いてAWS APIを叩くのは、よくあるケースかと思います。

私もよくLambda上でboto3を使いますが、先日Lambdaのboto3バージョンではカバーされていない機能を使用し、エラーになってしまったことがありました。 その際、Lambdaのboto3バージョンを確認する必要がありましたが、ぱっとやり方が思い浮かびませんでした。

そこで今回は、Lambdaのboto3バージョンを確認する方法をメモします。

Lambdaのboto3バージョンを確認する方法

大きく分けて、以下の二つの方法があります。

  • ドキュメントからLambdaに使われているboto3バージョンを確認する
  • Lambdaを実行してboto3バージョンを確認する

それぞれ見ていきます。

ドキュメントから確認する

まず一つ目のやり方は、ドキュメントからLambdaのboto3バージョンを確認することです。

以下のドキュメントに、Lambdaランタイム毎のboto3/botocoreバージョンが記載されています。

Lambda runtimes - AWS Lambda

ドキュメントにLambdaのboto3/botocoreバージョンが記載されている(オレンジ枠)

Lambdaのランタイムを確認して、上記ドキュメントからboto3バージョンを確認するのが一番手っ取り早い確認方法かもしれません。

しかし、ドキュメントがちゃんと最新化されているか、は注意する必要があります (特に、日本語ページはしばしば最新版が反映されていないので注意が必要です)

Lambda上から確認する

二つ目のやり方は、Lambdaを実行してboto3バージョンを確認することです。

boto3/botocoreのバージョンは、boto3.__version__botocore.__version__で取得することが出来ます。

よって、例えば以下のようにboto3.__version__botocore.__version__を出力させれば、boto3/botocoreのバージョンを確認できます。

import boto3
import botocore

def lambda_handler(event, context):
    
    print(f'boto3 version: {boto3.__version__}')
    print(f'botocore version: {botocore.__version__}')
# 出力結果
boto3 version: 1.16.31
botocore version: 1.19.31

ドキュメントでの確認とは違い、こちらのやり方では確実にLambdaで使用されているboto3のバージョンを調べることが出来ます。

おわりに

今回は、Lambdaのboto3バージョンを確認する方法を簡単にメモしました。

boto3の新しいリリース機能を使いたいときは、Lambdaのboto3バージョンが追い付いていない可能性があります。 そんな時は、さっとLambdaのboto3バージョンを確認できるとよいですね。

boto3には常日頃お世話になっているので、もっと詳しくなっていきたいところです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

Lambda runtimes - AWS Lambda

Troubleshoot Python (Boto 3) Lambda function runtime errors

python - Check Boto3 Version - Stack Overflow

aws s3 cpコマンドで標準入出力をデータ出力/入力先に指定する | AWS CLI

AWS CLIのs3 cpコマンドにて、データの出力/入力先に標準入出力を指定する方法の備忘録です。

はじめに

こんにちは、@bioerrorlogです。

AWS CLIのs3 cpコマンドは、s3のオブジェクトをコピーできる便利なコマンドです。 主に以下のようにして使います。

aws s3 cp [コピー元 localパス/S3 URI] [コピー先 localパス/S3 URI]

先日、このコピー元/コピー先のパスとして、標準入出力を指定できることを知りました。

今回は、そのやり方をメモします。

環境

今回の作業環境は以下です:

aws-cli: 2.1.16
OS: Amazon Linux 2

cpコマンドで標準入出力を活用する

標準入出力の指定方法

まず結論から、コピー元/コピー先のパスに標準入出力を指定するには - を指定します。

例えば、S3上のオブジェクトの中身を標準出力に表示するには以下のようなコマンドを実行します。

aws s3 cp s3://bucket-name/object.txt -


ドキュメントにも、以下のように記載されています。

標準入力:

The following cp command uploads a local file stream from standard input to a specified bucket and key:
aws s3 cp - s3://mybucket/stream.txt


標準出力:

The following cp command downloads an S3 object locally as a stream to standard output. Downloading as a stream is not currently compatible with the --recursive parameter:
aws s3 cp s3://mybucket/stream.txt -

上記にも記載があるように、--recursiveパラメータを指定して標準出力にデータを出力することはできませんので、そこは注意が必要です。

具体例

では、実際にいくつか利用例を示します。

まず、単純にS3オブジェクト内容を標準出力に表示させまてみます。

$ aws s3 cp s3://target-bucket-001/abc.txt -
aaa
bbb
ccc

S3に配置したファイル内容がそのまま標準出力に表示されました。


標準入出力を使えるということは、パイプで別コマンドと自由に処理をつなげることもできます。

$ aws s3 cp s3://target-bucket-001/abc.txt.gz - | gunzip | grep "ccc"
ccc

上記コマンド例では、gzip圧縮されたS3ファイルを解凍->検索しています。


パイプでS3オブジェクトの出力->入力を繋げれば、1ラインでS3に再格納することもできます。

$ aws s3 cp s3://target-bucket-001/abc.txt.gz - | gunzip |  aws s3 cp - s3://target-bucket-001/gunzip_abc.txt


このように、標準入出力を利用して自由にファイルを処理出来ます。

おわりに

今回は、aws s3 cpコマンドで標準入出力を利用する方法を簡単にメモしました。

ちょっとしたTipsではありますが、パイプもうまく利用すればなかなか強力な手段になると思います。

どなたかの役に立てば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

cp — AWS CLI 1.25.76 Command Reference

AWS Command line: S3 content from stdin or to stdout

amazon web services - How to use AWS S3 CLI to dump files to stdout in BASH? - Stack Overflow

S3 ListBucketsの実行に必要なIAM権限 | AWS

S3 ListBucketsの実行に必要なIAM PolicyのAction権限について整理します。

はじめに

おはよう。@bioerrorlogです。

S3のAPIを利用する際のIAM Policy設定にはしばしば悩まされます。 S3から提供されているAPIをそのままIAM Policyの"Action"として指定できないことが多いからです。

例えばS3のListBucketsを実行する際、IAM Policyの"Action"に"s3:ListBuckets"としてそのまま権限を指定することはできません。 IAM PolicyのActionテーブルには"s3:ListBuckets"は定義されていないからです。


[関連記事] IAM Policyの"Action"に指定できる権限の一覧はどこにあるのか


そこで今回は、S3のListBuckets実行に必要なIAM PolicyのAction権限について整理します。

検証方法

Lambdaからboto3のlist_buckets()を実行し、必要なIAM Policy権限を調べます。

f:id:BioErrorLog:20210123124952p:plain
LambdaからListBucketsを発行し、必要なIAM権限を調べる

Lambdaでは、以下のシンプルなコードを実行します:

import boto3

s3_client = boto3.client('s3')

def lambda_handler(event, context):
    
    response = s3_client.list_buckets()
    print(response)
  • Lambda runtime:
    Python 3.8

  • boto3 version:
    boto3-1.15.16 botocore-1.18.16

S3 ListBucketsの実行に必要なIAM権限

結論

まず結論から言うと、必要なAction権限は以下の2つです:

  • "s3:ListBucket"
  • "s3:ListAllMyBuckets"

IAM Policyドキュメントは以下のようになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "*"
        }
    ]
}


以降、ListBucketsの実行に必要なIAM権限を検証していきます。

検証

まず、S3への権限を何も付与せずにLambdaを実行すると、以下のエラーが出力されます。

[ERROR] ClientError: An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied

当然ですが、AccessDeniedエラーが出ました。


次に、試しに"s3:ListBuckets"の権限を指定してみます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBuckets"
            ],
            "Resource": "*"
        }
    ]
}

こちらも当然、同様のAccessDeniedエラーが吐かれました。 "s3:ListBuckets"というActionは定義されていないからです。


次は、"s3:ListBucket"または"s3:ListAllMyBuckets"の権限をそれぞれ単体で付与して実行してみます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": "*"
        }
    ]
}

または

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": "*"
        }
    ]
}

しかし、どちらのケースも同様のAccessDeniedエラーが吐かれました。


そして、次のように"s3:ListBucket"と"s3:ListAllMyBuckets"の両方を許可してみます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "*"
        }
    ]
}

これでようやく、エラーなくlist_buckets()を実行することが出来ました。

おわりに

今回は、S3 ListBucketsの実行に必要なIAM権限をメモしました。

S3から提供されているAPIはそのままIAM Policyの"Action"として指定できないことが多いので、よくIAM Policyの設定には苦労します。 今回はListBuckets APIについて書きましたが、他にも紛らわしい権限設定のAPIがあります。

必要なAction権限をすぐに調べられる仕組みがあればよいのですが、、
もしあれば是非教えて貰いたいです。

[関連記事]
www.bioerrorlog.work

www.bioerrorlog.work

参考

ListBuckets - Amazon Simple Storage Service

S3 — Boto3 Docs 1.17.93 documentation

Actions, resources, and condition keys for Amazon S3 - Service Authorization Reference

IAM Policyの"Action"に指定できる権限の一覧はどこにあるのか

IAM Policyの"Action"区内に指定できるaction権限の一覧が記載されている場所の備忘録です。

はじめに

こんにちは、@bioerrorlogです。

IAM Policyの"Action"には、各AWSサービスのaction権限を指定します。 しかし、各サービスで提供されている全てのAPIが、IAM Policyの"Action"に指定できるわけではありません。 逆に、サービスからAPIとして提供されていないものでも、IAM Policyの"Action"に指定できるものがあります。

ドキュメントにも、以下のように記載されています。

Not all API operations that are defined by a service can be used as an action in an IAM policy. In addition, a service might define some actions that don't directly correspond to an API operation.


例えば、S3ではListBucketsというAPIが提供されていますが、IAM Policyの"Action"に "s3:ListBuckets"としてそのまま権限を指定することはできません。 サービスのAPI Referenceに記載されているからといって、必ずしもIAM Policyの"Action"に記載できる訳ではない、ということです。


[関連記事] S3 ListBucketsの実行に必要なIAM権限


では、IAM Policyの"Action"に指定できるaction権限の一覧はどこで調べればよいのでしょうか?

その場所を見つけたので備忘録を残します。


IAM Policyの"Action"に指定できるaction権限の一覧

場所

IAM Policyの"Action"に指定できるaction一覧は、以下に記載されています。

docs.aws.amazon.com

使い方

使い方は単純です。

まず、サイドバーから対象のサービス(例: S3)を選択します。


サービス毎のページに飛んだら、そこに"Action"として指定できるaction権限の一覧があります。


ちなみに、このドキュメントにはActionに関する情報だけでなくResource typeやCondition keyについての情報も記載されています。 IAM Policyを設計する際には大いに参考にできそうです。

おわりに

今回は、IAM Policyの"Action"に指定できるaction権限一覧の場所を記しました。

これまでは、各サービスのAPI Referenceを参照しながらIAM Policyを書くことが多かったので、たまに権限付与が上手くいかないケースがありました。 これからは今回取り上げたドキュメントを参照して、正しくActionを把握していきたいところです。

それにしても、権限周りはなかなかに奥が深くて面白いですね。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

Actions, resources, and condition keys for AWS services - Service Authorization Reference