この記事で伝えたいこと(ポイント)
- AWS SDKがどんなものだったか改めて振り返る
- 書き方の例をいくつかみる
- boto3の定義が書いてあるドキュメントの読み方
はじめに
この記事ではAWSが提供するAWS SDK for Python (boto3)(以下、本文ではboto3)を手を動かしながら振り返る内容となっています。
主な内容としては実践したときのメモを中心に書きます。(忘れやすいことなど)
誤りなどがあれば修正していく想定です。
今回は重要だと思うポイントや実務で4年〜5年使ってみての見解を交えてAWS SDK for Pythonについて説明できたらと思います。
なお、解説記事ついては【AWS】用語を整理しながら学ぶAWS AWS SDK for Python (Boto3)を参照していただけますと幸いです。
結論を言うとAWS SDKって何者
AWSが提供するAPIを手軽に実行できるようにした開発者ツールです。
復習:AWS SDK for Pythonとは
AWSの公式サイトには下記のように表現されています。
AWS での構築ツール
AWS でアプリケーションを開発および管理するためのツール
選択したプログラミング言語を使用して、AWS でアプリケーションを簡単に開発する
Python 固有の API と有益なライブラリを使って、アプリケーションを開発する
主にアプリケーション開発者向けに提供されているソフトウェアと解釈できます。
AWSリソースの作成、削除、情報取得ができます。
実際に触ってみて思うこと
強みは使い慣れたプログラミング言語でAWSリソースの作成・削除・情報の取得ができる
という理解でしたが、AWS SDKの強みはリソース情報の取得
にあると思います。
リソースを作成するだけであれば、AWS CDKやIaC(CloudFormationやTerraformなど)で十分である場合がほとんどです。もちろん、これらはインフラストラクチャーに携わる人が主に利用するのでそうではないとも言えます。
また、アプリケーションから条件に合わせてリソースを作成する場合においてとても有効な手段になります。他にはAWSマネジメントコンソールから参照が難しいリソース情報を簡単に参照できるのは他にはない強みです。
環境の構築方法
では実際に使うためにはどのような環境を構築すれば良いのでしょうか。
以下の方法で環境構築が可能です。
- パッケージマネージャ(pip)を使ってそのままローカルPCにパッケージをインストールして利用(ローカル)
- Python仮想環境(venv)を構築して仮想環境にインストールして利用(venv)
- コンテナ開発環境にインストールして利用(コンテナ)
それ以外の方法ではクラウドIDEを使った方法があります。認証情報はホームディレクトリにある.aws/credential
というところに保存されますので認証情報が読み取れれば、どんな環境でも構いません。
構築方法の違い
いくつか示した上でどんな環境でも良いという話をしました。構築方法によってどんな違いがあるのか経験を元に説明します。
結論から述べると、とくに理由がない限りはコンテナベースの開発環境を構築することをオススメします。理由としてはboto3およびPythonはバージョンとパッケージのマネジメントが肝となるからです。
項番 | 構築方法 | メリット | デメリット |
---|---|---|---|
1 | ローカル | Pythonがインストールされていれば、すぐに扱える。 | チーム開発では不向き |
2 | 仮想環境 | メインとなるPython環境とセパレートしてプロジェクトを分離できる。 | ECSやLambdaを使ってアプリケーションを開発している場合は不向き |
3 | コンテナ | Pythonのバージョンも含め再現性の高い環境が構築できる。 | コンテナイメージが必要 |
補足:ローカル開発環境について
チーム開発に不向き
ということですが、最低でも以下の設定をメンバー間で共有できれば問題ありません。
- Pythonのバージョン
- pipの設定情報(pip.conf)
- インストールされたpipパッケージ情報
pipの仕様に阻まれる
pip installの仕様でパッケージインストールに失敗する場合があります。経験上では以下のケースが多いです。
-
--break-system-packages
を必要とする場合 -
--user
インストールを必要とする場合 -
--trusted-host
を必要とする場合
--break-system-packages
を必要とする場合
システムでインストールされているパッケージがオーバーライドされるのを防ぐために導入されたオプションです。Python3.11、pip 23.0で導入された機能です。
参考:Bump for release · pypa/pip@368c7b4
対策としてはシステムにインストールされたPythonパッケージに対して干渉しない形でPythonのパッケージをインストールする必要があります。
つまりは仮想環境を構築して使いましょう
ということです。あるいは--user
を使いましょう。(後述)
詳しくはPython Packaging User Guideを参照してください。
外部から管理される環境 - Python Packaging User Guide
--user
インストールを必要とする場合
システムパッケージに干渉しない形でインストールするには--user
オプションを利用します。管理者権限を使わない場合にも有効です。
詳しくはPython Packaging User Guideを参照してください。
参考:パッケージをインストールする - Python Packaging User Guide
--trusted-host
を必要とする場合
信頼済みのパッケージレジストリからパッケージをインストールする時に利用します。
たとえば、SSLインスペクションが導入されている環境で利用することがあります。
証明書を使っている場合
証明書を使ってboto3を扱う場合はAWS_CA_BUNDLE
という環境変数に証明書のパスを設定する必要があります。あるいはboto.coreの設定にしておく必要があります。
参考:Configuration - Boto3 1.38.18 documentation
AWS SDK for Pythonの基本
ここからは実際に触っていきたいと思いますが、まずは基本をおさえておきましょう。
boto3は主に以下の流れで利用します。
1.セッションを構築する
2.Client API / Resource APIオブジェクトを作成する
3.オブジェクトからメソッドを実行する
4.戻り値を処理して表示
Client API / Resource APIって何
boto3には主にclientとresourceの2つがあります。
- client:アクセス元の操作について扱う場合
- resource:指定されたリソースについてダイレクトにアクセスしたい場合
実際のところclientが扱えれば、だいたいのことはできます。resource APIはほとんど利用しないです。(全く利用しないわけではないです)
補足:resource APIについて
resource APIについては今後の機能追加を予定していないという言及があります。
また、一時は廃止するという話まで出てきましたが、すぐにアナウンス文が修正されるということもありました。
※リアルタイムで見ていたこともあって当時はとても驚いたことを覚えています。
参考:More info about resource deprecation? #3563
今後の利用についてはとくに理由がない限り、client APIの利用を検討したほうが良いでしょう。
書き方の例:サクッと書いてみる
では実際に書いてみましょう。
アカウント情報を取得する
とてもベーシックで誰でも簡単に実行できるメソッドとしてAWS STSのAPIを呼び出すというのがあります。以下のコードを実行するとAWSのアカウントIDが表示されます。
import boto3
boto3_session = boto3.Session()
sts = boto3_session.client('sts')
id_info = sts.get_caller_identity()
print(id_info['Account'])
一見して問題ないコードに思えますが、このコードには問題があります。
それは実行するまでどのAWSアカウントのIDが取得されるかわからない
という点です。
認証情報を参照する優先順位についてはboto3に以下の記載があります。
Boto3は認証情報の検索時に複数の場所を検索します。Boto3が認証情報を検索する仕組みは、可能性のある場所のリストを検索し、認証情報が見つかった時点で検索を停止することです。Boto3が認証情報を検索する順序は以下のとおりです。
参考:認証情報 - Boto3 1.38.18 ドキュメント
この問題を解決する場合はAWS_DEFAULT_PROFILE
の環境変数や.aws/credential
を設定する必要があります。あるいはオススメはしませんが、以下のようにプロファイルを指定して書くことも可能です。
from boto3 import Session
boto3_session = Session(profile_name="account_profile")
sts = boto3_session.client('sts')
id_info = sts.get_caller_identity()
print(id_info['Account'])
Lambdaの関数一覧を取得する
次にLambdaの関数一覧を取得する例を見ていきましょう。
import boto3
boto3_session = boto3.Session()
client = boto3_session.client('lambda')
for function in client.list_functions()['Functions']:
print(function['FunctionName'])
先ほど同様にこのコードには認証情報に関する問題を抱えていますが、結論から先に述べるとリージョンが実行されるまで不明なため、どの関数一覧を取得するのかわからない
という問題があります。
この問題を解決するにはセッション構築時にリージョンを指定する必要があります。
たとえば、us-east-1
の関数一覧を取得する例です。
import boto3
boto3_session = boto3.Session(region_name='us-east-1')
client = boto3_session.client('lambda')
for function in client.list_functions()['Functions']:
print(function['FunctionName'])
ページングとNextToken
さまざまなメソッドを持つboto3ですが、実は万能ではなく一度のリクエストですべてのデータを取れないケースがあります。たとえば、リソースが多い場合においては分割して取得する必要があります。
分割して取得する場合は取得件数の最大値を超えた時にNextTokenが発行されますのでNextTokenを使って再度、リクエストを送信します。
塊毎にちょっとずつデータを取っていく、この操作をページングと言います。150件あって100件までは一度に取得できる上限であれば、2回のリクエストが必要です。
具体的には以下のような実装例です。
if "NextToken" in table_list:
next_token = table_list["NextToken"]
has_next_token = True
while has_next_token:
next_data = session.client("glue").get_tables(NextToken=next_token)
table_list["DatabaseList"].extend(next_data["DatabaseList"])
if "NextToken" in next_data:
next_token = next_data["NextToken"]
else:
has_next_token = False
あるいは各client APIに実装されているpagenatorを使うと良いでしょう。
クロスアカウントアクセスを意識する
ここまででわかることとしてはboto3を扱う上ではセッションがより重要になるということです。
AWSではセキュアに認証する手段としてAWS STSが提供されています。普段意識することがないですが
これがboto3をクロスアカウントアクセスする際に役に立ちます。
以下のコードはAWS STSを使ってクロスアカウントアクセスを実行するメソッドです。
def get_resource_details2(role, external_id, region):
# ロールの引き受け
sts = boto3.client("sts").assume_role(
RoleArn=role,
RoleSessionName="SessionName",
ExternalId=external_id)
# Sessionオブジェクトの生成
boto3_session = boto3.Session(
aws_access_key_id=sts["Credentials"]["AccessKeyId"],
aws_secret_access_key=sts["Credentials"]["SecretAccessKey"],
aws_session_token=sts["Credentials"]["SessionToken"],
region_name=region)
# クライアントオブジェクトの生成
ec2 = boto3_session.client('ec2')
rds = boto3_session.client('rds')
s3 = boto3_session.client('s3')
アクセス時にはロール名と外部IDを使用しています。上記のように実装することで同一セッション、特定のリージョンに対して複数のAPIを実行できるようになります。
また、RoleSessionName
を設定することでセッション名を明確に管理できるようになります。
補足:PEP8をうまく扱う
実際にコードを書いているとPEP8による警告が表示されてコーディングしにくいところが出てきます。とくにPythonのコーディング規約には1行の文字数を79文字に定めています。この規約を守るのがboto3では難しいです。
参考:maximum-line-length - PEP 8 – Style Guide for Python Code | peps.python.org
なお、このPythonのコーディング規約は無視することが可能であり、flake8を利用されている場合は.flake8
ファイルをリポジトリにおくことで無視することが可能です。
[flake8]
ignore = E501
参考:Line too long (82 > 79 characters) (E501)
あるいは1行の文字数を任意の文字数にすることも可能です。
※120文字にする場合
[flake8]
max-line-length = 120
boto3のメソッド名を探索する
ここまででboto3の特徴・使い方をおさえたところで実際に使ってみると、とある壁にぶつかると思います。というのもboto3はAWSのサービスに対していろんなAPIを実行できるということでたくさんのメソッドがあります。
boto3はメソッド名がたくさんあるため、「自分の欲しい情報を取ってきてくれるメソッドはどれだ?」という状況になりがちです。
昨今においてはAIに聞くことでなんとなくやってくれるところがありますが、ドキュメントを読めるようになった方がいささか早いかもしれません。
※実際のところ、生成したコードを精査するためにドキュメントを探索することがあります。
そこでboto3ドキュメントを読むコツとしては個人的に以下のやり方がオススメです。
- 使いたいサービスを探す
- たとえば、VPCならEC2のページを開く
- 英単語からやりたいことを想像する
- ネットワークACLを作りたいなら
create
- ネットワークACLを作りたいなら
- 単語を検索する
-
create
から始まるものを文書内から検索する
-
- メソッドの詳細を追う
- Request Syntaxを見る
- parametersを見て、requiredになっているものメモする
- Response SyntaxとResponse Structureをチェックする
補足:単語を検索する
Lambda - Boto3 1.38.18 documentationをベースに見ていくとわかるとおり、基本的に動詞 + 名詞
の組み合わせでメソッド名が定義されています。
作成と削除はcreate
とdelete
で大変わかりやすいですが、リソース情報の取得には少しだけクセがあります。
リソース情報の取得はlist
あるいはget
を使うことで実現できますが、それぞれで使い方が異なります。
list
は一覧の取得、get
は特定のリソースに対して詳細情報を取得するといったニュアンスが強いです。
たとえば、Lambdaにおいてはlist_functions
を実行して関数名をget_function
で関数の詳細を取得します。具体的には以下のコードです。
import boto3
boto3_session = boto3.Session(region_name='us-east-1')
client = boto3_session.client('lambda')
for function in client.list_functions()['Functions']:
print(client.get_function(FunctionName=function['FunctionName'])['Configuration'])
まとめ
AWS SDK for Python (boto3) とは何かや実践的な使い方や注意点を解説しました。
今までずっと触ってきてハマったところや内在する不具合に気づけるようになったのは使い始めて3年目くらいだということを覚えています。とくにインフラ周りまで面倒をみるとコードの悪いところに気づけたり、チームで開発しているときに気づけたりすることが多いです。
また、個人の環境ではかなり自由にやっているため、制約のある社内環境でやってみると動かないことがよくあります。そういった場合に細かい設定方法を調査して知ることがよくありました。
一番気を遣ったところとしてはソースコードをいかに修正せずに現在の環境に対応させるかというところです。
認証プロファイルやリージョン名、SSL対策はその典型と言えるでしょう。
なお、これらの設定はboto.coreの設定を変えることで対応が可能であり、具体的には.aws/config
を修正することで対応可能です。次はコンフィグ周りについて調べてみようと思いました。