画像等のリソースを別サーバに配置
2024年12月5日

画像等のリソースを別サーバに配置

4,556文字(読了まで約12分)

このブログのWebサーバはCloudflare Pagesにデプロイしています。 裏で動いているworkerはCDNエッジで動く処理らしく、あまり負荷をかけられないという特性があります。 ブログに掲載する画像なども増えていっていますので、余計な負担をかけないよう、画像等の静的なリソースについては、別環境(AWS S3)から取得するように構成してみます。

※後々調べると、1ファイル25MBまで・20000ファイルまでと上限も結構余裕があり、かつ画像などは自動的にCDNにキャッシュしてくれるらしいので必要なかったかも。  まあお勉強として・・。

現状、このブログのソースコードはgithub上で管理しており、mainブランチへのプッシュを受けて、自動的にCloudflare Pages側でのCI/CDが走るように構成しています。

graph LR DEV[開発マシン] GITHUB[githubレポジトリ] CP[Cloudflare Pages] DEV--push-->GITHUB GITHUB--トリガ-->CP CP--ビルド・デプロイ-->CP

現状では、画像ファイルも含めて、すべてのリソースをCloudflarePagesに送っていますが、今回、画像等のみをS3に送るようにしたいと思います。

graph LR DEV[開発マシン] GH[GitHubレポジトリ] CP[Cloudflare Pages] S3[AWS S3] GHA[Github Actions] DEV--push-->GH GH--トリガ-->CP GH--トリガ-->GHA GHA--デプロイ-->S3 CP--ビルド・デプロイ-->CP

今回は、Github Actionsを利用して、mainブランチの更新をトリガに、AWSCLIでS3へ画像等をデプロイするようにしてみます。

なお、ローカルマシン上での開発サーバとしては、画像等を含めた状態で動作させるものとし、ビルド・デプロイ時のみ、このとおりの取扱とします。

また、Github Actions側からAWSを操作しますので、その際の認証情報を安全に保つ方法もあわせて取り入れたいと思います。

(Cloudflare Pagesのように、AWS側でgithubの変更を検知してデプロイ・・・みたいな方法もあるのかもしれませんが、そこまで調べてません。)

  • 考え方
    • ✕ AWSのアクセスキーを発行して利用する・・・永続的なキーとなるため、危険
    • ◯ github actionsが、AWSロールにassume roleして利用する・・・一時的なキーで利用できるためより安全

まさに、↓のとおりです。

【GitHub Actions】IAMロールを利用したAWSへのアクセス - サーバーワークスエンジニアブログ

【GitHub Actions】IAMロールを利用したAWSへのアクセス - サーバーワークスエンジニアブログ

サーバーワークスエンジニアブログ
https://blog.serverworks.co.jp/github-actions-iam-role
  • AWSでの設定

    • AWSでgithub actionsを、外部IDとして見なすため、IDプロバイダを設定する
    • github actionsがassume roleするためのroleを用意する
      • 先述の外部IDを信頼する設定とする
      • IAMポリシーとしては、S3を操作する権限を設定する
  • githubでの設定

    • 画像ファイル等の配置ディレクトリの更新をトリガとする

    • AWSへのassume roleのうえ、aws-cliでS3バケットに画像フォルダを同期させる

    • 具体的なgithub actions の設定は以下

      .github/workflows/main.yml
      name: Deploy blog static resources to S3 bucket
       
      # push or pull_request on img
      on:
        push:
          branches:
            - main
          paths:
            - 'public/static/img/**'
        pull_request:
          branches:
            - main
          paths:
            - 'public/static/img/**'
       
      env:
        AWS_REGION: ap-northeast-1
        AWS_ROLE_ARN: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions-honox-techblog 
       
      jobs:
        deploy:
          name: Deploy
          runs-on: ubuntu-latest
          environment: production
          # These permissions are needed to interact with GitHub's OIDC Token endpoint.
          permissions:
            id-token: write
            contents: read
          steps:
          - name: Checkout
            uses: actions/checkout@v4
                
          - name: Configure AWS credentials from IAM Role
            uses: aws-actions/configure-aws-credentials@v4
            with:
              role-to-assume: ${{ env.AWS_ROLE_ARN }}
              aws-region: ${{ env.AWS_REGION }}
       
          - name: Sync files with S3 Bucket
            env: 
              S3_UPLOAD_BUCKET: ${{ secrets.S3_UPLOAD_BUCKET }}
            run: |
              aws s3 sync ./public/static/img s3://$S3_UPLOAD_BUCKET/public/static/img --delete --quiet

  • 記事作成時点では、Cloudflareがgithubからコードを取得する設定として、ディレクトリを除外する機能がないと見られる
  • いったんgithubから画像を取得してしまうことは妥協し、ビルドプロセスで画像フォルダを除去することとする
  • vite.config.tsで以下の通り設定する
vite.config.ts
export default defineConfig(({ mode, command }) => {
	if (mode === "client") {
      ・・・略・・・
	}
	return {
		build: {
			emptyOutDir: false,
			rollupOptions: {
				input: path.resolve(__dirname, "./app/server.ts"),
        ・・・略・・・
			},
		},
		plugins: [
			{
				name: "exclude-public-folders",
				apply: "build", // build時のみ。開発サーバには適用されない
				closeBundle() {
					const distPath = path.resolve(__dirname, "dist");
					const excludeDir = path.resolve(distPath, "static/img"); // 除外するフォルダ
					if (fs.existsSync(excludeDir)) {
						fs.rmSync(excludeDir, { recursive: true, force: true }); // フォルダを削除
						console.log(`Excluded folder: ${excludeDir}`);
					}
				},
			},
      ・・・略・・・
		],
	};
});

あとは当然ですが、画像ファイルのsrcとして、S3バケットのURLを指すようにソースコードの修正を行います。

画像のURLを取得するユーティリティ関数を作っているため、この部分で利用する環境変数の値を差し替えることで対応しました。 (開発環境ではlocalhostとして設定)

/**
 * 画像のsource URLを構成する
 * @param filename
 * @returns
 */
export function imgSrcUrl(filename: string) {
	if (!c) c = useRequestContextTyped();
	return c.env.RESOURCE_SERVER + c.env.IMGSRC_BASEPATH + filename;
}

画像ファイルについては、S3から取得されていることがわかります。 結果

  • 画像ファイルについて、Cloudflare Pagesとは別のサーバ(S3)に配置できるように、デプロイの流れを制御しました
  • リポジトリへのプッシュで、Cloudflare Pages・S3へのデプロイを自動で行えるようにしました

以上です。

- コメント -

  1. aa [ 2024年12月14日 16:42 ]
    bb
  2. aa [ 2024年12月14日 16:43 ]
    bb
  3. aa [ 2024年12月14日 16:43 ]
    bb

このサイトではcookieを利用して、サイト訪問者の識別に利用します。 cookieの利用に同意いただくことで、サイト訪問者は記事のいいね機能等をご利用いただけます。 なお、サイト運営者はアクセス統計としてcookieの情報を利用する場合があります。