S3 のプレフィックスを理解した!
S3 にオブジェクトをアップするとき、バケットの中にフォルダを複数作ってました。フォルダ or ディレクトリって感じでした。
下記を読んで、驚きました。今更ながら発見です。
Amazon S3 では、バケットとオブジェクトが主要なリソースであり、オブジェクトはバケットに格納されます。Amazon S3 はフラットな構造であり、ファイルシステムに見られる階層はありません。ただし、構造を分かりやすくするため、Amazon S3 コンソールでは、オブジェクトのグループ化の方法としてフォルダの概念をサポートしています。これを行うために、オブジェクトに共通の名前プレフィックスを使用します (つまり、共通の文字列で始まる名前が付けられます)。オブジェクト名はキー名とも呼ばれます。
フォルダを使用して Amazon S3 コンソールでオブジェクトを整理する - Amazon Simple Storage Service
フォルダという階層は存在しなく、あくまでオブジェクトのグループ化のため「フォルダ」という概念を使ってるんですね。また、フォルダパス的なものが「プレフィックス」なんですね。
俗にいう「ファイルサーバ」をよく扱っていたので、オブジェクトストレージの理解がだいぶ間違ってました。衝撃的だったのでメモ。
Lambda + RDS Proxy を利用して Aurora PostgreSQL にアクセスする
検証のためにLambda + RDS Proxy + Aurora PostgreSQL を構築したが、時間がかかったり、はまったりしたのでメモとして残す。
(やりたかったこと)
- Lambda 〜 RDS Proxy 間は、IAM認証を利用
- RDS Proxy から Secrets Manager へアクセス(Lambda にクレデンシャルを埋め込まない)
- Lambda から クエリを投げる
(作業概要)
- EC2 からAurora へアクセス、テーブルを作成
- Lambda 作成 、 Aurora へアクセス(Lambda レイヤーの準備)
- Lambda から Aurora へテストでアクセス(クエリをなげる)
- RDS Proxy 、Secrets Manager 、Lambda の設定
(作業1 .EC2 からAurora へアクセス、テーブルを作成)
EC2 へpsql をインストール
sudo yum -y install postgresql.x86_64
EC2 からAurora へアクセス
psql -h <エンドポイント> -U <ユーザ名>
Aurora にユーザ/データベース/テーブルの作成
create user post_user01 with password '*******';
create database post_user_database owner=post_user01;
create table A(id serial primary key, name text);
insert into A(name) values('rili'),('so!'),('oh!');
GRANT all ON A TO post_user01;
ここでの作業が原因でLambdaでの作業時にはまった。新しくテーブルを作成したが、間違えて「デフォルトのデータベース」上に作成していた。Lambda からは「新しいデータベース」のテーブルにアクセスしてたので、クエリが通らなかった。
(作業2.Lambda 作成 、 Aurora へアクセス(Lambda レイヤーの準備))
Lambda から PostgreSQL にアクセするために、外部ライブラリが必要とのこと。今回は、先人のものを利用することに。下記を参考に作業。本当に感謝です。
(参考にしたサイト)
AWS LambdaでPython外部ライブラリのLayerを作る前に - Qiita
Klayers/deployments/python3.8 at master · keithrozario/Klayers · GitHub
Lambda の作成は下記を参考。こちらも本当に感謝です。
【AWS】LambdaからRDS Proxy経由でPostgreSQLへ接続する | SEのプログラミングと英語の勉強ブログ
(作業3.Lambda から Aurora へテストでアクセス(クエリをなげる))
最初は RDS Proxy を挟まずに、Lambda からアクセス。上述の通り、テーブルの作成場所を誤ったためはまっていました。切り分けとして、実行する SQL を変えてみました。PostgreSQL 上の時刻を確認するクエリを投げたら、応答があったのでデータベース周りを調査して無事解決。
(作業4.RDS Proxy 、Secrets Manager 、Lambda の設定)
RDS Proxy 、Secrets Manager 、Lambda の設定も上記サイトを参考。以下ではまった。
- RDS Proxy のロールに適用するポリシーに誤りがあった。Resource に Secrets Manager に作成した「シークレットのARN」を入れること。
- Lambda のコード内で IAM 認証の記述。「generate_db_auth_token」で token を作成する。その token を利用して DB へアクセするコードを記述。
- Lambda への証明書インポート、コードの記述
※Lambda から Secrets Manager へのアクセスするコードは Secrets Manager コンソールにサンプルコードがあり便利だった。
Boto3でS3に読み書きする
「クラウド開発入門」を参考にして、Boto3を使ってS3に対していろいろな操作をした。そこで「はまったこと」「学んだこと」を備忘で記載。
はまったこと
-
-
- Jupyter Notebookを使った操作
S3上にファイルを作成する、読み込むなど複数の作業をしようとすると権限エラーが出てしまった。下記のサイトを参考に解決。スレッドセーフではないとのこと(よく分かってません)。
PythonのAWSライブラリBoto3のSessionはスレッドセーフではないよという話 | DevelopersIO
- S3上のオブジェクト名を表示する
前回に引き続き、JSONに適切に対応できなかった。「client.list_objects」を利用して、JSONで結果を出すことはすぐに成功した。しかし、2つあるオブジェクト名(Key)のみ表示したく、試行錯誤した。最終的に以下の形で表示できた。ググった感じだと、for などを使ってみればうまくいきそうだなと思ったが今回は諦めた。
objects = response['Contents']
print(objects[0]['Key'])
print(objects[1]['Key'])
- Jupyter Notebookを使った操作
-
学んだこと
-
-
- session を利用して、AWSシークレットキーの設定ができる
- S3のオブジェクトを一覧で一括表示するには工夫が必要(1000over)
-
S3のイベントをトリガーにS3にファイルをアップロードする
GWで時間も取れたので、初心者レベルから少しでもレベルアップを目指してコードの練習をした。今回のお題は以下。
・S3のイベントをトリガーとする
・Lambdaを起動して、S3にファイルを作成する
最終系のLambda関数
import boto3client = boto3.client('s3')
def lambda_handler(event,context):
input_event_name = event["Records"][0]["eventName"]
input_event_object = event["Records"][0]["s3"]["object"]["key"]
response = client.put_object(
Body = input_event_name,
Bucket = 'xxxxx-xxxxx-output',
Key = input_event_object+'.txt'
)
はまったこと
- 無駄に「,」を入れてしまった
不要なところに「,」を入れてしまったので、エラーとなった。ログを見てもそれが原因とはすぐにわからず切り分けに時間がかかった。 - 変数の使い方
Body、Key をS3から受け取ったイベントの内容に合わせて変化させたかった(ハードコードしたくなかった)。それを実現する記載方法を試行錯誤した。上記が正解とは言えないかもしれないが適切に動いたから、一応「OK」とする。
「response ~」の記載を lambda_handler 関数に含めず、別の関数で考えていた。しかし、参考にしたサイトではまとめていた。シンプルでよいなと思い真似た。本当に助かりました。 - イベントからの情報取得
AWSのサイトに「event['Records'][0]['s3']['bucket']['name']」と記載があった。過去にも似たような記載を見たことがあったがコピペしていたので、今回はせっかくの機会なのでその意味を深掘りしてみた。
私の理解は以下である。
・リストと辞書の組み合わせ
・[0]はリストの番号である
・[0]以降は取得したいデータの階層を辿っていく
コード書くことが仕事のメインではないので、時間があるときに少しでもやらないと忘れてしまう。
(参考サイト)
ロードバランサーとNLB
オンプレをメインとしてたころ、私が担当するお客様では導入が少なかった。理由は高価であるからだ。なので、触る機会が少なかった。クラウドをやり始めてからは、導入前提で話が始めることが多い。直近でAWSのNetwork Load Balancer を触る機会が多かったので、備忘として記録する。
ELBとは
AWS上のロードバランシングサービスで2022/04 時点で以下の4つがある。
・Application Load Balancer
・Network Load Balancer
・Gateway Load Balancer
・Classic Load Balancer
BlackBeltのELBには、「スケーラブル」「安価な従量課金」「運用管理が楽(マネージドだから)」「豊富な連携機能(i.g Auto Scaling、Route53、Cloud Formationなど)」と記載。今回はELBの中でも Network Load Balancer(NLB)に焦点を当てる。
NLBはIPアドレスが固定
なんらかの理由で、ELBのIPを固定したいとなればNLB一択となる。「なぜ、IPを固定する必要があるか?」をしっかりDive Deepすることは忘れずに。
NLBのスケール
ELBはそれ自体、負荷に応じて自動でスケールする。NLBはスケールする際にもIPアドレスは固定したままである。ALB/CLBはスケールする時はIPが変化する。ですけど、「毎秒数百万のリクエストを処理」となっているので、エンタープライズなお客様でないとスケールには出会わないかも。
ロードバランサーの種類
NLBはレイヤー4に対応するロードバランサーである。プロトコルリスナーは、TCP/UDP/TLSとなっている。しかし、PrivateLinkと連携する時は、TCP/TLSのみのサポートとなる点は注意。
スティッキーセッションもサポート
NLBはスティッキーセッションに対応している。スティッキーセッションとは、「同じユーザから来たリクエストを同じターゲットグループに送信」する機能である。NLBは送信元IPでルーティングするようである。私がAWSを学び始めた時点では未対応だったが、気づいたら対応していた。アップデートは要チェックですね。
コネクションタイムアウト
NLBは固定値で350秒となる。ALB/CLBは、変更可能。
ターゲットグループ
ターゲットグループに、IP/インスタンス/ALBを指定できる。ALBを利用したいが「IPアドレスを固定する必要がある」といった場合に、NLBの裏でALBを利用することができる。
NLBを利用してFTPのアクティブモードをバランシングできるのか?
他の方のBlogをみるとパッシブモードの検証は多かったが、アクティブモードが見つからなかったので試してみた。検証環境は以下である。
・2つのVPCを用意して、片方をFTP Server(EC2) + NLB、もう片方をFTP Client(EC2)とした
・EC2はそれぞれ1台である
・2つのVPCはピアリング接続をした
結論はうまくいった。EC2の数を増やしてのテストはしていない。アクティブモードのコントロールコネクションは、FTP ClientからEC2への通信となりこれはNLBでうまく捌いてくれる。気になるのでは、アクティブモードのデータコネクションである。これはFTP ServerからFTP Client宛の通信でありNLBの「バック」から発信される。今回の検証環境ではうまくいったが、EC2の台数が増えた場合に期待通りに動くかはなんとも言えない。
参考サイト (わかりやすい)
Cookieやセッションを整理する
Webアプリケーションにおいて、ユーザを管理する際にCookieやセッションといった言葉を何気に使っていたので一旦整理してみた。
Cookieとは
Webアプリがユーザ側に保存するデータ。最大4KBまでしか保存できない。ユーザIDやアクセス履歴などの情報をCookieに含めることで、Webアプリにアクセスした時にユーザに最適な情報を表示できる。CookieはHTTP通信のヘッダーでやりとりされる。リクエストヘッダーでCookieをWebアプリになげる。 Webアプリ側のレスポンスで「set-cookie」を指定して、ブラウザ側にCookieを返す。
セッションとは
Webアプリ側でユーザの情報を保持することに利用される。HTTPはステートレスなので、アプリにログインしたユーザの情報をそのままだと持てない。ユーザごとに異なる画面やサービスを提供するために、利用されるのがセッションである。ユーザのアクセスの際に「ユーザを特定する」ために利用されるのが、Cookieである。
Boto3 EC2の情報を取得
プログラミングスキル向上を目指し、自分で手を動かしてコードを書いていこうと思う。 まずは、入門レベルから。今回は、「EC2の情報を取得する」コードを書いてみた。
import boto3 client = boto3.client('ec2') response = client.describe_instances() #jsonファイルのReservations から情報を取得、EC2台数分必要なのでfor を使う for instance in response['Reservations']: #Reservations 配下のInstancesから情報を取得、EC2台数分必要なのでfor を使う for instance2 in instance['Instances']: #Instances>Placementから情報を取得 az = instance2['Placement']['AvailabilityZone'] #Instances>Stateから情報を取得 state = instance2['State']['Name'] print("InstanceID:" +instance2['InstanceId'], "Type:" +instance2['InstanceType'], "AZ:" +az, "Status:" +state )
はまったところ。「az」の情報を取得する際に、「Placement」からうまく情報を引っ張れなかった。 JSONの階層を見間違いしていたためである。次回以降は気をつけたい。