はじめに
2025 年 12 月 10 日、AWS は Amazon Elastic Container Service(ECS)の新機能を発表しました。
AWS Fargate 上で動作する Linux タスクにおいて、OCI(Open Container Initiative)イメージに定義されたカスタム停止シグナル(STOPSIGNAL)をサポートする機能です。
この機能により、Fargate 上のコンテナが EC2 起動タイプと同様に、アプリケーション固有の終了シグナルを利用できるようになりました。
本記事では、新機能の詳細、従来との違い、実際の使い方、コストや制限事項についてまとめています。
新機能の概要
今回発表された新機能により、Fargate 上のコンテナをアプリケーションに最適な方法でグレースフルシャットダウンできるようになりました。
主な特徴
主な特徴としては以下の 3 つです。
- コンテナイメージに定義された停止シグナルの自動認識
- EC2 起動タイプとの動作統一
- 既存環境への影響なし
コンテナイメージに定義された停止シグナルの自動認識
Dockerfile の STOPSIGNAL 命令で指定したシグナルを、Fargate が自動的に認識し送信します。
アプリケーションが期待する終了シグナルを利用することで、適切なグレースフルシャットダウンが可能になります。
EC2 起動タイプとの動作統一
これまで EC2 起動タイプでは利用できていた STOPSIGNAL のサポートが、Fargate でも利用可能になりました。
これにより、起動タイプに関わらず一貫したコンテナ終了動作を実現できます。
既存環境への影響なし
STOPSIGNAL が未設定のコンテナイメージは、従来通り SIGTERM を受信します。
既存のタスク定義やコンテナイメージを変更することなく、新機能を利用できます。
仕組み
カスタム停止シグナルは、ECS Container Agent がコンテナイメージの設定を読み取ることで実現されます。
タスク停止時、ECS Container Agent はコンテナイメージの設定から STOPSIGNAL 命令で定義された停止シグナルを読み取り、そのシグナルをコンテナに送信します。
STOPSIGNAL が未定義の場合は、デフォルトとして SIGTERM が送信されます。
その後、タスク定義の stopTimeout(デフォルト 30 秒)で設定された時間が経過すると、SIGKILL が送信されます。
何が変わったのか
今回発表された新機能により、Fargate におけるコンテナ終了処理が大きく改善されました。
コンテナ終了における従来の課題と新機能による変化を見ていきましょう。
従来の課題
主な課題としては以下の 3 つがありました。
- Fargate では全コンテナに固定的な SIGTERM
- アプリケーション固有の終了処理の困難さ
- EC2 起動タイプとの動作の違い
Fargate では全コンテナに固定的な SIGTERM
Fargate 上で動作するすべてのコンテナは、停止時に常に SIGTERM を受信していました。
アプリケーションが他のシグナルを期待していても、Dockerfile の STOPSIGNAL 命令は無視され、SIGTERM のみが送信されていました。
アプリケーション固有の終了処理の困難さ
言語やフレームワークによっては、SIGTERM 以外のシグナルでグレースフルシャットダウンを実装しているケースがあります。
これらのアプリケーションを Fargate で動作させる場合、期待通りの終了処理が実行されず、以下のような問題が発生していました。
- データベース接続プールが正しくクローズされない
- 進行中のリクエスト処理が中断される
- インメモリキャッシュが永続化されずに失われる
- ログやメトリクスが適切にフラッシュされない
EC2 起動タイプとの動作の違い
EC2 起動タイプでは、以前から STOPSIGNAL 命令がサポートされていました。
そのため、同じコンテナイメージでも EC2 と Fargate で終了時の動作が異なるという一貫性の問題がありました。
この動作の違いにより、起動タイプの移行時に予期しない問題が発生したり、マルチ環境での運用ガイドラインが複雑化するという課題がありました。
新機能による変化
新機能により、従来の課題がすべて解決されました。
カスタム停止シグナルのサポート
Fargate でも STOPSIGNAL 命令が認識されるようになり、固定的な SIGTERM の制約がなくなりました。
| 項目 | 従来(Fargate) | 新機能(Fargate) | 参考:EC2 |
|---|---|---|---|
| 停止シグナル | SIGTERM | STOPSIGNAL 準拠 | STOPSIGNAL 準拠 |
| カスタマイズ | 不可 | 可能 | 可能 |
コンテナイメージに定義された STOPSIGNAL がそのまま利用できるため、アプリケーションが期待するシグナルを送信できます。
アプリケーション最適化されたグレースフルシャットダウンの実現
各アプリケーションに最適な終了処理が可能になりました。
Go アプリケーションでは SIGQUIT によるスタックトレース出力と適切な終了、Java アプリケーションでは SIGINT によるシャットダウンフックの実行など、言語やフレームワークが推奨するシグナルを利用できます。
これにより、従来発生していた問題が解消されます。
EC2 起動タイプとの動作統一
EC2 と Fargate で同じ STOPSIGNAL の動作が保証されるようになりました。
| 項目 | 従来 | 新機能 |
|---|---|---|
| EC2 と Fargate の動作 | 異なる | 統一 |
| 起動タイプ移行時のリスク | あり | なし |
| 運用ガイドライン | 起動タイプ別に必要 | 共通化可能 |
これにより、起動タイプを気にせずコンテナイメージを設計でき、環境移行時のリスクが低減されます。
使い方
新機能の使い方を サンプルアプリケーションを使って説明します。
サンプルアプリケーションの準備
新機能を実際に試すために、シグナルハンドリングを実装した Go アプリケーションのサンプルを用意します。
このサンプルでは、SIGQUIT を受信したときに「Received SIGQUIT」というログを出力し、クリーンアップ処理を実行してから終了します。
アプリケーションコードの作成
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGQUIT)
fmt.Println("Application started")
go func() {
for {
fmt.Println("Working...")
time.Sleep(5 * time.Second)
}
}()
<-sigChan
fmt.Println("Received SIGQUIT, starting graceful shutdown...")
fmt.Println("Cleaning up resources...")
time.Sleep(2 * time.Second)
fmt.Println("Shutdown complete")
}
Dockerfile の作成
FROM golang:1.21 AS builder
WORKDIR /tmp
COPY main.go .
RUN go build -o app main.go
FROM ubuntu:22.04
STOPSIGNAL SIGQUIT
COPY --from=builder /tmp/app /app
CMD ["/app"]
Amazon ECR へのプッシュ
コンテナイメージをビルドし、Amazon ECR にプッシュします。
Docker イメージのビルド
# Dockerイメージをビルド
docker build -t custom-stopsignal-demo .
# ビルドされたイメージを確認
docker images | grep custom-stopsignal-demo
ECR リポジトリの作成
aws ecr create-repository \
--repository-name custom-stopsignal-demo \
--region ap-northeast-1
イメージのプッシュ
# ECR にログイン
aws ecr get-login-password --region ap-northeast-1 | \
docker login --username AWS --password-stdin \
<account-id>.dkr.ecr.ap-northeast-1.amazonaws.com
# イメージにタグ付け
docker tag custom-stopsignal-demo:latest \
<account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/custom-stopsignal-demo:latest
# プッシュ
docker push <account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/custom-stopsignal-demo:latest
アプリケーションのデプロイ
タスク定義の作成
{
"family": "custom-stopsignal-demo",
"executionRoleArn": "arn:aws:iam::<account-id>:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "app",
"image": "<account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/custom-stopsignal-demo:latest",
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/custom-stopsignal-demo",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
},
"stopTimeout": 30
}
]
}
サービスの作成とデプロイ
- 上記のタスク定義を登録
- サービスを作成してデプロイ
- タスク起動後、「Working...」というログが 5 秒ごとに出力されることを確認
動作確認
実際にカスタム停止シグナルが送信されているかを確認します。
タスクの停止
ECS コンソールからタスクを停止するか、サービスの「必要なタスク」を 0 に設定してタスクを停止します。
タスクログの確認
停止したタスクのログを確認し、「Received SIGQUIT」というログが出力されていることを確認します。
「Received SIGQUIT」というログが出力されており、STOPSIGNAL が正しく機能していることが確認できます。
新機能のメリット
新機能により、アプリケーション固有の終了処理を Dockerfile の設定だけで実現できるようになりました。
従来は、すべてのアプリケーションで SIGTERM に対応するコードを書く必要がありましたが、言語やフレームワークが推奨するシグナルをそのまま利用できます。
また、開発環境(Docker Desktop)と本番環境(Fargate)で同じ動作が保証されるため、ローカルでテストした通りに本番環境でも動作します。
これにより、環境差異による予期しない問題を回避できます。
コストと制限事項
新機能を利用する前に知っておくべきコストと制限事項について説明します。
料金への影響
カスタム停止シグナル機能の利用に追加料金は発生しません。
既存の AWS Fargate の料金のみが適用されます。
グレースフルシャットダウンによってタスクの停止時間がわずかに延びる可能性がありますが、Fargate の料金は秒単位での課金となるため、コストへの影響は軽微です。
むしろ、適切な終了処理によってデータ損失や再処理のコストを削減できる可能性があります。
制限事項
機能面の制限
- Linux タスクのみ対応(Windows タスクは非対応)
- stopTimeout の最大値は 120 秒
運用上の注意点
- アプリケーション側でのシグナルハンドリング実装が必要
- stopTimeout を適切に設定しないと、クリーンアップ処理完了前に SIGKILL で強制終了される可能性がある
- STOPSIGNAL が未設定の場合は SIGTERM が送信される(既存動作と同じ)
まとめ
今回発表された新機能により、Fargate でもコンテナイメージに定義された STOPSIGNAL を利用できるようになりました。
EC2 起動タイプとの動作が統一され、アプリケーション固有のグレースフルシャットダウンが可能になります。
新機能は追加コストなしで利用でき、既存環境への影響もありません。
STOPSIGNAL が未設定のコンテナは従来通り動作し続けるため、必要に応じて段階的に移行できます。
グレースフルシャットダウンが重要なアプリケーションでは、Dockerfile に STOPSIGNAL を追加し、アプリケーション側で適切なシグナルハンドリングを実装することをお勧めします。
まずは開発環境やステージング環境で動作を確認し、本番環境への適用を検討してください。
参考リンク
