1
1
paiza×Qiita記事投稿キャンペーン「プログラミング問題をやってみて書いたコードを投稿しよう!」

ECS環境で動作しているRuby on Railsの環境に、EventBridge Ruleでバッチ処理を組み込む

Posted at

概要

表題の構成でバッチ処理を構築したので、その構築方法について記載します。

前提条件

前提条件一覧

  • ECS環境でRuby on Railsのアプリが動作している
  • Terraformがインストールされている
  • ECSや Network関連(ALBIAM、セキュリティーグループ等)がTerraformで構築されている
  • Ruby on Railsのバージョンは、7.0以上

作成手順

Ruby on Rails

初期設定

  • EventBridge Ruleからrails runner(以下、rに省略)でコマンド叩く際、pathの入力を行わないで済む様にする為、下記を追加した
config/application.rb
config.eager_load_paths << Rails.root.join("lib", "batches")

上記の設定をした事で、ローカル環境では、下記のコマンドでバッチ処理の確認が可能

rails r "testBatch.execute"
# or 
bundle exec rails r "testBatch.execute"

メリット

  • 大規模なアプリケーションになった際、パフォーマンスの向上に繋がる
  • 特定のディレクトリ内のすべてのファイルが自動的に読み込まれる為、コードの整理が容易

補足

  • config.eager_load_pathsの記述を書かない場合は、libからのpathを指定してする事で、作成したバッチ処理のコードを実行する事が可能
rails r lib/batches/my_script.rb

バッチ処理の作成

  • lib内にbatchesディレクトリーを作成する
    (バッチ処理のディレクチリー名は、任意の名前の設定でも良い)
  • batchesディレクトリー内に、バッチ処理を行いたいファイルを記載する
# ディレクトリー作成
mkdir lib/batches

# ファイル作成
touch lib/batches/test.rb
  • require "logger"を追加して、ログを出力する
  • ActiveRecord::Base.connection.execute('test')は、ActiveRecordを通じて直接SQLを実行する
  • 今回の処理では、何らかのバッチ処理を動作させた仮定して、ActiveRecord::Base.connection.executeの処理を実装した
require "logger"

class TestBatch
  def self.execute
    logger = Logger.new(STDOUT)
    logger.info("----- batch を実行します。 -----")
    ActiveRecord::Base.connection.execute('test')
    logger.info("----- batch を実行しました。 -----")  
  end
end

Terraform

  • 各表題で記載されている内容をtfファイルに記載する
  • コメントアウトで注意点や設定内容について自身の見解を述べている

ディレクトリ構成

  • 下記の構成で組んでいます。必要に応じて変更して下さい
  • main.tfvariables.tfの内容に関しては、各々の書き方があるので、開発手法に応じて臨機応変に対応して下さい
.
├── main.tf
├── variables.tf
├── # その他のファイルは省略
├── ecs/
│   ├── task.tf
│   ├── cluster.tf
│   ├── service.tf
│   └── variables.tf
├── eventbridge/
│   ├── eventBridgeRule.tf
│   ├── variables.tf 
│   └── output.tf
└── iam/
    ├── iam.tf
    ├── variables.tf
    └── output.tf

ロールの作成

iam.tf
#------------------------------------------------------------------------------
# CLOUDWATCH EVENT ROLE
#------------------------------------------------------------------------------
resource "aws_iam_role" "scheduled_task_cw_event_role" {
  name = "batch-st-cw-role" 
  
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "events.amazonaws.com"
        }
      }
    ]
  })
}

# ECSのポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "scheduled_task_cw_event_role_cloudwatch_policy" {
  # 付与したいロールを記載
  role       = aws_iam_role.scheduled_task_cw_event_role.name
  # AWSのポリシーのarnを記載している(独自のポリシーを付与する事も可能)
  policy_arn = "arn:aws:iam::aws:policy/AmazonECS_FullAccess"
}

  • name : 任意の名前で良い。変更する場合は、リソース識別子を合わせて下さい
  • assume_role_policy : EventBridge Ruleに操作権限を持たせる為、権限を一時的に移譲する。これにより、他のAWSサービス(ここではEventBridge)がこのロールを使用して他のAWSリソースに対して、アクションを実行する事が可能となる
output.tf
output "scheduled_task_cw_event_role_arn" {
  value = aws_iam_role.scheduled_task_cw_event_role.arn
}

Terrform構築時の参考資料

バッチ処理の作成

eventBridgeRule.tf
#------------------------------------------------------------------------------
# CLOUDWATCH EVENT RULE
#------------------------------------------------------------------------------
resource "aws_cloudwatch_event_rule" "event_rule" {
  name = "test-batch"
  schedule_expression = "cron(30 18 * * ? *)"
  state               = "ENABLED" # ENABLEDにする事で、ルールが有効化される

  # 任意で記述
  tags = {
    Name  = "test-batch"
  }
}

#------------------------------------------------------------------------------
# CLOUDWATCH EVENT TARGET
# #------------------------------------------------------------------------------
resource "aws_cloudwatch_event_target" "ecs_scheduled_task" {
  target_id = "testBatch"
  rule      = aws_cloudwatch_event_rule.event_rule.name
  arn       = # ECSクラスタのarnを記述する
  role_arn  = # 上記で作成したiamロールのarnを記述する
  
  # nameとcommandの順番が入れ替わる為、ヒアドキュメントで記載
  input = <<EOF
  {
    "containerOverrides": [
      {
        "name": "test_rails_container",
        "command": ["bundle","exec","rails","runner","testBatch.execute"]
      }
    ]
  }
  EOF

  # ECSタスクを設定するためのブロック
  ecs_target {
    task_definition_arn = # ECSのタスク定義のARNを記述する
    group               = "production_batch" # 任意の名前で設定
    task_count          = "1"
    launch_type         = "FARGATE"
    platform_version    = "LATEST"

    # タスクのネットワーク設定を定義
    network_configuration {
      assign_public_ip = true # 必ずtrueにする
      security_groups  = ["sg-0123456789abcdef0", var.sg_id] # セキュリティーIDを記述する(複数記述可能。また、表記内容は、参考例を記述している)
      subnets          = ["subnet-0123456789abcdef0", var.public_subnet_a_id] # サブネットIDを記述する(複数記述可能。また、表記内容は、参考例を記述している)
    }
  }
}

  • schedule_expression : ratecronを使用して処理の実行期間を設定する
  • rate : 定期実行したい場合に適している。シンプルな繰り返しタスクに向いている
  • cron : 柔軟なスケジュールが必要な場合に使用する。特定の曜日や月など、複雑なスケジュール設定が可能
  • cron(30 18 * * ? *) : # 左から[分、時、日、月、曜日、年]を指定する。曜日に関しては、?の設定で良い
  • assign_public_ip : FargateタスクにパブリックIPを割り当てるための設定。ECRからイメージを取得できず、コンテナが起動しない為、必ずtrueにする

Terrform構築時の参考資料

参考資料

まとめ

今回は、Ruby on railsEventBridge Ruleを使用したバッチ処理を作成しました。時間制御で行うバッチ処理に関しては、公式が推奨しているAmazon EventBridge Schedulerを使用した方が良かったんですが、会社の意向でEventBridge Ruleを使用して作成しました。ただ、処理自体に大きな差はないので、EventBridge Ruleでも問題はないです。機会があれば、Amazon EventBridge Schedulerで構築したバージョンも記事として載せたいと考えています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1