概要
表題の構成でバッチ処理を構築したので、その構築方法について記載します。
前提条件
前提条件一覧
-
ECS
環境でRuby on Rails
のアプリが動作している -
Terraform
がインストールされている -
ECS
やNetwork
関連(ALB
、IAM
、セキュリティーグループ等)が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.tf
、variables.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
:rate
とcron
を使用して処理の実行期間を設定する -
rate
: 定期実行したい場合に適している。シンプルな繰り返しタスクに向いている -
cron
: 柔軟なスケジュールが必要な場合に使用する。特定の曜日や月など、複雑なスケジュール設定が可能 -
cron(30 18 * * ? *)
: # 左から[分、時、日、月、曜日、年]を指定する。曜日に関しては、?
の設定で良い -
assign_public_ip
: FargateタスクにパブリックIPを割り当てるための設定。ECRからイメージを取得できず、コンテナが起動しない為、必ずtrue
にする
Terrform構築時の参考資料
参考資料
まとめ
今回は、Ruby on rails
とEventBridge Rule
を使用したバッチ処理を作成しました。時間制御で行うバッチ処理に関しては、公式が推奨しているAmazon EventBridge Schedulerを使用した方が良かったんですが、会社の意向でEventBridge Rule
を使用して作成しました。ただ、処理自体に大きな差はないので、EventBridge Rule
でも問題はないです。機会があれば、Amazon EventBridge Scheduler
で構築したバージョンも記事として載せたいと考えています。