GAT技術ブログ

株式会社ギブ・アンド・テイクの技術ブログ

GAT技術ブログ

90本の cron バッチを⼀括移行!EventBridge Scheduler + Run Command + EC2 実践ガイド

1. はじめに:AWSバッチ処理を動かすには?

AWS 上でバッチ処理を実装したいけど、結局どのサービスを使えばいいの?」

インフラやクラウドエンジニアであれば、直面したことがある人も多い疑問ではないでしょうか?

私自身、オンプレ環境で稼働していた約90本の cron バッチを AWS 上に移行する際、この問いに直面しました。

最終的には、色々と模索のうえ、「EventBridge Scheduler + Run Command + EC2( Linux )」構成に一気に90本移行しました。

やってみて分かったのは――
「設計はシンプルでも、落とし穴が多い!」
「ネット上にも、実践レベルの情報があまりない!」

この記事では、以下について共有し、どなたかの「AWS バッチ構成どうしよう問題」や「EventBridge Scheduler + Run Command + EC2( Linux )」導入時の参考となれば幸いです。

  • AWSバッチ処理を選定する際の基準

  • EventBridge Scheduler + Run Command + EC2( Linux )構成の注意点と Tips

2. AWSバッチ処理するなら?5つの主要パターン比較

よく検討される5つの構成について、特徴や課題を以下にまとめました。

この記事では、EventBridge Scheduler + Run Command + EC2Linuxで実装する場合の注意点やハマリポイントについて、後述で詳細に説明しています。

構成案 特徴・メリット 制約・課題
EventBridge Scheduler + Lambda サーバレスで実装が手軽。マネジメントコンソールで直接コードを記述・編集・デプロイが可能 実行時間15分制限。長時間/大量データ処理には不向き
Step Functions ワークフロー制御・エラー分岐・再実行が強力。並列実行・ジョブの依存関係も指定可能。各種AWSサービスとの統合性が極めて高い。可視化も◎ 単純なバッチには過剰。AWS 初学者には設計難易度高め
cron on EC2 オンプレ環境からのジョブの単純移行に適している。環境構築は容易 可視化・運用性に乏しい。EC2 の管理が必要
EventBridge Scheduler + Run Command + EC2 スケジュールを AWS 側で一元管理。 EventBridge Scheduler の cron 式 は、Quartz フォーマットであり、通常の cron 式とはフォーマットが異なる(※1)。 ログ・実行履歴管理に注意。EC2 の管理が必要
AWS Batch キュー制御・並列実行・ジョブの依存関係も指定可能。大量なリクエスト処理にむいており、HPCにも対応 コンテナ前提の設計。初期学習コストあり。単純なジョブ移行にはおもたい

※1:参考:AWS公式ドキュメント「Amazon EventBridge スケジューラ ユーザーガイド」https://docs.aws.amazon.com/ja_jp/scheduler/latest/UserGuide/schedule-types.html(2025年6月26日アクセス)


3. こんな場合におすすめ:「EventBridge Scheduler + Run Command + EC2( Linux」構成

以下に該当する場合、今回紹介する EventBridge Scheduler + Run Command + EC2( Linux )構成 は有力な選択肢です。

  • 既に EC2 やオンプレミスのサーバ上に多数のバッチが存在し、Lambda 等に載せ替えるのは難しい

  • バッチ処理長時間(数十分〜数時間)に及ぶ

  • 複雑な依存関係はなく、単独のバッチを時間指定で動かしたい

  • OS 上での cron 管理を脱却し、EventBridge Scheduler やタグベースでスケジュール管理を可視化・自動化したい

まさに「脱 OS 上での cron 設定第一歩として、やりすぎないシンプル構成を取りたい」ケースに最適です。

4. 実装内容とハマりどころ

一見シンプルに見える EventBridge Scheduler + Run Command + EC2( Linux )構成。しかし実際にバッチを移行してみると、設計・構築・運用の各フェーズで想定外のつまずきが数多く存在していました。

4-1. システム構成

構成図は以下のとおりです。

EventBridge Scheduler は、指定した cron 式に従って定期的に AWS Systems Manager の Run Command をトリガーします。

これにより、SSM ドキュメント(例:AWS-RunShellScript)を EC2 上で実行できます。


SendCommand の API では以下のような入力を定義できます。


SendCommand API で定義できるパラメータ例

{
  // 実行する SSM ドキュメント名(ここでは"AWS-RunShellScript"を指定)
  "DocumentName": "AWS-RunShellScript",

  "Parameters": {
    // 実行したいコマンドを指定
    "commands": [
       "echo 'whoami'の実行結果↓",
       "whoami",
       "echo 'pwd'の実行結果↓",
       "pwd"
    ]
  },

  // 対象インスタンスを指定
  // Key には "tag:<タグ名>" または "InstanceIds" を指定可能
  // Values にはタグの値またはインスタンスIDを配列で指定
  "Targets": [
    {
      "Key": "tag:Targets",
      "Values": [
        "example-tag-value"
      ]
    }
  ],

  // コマンドを同時に実行する最大数(例:"1" は順番に1台ずつ実行)
  "MaxConcurrency": "1",

  // エラー許容数(例:"0" は1台でも失敗すれば全体をエラー扱い)
  "MaxErrors": "0",

  // 配信タイムアウト(秒)
  "TimeoutSeconds": 60,

  // 実行結果を通知する SNS 通知設定
  "NotificationConfig": {
    // 通知先の SNS トピック ARN
    "NotificationArn": "arn:aws:sns:ap-northeast-1:123456789012:example-sns-topic",

    // 通知イベントの種類(例:失敗・キャンセル・タイムアウト時に通知)
    // All | InProgress | Success | TimedOut | Cancelled | Failed の中から選択可
    "NotificationEvents": [
      "Failed",
      "Cancelled",
      "TimedOut"
    ],

    // 通知タイミング
    "NotificationType": "Invocation"
  },

  // SNS 通知に使用するサービスロール ARN
  "ServiceRoleArn": "arn:aws:iam::123456789012:role/ExampleSnsPublishRole",

  // 実行結果ログの出力先 S3 バケット名
  "OutputS3BucketName": "example-output-bucket",

  // 出力先 S3 のプレフィックス
  "OutputS3KeyPrefix": "ssm-runcommand/"
}

SendCommand API で定義できるパラメータの詳細は以下の公式ドキュメントをご参照ください。

※参考:AWS公式ドキュメント「SendCommand - AWS Systems Manager」
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/APIReference/API_SendCommand.html
(2025年6月26日アクセス)

 

4-2. Run Command 利用時の注意点

4-2-1. マネコン上でのコマンド実行結果の可視性が弱い

Run Command の実行履歴は、以下のように一覧で表示されます。

なお、「リクエストされた日付」に記載されている日時は GMT 表記です。



コマンドの実行結果(標準出力・エラー出力)を確認するには、
① 該当のコマンド ID をクリック →
② 対象インスタンス ID をクリック →
③ 初めて詳細が確認可能になります。



このように、マネコン上でコマンド実行結果の詳細(標準出力やエラー出力)を確認するには、ひと手間かかります。

4-2-2. 実行履歴の保持期間は30日

以下の公式ドキュメントにある通り、Run Command の実行履歴は 最大30日間 しか保持されません。

各コマンドの履歴は、最大 30 日利用可能です。さらに、すべてのログファイルのコピーを Amazon Simple Storage Service に保存するか、すべての API 呼び出しの監査証跡AWS CloudTrail に維持することができます。

※引用:AWS公式ドキュメント「マネージドノードでのコマンドの実行」(2025年6月26日アクセス)URL:https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/running-commands.html

そのため、30日以上の保存が必要な場合は、Run Command の実行結果を、S3 バケットに出力しておくと安心です。

4-2-3. シェルの実行ユーザは root ユーザが既定

Run Command で実行されるコマンドは、デフォルトでは root ユーザーで実行されます。実際、Run Command 経由で whoami を実行すると、以下の通り出力結果は "root" になります。

4-2-4. Run Command のデフォルトの実行ディレクト

上記キャプチャのとおり、Amazon Linux 2023 では、Run Command のデフォルトの実行ディレクトリは /usr/bin です。

任意のディレクトリで実行したい場合は、以下のように "workingDirectory" パラメータを指定しましょう。

{
  // 実行する SSM ドキュメント名(ここでは"AWS-RunShellScript"を指定)
  "DocumentName": "AWS-RunShellScript",

  "Parameters": {
    // 実行したいコマンドを指定
    "commands": [
       "echo 'whoami'の実行結果↓",
       "whoami",
       "echo 'pwd'の実行結果↓",
       "pwd"
    ],
    // コマンドを実行したいディレクトリを指定
    "workingDirectory": [
      "/home/ec2-user"
    ]
  },
  ・・・省略

上記のコマンドを実行した結果が以下です。
指定した "workingDirectory" のディレクトリで、コマンドが実行されていることが確認できます。

4-2-5. タイムアウトの考え方に要注意

SSM Run Command を使ううえで誤解しやすいポイントの一つが「タイムアウト」の扱いです。

SendCommand API の TimeoutSeconds パラメータは、コマンドが対象インスタンスに配送されるまでの待機時間(配信タイムアウト)を意味しており、コマンドの実行時間の上限ではありません。

実際のコマンド実行時間の上限を指定したい場合は、executionTimeout パラメータを利用します。この値は、使用する SSM ドキュメントに定義されている制約に従います。

たとえば、AWSが提供する AWS-RunShellScript ドキュメントでは、以下のように executionTimeout が定義されています。

  • デフォルト値は 3600(=1時間)

  • 最大指定可能時間は 172800(=48時間)

{
  "schemaVersion": "1.2",
  "description": "Run a shell script or specify the commands to run.",
  "parameters": {
    "commands": {
      "type": "StringList",
      "description": "(Required) Specify a shell script or a command to run.",
      "minItems": 1,
      "displayType": "textarea"
    },
    "workingDirectory": {
      "type": "String",
      "default": "",
      "description": "(Optional) The path to the working directory on your instance.",
      "maxChars": 4096
    },
    "executionTimeout": {
      "type": "String",
      // 実行タイムアウトの既定値は3,600秒、最大で172800秒(48時間)まで指定可能
      "default": "3600",
      "description": "(Optional) The time in seconds for a command to complete before it is considered to have failed. Default is 3600 (1 hour). Maximum is 172800 (48 hours).",
      "allowedPattern": "([1-9][0-9]{0,4})|(1[0-6][0-9]{4})|(17[0-1][0-9]{3})|(172[0-7][0-9]{2})|(172800)"
    }
  },
  "runtimeConfig": {
    "aws:runShellScript": {
      "properties": [
        {
          "id": "0.aws:runShellScript",
          "runCommand": "{{ commands }}",
          "workingDirectory": "{{ workingDirectory }}",
          "timeoutSeconds": "{{ executionTimeout }}"
        }
      ]
    }
  }
}

実際に、以下のように executionTimeout を 5 と指定、sleep 7200 を含むコマンドを実行すると、実行開始から5秒後にタイムアウトとなります。

{
  // 実行する SSM ドキュメント名(ここでは"AWS-RunShellScript"を指定)
  "DocumentName": "AWS-RunShellScript",

  "Parameters": {
    // 実行したいコマンドを指定
    "commands": [
       "echo 'whoami'の実行結果↓",
       "whoami",
       "echo 'pwd'の実行結果↓",
       "pwd",
       "sleep 7200"
    ],
    // コマンドの実行時間を指定
    "executionTimeout": [ "5" ],
    // コマンドを実行したいディレクトリを指定
    "workingDirectory": [
      "/home/ec2-user"
    ]
  },
  ・・・省略

続いて、以下のように executionTimeout を 7500 と指定、sleep 7200 を含むコマンドを実行すると、問題なく実行が成功します。

{
  // 実行する SSM ドキュメント名(ここでは"AWS-RunShellScript"を指定)
  "DocumentName": "AWS-RunShellScript",

  "Parameters": {
    // 実行したいコマンドを指定
    "commands": [
       "echo 'whoami'の実行結果↓",
       "whoami",
       "echo 'pwd'の実行結果↓",
       "pwd",
       "sleep 7200"
    ],
    // コマンドの実行時間を指定
    "executionTimeout": [ "7500" ],
    // コマンドを実行したいディレクトリを指定
    "workingDirectory": [
      "/home/ec2-user"
    ]
  },
  ・・・省略

AWS-RunShellScript の executionTimeout のデフォルト値は 3600 なので、AWS-RunShellScript を使って1時間を超えるコマンドを実行したい場合は、Send Command API のパラメータ executionTimeout に、実行時間に応じた適切な値を明示的に指定する必要があります。

このように、SSM Run Command 経由で長時間バッチを実行する際は、タイムアウト値の設定に注意が必要です。

4-2-6. SSM エージェント内の並列ワーカー数の規定値は「5件」

SSM エージェント内でコマンドを並列実行するワーカ数(CommandWorkersLimit)は、デフォルトで5件 に設定されています 。

この上限を超えてコマンドが送信されると、超過分は内部キューに入り、順次処理されます。キュー待ち中のジョブは Run Command コンソール上で「進行中」と表示されます。

より多くの同時実行が必要な場合は、以下の手順で設定変更が可能です

1. /etc/amazon/ssm/amazon-ssm-agent.json ファイルの "CommandWorkersLimit" を任意の値に変更
2. amazon-ssm-agent サービスを再起動

sh-5.2$ cat /etc/amazon/ssm/amazon-ssm-agent.json
{
    "Profile":{
        "ShareCreds" : true,
        "ShareProfile" : "",
        "ForceUpdateCreds" : false,
        "KeyAutoRotateDays": 0
    },
    "Mds": {
        "CommandWorkersLimit" : 5,
        "StopTimeoutMillis" : 20000,
        "Endpoint": "",
        "CommandRetryLimit": 15
    },
    "Ssm": {
        "Endpoint": "",
        "HealthFrequencyMinutes": 5,
        "CustomInventoryDefaultLocation" : "",
        "HibernationMaxBackoffIntervalMinutes" : 60,
        "AssociationLogsRetentionDurationHours" : 24,
        "RunCommandLogsRetentionDurationHours" : 336,
        "SessionLogsRetentionDurationHours" : 336,
        "SessionLogsDestination": "none",
        "PluginLocalOutputCleanup": "",
        "OrchestrationDirectoryCleanup": ""
    },
    ・・・省略

もし、以下の通り amazon-ssm-agent.json ファイルが存在していない場合は、amazon-ssm-agent.json.template を amazon-ssm-agent.json というファイル名で、同一ディレクトリ内にコピーして使用すればOKです。

sh-5.2$ ls /etc/amazon/ssm
NOTICE.md  README.md  RELEASENOTES.md  amazon-ssm-agent.json.template  seelog.xml.template
sh-5.2$

 

5. まとめ

本記事では、AWS におけるバッチ処理の代表的な構成パターンを比較したうえで、「EventBridge Scheduler + Run Command + EC2( Linux )構成」に焦点を当て、構成方法・注意点・実装Tipsを詳細にご紹介しました。

特にこの構成は、以下のようなケースにおいて有力な選択肢となります。

  • 既存の cron バッチをできるだけそのまま移行したい
  • バッチ実行時間が15分を超え、Lambda では対応が難しい
  • 複雑な依存関係はなく、単発での時間指定実行が主
  • cron 設定を OS から切り離し、可視化・一元管理したい

一方で、「Run Command の実行履歴が見づらい」「実行結果が30日しか保持されない」「デフォルトの実行ユーザが root 固定」「デフォルトでは同時実行数に制限あり」「1時間以上コマンドやスクリプトを実行する際はタイムアウト値の設定に注意が必要」など、実装して初めて気づく落とし穴も多く存在しました。

こうしたポイントを押さえておくことで、導入後のトラブルを防ぎ、より安定したバッチ基盤の構築に繋がるはずです。

この記事が、どなたかの AWS 上でのバッチ処理設計の一助となれば幸いです。