目次
はじめに
なぜAWS CLIを学んだか?
日次処理システムを組む業務でAWS S3から自動でデータ連携させる必要があり学びました。
S3操作自体はマネージメントコンソールからもできますが、システムに組み込む場合はスクリプトに落とし込む必要があったので、CLIを使って操作しました。
なぜシステムに組み込むのにCLIが必要なのか?
システムに組み込む(今回は自動化として言及します)、自動化を行うための操作は明瞭な手順として定義される必要があります。手順が明確に定義されていなければ、毎回違った操作が行われ、期待した結果を得ることが難しくなります。
この手順の明確化というのが、つまるところスクリプトの記述ということです。そしてスクリプトでS3の操作を記述できるツールがAWS CLIです。
注意点
ちなみに、手順の明確化 = スクリプトの記述、みたいな言及をしましたが、あくまで今回の案件においてです。
別の手段としては、アプリケーションに備わっているバッチ実行システムを使用して自動化を実現することもできます。AWS S3だとS3バッチオペレーションというサービスがあるみたいです。気になる方は調べてみてください(cf. Amazon S3 バッチオペレーション)
ナレッジとして記載すること
私が携わった案件の環境はWindowsOSのEC2(仮想サーバ)だったため、Windows PowerShellをスクリプトとして使用してAWS CLIを記述しました。AWS CLI自体はシェルスクリプトで記述することを基本としているっぽいです(cf. What is the AWS Command Line Interface?)。なのでWindowsであればコマンドプロンプトでも使用できますし、UNIX系のBashでも使用することができます。
しかし、AWS CLI自体の記述方法は共通なので、今回はAWS CLIの記述方法にフォーカスしてナレッジを記載します。 AWS S3の操作を自動化する必要があったり、大量のファイルを操作する必要がある方は参考になるかと思います(逆にそれ以外の操作においてはマネージメントコンソールで事足りる気がしてます)。
AWS CLI使用の準備
準備①:AWS CLIのダウンロード
1.下記リンクからダウンロードできます(画像赤枠部分)。
・AWS コマンドラインインターフェイス:https://aws.amazon.com/jp/cli/
2.ダウンロードしたファイル(Windows版なら.msi)を起動します。
3.起動したセットアップウィザードに沿って設定する。
基本的に難しいことはないと思いますが、1点注意点として、このあと環境変数PATHを通すのでexeファイルの保存場所だけ覚えておきましょう。 デフォルトだとC:\\Program Files\\Amazon\\AWSCLIV2\\
配下になると思います。
準備②:AWS CLIの環境変数PATHの設定
ターミナル(黒い画面)でコマンドを実行するために環境変数PATHを追加します。インストール設定によってはすでにPATHが追加されているかもしれませんが確認しておくのが吉です。
環境変数PATHが追加されていれば、ターミナル上でaws コマンドを実行できるはずです。試しに下記コマンドを実行してみましょう。
aws help
awsのPATHが通っていれば下記の画像の内容が返ってきます(対話モードになるのでCtrl + Cで解除します)。
🤔 aws helpでエラーが出る場合
考えられる大きな原因は2つあります。
- PATHがうまく通ってない
- インストールがうまくいっていない
上記2つの問題を切り分けるため、exeファイルのPATHを絶対参照で指定して起動してみます(参照のファイルパスは自分の設定したパスに置き換えてください)。
- コマンドプロンプト:
”C:\\Program FIles\\Amazon\\AWSCLIV2\\aws.exe” help
- Windows PowerShell:
.”C:\\Program FIles\\Amazon\\AWSCLIV2\\aws.exe” help
下記画像の様になっていたらPATHの設定がうまくいっていない可能性があるので、環境変数をもう一度確認してみましょう。
上記コマンドでもエラーが出る場合は、インストールがうまくいっていない可能性があります。再度インストーラからインストールを行いましょう。
前提①:AWS CLIの文法
AWS CLIコマンドの文法は下記の様になっています。
aws [オプション] <コマンド> <サブコマンド> [パラメータ]
[オプション]と[パラメータ]に関してはコマンドによってあったりなかったりします。
今回のS3の操作の文法は下記のとおりです。
aws <s3|s3api> <サブコマンド> [オプション] [引数]
コマンドとしてはs3かs3apiを使用しており、そのうえで各種操作に応じてサブコマンド、オプションを指定するようになっています。
前提②:用語説明
- S3:
Simple Strage Serviceの略。名前通りストレージを借りられるサービスです。 - バケット:
オブジェクトを保存するコンテナです。このコンテナの中にファイルなどのオブジェクトを入れて保管できます。 - プレフィックス:
英語の直訳だと接頭辞の意で、文字列の頭に付随する文字列を意味しますがS3においては別の意味を持ちます。仮想的に階層構造(ディレクトリ)を表現するファイルパスのようなものです。厳密には異なりますがローカル環境のディレクトリのイメージで大丈夫です。具体的には下記の様な文字列です。
test/nested/
- S3のファイル指定(URI):
AWS CLI上でファイル指定を行う場合下記のURIのルールに従って記述します。
s3://<バケット名>/<プレフィックス>/<ファイル名>
- S3内のデータ構造:
バケット内のデータはプレフィックスによって一見階層構造を持つように見えますが、厳密には異なります。キーバリューペアのようにキーに対してファイルが一意になる形で格納されているため、内部でのデータは階層によって分かれていないそうです。詳細は下記リンクを参照してください。
Amazon S3 とは:https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/Welcome.html
認証
AWS CLIはAWSサービスに対する操作をスクリプトを通して行えるサービスです。そのため、CLIの操作対象となるAWSサービスとつなげるためにアカウント認証が必要となります。
1.ターミナル上で下記を入力します。
aws configure
2.下記のようにアクセスキーとシークレットアクセスキーを問われるので画面の項目を入力していきます。
3.上記の情報を入力したら認証ファイルが作成されます。この情報間違っていなければ正常にAWSサービスにアクセスできるようになっているはず。
4.入力された情報はプロファイルとして(デフォルト設定なら)下記ディレクトリにcredentialsというファイル名で格納されています。
C:\\User\\<ユーザー名>\\.aws\\
🤔 開発用と本番用でアカウントを分けて運用したいときはどうするの?
開発時はフルコントロールのアカウントで開発し、本番時はアクセス制限を設けたいというケースがあります。その場合、どちらのアカウントもセットアップをする必要があるので、複数のアカウントを切り替える必要があります。 具体的なやり方は主に二つあります。
- スクリプトに環境変数として、実行時に使用するプロファイルを記述しておく
- コマンド実行時にconfigureコマンドでプロファイルを指定する
一つのシステムでプロファイルを切り替える必要があるケースは考えづらいので、基本的には1のやり方で対応します。2に関しては個人的にはかき捨てのスクリプトのときには便利なイメージです。
詳細については下記が参考になります。
参考にしたサイト:https://www.task-notes.com/entry/20141026/1414322858
AWS CLIの基本操作
基本操作:高レベルコマンド
高レベルコマンドの高レベルはレイヤーのイメージです。よりユーザー(アプリケーション)に近いインターフェースの操作を意味しています。使用難易度が高レベルではなく、コマンドそれ自体がユーザーに近くて高レベルということのようです。
下記のバケット、プレフィックス、ローカルディレクトリをコマンド例に使って説明します。
環境サンプル
バケット:my-bucket
プレフィックス1:my-prefix/no1/
プレフィックス2:my-prefix/no2/
ローカルディレクトリ:C:\\Program Files\Local_Dir\
ファイル:test.txt
ls:リスト
コマンド:aws s3 ls s3://my-bucket/my-prefix/no1
概要:
S3の指定したURIにあるファイルやプレフィックスを取得できます
詳細:
aws s3 ls <s3のUri>
の形式でコマンドを入力します。s3://<バケット名>/<プレフィックス名>
戻り値はWindows PowerShellではarray型で1要素には下記内容がテキスト形式で格納されています。
最終更新日(LWT):
yyyy-MM-dd HH:mm:ss形式の日時。OSのロケールで表示形式は変わると思われる。
サイズ(ファイルサイズ):
単位はbyte。プレフィックスがオブジェクトの場合は表記なし。
オブジェクト名:
指定したプレフィックス配下にあるファイル名 or プレフィックス名(プレフィックス名の場合 PRE という接頭辞が付く)
🤔 最終更新日、サイズ、オブジェクト名の値を取り出して条件指定したい場合
例えば、昨日更新されたファイルのみを表示させたい場合はどのような方法があるでしょうか。
aws s3 ls
コマンドは一つのオブジェクトのメタ情報(最終更新日やサイズなど)をテキストで格納しています。そのため、aws s3 lsコマンドで最終更新日を取り出して条件指定する場合は文字列の操作以外の方法はないです。シェルスクリプトで文字列に対して正規表現一致条件でフィルタをかけて、目的のメタ情報を取り出せなくはないですが、あまりスマートではないです。
オブジェクトのメタ情報に直接アクセスしたい場合はAPIレベルコマンドを使用しましょう(s3api list-objectなど)。別の記事にて追記します。
cp:コピー
コマンド1:aws s3 cp s3://my-bucket/my-prefix/no1/test.txt s3://my-bucket/my-prefix/no2/
コマンド2:aws s3 cp s3://my-bucket/my-prefix/no1/test.txt C:\\\\Program Files\\Local_Dir\\
概要:
指定したファイルを宛先の場所にコピーします。コピー元とコピー先は、S3→S3、S3→Local、Local→S3が可能です(Local→Localは不可)。
詳細:
aws s3 cp <s3Uri | Local> <s3Uri | Local>
の形式でコマンドを入力します。
🤔 指定したプレフィックス配下のファイルをすべてコピーしたい場合
--recursive
というパラメータで再帰的にコピーができます。aws s3 cp
コマンドの末尾--recursive
を付けると、指定した場所にあるオブジェクトの分だけ繰り返し処理ができます。 下記のようにコピー元のファイル名を指定せずに記述します。 aws s3 ls s3://my-bucket/my-prefix/no1/ C:\\\\Program Files\\Local_Dir\\ --recursive
sync:同期
コマンド:aws s3 sync s3://my-bucket/my-prefix/no1/ s3://my-bucket/my-prefix/no2/
概要:
指定したプレフィックスorフォルダを宛先の場所と同期します。同期元と同期先は、S3→S3、S3→Local、Local→S3が可能です(Local→Localは不可)。
詳細:
aws s3 sync <s3Uri | Local> <s3Uri | Local>
の形式でコマンドを入力します。
cpと違う点は、cpはコピー先とコピー元のファイルの状態関係なくコピーが行われるのに対し、syncは同期元と同期先の差分がなければファイルの更新は行われない点です。そのため、更新があったファイルだけダウンロード or アップロードしたい場合に適したコマンドです。
また、同期元も同期先も場所を指定するため、cpにおける--recursive
と同様の挙動をします。
🤔 何を基準に差分があると判断しているのか
公式にはバージョンとサイズで判断しているような記述があります(aws s3 sync)。
バージョンが何を指すのかわからないのですが、デフォルトではサイズが同じだとsyncが実行されない可能性があります。更新されてもファイルサイズが変わらない可能性がある場合は、--exact-timestamps
パラメータを付けるとタイムスタンプの不一致でもsyncが実行されるようになります。
mv:移動
コマンド:aws s3 cp s3://my-bucket/my-prefix/no1/test.txt s3://my-bucket/my-prefix/no2/
概要:
指定したファイルを宛先の場所に移動します。移動元と移動先は、S3→S3、S3→Local、Local→S3が可能です(Local→Localは不可)。
詳細:
aws s3 mv <s3Uri | Local> <s3Uri | Local>
の形式でコマンドを入力します。
移動元を指定する際は基本的にはファイル名(text.txt)まで指定する必要があります。移動先に関してはファイル名を省略可能です。省略した場合は移動元の命名を引き継ぎます。
🤔 指定したプレフィックス配下のファイルをすべて移動したい場合 --recursive
というパラメータで再帰的にmoveができます(aws s3 cpと同じ)。
rm:削除
コマンド:aws s3 rm s3://my-bucket/my-prefix/no1/test.txt
概要:
S3の指定したURIにあるファイルを削除できます。
詳細:
aws s3 rm <s3のUri>
の形式でコマンドを入力します。
重要なTipsとして、上記のコマンドを仮で実行できる--dryrun
というオプションがあります。--dryrun
で実行すれば、実行せずに想定結果が返ってくるので、--dryrun
で想定結果を確認してから実行する習慣を身に着けるのが良いです。
コマンド実行の正否の判断:リターンコード
リターンコードとは、aws cliコマンドの実行結果の正否を示すコードです。
ターミナル上で直にコマンドを実行する場合などは、エラーメッセージが画面に表示されるのでコマンドの正否が一目瞭然です。
しかし、バッチとして日次システムに組み込む際はターミナル自体を開いていないケースがほとんどかと思います。なのでリターンコードで実行の正否を確認することになります。aws cliコマンドが正常に行われる前提のシステムの設計の仕方もあるかもしれませんが、エラーがどのステップで生じたかログに明示的に記録されるようにするためにリターンコードを用いたバリデーションをした方が良いでしょう。
aws cliコマンドが実行された後に返されるリターンコードですが、Windows PowerShellにおいては$LASTEXITCODE
という変数に格納されています。aws cliコマンド実行後のスクリプトで、$LASTEXITCODE == 0
であれば正常終了となります。
それ以外の値であれば何かしらのエラーで正常に実行されていない可能性があります。リターンコードの値の意味は下記のリンクの通りです。
AWS CLI からのリターンコード:https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-returncodes.html
バッチ処理のスクリプト作成
最後にバッチスクリプトの作成についてです。
上記の基本的なコマンドだけで簡易的なバッチ処理を実装できます。例えば下記のようなファイル操作をスクリプトで実現できます。
処理実行手順
- S3プレフィックス(ディレクトリ)やローカルディレクトリを変数に定義
- S3の
sync
フォルダからLocalのsync
フォルダに差分のファイルを同期 - 同期完了を確認したのち、S3の
backup
フォルダに当日のyyyyMMdd
のフォルダにコピーをバックアップ
解説
S3のsyncフォルダには日次でdaily_file.csvが連携され、週次、月次でそれぞれweekly_file.csv、monthly_file.csvが連携されるようになっている。連携されたファイルのみをLocalのsyncフォルダにダウンロードし、バックアップはS3で持つようなシステム。
# Windows PowerShellでのバッチ処理(ps1ファイル)
<# 変数定義 #>
# 本日日付
$currentDate = (Get-Date).ToString("yyyyMMdd")
# s3プレフィックス
$s3HomeDir = "s3://my-bucket/"
$s3SyncDir = -join ($s3HomeDir, "sync")
$s3backupDir = -join ($s3HomeDir, "backup")
$s3backupCurrentDir = -join ($s3backupDir, $currentDate)
# Localディレクトリ
$localHomeDir = "C:\\Program Files"
$localSyncDir = Join-Path $localHomeDir "sync"
<# 変数定義ここまで #>
# 日次処理開始宣言
Write-Host "日次処理を開始します。"
try{
# S3のsyncフォルダとLocalのsyncフォルダと同期(1)
aws s3 sync $s3SyncDir $localSyncDir --exact-timestamps
# aws s3 syncコマンドのバリデーション
if ($lastexitcode -ne 0) {
throw "Aws Cli Execution Error. Return Code: ${lastexitcode}"
}
# S3のbackupフォルダにS3のsyncフォルダの中のファイルをコピー(2)
aws s3 cp $s3SyncDir $s3backupCurrentDir --recursive
# aws s3 cpコマンドのバリデーション
if ($lastexitcode -ne 0) {
throw "Aws Cli Execution Error. Return Code: ${lastexitcode}"
}
}catch{
Write-Output "An Error Occured"
Write-Output $_
}
# 正常終了
Write-Host "日次処理を完了しました。"
exit 0
上記の図のような簡易的なファイルの受け渡しであれば、高レベルコマンドだけで実現できます。
ファイル名のサフィックスやメタ情報を利用して判定・フィルタ処理を行う場合は、--exclude
、--include
や--query
などの少しだけ込み入ったオプションを使う必要があったり、APIレベルのコマンドを使用する必要があったりします。
そちらについては後日記事化していきます。
おわりに
AWS CLIの設定から基本操作まで一通り説明しました。私がAWS CLIを初めて使ったときは、右も左もわからない状態だったので上記の簡易的なバッチ処理を書くのも苦労しました。結構当たり前のところで躓いてエラーを出していたりしたので、そういう当たり前のこともちゃんと記載してみました。
AWS CLIを以後使う方が同じような苦しみに合わずに、この記事で躓きポイントをうまく超えていただければ書いた甲斐があったというものです。
参考リンク
- aws configureについての詳細設定方法の参考 【AWS】CLIの初期設定について(認証情報とコマンド補完) – TASK NOTES
- AWS CLI リターンコード AWS CLI からのリターンコード – AWS Command Line Interface
- aws s3 高レベルコマンドリファレンス
データ活用でお困りの方へ
私たちDX-Accelerator事業では、データ活用についての様々なスキルを持った人材が常駐でデータ活用支援を行うサービスを提供しています。
当事業はローンチから約3年(24年9月時点)ですが、これまでに様々な業界・業種のお客さまのお手伝いをさせていただいております。
少しでも興味を持ってくださったり、すでにご相談をしたいことがある方はお気軽にご相談ください。現在あなたの組織のフェーズがどこにあるかは関係ありません。まずはお話をしましょう。
もう少しサービスについて知りたい方はサービス紹介資料もご用意しています。