はじめに

Webサーバー上で稼働するアプリは、ソースの管理にはCodeCommitが、自動デプロイとしてはCodePipeline + CodeDeploy + CodeCommit(ビルドが必要な場合は + CodeBuild)などの構成が使われますが、CodeCommitではサイズの大きなファイルを管理することは適していません。
そのようなサイズの大きなのファイルをデプロイする方法として、ファイルをS3上に配置し、aws-cliを使用して取得及び配置するシェルを考えてみました。

前提条件

・対象のEC2のIAMロールに対象のS3へのGETとLISTの権限が付与されていること。
・EC2にaws-cliのVersion2がインストールされていること(version 2.15.24にて確認)。
・今回のサンプルではS3バケット:sapmle-bucketを用意し、その配下にそれぞれ以下のようなディレクトリとファイルが配置されていることとします。

[sapmle-bucket]バケット
  - [testDir]ディレクトリ
    - [test1.txt]ファイル
    - [test2.txt]ファイル
    - [test3.txt]ファイル

・EC2とS3は同一リージョンに存在するものとして説明します。
・EC2内でのユーザーはtest_userとします。
・シェルについてはBASHでの記載方法になります。

シェルでの処理内容

  1. S3から取得したファイルを配置するディレクトリへ移動する
  2. aws-cliを使用してS3の特定のバケット及びフォルダ内のファイル一覧からファイル名を取得する
  3. aws-cliを使用してS3からファイルを取得する

手順1. S3から取得したファイルを配置するディレクトリへ移動する

まずは以下のコマンドでディレクトリを移動します。
ディレクトリに関してはシェルを実行するユーザーが権限を保持していれば好きな場所で問題ありません。(今回は/home/test_user/配下とします)

cd /home/test_user

手順2. aws-cliを使用してS3の特定のバケット及びフォルダ内のファイル一覧からファイル名を取得する

aws-cliを使用してS3のバケットやオブジェクトの一覧表示を取得するには以下の構文を使用します。

$ aws s3 ls {target} [--options]

{target}には「s3://」に続いてバケット名やディレクトリを「/」区切りで指定します。
今回の場合は「s3://sample-bucket/testDir/」となります。
[–options]にはバケットが配置されているリージョンを指定する「–region」や、クレデンシャルを指定する「–profile」などがありますが、今回は特に指定しません。
オプションの詳細はAWS公式のドキュメントにまとまっています。
コマンドを実行してみると以下のような結果になります。

$ aws s3 ls s3://sample-bucket/testDir/
2024-03-20 00:00:10 0
2024-03-20 00:00:27 6 test1.txt
2024-03-20 00:00:55 6 test2.txt
2024-03-20 00:00:43 6 test3.txt

上記はファイルまたはディレクトリの「作成日 作成時間 サイズ ファイル名」となっており、サイズが0の要素がディレクトリ(testDir)になります。
後続の手順3にてS3からファイルを取得する際にファイル名が必要になるのですが、現状だとファイル名以外の不要な情報が含まれており、ディレクトリ内にある複数のファイル名(ディレクトリ名)が取得されてしますので、awkコマンドにてファイル名だけを抽出し、headコマンドでファイル名を1つに絞ります。

$ aws s3 ls s3://sample-bucket/testDir/ | awk '{print $4}' | head -n 1
 

上記のコマンドの結果だと、aws-cliのS3のlsコマンドの結果の先頭にあるディレクトリ名(空文字)となってしまいます。
そのため、sortコマンドにてファイルの作成日時やファイル名で降順ソートすることで対応します。
ファイルの作成日時で降順ソートする場合

$ aws s3 ls s3://sample-bucket/testDir/ | sort -r | awk '{print $4}' | head -n 1
test2.txt

ファイル名で降順ソートする場合

$ aws s3 ls s3://sample-bucket/testDir/ | awk '{print $4}' | sort -r | head -n 1
test3.txt

手順3. aws-cliを使用してS3からファイルを取得する

aws-cliを使用してS3のバケットやオブジェクトからファイルを取得する場合は以下の構文を使用します。

aws s3 cp {target} [--options] {target-dir}

{target}には「s3://」に続いてバケット名やディレクトリ、ファイル名を「/」区切りで指定します。
[–options]にはlsと同じようにいくつかのオプションが用意されています。
オプションの詳細はAWS公式のドキュメントにまとまっています。
{target-dir}はS3から取得したファイルを配置するEC2上のディレクトリのパスを指定します。
今回は現在のディレクトリ配下とする「./」を指定します。
コマンドとしては以下のような形になります。

aws s3 cp s3://sample-bucket/testDir/「手順2で取得したファイル名」 ./

手順を組み合わせてシェルファイルを作る

上記の手順を踏まえて、「S3の指定されたディレクトリにある最新のファイルを1つ取得する」シェルを作成してみます。
今回のシェルファイルは「/home/test_user/get_latest_file_from_s3.sh」とします。

#!/bin/bash

# S3から取得したファイルを配置するディレクトリへ移動する
cd /home/test_user

# aws-cliを使用してS3の特定のバケット及びフォルダ内のファイル一覧からファイル名を取得する(ファイルの作成日時降順)
TARGET_FILE=`aws s3 ls s3://sample-bucket/testDir/ | sort -r | awk '{print $4}' | head -n 1`

# aws-cliを使用してS3からファイルを取得する
aws s3 cp s3://sample-bucket/testDir/${TARGET_FILE} ./

上記のシェルでは最新ファイルの取得までしか行っていませんが、さらにコマンドを追加することでダウンロードしたファイルを開いたり起動したりなども自動化することができます。

最後に

シェルファイルの準備ができたら、シェルファイルに実行権限を付与して直接実行する、EC2の起動時に実行されるようにユーザーデータに登録する、systemdに登録して自動起動するなど色々とできます。
aws-cliのS3には他にもバケットを作成するためのmbコマンドや、オブジェクトを削除するためのrmコマンド等、色々なコマンドが用意されています。
今回は使用していないコマンドについても使い方は難しくないのでAWS更新ページ「AWS CLI で高レベル (S3) コマンドを使用する」を参考にしてください。