AWS関連

【AWS】JAWS-UG CLI専門支部 #237R CloudFront入門|参加レポート

はじめに

今回はJAWS-UG CLI専門支部 #237R CloudFront入門(2021/11/25 開催) の勉強会の参加レポートになります。

前回の参加から少し間が空いてしまったのですが、「CloudFront をAWS CLIで触るってどんな感じなんだろう?!」という思いから参加してみました。

結果的に相変わらず学びの多い勉強会や、、と再認識したことだけ先にお伝えしておきます。

AWS に興味をお持ちの方は、かなり楽しめる勉強会だと思いますので参加したことのない方は是非。

(Twitter のSpaces で平日の朝9時から開催されているオハヨーAWS でも、AWS の方が「社内にもCLI専門支部にはお世話になったって方は多い」と言ってました)

ハンズオンの概要

今回参加したハンズオンの流れは、ざっくり以下のようなものです。

  • オリジンとなるS3 バケットの構築(静的Webサイトホスティング)
  • CloudFrontディストリビューションの構築 (HTTP)
  • コンテンツの更新
  • キャッシュ無効化の作成
  • 後片付け

詳細については割愛しますが、ハンズオンでは「コピペで作業を進めれる」ように構成されているので、完走のハードルはかなり低いと思います。
(今回利用した手順書はコチラ。)

今回のハンズオンも当日は手を動かせなかったので、後日一人で作業を進めてみましたが、「ハンズオン環境への権限追加」から「コンテンツの更新」までちょうど1時間ほどで進めることができました。

個人的には、主催者である波田野さん の解説とか小話とかを聞けるのが最も楽しみなことの一つです笑。

学びメモ

前述の通り、今回も得るものが多いハンズオンだったのですが、

特に気になった点についてピックアップしてみます。(なかなかの量になってしまった…笑)

なお、以下に記載するコマンド例は今回のハンズオン手順書内の記載を転記したものです。(事前の変数セットの部分は省略してるので、転記部分単体では利用できません)

複数ポリシーをロールにアタッチする

いきなり CloudFront 関係ないですが笑、配列を利用したスクリプトです。

AWS CLI コマンドと配列を利用して、IAMロールに対して複数のIAMポリシーをアタッチしています。

このように、スクリプトやコマンドを手順書化する際のTips? についての知見を得ることができる点もAWS CLI 専門支部の特徴です(だと勝手に思ってます)。

自分で手順書を作成する際にも参考にさせていただきたい部分です。

# IAMポリシーのARNを取得
ARRAY_IAM_POLICY_ARNS=$(
  echo $( \
    for i in $(echo "${ARRAY_IAM_POLICY_NAMES}");do
      aws iam list-policies \
        --max-items 1000 \
        --query "Policies[?PolicyName==\`${i}\`].Arn" \
        --output text
    done \
  ) \
) \
  && echo "${ARRAY_IAM_POLICY_ARNS}"

上記コマンドでは、変数 ARRAY_IAM_POLICY_NAMES に’CloudFrontFullAccess AmazonS3FullAccess’ がセットされている状態です。

配列をループさせて、複数のIAMポリシーのARN を取得しています。

# IAMポリシーをIAMロールにアタッチ
for i in $(echo "${ARRAY_IAM_POLICY_ARNS}");do
  aws iam attach-role-policy \
    --role-name ${IAM_ROLE_NAME} \
    --policy-arn ${i}
done

上記コマンドでは、上で取得したIAMポリシーのARN (2つ)をループさせて、IAMロールへのアタッチを行っています。

ちなみに、片付けの際に使用する iam detach-role-policy コマンドでも同様の手法が利用されていました。

AWS アカウントID を取得する

# AWS_ID を取得
AWS_ID=$( \
  aws sts get-caller-identity \
    --query 'Account' \
    --output text \
) \
  && echo ${AWS_ID}

こちら基本かもしれないですが、、利用頻度が高そうなのでピックアップです。

自身のAWS アカウントID を取得して、S3バケットの重複回避に利用しています。

静的Webサイトホスティングを設定する

# 静的Webサイトホスティングの設定
aws s3 website "s3://${S3_BUCKET_NAME}" \
  --index-document ${S3_DOC_INDEX} \
  --error-document ${S3_DOC_ERROR}

こちらは利用頻度はそこまで高くない?かもしれませんが、こんなシンプルなコマンドで静的Webサイトホスティングの設定できるんだな、と感じたのでピックアップ。

静的Webサイトホスティング設定を確認する

# 静的Webサイトホスティングの設定を確認
aws s3api get-bucket-website \
  --bucket ${S3_BUCKET_NAME} \
  --query "length(@)"

こちらのコマンドでは、 –query “length(@)” というオプション指定について触れておきます。

length を使用することで要素のカウントの取得が可能なので、今回のような存在確認手順などで利用できるかと思います。

なお、上記コマンドの結果、「2」という出力結果が得られればOKという確認方法で利用されていました。

ちなみに、query オプションを指定しない場合は、次のような実行結果となります。

$ aws s3api get-bucket-website \
> –bucket ${S3_BUCKET_NAME}
{
“IndexDocument”: {
“Suffix”: “index.html”
},
“ErrorDocument”: {
“Key”: “error.html”
}
}

S3バケットとファイルの同期をとる

# S3バケットとファイルの同期
dir_current=$(pwd)
cd ${DIR_S3_SYNC} \
  && aws s3 sync . "s3://${S3_BUCKET_NAME}/" \
    --exclude "${S3_SYNC_EXCLUDE}" \
    --acl ${S3_SYNC_ACL} \
  && cd ${dir_current}

カレントディレクトリのファイルを、指定したS3バケットに同期するコマンドで、下記オプションとともに利用します。

–exclude オプションで同期対象外とするファイルを指定
–acl オプションでアクセスコントロールリストの指定

CloudFrontディストリビューションを作成する

# CloudFrontディストリビューションの作成
aws cloudfront create-distribution \
  --origin-domain-name "${CLOUDFRONT_ORIGIN_DOMAIN_NAME}" \
  --default-root-object ${CLOUDFRONT_DISTRIBUTION_DEFAULT_ROOT_OBJECT} \
  > ${FILE_CLOUDFRONT_DISTRIBUTION_OUTPUT}

ディストリビューションの作成コマンドも、意外とシンプルだと感じました。

AWS CLI コマンドで環境構築を行うと、一つ一つの操作(API 実行)の粒度が小さくなり、理解しやすくなるのでホント面白いなと思います。

タグ設定文字列を生成する

# タグ設定文字列の生成
STRING_CLOUDFRONT_TAGS="Items=[{Key=${CLOUDFRONT_TAG_KEY},Value=${CLOUDFRONT_TAG_VALUE}}]" \
&& echo ${STRING_CLOUDFRONT_TAGS}

めちゃくちゃ細かい話になりますが、タグ生成時に利用する「文字列の作成」についてです。

後述のタグ生成時に利用します。

ちなみに実行結果(作成される文字列)は以下の通り。Value 値は今回のハンズオン用なので参考までに。

Items=[{Key=Name,Value=handson-cli-cloudfront-distribution}]

タグを生成する

# タグの生成(付与)
aws cloudfront tag-resource \
  --resource ${CLOUDFRONT_TAG_RESOURCE} \
  --tags "${STRING_CLOUDFRONT_TAGS}"

こちらは「タグ情報の付与」を行うコマンドです。

何気にAWS CLI でタグを付与したことがなかったので、、いい気付きとなりました。

ちなみに、タグを外す際は cloudfront untag-resource コマンドを利用するようです。

また、EC2 インスタンスへのタグ付与については、 ec2 create-tags コマンドを利用するようです。

CloudFrontディストリビューションの存在を確認する

# CloudFrontディストリビューションの存在確認
for i in $( 
  aws cloudfront list-distributions \
    --query "DistributionList.Items[].ARN" \
    --output text \
); do
  j=$( \
    aws cloudfront list-tags-for-resource \
      --resource ${i} \
      --query "Tags.Items[?Key == \`Name\` && Value == \`${CLOUDFRONT_DISTRIBUTION_TAG_NAME}\`].Value" \
      --output text \
  )
  if [ "${j}x" != 'x' ]; then echo "${j}"; fi
done

はじめにディストリビューションのARN一覧を取得して、

Name タグの情報が任意の文字列と一致するものを抽出して(Name タグのValue 値を)出力しています。

このチェック方法については以下のように”課題” が掲載されており、「もっとシンプルにできないものか」という思いを感じましたが(ただの私の妄想です)

私としては「こんな確認方法もあるんだな」と良い学びになりました。

課題
list-distributionsコマンドがタグ表示できないため、全てのディストリビューションに対してlist-tags-for-resourceコマンドでタグの有無をチェックするしか方法がない。(サポートには未確認)

ディストリビューションの情報を取得する

# ディストリビューションのステータスを取得
CLOUDFRONT_DISTRIBUTION_STATUS=$(
  aws cloudfront get-distribution \
    --id ${CLOUDFRONT_DISTRIBUTION_ID} \
    --query 'Distribution.Status' \
    --output text \
) \
  && echo ${CLOUDFRONT_DISTRIBUTION_STATUS}

ディストリビューションの各種情報の取得には、 cloudfront get-distribution コマンドを利用します。

ディストリビューションID とともに get-distribution コマンドを利用することで取得が可能です。

他にも、ドメイン名を取得しているコマンドもあったので転記しておきます。

# ディストリビューションのドメイン名を取得
CLOUDFRONT_DOMAIN_NAME=$(
  aws cloudfront get-distribution \
    --id ${CLOUDFRONT_DISTRIBUTION_ID} \
    --query 'Distribution.DomainName' \
    --output text \
) \
  && echo ${CLOUDFRONT_DOMAIN_NAME}

(query オプションの指定内容が違うだけ)

ファイルのタイムスタンプを比較する

こちら、AWS とは関係なくなってしまうのですが笑、学びになったので。

今回取り扱ったコンテンツ(ファイル)の更新前後の確認に利用しているコマンドなのですが、このあたり不慣れな私としては学びがありました。

# ファイルのタイムスタンプを取得(before/ after)
UNIXTIME_BEFORE=$( \
  date -r ${FILE_LOCAL} +%s \
) \
  && echo ${UNIXTIME_BEFORE}

UNIXTIME_AFTER=$( \
  date -r ${FILE_LOCAL} +%s \
) \
  && echo ${UNIXTIME_AFTER}

ファイルの編集前後でタイムスタンプを取得して、

# ファイルのタイムスタンプを比較
OFFSET_UNIXTIME=$( \
  expr ${UNIXTIME_AFTER} - ${UNIXTIME_BEFORE} \
) \
  && echo ${OFFSET_UNIXTIME}

2つのタイムスタンプを比較する。以上です笑。

キャッシュの無効化を作成する

# キャッシュの無効化を作成
aws cloudfront create-invalidation \
  --distribution-id ${CLOUDFRONT_DISTRIBUTION_ID} \
  --paths ${CLOUDFRONT_PATHS}

CloudFront でキャッシュの無効化を行う際には、cloudfront create-invalidation を利用します。

その後 cloudfront list-invalidations コマンドを利用してステータスを取得することもできますが、

キャッシュの無効化が作成されるとすぐに適用が実行されるので、数秒ほどで「InProgress → Completed」となります。

# CloudFrontキャッシュ無効化エントリのステータスを確認
CLOUDFRONT_INVALIDATION_STATUS=$( \
  aws cloudfront list-invalidations \
    --distribution-id ${CLOUDFRONT_DISTRIBUTION_ID} \
    --query "InvalidationList.Items[?Id ==\`${CLOUDFRONT_INVALIDATION_ID}\`].Status" \
    --output text \
) \
  && echo ${CLOUDFRONT_INVALIDATION_STATUS}

上記はキャッシュ無効化のID を指定してステータスを取得するコマンドです。

CloudFront ディストリビューションを無効化&削除する

CloudFront ディストリビューションを削除するためには、事前に「無効化」してから「削除」する 必要があります。

また、AWS CLI を利用して更新を行う際は、ETag と呼ばれる一意の(定期的に置き換わる)ID を取得&利用する必要があります。

後片付けの手順でも、このように学びがたくさん。。あざます。

# ETAGの取得
CLOUDFRONT_ETAG=$(
  aws cloudfront get-distribution \
    --id ${CLOUDFRONT_DISTRIBUTION_ID} \
    --query 'ETag' \
    --output text \
) \
  && echo ${CLOUDFRONT_ETAG}

まずは cloudfront get-distribution コマンドを利用してETag を取得します。

# ディストリビューションの無効化
aws cloudfront update-distribution \
  --id ${CLOUDFRONT_DISTRIBUTION_ID} \
   --distribution-config file://${FILE_CLOUDFRONT_DISTRIBUTION_CONFIG_DOC} \
   --if-match ${CLOUDFRONT_ETAG}

上で取得したETag と、事前に作成した設定ファイルを利用してディストリビューションの更新(無効化)を行います。
(設定ファイルの内容は割愛)

# ディストリビューションの削除
aws cloudfront delete-distribution \
  --id ${CLOUDFRONT_DISTRIBUTION_ID} \
  --if-match ${CLOUDFRONT_ETAG}

無効化したディストリビューションについて、削除を行います。

(余談)

特に大きくハマることはなかったのですが、一点だけ(私の環境では)スムーズに行かない部分があったので共有です。

※私の構築した環境のみの問題かもしれませんが、一応共有させていただきます。

「事前作業0. インスタンスプロファイルのIAMロールへのIAMポリシーのアタッチ」手順において、変数 IAM_INSTANCE_PROFILE_NAME に格納する文字列が手順書の通りだとIAMロール名の取得がうまくいきませんでした。

私の環境では、変数に下記文字列をセットすることにより、iam get-instance-profile コマンドでのIAMロール名取得が可能となりました。

IAM_INSTANCE_PROFILE_NAME=”handson-cloud9-environment-role”

なお、特に指定を行っているわけではないのでIAMロール名とインスタンスプロファイル名は同じ(handson-cloud9-environment-role)となっている状態です。

まとめ

気になった部分をピックアップしていったら、ほとんどが気になる部分でした。笑

CloudFront を利用したことはあったものの、AWS CLI を利用して操作したことがなかったのでいい経験になり良かったです。

AWS CLI でリソースを操作すると、「画面ポチポチやってたらなんかできた(残るのは曖昧な記憶のみ)」 から卒業できるので本当にオススメです。

”とにかく触ってみる” だけであればコンソール画面での操作も個人的には全然アリだと思ってますが、

情報共有や再現性の面を考えると圧倒的にAWS CLI が有利ですよね。(引き続き勉強がんばります)

以上です。最後まで読んでいただきありがとうございました。