ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

EC2インスタンスを指定した時刻に起動して不要ファイルを削除する

この記事を共有する

目次

こんにちは、菅野です。
今回は、Amazon EC2 (以下 EC2 ) を起動させてその中にある不要なファイルを削除する方法をご紹介させていただきます。不要なファイルを手動で削除する運用をされている方の参考になれば幸いです。

はじめに

今回検証した構成は以下図となります。 構成図.png

  • Amazon VPC (Amzaon VPC Internet Gateway を含む) と EC2 は作成済みの状態から実施いたしますので、以下をご参考に環境をご準備ください。

VPC を作成する
インターネットゲートウェイを使用して VPC のインターネットアクセスを有効にする
Amazon EC2 の使用開始

  • 稼働 OS としては Amazon Linux 2023 を使用しております。別の Linux ディストリビューションにて検証される場合は、以下を参考にAWS CLIをインストールしてください。

AWS CLI の最新バージョンのインストールまたは更新

不要ファイル削除タスクの流れは以下の通りです。
1. 設定したスケジュールにて Amazon EventBridge(以下 EventBridege) から、AWS Lambda(以下 Lambda) 側に処理実行の命令を送る
2. Lamda で EC2 インスタンスを起動する
3. 起動した EC2 インスタンスの cron ジョブにて 不要ファイル削除処理を実施する
4. 不要ファイルを削除し、EC2 停止・SNS 送信用 Lambdaをキックする
5. EC2 停止・メッセージ通知用 Lambda により EC2 停止と SNS にメッセージ(処理結果)を送信する
6. Lambda から送信されたメッセージ(処理結果)を SNS Topic 内で設定したメールアドレスに送信する

今回のゴール

  • Lambda と EC2 の Bashスクリプトを使用して EC2 を起動して不要ファイルを削除するタスクが作成できること
  • EventBridege を使用して設定したタスクをスケジュール実行できること
  • 実行結果をメール送信できること

それでは実際に、不要ファイル削除の手順についてご紹介いたします。

メール送信用 SNS Topic の作成

■ 1. マネジメントコンソール (Tokyoリージョン)にログインして、画面上の検索窓から「SNS」と入力し、「Simple Notification Servie」-「トピック」-「トピックの作成」にて「トピックの作成」画面を開きます。

■ 2. 以下の通り設定し「トピックの作成」をクリックします。

  • タイプ:スタンダード
  • 名前:任意の名前
  • 表示名(オプション):任意の表示名
    ※ 表示名はサブスクリプションで使用する名前になります。SMSメッセージ やメールの送信元はこちらの名前で届きます。

■ 3. 「トピック<トピック名>が正常に作成されました。」と表示されたら、作成したトピックから「サブスクリプションの作成」をクリックします。

■ 4. 「詳細」項目を以下の通り設定し、「サブスクリプションの作成」をクリックします。

  • プロトコル:Eメール
  • エンドポイント:<ファイル削除の結果を送信する送信先Eメールアドレス>

■ 5. 作成したサブスクリプションが「ステータス:保留中の確認」となるので、設定したメールアドレスに以下のようなメールが届いていることを確認し、「Comfirm subscription」をクリックします。 image-1.png

■ 6. 「Subscription Comfirmed !」と表示されていることを確認し、画面を閉じます。
※ 画面上の「click here to unsubscribe」の表示はクリックしないでください。

■ 7. 作成した Topic の サブスクリプションを確認し「ステータス:確認済み」となっていればサブスクリプションが有効になってます。

■ 8. サブスクリプションが有効になったことを確認後、Topic の ARN を控えておきます。
こちらは次の項目で作成する SNS Topic にメッセージを連携する Lamda 関数で使用します。 image-2.png

Lambda 関数 の作成

Lambda 関数 は用途別に以下の2つを作成します。

  • EC2 起動用 Lamda 関数
  • EC2 停止・SNS 送信用 Lamda 関数作成

EC2 起動用 Lamda 関数作成

■ 1. マネジメントコンソールの画面上の検索窓から「lambda」と入力し、「lambda」画面左のナビゲーションペインから「関数」-「関数を作成」をクリックします。

■ 2. 「一から作成」を選択し、「基本的な情報」項目は以下の通り設定します。

  • 関数名:任意の名前(EC2を起動する用と判別可能な名前を推奨します)
  • ランタイム:python 3.13 (最新版を使用しておりますが、3.9でも動作することを確認しております)
  • アーキテクチャ:x86_64

■ 3. 「アクセス権限」項目を「デフォルトの実行ロールの変更」から以下の通り設定し、「関数の作成」をクリックします。

  • 実行ロール:基本的な Lambda アクセス権限で新しいロールを作成

※「その他の構成」については今回設定しませんが、運用実務においてプライベートな環境で Lamda 関数を利用する場合、以下 URL を参考に 「VPC を有効化」を設定してください。 Lambda 関数に Amazon VPC 内のリソースへのアクセスを許可する

■ 4. 「関数 ~ を正常に作成しました。」と表示されたら、作成した関数の画面から「コード」タブを選択し、「コードソース」に以下を貼り付けます。

import boto3   # AWS リソースに関わる機能を扱うためのモジュールを有効化  
def lambda_handler(event, context):  
    # EC2インスタンスIDを指定  
    INSTANCE_ID = "<対象インスタンスID>"   # <対象インスタンスID>にファイル削除を実施するインスタンスIDを設定します  
    # EC2クライアントを作成  
    ec2_client = boto3.client('ec2')   # EC2 を Lambda から操作するためのモジュールに別名を設定  
    # EC2インスタンスの状態を取得  
    response = ec2_client.describe_instances(InstanceIds=[INSTANCE_ID])
    state = response['Reservations'][0]['Instances'][0]['State']['Name']  # 階層構造になっており「Reservations」の中の「Name」の値を(最終的に)取得しています  
    # インスタンスが停止している場合に起動  
    if state != 'running':
        ec2_client.start_instances(InstanceIds=[INSTANCE_ID])
        message = "EC2インスタンスを起動しました。"
    else:
        message = "EC2インスタンスはすでに起動しています。"  
    return {
        'statusCode': 200,  # Lambda 関数が正常に実行できた場合ステータスコード 200 で message に格納した値を出力します
        'body': message
    } 

■ 5. <対象インスタンスID> の箇所を起動するインスタンス IDに変更します。コードソース画面左の「Deploy」をクリックし、「関数 ~ が正常に更新されました。」と表示されることを確認します。

■ 6. Lamda 関数の中で EC2 を操作するため、作成された Lamda 関数用 Role (Lamda 関数名-role-ランダム英数字 )に「AmazonEC2FullAccess」を付与します。具体的な方法につきましては以下をご参照ください。 ロールに対するアクセス許可を更新する
※今回は検証のため マネージドポリシーである「AmazonEC2FullAccess」を付与しておりますが、実際に必要な権限は「ec2:StartInstances」です。

■ 7. Lamda 関数の実行時間を、「設定タブ」-「一般設定」-「編集」から以下の通り変更し、「保存」をクリックして新しいタイムアウト値を反映させます。

  • タイムアウト: 3 秒(デフォルト)→ 15 分 0 秒

※今回個別のテストは実施しませんが、こちらの Lamda 関数のテストを実施する場合は「テスト」タブから以下の通り設定し、「テスト」クリック後、「実行中の関数:成功」と画面上に表示され対象の EC2 インスタンスが起動することをご確認ください。

  • イベントアクションをテスト: 新しいイベントを作成
  • イベント名:任意の値
  • イベント共有の設定:プライベート
  • テンプレートバージョン:Hello World
  • イベント JSON:{}

EC2 停止・SNS 送信用 Lamda 関数作成

■ 1. マネジメントコンソールの画面上の検索窓から「lambda」と入力し、「lambda」をクリックします。「lambda」画面左のナビゲーションペインから「関数」-「関数を作成」をクリックします。

■ 2. 「一から作成」を選択し、「基本的な情報」項目は以下の通り設定します。

  • 関数名:任意の名前(EC2を起動する用と判別可能な名前を推奨します)
  • ランタイム:python 3.13 (最新版を使用しておりますが、3.9でも動作することを確認しております)
  • アーキテクチャ:x86_64

■ 3. 「アクセス権限」項目を「デフォルトの実行ロールの変更」から以下の通り設定し、「関数の作成」をクリックします。

  • 実行ロール:基本的な Lambda アクセス権限で新しいロールを作成
    ※ EC2 起動用 Lamda 関数と同様に「その他の構成」については今回設定しません。

■ 4. 「関数 ~ を正常に作成しました。」と表示されたら、作成した関数の画面から「コード」タブを選択し、「コードソース」に以下を貼り付けます。

import boto3   # AWS リソースと時間に関わる機能を扱うためのモジュールを有効化  
import time  
def lambda_handler(event, context):  
    ec2_client = boto3.client('ec2')   # Lambda から EC2 と SNS を操作するためのモジュールに別名を設定     sns_client = boto3.client('sns')  
    # インスタンスIDを設定
    instance_id = "<対象インスタンスID>"  
    # EC2インスタンスを停止  
    ec2_client.stop_instances(InstanceIds=[instance_id])  
    # 一時停止を入れる  
    time.sleep(120) # 2分待機   # 停止対象インスタンスの停止にかかる時間に応じて変更してください  
    # EC2インスタンスの状態を確認  
    response = ec2_client.describe_instances(InstanceIds=[instance_id])  
    state = response['Reservations'][0]['Instances'][0]['State']['Name']  
    if state == 'stopped':  
        sns_message = " ファイル削除処理を実行しました。ジョブ実行結果は「/work」配下のログを確認してください。EC2は停止済みです。"  
    else:  
        sns_message = " EC2が正常に停止できませんでした。 EC2 の状態を確認してください。ジョブ実行結果は「/work」配下のログを確認してください"  
    # SNS通知を実施  
    response = sns_client.publish(  
        TopicArn='<3 メール送信用 SNS Topic の作成 - ■ 8 で控えたARN>',  
        Message=sns_message   #if 文で設定したsns_message を SNS Topic に連携するためのメッセージとして設定しています  
    )  
    return response  # 戻り値としてSNS Topic への Publish を実施します

■ 5. 以下の箇所を修正後、コードソース画面左の「Deploy」をクリックし、「関数 ~ が正常に更新されました。」と表示されることを確認します。

  • 6行目:instance_id = "<対象インスタンスID>" ・・・停止する EC2 の インスタンス IDに修正
  • 10行目:time.sleep(120)   ・・・EC2 インスタンスが停止するのにかかる時間(秒)に修正
  • 20行目: TopicArn='<3 メール送信用 SNS Topic の作成 - ■ 8 で控えたARN>' ・・・左記太字通りに修正

■ 6. Lamda 関数の中で EC2 と SNS を操作するため、作成された Lamda 関数用 Role (Lamda 関数名-role-ランダム英数字 )に「AmazonEC2FullAccess」と「AmazonSNSFullAccess」を付与します。具体的な方法につきましては以下をご参照ください。
ロールに対するアクセス許可を更新する
※今回は検証のため マネージドポリシーである「AmazonEC2FullAccess」と「AmazonSNSFullAccess」を付与しておりますが、実際に必要な権限は「ec2:StopInstances」と「sns:Publish」です。

■ 7. Lamda 関数の実行時間を、「設定タブ」-「一般設定」-「編集」から以下の通り変更し、「保存」をクリックして新しいタイムアウト値を反映させます。

  • タイムアウト: 3 秒(デフォルト)→ 15 分 0 秒

※今回個別のテストは実施しませんが、こちらの Lamda 関数のテストを実施する場合は「テスト」タブから以下の通り設定し、「テスト」クリック後、「実行中の関数:成功」と画面上に表示され EC2 が正常に停止し、指定したメールアドレスに通知が発報されることをご確認ください。

  • イベントアクションをテスト: 新しいイベントを作成
  • イベント名:任意の値
  • イベント共有の設定:プライベート
  • テンプレートバージョン:Hello World
  • イベント JSON:{}

EC2 の設定

EC2 の設定としては不要ファイルを削除するための bash スクリプトの作成と それを自動実行するための cron 設定を実施します。

ファイル削除用 bash スクリプト作成

■ 1. 対象の EC2 OS にセッションマネージャーや ターミナルを使用した SSH などでログインします。

■ 2. 以下コマンドにて rootユーザーにスイッチします。

$ sudo su -

■ 3. スクリプトを作成したい場所に「cd」コマンドなどで移動し、以下コマンドで新規ファイルを開きます。
# vi <スクリプト名>.sh  
例:vi file_delete.sh

■ 4. 以下のコマンドでインサートモードに変更後、bash スクリプトの内容を貼り付けます。
  • インサートモードに変更
i
  • bash スクリプトの内容
#!/bin/bash  
# EC2のホスト名を取得  
HOSTNAME=$(hostname)  
# ログの出力ディレクトリを指定  
LOG_DIR="/work"   # ログを出力するディレクトリを設定しています 、ログ出力先に合わせて変更可能です  
LOG_FILE="${LOG_DIR}/${HOSTNAME}_FileDelete_$(date +%Y%m%d).log"  # 左記の場合 ホスト名 
 _FileDelete_yyyymmdd.logと出力されます  
# ログ出力開始  
exec > >(tee -a $LOG_FILE)  # 標準出力を tee コマンドに渡し、ログファイルに追記しながら表示します  
exec 2>&1                   # 標準エラー出力を標準出力と同じ場所にリダイレクトします  
echo "ログ出力開始: $(date)"  
# Disk 使用率の確認  
df -Th  
# 指定の作成日付が経過した特定のファイルを検索  
SEARCH_DIR="/work"         # 削除対象ファイルが存在するディレクトリを設定します  
DELETE_BEFORE="-mtime +60" # 更新日付が設定した日よりも前のファイルを対象にしています(この設定では60日)  
FILE_NAME="screenshot*"    # 削除対象のファイル名を設定しています(この場合はscreenshot~というファイル名が対象)
# 削除コマンド組み立て  
FILES_TO_DELETE=$(find $SEARCH_DIR -type f $DELETE_BEFORE -name $FILE_NAME )  
if [[ -n "$FILES_TO_DELETE" ]]; then  
    echo "削除対象ファイルを検索しました: $FILES_TO_DELETE"  # 削除対象の一覧を表示します  
    # ファイルの削除  
    for file in $FILES_TO_DELETE; do  
        if rm -f "$file"; then  
            echo "削除しました: $file"  # 削除ファイルごとに削除に成功すると「削除しました:ファイル名」と表示  
        else  
            echo "削除エラー: $file"   # 削除に失敗したファイルがある場合、そこで処理が中断されます  
            break  
        fi  
    done  
else  
    echo "削除対象ファイルが存在しないため処理を終了しました。"   # 削除対象が無い場合、何もせずに処理を終了します  
fi  
# ログ出力停止  
echo "ログ出力停止: $(date)"    
exec &>/dev/null    
# Lambda関数を呼び出す  
aws lambda invoke --function-name <"EC2 停止・SNS 送信用 Lamda 関数名"> response.json  # lambda 呼び出し処理結果がスクリプトと同じディレクトリの「response.json」に出力されます  
echo "Lambda関数を呼び出しました。"

■ 5. 以下の箇所を修正し、「esc」キー でコマンドモードに変更した後、「:」キー +「wq」で内容を保存します。

  • 5行目:LOG_DIR="/work" ・・・ログの出力先ディレクトリに修正
  • 15行目:SEARCH_DIR="/work" ・・・削除対象ファイルが存在するディレクトリに修正
  • 16行目:DELETE_BEFORE="-mtime +60" ・・・削除対象とするファイルの更新日付を修正(例は60日以前)
  • 17行目:FILE_NAME="screenshot*" ・・・削除するファイル名を設定(正規表現使用可能)
  • 38行目: <"EC2 停止・SNS 送信用 Lamda 関数名"> ・・・左記太字の部分を記載の関数名に修正

■ 6. 以下のコマンドにてコマンドモードに変更し、内容を保存します。

  • 「esc」キー でコマンドモードに変更
  • 設定内容を保存(以下コマンドを入力しEnter)
:wq

■ 7. 以下コマンドにて想定通りの内容が保存されているか確認します。
# cat <スクリプト名>.sh  
例:cat file_delete.sh

■ 8. 以下コマンドにて root ユーザーだけが実行できるように修正します。

# chmod 744 <スクリプト名>.sh  
例:chmod 744 file_delete.sh  

※上記実行後、以下コマンドにて修正したスクリプトの権限が「rwxr--r--」であれば問題ございません。

ls -l

bash スクリプト の cron への登録

今回、RHEL 公式の 設定ページが存在することと、設定の容易さから cronie を使用してスクリプトを定期実行します。
現在 デフォルトでは Amazon Linux 2023 へ cronie パッケージは提供されていないため、パッケージを追加でインストールできない場合は以下を参照して systemd.timer をご利用ください。

systemd/タイマー
systemd タイマーの置き換え cron

■ 1. root ユーザーにて以下コマンドで cronie パッケージをインストールします。

# dnf install cronie -y

■ 2. 以下コマンドで crondサービスを起動し、また自動起動するように設定します。
# sytemctl start crond.service  
# systemctl enable crond.service

■ 3. 以下コマンドにて root ユーザー用 cron の編集画面を開きます。
# crontab -e

■ 4. 以下のコマンドでインサートモードに変更後、下記URL を参考に cron に スケジュールと実行するスクリプトを記載します。
  • インサートモードに変更
i

cronジョブのスケジュール設定

例
10 12 17 * * /script/file_delete.sh    # 左記の場合は root ユーザーにより毎月17日の12時10分に /script/file_delete.sh を実行 

※実行時刻は EC2 起動用 Lambda 関数により EC2 インスタンスが正常起動した後の時間に設定する必要があります。

■ 5. 以下のコマンドにてコマンドモードに変更し、内容を保存します。

  • 「esc」キー でコマンドモードに変更
  • 設定内容を保存(以下コマンドを入力しEnter)
:wq

■ 6. 以下コマンドにて保存した内容が反映されていることを確認します。
# crontab -l

Event Bridege ルールの作成

■ 1. マネジメントコンソールの画面上の検索窓から「EventBridege」と入力し、「EventBridege」サービスを開きます。「EventBridege」画面左のナビゲーションペインから「ルール」-「ルールを作成」をクリックします。

■ 2. 「ルールの詳細」を以下の通り設定し、「続行してルールを作成する」をクリックします。

  • 名前:任意の値
  • 説明:任意の値
  • イベントバス:default
  • 選択したイベントバスでルールを有効にする:無効
  • ルールタイプ:スケジュール

■ 3. 「スケジュールを定義」を以下の通り設定し、「次へ」をクリックします。

  • スケジュールパターン:特定の時刻(~)に実行されるきめ細かいスケジュール。
  • Cron 式 (※以下 URL を参照して実行する日を設定してください)

cron 式と rate 式を使用して Amazon EventBridge でルールをスケジュールする

■ 4. 「ターゲットを選択」を以下の通り設定します。

  • ターゲット 1 :AWS のサービス
  • ターゲットを選択:Lambda 関数
  • ターゲットの場所:このアカウントのターゲット
  • 関数:<EC2 起動用 Lamda 関数作成>にて作成した Lambda 関数

■ 5. 「バージョン/エイリアスを設定」を以下の通り設定し「次へ」をクリックします。

  • 許可 :■ 実行ロールを使用(推奨) ・・・チェックを付けます
  • 実行ロール:この特定リソースについて新しいロールを作成
  • ロール名:任意(※名前は自動生成されますが変更可能です)
  • 関数:<EC2 起動用 Lamda 関数作成>にて作成した Lambda 関数

■ 6. 「タグを設定-オプション」はタグを設定する場合「Add new tag」をクリックしてタグを設定し、「次へ」をクリックします。

■ 7. 「レビューと作成」画面にて設定した内容に誤りが無いことを確認し、「ルールの作成」をクリックします。

■ 8. 「ルール ~ は正常に作成されました。」と表示されることを確認後、起動用 Lamda 関数の画面に遷移します。

■ 9. 「関数の概要」から「トリガーの追加」をクリックします。

■ 10. 以下の通り設定し、「追加」をクリックします。

  • トリガーの設定:EventBridege (CloudWatch Events)
  • ルール:既存のルール
  • 既存のルール:<6 Event Bridege ルールの作成 ■1-■8 で作成したルール>

■ 11. EventBridege トリガーが EC2 起動用 Lambda 関数に追加されることを確認し、設定したトリガーの EventBridege ルールのページに遷移し、 画面右上の「有効化」をクリックします。
ルール有効化確認画面にて「有効化」をクリックします。

■ 12. 「ルール ~ は正常に更新されました。」と表示されることを確認し、スケジュール実行の時刻まで待ちます。

■ 13. スケジュール実行日時になったらマネジメントコンソールから「CloudWatch」-「ロググループ」から EC2 起動と停止のLambda に更新が無いか逐一確認し、更新があった場合「error」が発生していないか確認します。

■ 14. SNS Topic のサブスクリプションにて設定したメールアドレスに以下のようなメールを受信していることを確認します。 image-3.png

■ 15. EC2を起動し、ログイン後対象ファイルが削除されていてログが以下の通り正常に出力されていることを確認します。 image-4.png

まとめ

Event Bridege と Lambda を連携し、また Lambda と EC2 に作成した Bash スクリプトをAWS CLI を介して連携させることによって、以下の処理が1度に実行できるようになりました。

  • EC2 起動
  • EC2 の不要ファイル削除
  • EC2 の停止およびメール通知

次回は EC2 から Lambda に処理命令を送信する際に EC2 側の処理結果を連携できるように工夫してみたいと思います!

この記事は私が書きました

菅野 索

記事一覧

趣味:ジョギング、散歩
最近体重の増加が気になるので、ダイエット頑張ってます。

菅野 索

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。