9/24、JAWS-UG CLI専門支部にてS3でWebサイトホスティングするハンズオンを受講しました。ここのところ仕事と重なってなかなか参加できませんでしたが、久々の参加レポートを書いていきます。
目次
イベントページ
S3概要
S3の正確な情報を知るには、やはり公式ドキュメントを読むのが一番だと思いますが、今回学んだことのポイントは、以下2点です。
S3のCLIコマンドの種類
アクセス制御
S3のCLIコマンドには2種類あることは気になっていましたが、今回初めて知りました。AWS CLIユーザーガイドにも書いてあったこと、復習で読み直して知りました。まだまだ公式ドキュメントの読み込みが足りないですね(汗)気になったらすぐに知らべる癖をつけねば…
ハンズオン
手順と構成図
手順一式はこちらです。また、今回のハンズオン構成図は以下の通りです。
コマンド
構成図上、保守担当者想定のIAMユーザを作成する必要がありますが、IAMユーザ、IAMグループ、IAMポリシ作成に使ったコマンドは割愛します。S3に関するコマンドのみ書きます。
バケットの作成
s3api create-bucket
でバケット作成をします。バケット名とバケットの作成ロケーションを指定します。なお、先にログ用バケットを作成し、その後コンテンツバケットを作成します。
aws s3api create-bucket \ --bucket ${S3_BUCKET_NAME} \ --create-bucket-configuration "LocationConstraint=${S3_BUCKET_LOCATION}"
以下の通り結果が表示されたら作成成功です。
{ "Location": "http://handson-cli-s3-website-logging-website-XXXXXXXXXXXX-log.s3.amazonaws.com/" }
バケットの存在確認は、s3api list-buckets
で行います。
aws s3api list-buckets \ --query "Buckets[?Name == \`${S3_BUCKET_NAME}\`].Name" \ --output text
コマンド実行すると、以下のように表示されます。
handson-cli-s3-website-logging-website-XXXXXXXXXXXX-log
ちなみに、オプションをつけずにs3api list-buckets
を実行すると、JSON形式で以下のように表示されます。
queryオプションのJMESPathは、Buckets内のNameに${S3_BUCKET_NAME}が含まれているものを抽出するという意味です(と読み取りましたが、間違っていたらご指摘ください)。
{ "Buckets": [ { "Name": "handson-cli-s3-website-logging-website-XXXXXXXXXXX-log", "CreationDate": "2020-09-26T02:08:56.000Z" } ], "Owner": { "DisplayName": "XXXXXXXXXXX", "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } }
また、作成バケットのリージョンを確認します。
aws s3api get-bucket-location \ --bucket ${S3_BUCKET_NAME} \ --output text
東京リージョンに作成されている場合は、ap-northeast-1
と表示されます。
ログバケットのACL(アクセス権限)更新
s3api put-bucket-acl
でACLの設定を行います。ログ配信グループに「オブジェクトの書き込み」と「バケットのアクセス権限の読み取り」の権限を付与します。URIは、S3で定義されているログ配信グループのものです(詳しくはこちらに記載があります)。コマンド実行後にエラーが出力されなければOKです。
aws s3api put-bucket-acl \ --bucket ${S3_BUCKET_NAME} \ --grant-write 'URI="http://acs.amazonaws.com/groups/s3/LogDelivery"' \ --grant-read-acp 'URI="http://acs.amazonaws.com/groups/s3/LogDelivery"'
s3api get-bucket-acl
にて、ログバケットのACLが、ログ配信グループからのオブジェクト書き込み(WRITE)とアクセス権限の読み取り(READ_ACP)を許可していることを確認します。許可されている場合は、WRITE READ_ACP
と表示されます。
aws s3api get-bucket-acl \ --bucket ${S3_BUCKET_NAME} \ --query 'Grants[?Grantee.URI == `http://acs.amazonaws.com/groups/s3/LogDelivery`].Permission' \ --output text
コンテンツバケットの設定
ログ設定を s3api put-bucket-logging
で設定します。コマンド実行後にエラーが出力されなければOKです。
aws s3api put-bucket-logging \ --bucket ${S3_BUCKET_NAME} \ --bucket-logging-status file://${FILE_S3_BUCKET_LOGGING_DOC}
バケットログ設定が有効になっていることを s3api get-bucket-logging
で確認します。
aws s3api get-bucket-logging \ --bucket ${S3_BUCKET_NAME}
設定されている場合は、コマンド実行後以下の通り表示されます。
{ "LoggingEnabled": { "TargetPrefix": "Logs/", "TargetBucket": "handson-cli-s3-website-logging-website-XXXXXXXXXXXX-log" } }
s3api put-bucket-policy
でバケットポリシを適用します。あらかじめ作成したポリシファイルを読み込みます。コマンド実行後にエラーが出力されなければOKです。
aws s3api put-bucket-policy \ --bucket ${S3_BUCKET_NAME} \ --policy file://${FILE_S3_BUCKET_POLICY_DOC}
バケットポリシが存在することを確認します。
aws s3api get-bucket-policy \ --bucket ${S3_BUCKET_NAME}
コマンド実行後に以下のように表示されたら成功です。
{ "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"AddPerm\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::handson-cli-s3-website-logging-website-XXXXXXXXXXXX/*\"}]}" }
s3api put-bucket-website
でWebサイトホスティング設定をします。あらかじめ作成した設定ドキュメントを読み込みます。コマンド実行後にエラーが出力されなければOKです。
aws s3api put-bucket-website \ --bucket ${S3_BUCKET_NAME} \ --website-configuration file://${FILE_S3_BUCKET_WEBSITE_DOC}
なお、設定ファイル(${FILE_S3_BUCKET_WEBSITE_DOC})は以下のJSONを読み込ませます。エラードキュメントファイルとインデックスドキュメントの設定です。
{ "ErrorDocument": { "Key": "error.html" }, "IndexDocument": { "Suffix": "index.html" } }
s3api get-bucket-website
でWebサイトホスティングの設定が存在することを確認します。
aws s3api get-bucket-website \ --bucket ${S3_BUCKET_NAME} \ --query "length(@)"
先のJSONを読み込ませて、エラードキュメントとインデックスドキュメントを設定しました。そのため、コマンド実行後に設定数が2
と表示されればOKです。
Webコンテンツの公開
コンテンツバケットにアクセス確認します。コマンド実行後に0が表示されればOKです。
aws s3 ls s3://${S3_BUCKET_NAME} \ > /dev/null 2>&1; echo $?
s3 sync
を使い、あらかじめ準備したインデックスドキュメントとエラードキュメントが格納されているドキュメントに移動し、ドキュメントをコンテンツバケットに転送します。なお、--exclude
で‘git
を転送対象外にしています。
dir_current=$(pwd) cd ${DIR_S3_SYNC} \ && aws s3 sync . "s3://${S3_BUCKET_NAME}/" \ --exclude "${S3_SYNC_EXCLUDE}" \ && cd ${dir_current}
ドキュメントがアップされたことを、aws s3 ls s3://${S3_BUCKET_NAME}
で確認します。コマンド実行後、例えば以下のように転送したドキュメントが表示されればOKです。
2020-09-25 01:23:45 186 error.html 2020-09-25 01:23:45 55560 img.jpg 2020-09-25 01:23:45 255 index.html
curlコマンドでWebサイトにアクセスできることを確認します。
curl ${S3_BUCKET_WEBSITE_ENDPOINT}
インデックスドキュメントのHTMLが表示されればOKです。
次にステータスコード200が返ってくることを確認します。
curl -LI -Ss \ -o /dev/null \ -w '%{http_code}\n' \ ${S3_BUCKET_WEBSITE_ENDPOINT}
ログファイルの確認
以下の通り、ログバケットにログプレフィックスのファイルが作られていることを確認します。
aws s3 ls s3://${S3_BUCKET_NAME}/${S3_OBJECT_PREFIX}/
ファイルが作成されている場合、コマンド実行後に以下のように出力されます。
2020-09-26 05:18:26 2935 2020-09-26-05-18-25-A44181ED2D12C6DA 2020-09-26 05:18:27 1468 2020-09-26-05-18-26-4CA7D54903B72B4F 2020-09-26 05:18:49 734 2020-09-26-05-18-48-13AABCAA53BD5E8E 2020-09-26 05:18:57 1416 2020-09-26-05-18-56-A8F517B37FCB32B4 2020-09-26 05:19:02 2109 2020-09-26-05-19-01-C7FFC74DA7AEB437 2020-09-26 05:19:08 3550 2020-09-26-05-19-07-02E2F4A93A96D79B
S3バケットの破棄
コンテンツバケットとログバケットを以下のコマンドで削除します。
まずは、s3 rm
に--recursive
オプションをつけてバケット内のオブジェクトを削除します。コマンド実行後に削除されたオブジェクトが表示されます。
aws s3 rm s3://${S3_BUCKET_NAME} \ --recursive
s3api list-objects-v2
でオブジェクトが存在しないことを確認します。コマンド実行後にエラーが出力されなければOKです。
aws s3api list-objects-v2 \ --bucket ${S3_BUCKET_NAME} \ --max-items 1000
s3api delete-bucket
でバケットを削除します。コマンド実行後にエラーが出力されなければOKです。
aws s3api delete-bucket \ --bucket ${S3_BUCKET_NAME}
s3api list-buckets
でバケットが存在しないことを確認します。コマンド実行後にエラーが出力されなければOKです。
aws s3api list-buckets \ --query "Buckets[?Name == \`${S3_BUCKET_NAME}\`].Name" \ --output text
ハンズオンは以上です。
LT
今回はLTが2本ありました。
AWS CLIで月160万円の負債を解消した話 大内さん
資料はこちらです。
3日間の新人研修でかかるAWS費用(EIP+EC2+RDS(約2,000円/月))をAWS CLIで解消したというお話でした。800人分の研修用環境を後片付けするのは大変ですし、削除漏れがあると膨大な費用になります。それをAWS CLIでShellを組んで実行するだけで最小限に抑えたことには驚きでした!目に見える結果を技術を駆使して出したことに敬意を抱くばかりでした。
CDKについて 佐藤さん
突発のLTのため資料はありませんでしたが、CDKについてのお話でした。プログラミングでAWSに環境構築できるのは面白そうだと思っていましたが、プログラミングの素養がほとんどなくCDK途中で挫折してしまいました。CLIで理解を深めた上でCDKもいずれ再挑戦してみたいと思います。
最後に
Webサイト公開のように見えやすい結果のあるハンズオンだと、「ハンズオンやり切った!」という実感がとても強いです。今回のハンズオンも楽しみながら参加できて勉強になりました。そういえば、LTのあるCLI専門支部ハンズオンに参加したのは初めてでした。今回の大内さんを聞き、自分が学んだことを組織や顧客のプラスになることに使う、そんな仕事を実現したいと思いました。また、今回のハンズオンを終えて、自分もどこかでLT登壇したいと思いました。今年の初めに技術ネタで登壇したいとブログに書いておきながら、やれずに今年も残り3か月…いいかげん挑戦しようと思います。少しでも良い話ができるよう、気合入れなおして今後のCLI専門支部ハンズオンにも臨みたいです!