オンプレのApache → Tomcat連携

オンプレでは Apache httpd と Tomcat は別プロセス・別サーバーで動作し、mod_jk モジュールを通じてAJP(Apache JServ Protocol)で連携するのが標準的な構成だ。

オンプレ:Apache → Tomcat 連携構成
クライアント
    │ HTTPS
    ▼
Apache httpd(ポート443)
    │ AJP(ポート8009)
    ▼
Tomcat(ポート8009 / AJPコネクタ)
    ├── セッション(JVMメモリ or DeltaManager レプリケーション)
    ├── WAR(/webapps/myapp.war)
    └── スレッドプール(maxThreads=200等)

workers.properties:
  worker.tomcat1.host=192.168.1.10
  worker.tomcat1.port=8009
  worker.tomcat2.host=192.168.1.11
  worker.tomcat2.port=8009
  worker.loadbalancer.balance_workers=tomcat1,tomcat2

このときApacheは以下の役割を担っている。

  • SSL終端・静的コンテンツ配信(PART 01・02で解説)
  • mod_jkによるクラスタ管理(ワーカー定義・重み付け・フェイルオーバー)
  • スティッキーセッション(同一クライアントを同じTomcatへ誘導)

AJPが不要になる理由

AWSでは、Apache httpdが担っていた「SSL終端・静的配信・ルーティング」の役割がALBとS3 + CloudFrontに引き渡される。その結果、Apache httpdが不要になり、AJP接続も自動的に不要になる

AWS:ALB → コンテナ 直接転送
クライアント
    │ HTTPS
    ▼
ALB(ポート443)
    │ HTTP(ポート8080)← AJP不要・直接HTTP転送
    ▼
ECS コンテナ
    ├── Nginx sidecar(任意)← 必要な場合のみ
    │       │ HTTP(ポート8080)
    │       ▼
    └── Spring Boot(組込Tomcat・ポート8080)
            ├── セッション → ElastiCache Redis
            └── JAR(WAR不要)

💡 Spring Boot と組込Tomcat

Spring Boot はデフォルトでTomcatを組み込んでおり、HTTPで直接リクエストを受け付けられる。Apache httpdを間に挟む必要がないため、ALBから直接 :8080 に転送するだけでよい。AJPコネクタは無効化(デフォルト無効)のままでよい。

セッション管理の根本的な変化

これがオンプレ→AWS移行で最も設計が変わる部分だ。オンプレではTomcatのJVMメモリにセッションを保持するため、スティッキーセッション(同じサーバーへ誘導)が必要だった。

セッション管理の変化
【オンプレ:スティッキーセッション必須】

クライアントA → Apache → Tomcat1(セッションA はここにある)
クライアントB → Apache → Tomcat2(セッションB はここにある)

問題:Tomcat1が落ちるとクライアントAのセッションが消える
対策:DeltaManagerで全Tomcat間でセッションをレプリケーション
    → Tomcat台数が増えるほどレプリケーションコストが増大

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

【AWS:スティッキーセッション不要】

クライアントA → ALB → ECSコンテナ1 ↘
クライアントB → ALB → ECSコンテナ2 → ElastiCache Redis(セッション共有)
クライアントA → ALB → ECSコンテナ3 ↗

全コンテナが同じRedisからセッションを読み書き
→ どのコンテナに振られてもセッションが継続する
→ コンテナが落ちてもセッションはRedisに残る

Spring Session + ElastiCache の設定(Spring Boot):

application.yml(Spring Session + Redis)
spring:
  session:
    store-type: redis
    timeout: 1800  # 30分
  data:
    redis:
      host: ${REDIS_ENDPOINT}   # ElastiCacheのエンドポイント
      port: 6379
      ssl: true                 # ElastiCache は TLS推奨

# 依存関係(build.gradle)
# implementation 'org.springframework.boot:spring-boot-starter-data-redis'
# implementation 'org.springframework.session:spring-session-data-redis'

ALBターゲットグループ(mod_jkの代替)

mod_jkのワーカー設定(クラスタ管理・ヘルスチェック・フェイルオーバー)に相当する機能は、ALBのターゲットグループが担う。

mod_jk設定ALBターゲットグループ
worker定義・重み付けターゲットグループの重み設定
ヘルスチェック(ping)HTTPヘルスチェック(/actuator/health等)
障害ノードの自動切り離しヘルスチェック失敗でderegistration自動実行
スティッキーセッション設定不要(ElastiCacheでセッション共有)
ワーカー台数変更(手動)ECS Auto Scaling(自動)

デプロイ方式の変化(WAR → コンテナイメージ)

オンプレではTomcatのwebapps/ディレクトリにWARファイルを配置して再起動するというデプロイが標準だった。AWSではコンテナイメージとしてビルド・プッシュ・Blue/Greenデプロイを行う。

項目オンプレ(WAR)AWS(コンテナ)
成果物myapp.warDockerイメージ(ECRにプッシュ)
配置方法webapps/にSCP・Tomcat再起動ECSタスク定義の更新 → サービス更新
ダウンタイムあり(再起動中)なし(Blue/Greenデプロイ)
ロールバック前バージョンWARを手動配置前バージョンタスク定義に切り戻し
JVM設定setenv.sh, catalina.shECSタスク定義の環境変数(JAVA_OPTS)

対比表

項目オンプレAWS
接続方式Apache mod_jk → AJP → TomcatALB → HTTP → コンテナ(組込Tomcat)
クラスタ管理workers.propertiesALBターゲットグループ
セッション管理JVMメモリ or DeltaManagerレプリケーションElastiCache Redis(Spring Session)
スティッキーセッション必須不要
スケールアウト事前台数見積・手動追加ECS Auto Scaling(自動)
デプロイWARファイル配置・Tomcat再起動コンテナイメージ更新・Blue/Green

ハマりポイント

⚠️ AJPポートのセキュリティ(CVE-2020-1938)

Spring Boot 2.3以降ではAJPコネクタがデフォルト無効になっているが、古いアプリをそのままコンテナ化すると8009ポートが開いたままになる場合がある。AWSへの移行時にAJP設定を明示的に無効化することを確認すること。

⚠️ セッションのシリアライズ要件

ElastiCacheにセッションを保存する場合、セッションに格納するオブジェクトがすべてSerializableを実装している必要がある。既存のTomcatアプリをそのまま移行すると、Serializableでないオブジェクトがセッションに含まれていてエラーになるケースがある。

次の記事では…

PART 04 では帳票処理を扱う。NASを使ったファイル格納からS3 + presigned URLへの移行、同期・非同期の帳票生成パターンの選定基準を解説する。