AstroをGitHub ActionsでAWS に自動デプロイしてみた
この記事は「株式会社メンバーズ Jamstack研究会主催 Advent Calendar
2023」の19日目の記事です。
はじめに
最近、話題の静的サイトジェネレーター「Astro」で個人ブログを作り、GitHub上でコード管理し、Amazon S3 + CloudFrontへGitHub Actionsで自動デプロイできるようにするまでの手順をまとめました。
前提条件
この記事では、GitHubアカウントやリポジトリ、AWSアカウントは作成済みである前提で手順をご紹介します。
また今回は、取得したドメインで公開されたページにアクセスする方法などは割愛させていただきます(AWSドキュメントのこちらをご参照ください)。
実行環境
今回は以下のツールおよびバージョンがインストールされた環境で実行しています。
Node.js v18.19.0
Astroをインストールする
Astro Docs > Astroを自動CLIでインストール の手順に沿って、ローカル環境にAstroプロジェクトを作成します。
自動CLIを使ったインストールの場合、コマンドライン上で「どこにプロジェクトのディレクトリ作る?」や「TypeScript使う?」などと英語で尋ねてくれるので、それに回答しながらインストール作業を進めます。
その中で「新しいGitリポジトリにする?」と尋ねられますが、今回はGitHubでコード管理したいので「Yes」と回答します。
# npmでAstroプロジェクトを作成
npm create astro@latest
~~~
╭─────╮ Houston:
│ ◠ ◡ ◠ Good luck out there, astronaut! 🚀
╰─────╯
インストールが完了すると、私のことを"astronaut"(宇宙飛行士)と呼んでくれます🧑🏻🚀(左のHoustonの笑顔がかわいい)
ひとまず、ローカル環境にAstroプロジェクトができたので、configファイルを編集したり、見た目を整えたり、記事を書いたりしてみてください。
AWSリソースを作成する
続いて、作ったAstro製ブログを公開するためのデプロイ先であるAmazon S3とCloudFrontのリソースを作成します。また、GitHub ActionsからS3バケットにアップロードする際に必要なAWSの認証情報(IAMユーザー)も作成していきます。
では、Astro Docs > Deploy your Astro Site to AWS に記載の手順を参考に、AWSマネジメントコンソールから各種リソースを作成していきます。
※リソース作成に必要な設定の選択項目などの解説は、今回は省略させていただきます。詳しく知りたい方は、ぜひAWS公式ドキュメントなどをご参照ください。
1. S3バケットを作成する
まずはビルドしてできたファイルを置くバケットを作成します。
AWSマネジメントコンソール > S3ページ > 「バケットを作成」ページにて、以下のように設定(明記していない項目はデフォルトのままで結構です)してバケットを作成します。最後に画面下部の「バケットを作成」ボタンを押すとバケット作成が完了します。
一般的な設定
バケット名
任意の名前を入力(誰も使っていない名前である必要があります)。
2. CloudFrontディストリビューションを作成する
続いて、1.で作成したS3バケットをオリジンとするCloudFrontディストリビューションを作成します。また、今回はディストリビューション作成時にOAC(Origin Access Control)を作成し、OACを利用してS3バケットへのアクセスをここで作成するCloudFrontディストリビューションからのみ受け付けるよう制限を設けたいと思います。
2-1. ディストリビューションを作成する
AWSマネジメントコンソール > CloudFrontページ > 「ディストリビューションを作成」ページにて、以下のように設定してディストリビューションを作成します。最後に画面下部の「ディストリビューションを作成」ボタンを押すとディストリビューション作成が完了します。
オリジン
オリジンドメイン
1.で作成したS3バケットを選択。
オリジンアクセス
「Origin access control settings (recommended)」を選択するとすぐ下に「Origin access control」項目が表示されるので「コントロール設定を作成」ボタンを押し、「Create control setting」にて新しいOACを作成します。
デフォルトのキャッシュビヘイビア
ビューワープロトコルポリシー
今回は「Redirect HTTP to HTTPS」を選択。
ウェブアプリケーションファイアウォール(WAF)
今回は「セキュリティ保護を有効にしないでください」を選択。
設定
デフォルトルートオブジェクト
「index.html」と入力。
2-2. バケットポリシーを更新する
ディストリビューションの作成が完了すると、自動的に作成したディストリビューションページに遷移し、画面上部に下図のような、バケットポリシーの更新をお知らせしてくれるアラートが出ます。このアラートに従わないと作成したディストリビューションからオリジンであるS3バケットにアクセスができないので、忘れずに対応しましょう!(丁寧にアラートを出してくれて非常にありがたいです!)
ではアラートに従って、まずは「ポリシーをコピー」します。すると以下のようなJSON形式のテキストがコピーされています。
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::${バケット名}/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::${AWSアカウントID}:distribution/${OAC ID}"
}
}
}
]
}
続いて「S3バケットの権限に移動してポリシーを更新する」リンクをクリックします。すると、別タブで1.で作成したS3バケットのアクセス許可タブが開かれるので「バケットポリシー」の「編集」ボタンを押して「バケットポリシーを編集」ページで、エディタ部分に先程コピーしたポリシーをペーストして保存します(下図をご参照ください)
これでCloudFrontディストリビューションからS3バケットにアクセスできるようになりました。では、念の為アクセスできるか確認してみましょう!
2-3. CloudFrontからS3へアクセスできるか確認する
作成したバケットにHTMLファイルをアップロードします。
今回は、アップロードするファイル名を「index.html」として適当なHTMLファイルを用意してアップロードします。ディストリビューションドメインをブラウザで開きます。
ディストリビューションドメイン名は、AWSマネジメントコンソール > CloudFrontページ > 作成したディストリビューションページを開き、一般タブ内に記載されています。ディストリビューションドメイン名をコピーし、ブラウザで開き、アップロードしたHTMLファイルの内容が表示されたら確認OKです。
もし確認できない場合(Access Deniedなどの表示が出るなど)は、バケットポリシーの更新が保存されていない可能性があるので、バケットポリシーが正しく設定されているか確認してみてください。
また、コピペすべきバケットポリシーを忘れた場合は、上記2-2.のJSONをお使いください(バケット名やアカウントIDやOAC IDは各自置き換えてください)。
ちなみに今回はディストリビューション作成時に、ビューワープロトコルポリシーで「Redirect HTTP to HTTPS」を選択したので、http://で開くと自動でhttps://にリダイレクトされます。
3. IAMユーザーを作成する
最後に作成するAWSリソースとして、IAMユーザーを作成します。
これは、GitHub Actionsでビルドして生成された静的ファイルたちをS3バケットにアップロードする際の認証として必要となります。
また、ここで作成するIAMユーザーは、S3にファイルをアップロードしたり、CloudFrontディストリビューションのキャッシュを削除するためのものなので必要最低限な権限を持たせるようにポリシーを作成します。
3-1. IAMポリシーを作成する
まずは、IAMユーザーにアタッチするポリシーを作成しておきます。
AWSマネジメントコンソール > IAMページ 左サイドバーから「ポリシー」をクリックし「ポリシーの作成」ボタンを押します。
ポリシーエディタに、以下のJSONをペーストし、ポリシー名を入力してポリシーを作成してください。
ペーストの際、DISTRIBUTION_ARNとBUCKET_NAMEはそれぞれ置き換えてください。 DISTRIBUTION_ARNは、AWSマネジメントコンソール > CloudFrontページ > ディストリビューション > 一般タブ 「ARN」に記載されています。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:ListBucket",
"s3:DeleteObject",
"cloudfront:CreateInvalidation"
],
"Resource": [
"<DISTRIBUTION_ARN>",
"arn:aws:s3:::<BUCKET_NAME>/*",
"arn:aws:s3:::<BUCKET_NAME>"
]
}
]
}
3-2. IAMユーザーを作成する
続いて、AWSマネジメントコンソール > IAMページ 左サイドバーから「ユーザー」をクリックし「ユーザーの作成」ボタンを押し、以下のように設定してIAMユーザーを作成します。
ユーザーの詳細を指定
ユーザー名
任意の名前を入力。
AWSマネジメントコンソールへのユーザーアクセスを提供する
チェックを外したままで構いません。
許可を設定
許可のオプション
「ポリシーを直接アタッチする」を選択。
許可ポリシー
3-1.で作成したIAMポリシー名を選択。
3-3. アクセスキーを作成する
最後に、作成したIAMユーザーのアクセスキーを作成します。このアクセスキーと同時に作成されるシークレットアクセスキーを用いて、GitHub ActionsからAWSへの認証を行います。
3-2.で作成したユーザーページを開き、概要の「アクセスキーを作成」をクリックし、以下のように設定し、アクセスキーを作成します。アクセスキーの作成が完了すると、アクセスキーとシークレットアクセスキーが画面上に表示されますが、シークレットアクセスキーはこの画面を離れると再度表示されることはありません。忘れずにコピー または CSVファイルをダウンロードしておきましょう。
ユースケース
いずれかを選択し「上記のレコメンデーションを理解し、アクセスキーを作成します。」と表示された場合は、文言左側にチェックを入れます。
GitHub Actionsのワークフローを記述する
続いて、作ったAstro製ブログをGitHub Actionsでビルド/デプロイし、生成された静的ファイルをS3バケットにアップロード→CloudFrontのキャッシュ削除を行うワークフローを作成していきます。
では、Astro Docs > Deploy your Astro Site to AWS > Continuous deployment with GitHub Actions に記載の手順を参考に、ワークフローを作成します。
workflowのyamlを記述する
まずは、ローカル環境のAstroプロジェクトディレクトリ内に、GitHub Actionsのワークフローを定義するファイルを作ります。以下のコードを実行するとAstroプロジェクトディレクトリの直下に、.github/workflows/deploy.ymlファイルが作成されます。
# Astroプロジェクトのディレクトリに移動して、下記を実行してください。
# フォルダを作成
mkdir -p .github/workflows
# 定義ファイルを作成
touch .github/workflows/deploy.yml
ファイルが作成されたら、エディタ等でdeploy.ymlを開き、以下のYAMLテキストをペーストします。このYAMLは、前述のAstro Docsから拝借したものです。このワークフローでは、mainブランチへのpushをトリガーに、ジョブが実行され、そのジョブ内でAWSの認証情報を設定し、npmモジュールがインストールされ、ビルド、S3バケットへのアップロード、CloudFrontのキャッシュ削除が行われます。
name: Deploy Website
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Install modules
run: npm ci
- name: Build application
run: npm run build
- name: Deploy to S3
run: aws s3 sync --delete ./dist/ s3://${{ secrets.BUCKET_ID }}
- name: Create CloudFront invalidation
run: aws cloudfront create-invalidation --distribution-id ${{ secrets.DISTRIBUTION_ID }} --paths "/*"
そして、お気づきの方もいらっしゃるかと思いますが、この定義の中に${{ secrets.xxx }}という変数が登場します。これは、GitHub Actionsで利用できるリポジトリ専用の環境変数を指しています(詳しくは、GitHub Docs > GitHub Actions でのシークレットの使用 をご覧ください)
では、この変数を使えるようにGitHubのシークレットを作成しましょう。
secretsにAWS認証情報を格納する
GitHubリポジトリを開き、Settingsタブ > 左サイドバーから「Secrets and variables」 > 「Actions」をクリックします。
「Actions secrets and variables」ページの「Secrets」タブを開き、「New repository secret」ボタンを押して、シークレット(変数)作成画面に遷移します。
以下のように入力し「Add secret」を押してシークレットを保存します。
今回deploy.yml内で記述したシークレットは下記の4つですので、それぞれ作成します。
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
BUCKET_ID
DISTRIBUTION_ID
mainブランチにpushする
では最後に、リモートのmainブランチにpushしてみましょう!
git add .
git commit -m "first commit."
git push origin main
無事pushが成功したら、GitHubリポジトリ > Actionsタブを開きます。
すると早速ワークフローが実行されます(下図)。
今回実行中のワークフローの進捗をリアルタイムで見ることができるので、見守っていると特にエラーなければ無事にワークフローが完了します(下図)
では、いよいよ先程のCloudFrontのURLを開いてみます。
すると無事ページが更新されていることが確認できました!(今回はAstroプロジェクト立ち上げ時に、ブログテンプレートを使うようにしたので下図のようなページが表示されています)
さいごに
今回は、Astroを自動ビルド/デプロイする方法をご紹介しました。
Astroは公式ドキュメントも非常に充実しており、VercelやHerokuやCloudflare Pagesなどへのデプロイ手順がまとめられていたり、microCMSやContentfulやWordPressなどのCMSを利用したコンテンツ管理方法も紹介してくれています。
まだまだたくさん試してみたいことがあり、今後もAstroから目が離せません。
また機会があれば他ホスティングサービスへのデプロイやCMSを使った運用を記事にできればと思います。
最後までご覧いただきありがとうございました!この記事がどなたかのお力になれれば幸いです。