目次
はじめに
お疲れ様です、寺井です。
今回はみんな大好き 「自動化」です。
特定のイベントを検知して、後続処理を実行する
イベントドリブンなアーキテクチャを作ってみました。
背景
<要望>
アプリケーションファイルの変更はローカルで行う
変更を行う度にサーバー(EC2)へファイル更新しにいくのが面倒
<解決策>
S3へのファイルアップロードをトリガーに、自動でEC2へS3のファイルを同期させる
完成イメージ(構成図)
実装
前提
- 全て東京リージョンを利用
- VPC、サブネット、ルートテーブル、セキュリティグループは設定済
今回はEC2からS3バケットへのファイル同期に焦点を当ててお話しますので、VPC周りやEC2の起動に関する説明は省略します。
EC2の準備
まずはWebアプリケーションサーバーとしてEC2インスタンスの準備をします。
IAMポリシー
EC2には以下のAWS管理ポリシーを付与したIAMロールをアタッチします。
- AmazonS3FullAccess
- [S3] アクセス用途
- AmazonSSMManagedInstanceCore
- [SSM Run Command] 実行用途
OS
今回は [RHEL8.7]を使用しています
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.7 (Ootpa)
ミドルウェア
PHPファイルをブラウザで確認するため、PHPとApacheをインストールしておきます。
$ php -v
PHP 7.4.30 (cli) (built: Jun 7 2022 08:38:19) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
$ httpd -v
Server version: Apache/2.4.37 (Red Hat Enterprise Linux)
Server built: Jul 28 2022 23:43:33
「AWS CLI」のインストール
こちらのページの内容でインストールを実施
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
︙
$ ls
awscliv2.zip
$ unzip awscliv2.zip
︙
$ sudo ./aws/install
$ aws --version
aws-cli/2.10.1 Python/3.9.11 Linux/4.18.0-425.10.1.el8_7.x86_64 exe/x86_64.rhel.8 prompt/off
「SSM Agent」のインストール
今回は [RHEL 8系]を使用するので、以下のページの内容でインストールを実施
$ dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
︙
$ systemctl enable amazon-ssm-agent
$ systemctl start amazon-ssm-agent
$ systemctl status amazon-ssm-agent
● amazon-ssm-agent.service - amazon-ssm-agent
Loaded: loaded (/etc/systemd/system/amazon-ssm-agent.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2023-02-20 16:08:30 JST; 15min ago
Main PID: 1368 (amazon-ssm-agen)
Tasks: 17 (limit: 4645)
Memory: 104.6M
CGroup: /system.slice/amazon-ssm-agent.service
tq1368 /usr/bin/amazon-ssm-agent
mq1454 /usr/bin/ssm-agent-worker
S3バケットの作成
作成したS3バケットの直下に「app/」というフォルダを作成し、その中に「index.php」を設置します。
「s3 sync」コマンドの確認
AWS CLIで実行する 「s3 sync」コマンドについて挙動の確認をしておきます。
S3バケットの状態を確認
# S3バケットの確認
$ aws s3 ls
2023-02-13 14:23:41 s3sync-test-bucket-20230213
$ aws s3 ls s3://s3sync-test-bucket-20230213
PRE app/
$ aws s3 ls s3://s3sync-test-bucket-20230213/app/
2023-02-13 14:27:01 23 index.php
S3のファイルをEC2側に同期させる
# 構文
$ aws s3 sync <source> <target> [--options]
# 現在のディレクトリは空の状態
$ ls -l
合計 0
# 「s3sync-test-bucket-20230213/app/」内のファイルを現在のディレクトリ「.」に同期
$ aws s3 sync s3://s3sync-test-bucket-20230213/app/ .
download: s3://s3sync-test-bucket-20230213/app/index.php to ./index.php
$ ls -l
合計 4
-rw-r--r-- 1 root root 23 2月 13 14:27 index.php
S3のファイルがEC2側にダウンロードされた
EC2側のファイルをS3側に同期させる
先程とは逆パターンの挙動を確認
# 現在のディレクトリは空の状態
$ ls -l
合計 0
# S3側にはファイルがある状態
$ aws s3 ls s3://s3sync-test-bucket-20230213/app/
2023-02-13 14:27:01 23 index.php
# 現在のディレクトリ「.」を「s3sync-test-bucket-20230213/app/」に同期
$ aws s3 sync . s3://s3sync-test-bucket-20230213/app/
# 実行しても反応なし
実行されません。一旦別のファイル[index1.php]を作成してみます。
# 既にS3に置いてあるファイル名とは別のファイルを作成
$ vi index1.php
$ ls -l
合計 4
-rw-r--r-- 1 root root 8 2月 13 14:49 index1.php
# 「s3 sync」の実行
$ aws s3 sync . s3://s3sync-test-bucket-20230213/app/
upload: ./index1.php to s3://s3sync-test-bucket-20230213/app/index1.php
アップロードだけ実行された
削除を伴うファイル同期
先程の「AWS CLI での高レベル (S3) コマンドの使用」ページを良く読んでみると、削除を伴う場合は「--delete」オプションが必要とのこと
通常、s3 sync は欠落しているか古くなったファイルやオブジェクトを、ソースとターゲットの間でコピーします。ただし、--delete オプションを指定して、ソースに存在しないファイルまたはオブジェクトをターゲットから削除することもできます。
勢いでコマンド走らせてしまって、意図せずファイルが削除されてしまうこともありそうなので、これは有り難い。
# S3の状態確認(「index.php」と「index1.php」の2つのファイルを設置)
$ aws s3 ls s3://s3sync-test-bucket-20230213/app/
2023-02-13 14:27:01 23 index.php
2023-02-13 14:51:14 8 index1.php
# EC2側の状態確認
$ ls -l
合計 4
-rw-r--r-- 1 root root 23 2月 13 14:27 index.php
# 「s3 sync」の実行
$ aws s3 sync --delete . s3://s3sync-test-bucket-20230213/app/
delete: s3://s3sync-test-bucket-20230213/app/index1.php
# S3の状態確認
$ aws s3 ls s3://s3sync-test-bucket-20230213/app/
2023-02-13 14:27:01 23 index.php
EC2側にはなかった「index1.php」ファイルがS3から削除(=同期)された
S3のファイルをサーバー側と同期させることも、その逆も可能です。
補足:同じファイルを同期する場合
「おんなじファイルはどうなるんやろう…」と気になって夜も眠れなくなる夢を見たので更に検証してみました。
EC2→S3へのsync
EC2側とS3側のファイルが全く同じものである状態で挙動を確認します。
# EC2側のファイルの状態
$ ls --full-time
合計 4
-rw-r--r-- 1 root root 29 2023-02-17 12:19:01.874374467 +0900 index.php
$ aws s3 ls s3://s3sync-test-bucket-20230213/app/
2023-02-17 12:19:01 29 index.php
# 「s3 sync」実行
$ aws s3 sync . s3://s3sync-test-bucket-20230213/app/
# 差分が無いと何も起こらない
続いて、EC2側のファイルを変更せずに保存しなおして、挙動を確認します。
# EC2側のファイルを編集し
$ vi index.php
# 変更せずに保存
$ ls --full-time
合計 4
-rw-r--r-- 1 root root 29 2023-02-17 12:21:05.860578665 +0900 index.php
# 「s3 sync」実行
$ aws s3 sync . s3://s3sync-test-bucket-20230213/app/
upload: ./index.php to s3://s3sync-test-bucket-20230213/app/index.php
$ aws s3 ls s3://s3sync-test-bucket-20230213/app/
2023-02-17 12:21:39 29 index.php
中身を変更せずに保存しなおしても「s3 sync」が実行されたので、ファイルの中身は関係なく、タイムスタンプで判断されるようです。
S3→EC2へのsync
逆パターンでファイルを変更せずにS3にファイルをアップロードし直して、コマンドを実行しても何も返ってこない…。
# S3のファイルをEC2側にsyncさせる
$ aws s3 sync s3://s3sync-test-bucket-20230213/app/ .
よくよく調べたところ以下のドキュメントに遭遇
参考:AWS CLI 1.27.73 Command Reference|s3 sync
デフォルトの動作では、同じサイズのアイテムは無視されます。
なんでや?!
ファイルサイズが変わらず内容が少し変わるパターンってありそうなんですが…。
ということで、ファイルサイズではなくタイムスタンプでsyncさせたいときは、「--exact-timestamps」オプションをつけて実行する必要がありますのでご注意を。
# S3のファイルをEC2側にsyncさせる(タイムスタンプで判断)
$ aws s3 sync --exact-timestamps s3://s3sync-test-bucket-20230213/app/ .
download: s3://s3sync-test-bucket-20230213/app/index.php to ./index.php
ここまでの振り返り
必要な情報が増えてきたので一旦まとめます。
WEBサーバーに設置しているアプリケーションのパス
- /var/www/html/s3sync_dir/app/
アプリケーションファイル(index.php)
<?php
// 心ばかりのPHP要素
$version = "1.0";
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test-app|トップページ</title>
</head>
<body>
<h1 style="text-align: center;">アプリケーション</h1>
<p style="text-align: center;">Version:<?= $version ?></p>
</body>
</html>
S3 URI
s3://s3sync-test-bucket-20230213/app/
S3からEC2にファイルを同期させるコマンド
タイムスタンプで実行するか否かを判断して、S3の対象ディレクトリを EC2の対象ディレクトリに同期するコマンド
$ aws s3 sync --exact-timestamps s3://s3sync-test-bucket-20230213/app/ /var/www/html/s3sync_dir/app/
※実際に実行する際のWEBサーバーのパスや、S3 URIに関しては、適宜ご自身の環境に読み換えてください。
まとめ
いらぬ検証をしたせいで、かなり長くなったので、今回は一旦ここまでとします。
次回は[EventBridge]の作成と[SSM Run Command]の設定を行って、一連の動作を確認していきたいと思います。
ここまでお読みいただきありがとうございました!
次回も宜しくお願いします。
続きはこちら:
【AWS SSM Run Command】S3イベントで自動的にファイルを同期させる[前編]
好きなこと:音楽、猫、お酒、ゲーム、効率化
経歴:音楽専門学校 → テレビ業界AD → 通信回線代理店 → IT関連職業訓練 → 2022.12~ 株式会社ディーネット