<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>トラブル | ナギ｜システム基盤エンジニアの知見録</title>
	<atom:link href="https://sys-univ.com/category/incident/feed/" rel="self" type="application/rss+xml" />
	<link>https://sys-univ.com</link>
	<description>大手SIer20年超｜要件定義から設計・構築・試験・移行・運用まで、実務で使える知見を発信</description>
	<lastBuildDate>Sun, 01 Nov 2026 00:09:05 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/>
<atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/>
<atom:link rel="hub" href="https://websubhub.com/hub"/>
<atom:link rel="self" href="https://sys-univ.com/category/incident/feed/"/>
	<item>
		<title>PHP2Shellへの緊急対応はSIerの想定内？｜なぜ大騒ぎになったのか</title>
		<link>https://sys-univ.com/dev/php2shell-vulnerability-response/</link>
					<comments>https://sys-univ.com/dev/php2shell-vulnerability-response/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 01:52:48 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[システム開発]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=3574</guid>

					<description><![CDATA[2026年10月21日の夜、国内の多くのWebサービスが緊急メンテナンスに入りました。原因は、PHP本体に見つかった2件の重大な脆弱性、通称「PHP2Shell」です。首相がWebサイトの一時停止まで呼びかけ、社会的にも [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>2026年10月21日の夜、国内の多くのWebサービスが緊急メンテナンスに入りました。原因は、PHP本体に見つかった2件の重大な脆弱性、通称「PHP2Shell」です。首相がWebサイトの一時停止まで呼びかけ、社会的にも大きな話題になりました。</p>
<p>大手SIerで20年超、大規模な業務システムの基盤構築や運用に携わってきた私が、今回の騒ぎを見て感じたのは、<strong>CVSS 9点台の重大な脆弱性が見つかり、緊急対応を迫られる事態は、私が携わってきたシステムでは想定内だった</strong>ということです。</p>
<p>PHP2Shellという個別の脆弱性を予測していたわけではありません。通常SIerでは、重大な脆弱性が発見されることを前提に、対応基準や正常性確認の手順を平時から整備しています。</p>
<p>本記事では、PHP2Shellが大きな問題になった背景を整理し、運用の現場が重大な脆弱性をどう判断し、どう対策しているのかを解説します。</p>
<blockquote>
<p>本記事は2026年10月30日時点の公開情報に基づいています。仮想事例と明記した部分は説明用に構成したものです。</p>
</blockquote>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">PHP2Shellの重大性と社会的な影響</a><ol><li><a href="#toc2" tabindex="0">PHP本体に見つかった2件の重大な脆弱性</a></li><li><a href="#toc3" tabindex="0">CVSSとは何か</a></li><li><a href="#toc4" tabindex="0">首相による注意喚起とWebサイトの一時停止</a></li><li><a href="#toc5" tabindex="0">PHPの普及範囲と管理体制の多様さ</a></li></ol></li><li><a href="#toc6" tabindex="0">重大な脆弱性への対応は、平時から設計している</a><ol><li><a href="#toc7" tabindex="0">CVSSに応じた対応基準を準備する</a></li><li><a href="#toc8" tabindex="0">業務重要度によって対応方法を変える</a></li><li><a href="#toc9" tabindex="0">正常性確認まで事前に準備しておく</a></li></ol></li><li><a href="#toc10" tabindex="0">CVSSが高くても、必ずパッチを適用するわけではない</a><ol><li><a href="#toc11" tabindex="0">仮想事例：未使用の管理サービスにCVSS 8点台の脆弱性</a></li><li><a href="#toc12" tabindex="0">パッチを適用しないことは、放置することではない</a></li></ol></li><li><a href="#toc13" tabindex="0">PHP2Shellなら、現場ではどう対応するか</a><ol><li><a href="#toc14" tabindex="0">PHPの採用領域と運用体制の違い</a></li><li><a href="#toc15" tabindex="0">影響対象はアプリケーションではなくPHPランタイム</a></li><li><a href="#toc16" tabindex="0">仮想事例：LB配下の公開Webシステム</a><ol><li><a href="#toc17" tabindex="0">①〜③ 影響を調査し、必要なら公開を止める</a></li><li><a href="#toc18" tabindex="0">④ パッチを適用し、実際の稼働状態を確認する</a></li><li><a href="#toc19" tabindex="0">⑤ セキュリティ確認と正常性確認を行う</a></li><li><a href="#toc20" tabindex="0">⑥ LB配下へ段階的に再公開する</a></li></ol></li><li><a href="#toc21" tabindex="0">PHPだけに特別な対処をしているわけではない</a></li></ol></li><li><a href="#toc22" tabindex="0">脆弱性対応で本当に重要なのは、更新できる状態を維持すること</a><ol><li><a href="#toc23" tabindex="0">緊急時に「すぐ更新できない」理由</a></li><li><a href="#toc24" tabindex="0">更新できる状態を維持することも運用設計</a></li><li><a href="#toc25" tabindex="0">脆弱性対応とは、パッチを当てる作業ではない</a></li></ol></li><li><a href="#toc26" tabindex="0">参考文献</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">PHP2Shellの重大性と社会的な影響</span></h2>
<h3><span id="toc2">PHP本体に見つかった2件の重大な脆弱性</span></h3>
<p>PHP2Shellは、PHPの実行基盤に見つかった2件の脆弱性の総称です。CVE-2026-109618はメモリ不足（OOM）時のエラー処理に、CVE-2026-109619はリクエスト処理に関わる内部状態の管理に起因します。いずれも認証なしで遠隔からサーバー上の任意のコードを実行されるおそれがあり、PHPのセキュリティチームは2件ともCVSS v4.0で9.2と評価しています。修正版は10月21日に公開されました。</p>
<div style="overflow-x: auto; width: 100%;">
<table>
<thead>
<tr>
<th scope="col">PHPのバージョン系統</th>
<th scope="col">修正版</th>
<th scope="col">サポート状況</th>
</tr>
</thead>
<tbody>
<tr>
<td>PHP 8.2</td>
<td>8.2.35</td>
<td>2026年12月31日でサポート終了</td>
</tr>
<tr>
<td>PHP 8.3</td>
<td>8.3.36</td>
<td>セキュリティ修正のみ</td>
</tr>
<tr>
<td>PHP 8.4 / 8.5</td>
<td>8.4.27 / 8.5.12</td>
<td>サポート中</td>
</tr>
</tbody>
</table>
</div>
<p>注意したいのは、サポート切れの古いPHPだけが対象ではなかったことです。サポート中の8.2〜8.5系も、修正版より前はすべて影響を受けます。8.1以前には公式の修正版がなく、7.4・8.0・8.1向けに最小限の修正コードが出たのみです。IPAは、調査に関わったWiz社の情報として、PHP 5.4以降は少なくともいずれかの影響を受けると紹介しています。</p>
<p>悪用の状況について、IPAは10月27日の更新で、米国CISAが2件を「悪用が確認された脆弱性」の一覧（KEVカタログ）に追加したことを紹介し、国内での攻撃被害は把握していないとしています。攻撃が観測されたことと、実際に侵害された被害が確認されたことは、分けて受け止める必要があります。なお、JPCERT/CCは10月29日の更新で、あるファイアウォール製品の特定バージョンについて、侵害成功を示唆する痕跡が確認されたとの報告を紹介しています。</p>
<h3><span id="toc3">CVSSとは何か</span></h3>
<p>CVSS（Common Vulnerability Scoring System）は、脆弱性の深刻度を0.0〜10.0で評価する共通指標です。CVSS v4.0では7.0〜8.9が「High（重要）」、9.0〜10.0が「Critical（緊急）」で、PHP2Shellの9.2は最も深刻な区分に当たります。ただし、公表される基本評価値は、個々のシステムで実際に攻撃が成立するか、どの順に対処すべきかまでは示しません。</p>
<h3><span id="toc4">首相による注意喚起とWebサイトの一時停止</span></h3>
<p>高市首相は21日21時55分ごろ、Xで「今夜に対応して頂きたい大至急のお願い」としてパッチの適用準備を呼びかけ、適用が難しい場合は「ウェブサイト等を一時的に停止させることも、リスクを低減させるための有効策の一つ」と述べました。同じ夜、BASE、pixiv、niconico、DMM.comなどが予防的にメンテナンスに入ったと報じられています。</p>
<p>一般の利用者には前例のない非常事態に映ったかもしれません。しかし、OS、Webサーバー、Javaランタイム、RDBMSでも、重大な脆弱性は繰り返し報告されてきました。CVSS 9点台の脆弱性を調べ、緊急対応の要否を判断すること自体は、企業システムの運用では特別なことではありません。</p>
<h3><span id="toc5">PHPの普及範囲と管理体制の多様さ</span></h3>
<p>では、なぜ今回はこれほど大きな問題になったのか。背景の一つは普及範囲の広さです。W3Techsの調査（2026年10月29日時点）では、サーバー側の言語を判別できるWebサイトの69.2%がPHPを使っています。</p>
<p>もう一つは、システムの管理体制と更新可能性の違いです。専門の運用組織が管理するシステムもあれば、ホスティング事業者や制作会社に運用を任せているサイトもあります。</p>
<p>W3Techsの2026年10月31日時点の集計では、PHPを使うサイトの26.4%が7系、7.6%が5系でした。<strong>少なくとも約3分の1が、PHP本家のサポートを終了したEOL（End of Life）のバージョンを利用していた</strong>ことになります。EOLとは製品やバージョンのサポート終了を意味し、通常は開発元からセキュリティ修正が提供されなくなります。</p>
<p>私が携わってきた企業システムでは、OSやミドルウェアがEOLを迎える前に、更新や移行を計画することを基本としていました。やむを得ずEOL後も利用する場合には、延長サポートや攻撃経路の制限など、代替策と残存リスクを評価する必要があります。期限や対策を管理したうえでの継続利用と、更新されないまま残っている状態とでは、緊急時に取れる対応が異なります。</p>
<p>今回のPHP2Shellは、サポート中のバージョンにも影響した重大な脆弱性です。広く普及したPHPに問題が見つかり、通常の更新が難しい環境も相当数存在していたことが、騒動を大きくした要因の一つではないかと考えています。</p>
<h2><span id="toc6">重大な脆弱性への対応は、平時から設計している</span></h2>
<h3><span id="toc7">CVSSに応じた対応基準を準備する</span></h3>
<p>ここからは、私が実際に携わってきたシステムの運用を紹介します。すべてのSIerや企業システムが同じ水準にあるという意味ではなく、あくまで私の経験の範囲です。</p>
<p>私が関わったシステムでは、ベンダーのセキュリティアドバイザリ、IPAやJPCERT/CCの注意喚起、OSやミドルウェアの更新情報を継続的に監視し、管理対象の製品に関係する脆弱性を抽出していました。そのうえで、CVSSの重大度に応じた対応基準に照らし、対象サーバーの範囲、対応期限、緊急対応の要否を判断します。CVSS 9点台で緊急対応になることも、運用上の想定に含めて手順を整えていました。</p>
<p>ただし、CVSSは初期判断の材料です。9点台でも、攻撃に必要な機能を使っておらず成立条件がない場合があります。逆に8点台でも、インターネットから直接攻撃でき、すでに悪用が確認されているなら優先すべきです。<strong>脆弱性の重大度と、自分たちのシステムでの実際のリスクは、分けて評価する必要があります。</strong></p>
<h3><span id="toc8">業務重要度によって対応方法を変える</span></h3>
<p>もう一つの軸が業務重要度です。私が関わったシステムでは、業務への影響に応じて区分していました。以下に簡略化したイメージを示します。</p>
<div style="overflow-x: auto; width: 100%;">
<table>
<thead>
<tr>
<th scope="col">区分</th>
<th scope="col">特徴</th>
<th scope="col">緊急対応で重視すること</th>
</tr>
</thead>
<tbody>
<tr>
<td>超クリティカルな基幹系</td>
<td>停止が業務や顧客に大きな影響を及ぼす</td>
<td>継続性、安全な切替方法、代替手段</td>
</tr>
<tr>
<td>中間的な業務システム</td>
<td>短時間の計画停止であれば調整可能</td>
<td>停止時間の調整、影響範囲の確認</td>
</tr>
<tr>
<td>バックオフィス系</td>
<td>一時的な停止を許容できる</td>
<td>必要に応じた迅速な停止と確実な復旧</td>
</tr>
</tbody>
</table>
</div>
<p>この区分に脆弱性の攻撃可能性を組み合わせて判断します。停止できるシステムにCritical級の脆弱性があり、外部からの攻撃を防げないなら、止めて修正します。停止の影響が大きい基幹系では、冗長構成や代替手段で業務への影響を抑える方法を検討します。</p>
<p>ただし、冗長構成があるからといって、未修正のサーバーを攻撃可能なまま公開し続けてよいわけではありません。片系ずつ適用する場合も、未修正側の攻撃経路を遮断できることが前提です。安全な暫定策がなければ、基幹系でも緊急停止を選ぶ場合があります。</p>
<h3><span id="toc9">正常性確認まで事前に準備しておく</span></h3>
<p>特に重要だと考えているのが、パッチ適用後の正常性確認です。携わってきたシステムでは、業務重要度の区分ごとに正常性確認スクリプトとテスト項目一覧を整備していました。確認するのは、プロセスの稼働、Web/APサーバーからのDB接続、主要な業務画面やトランザクション、外部システムとの連携、ログ出力と監視、冗長構成での切替や負荷分散です。範囲と深さは、重要度と変更内容に応じて変えます。</p>
<p>緊急時の深夜に確認項目を一から洗い出せば、時間がかかり確認漏れも起きます。手順が手元にあれば、再開の判断を速く下せます。想定内とは、対応が楽に済むという意味ではありません。徹夜になっても、何をどの順に確認し、誰が再開を判断するかが決まっていることです。何から手を付けるか分からず、手探りで朝を迎える徹夜とは違います。</p>
<p>このような準備は運用設計の一部です。NISTのパッチ管理ガイド（SP 800-40 Rev.4）も、定期適用、緊急適用、緊急の緩和策、パッチを適用できない資産といった場面ごとに、対応を事前に計画することを推奨しています。パッチ・脆弱性管理に加え、起動停止や開局・閉塞などの具体的な設計項目は、運用設計書の目次サンプルを解説した次の記事で整理しています。</p>

<a href="https://sys-univ.com/dev/opedesign/" title="運用設計とは？運用設計書の目次サンプルと項目一覧｜システム基盤エンジニア視点" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-160x90.jpg 160w, https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-120x68.jpg 120w, https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-320x180.jpg 320w, https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">運用設計とは？運用設計書の目次サンプルと項目一覧｜システム基盤エンジニア視点</div><div class="blogcard-snippet internal-blogcard-snippet">運用設計とは何かをシステム基盤エンジニアの実務目線で解説します。運用設計書の目次サンプルと検討項目一覧を示し、監視・ログ・バックアップ・ジョブ管理、誰がやるのか、要件定義・基本設計との関係、処理方式設計との双方向連携を整理します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.14</div></div></div></div></a>
<h2><span id="toc10">CVSSが高くても、必ずパッチを適用するわけではない</span></h2>
<h3><span id="toc11">仮想事例：未使用の管理サービスにCVSS 8点台の脆弱性</span></h3>
<p>ここでは、パッチを当てるかどうかを判断する技術を、説明用の仮想事例で考えます。</p>
<p>あるミドルウェアの管理用サービスに、CVSS 8点台の脆弱性が公表されたとします。特定のTCPポートで待ち受ける管理サービスを通じて攻撃が成立しますが、このサービスは業務では使っていません。この場合、全サーバーへの即時適用の前に、成立条件を確認します。</p>
<ol>
<li><strong>影響条件の確認</strong>：対象製品、バージョン、機能、攻撃経路を確認する。</li>
<li><strong>対象サーバーの特定</strong>：管理台帳から、該当製品を使うサーバーを洗い出す。</li>
<li><strong>利用状況の確認</strong>：管理サービスを業務で使っていないことを、設計書と実機の設定で確認する。</li>
<li><strong>稼働状態の確認</strong>：管理サービスが起動していないことを確認する。</li>
<li><strong>不要サービスの停止</strong>：起動していれば停止し、自動起動も無効化する。</li>
<li><strong>有効性の確認</strong>：該当ポートが待ち受けていないこと、別の経路から同じ脆弱性を悪用できないことを確認する。</li>
<li><strong>記録と判断</strong>：実施内容と残存リスクを記録し、承認を経て緊急パッチの適用を見送る。</li>
</ol>
<h3><span id="toc12">パッチを適用しないことは、放置することではない</span></h3>
<p>この例で伝えたいのは、<strong>パッチを見送る判断にも技術的な根拠が必要</strong>だということです。攻撃経路が特定のサービスに限られ、そのサービスを確実に無効化できるなら、緊急のリスク低減策として成立する場合があります。</p>
<p>ただし、攻撃経路が実際に遮断されていることを確認できなければなりません。ポートを閉じただけでは、別のインターフェースから攻撃が成立する可能性も残ります。脆弱性そのものは残っているため、構成変更やサービスの再有効化でリスクは戻ります。緊急適用を見送っても、定期メンテナンスでの更新計画は別途必要です。すでに侵害されている疑いがあれば、停止とは別に調査も欠かせません。</p>
<p dir="ltr">「脆弱性のある製品を使っている」ことと「その脆弱性を悪用できる状態にある」ことは、必ずしも同じではありません。この違いを実際のシステム構成や設定から調べ、対応方針を決めるのが、システム基盤エンジニアの仕事です。</p>
<p dir="ltr">パッチを当てるか、代わりの対策で済ませるか、どのリスクを残すか。この判断の考え方は、システムを作るときのセキュリティ要件定義で行うリスクアセスメントと同じです。対策の選び方から、残存リスクを関係者と合意するところまでは、次の記事で詳しく解説しています。</p>

<a href="https://sys-univ.com/dev/security/" title="セキュリティ要件定義の進め方｜リスクアセスメントから対策・残存リスクを決める方法" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/09/a730f6ed9dc0d4e45d16222f81050c32-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/09/a730f6ed9dc0d4e45d16222f81050c32-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/09/a730f6ed9dc0d4e45d16222f81050c32-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/09/a730f6ed9dc0d4e45d16222f81050c32-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/09/a730f6ed9dc0d4e45d16222f81050c32-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">セキュリティ要件定義の進め方｜リスクアセスメントから対策・残存リスクを決める方法</div><div class="blogcard-snippet internal-blogcard-snippet">セキュリティ要件定義を、RFPや上位基準を起点に、リスクアセスメント、差異評価、対策、残存リスクまで具体化する方法を解説。脅威・脆弱性の分析、関係者との合意、変更時の再アセスメントまで実務例で整理します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.09.17</div></div></div></div></a>
<h2><span id="toc13">PHP2Shellなら、現場ではどう対応するか</span></h2>
<h3><span id="toc14">PHPの採用領域と運用体制の違い</span></h3>
<p>まず、PHPがどのようなシステムで使われているかを整理します。</p>
<div style="overflow-x: auto; width: 100%;">
<table>
<thead>
<tr>
<th scope="col">領域</th>
<th scope="col">主な特徴</th>
</tr>
</thead>
<tbody>
<tr>
<td>従来型エンタープライズ基幹系</td>
<td>Java、.NET、COBOLなどの技術資産が多く、長期的な運用管理が重視される</td>
</tr>
<tr>
<td>一般Webサイト・CMS</td>
<td>WordPressなどを通じてPHPが普及し、管理主体や保守体制が多様</td>
</tr>
<tr>
<td>SaaS・EC・Webサービス</td>
<td>PHPが注文、在庫、契約など、事業の中核となる処理を担う場合がある</td>
</tr>
</tbody>
</table>
</div>
<p>たとえばBASEは、PHPによる大規模な商用ECを継続的にリアーキテクチャしてきた経緯を技術ブログで公開しています。システムの種類だけで管理水準が決まるわけではなく、SIerが管理するシステムにも古い環境は残り、一般のWebサイトにも高度な管理をしている例はあります。今回問われたのは、実行環境を誰が管理し、どれだけ迅速に更新できるかでした。</p>
<h3><span id="toc15">影響対象はアプリケーションではなくPHPランタイム</span></h3>
<p>PHP2Shellは、PHP本体の脆弱性です。WordPressやLaravelを更新しても解消しません。確認すべきなのは、実際にWebリクエストを処理しているPHPのバージョンと実行方式です。</p>
<p>PHP公式は、PHP-FPM、Apacheのmod_php、php-cgi、FrankenPHP、LiteSpeedなどを影響対象に挙げています。mod_phpではアプリケーションのコードが動く前に攻撃が成立することが実証され、最もリスクが高いとされました。PHP-FPMでも、CVE-2026-109619で条件付きの攻撃成立が確認されています。設定変更で一部の経路は減らせますが、PHP公式は完全な緩和策はないとし、更新を強く求めています。</p>
<h3><span id="toc16">仮想事例：LB配下の公開Webシステム</span></h3>
<p>ここからは説明用の仮想事例です。インターネットに公開されたWebシステムで、ロードバランサー（LB）の配下に複数台のWeb/APサーバーがあり、それぞれでPHPが動いているとします。DBや外部APIと接続しており、一時的なサービス停止は業務上許容できます。私なら、次の流れを基本に検討します。</p>
<div style="overflow-x: auto; width: 100%;">
<table>
<thead>
<tr>
<th scope="col">段階</th>
<th scope="col">対応内容</th>
<th scope="col">主な確認事項</th>
</tr>
</thead>
<tbody>
<tr>
<td>① 影響調査</td>
<td>PHPのバージョン、実行方式、公開経路、対象サーバーを確認</td>
<td>実際に稼働するPHPが影響対象か</td>
</tr>
<tr>
<td>② 停止判断</td>
<td>攻撃リスクと停止による業務影響を評価</td>
<td>公開の継続を許容できるか</td>
</tr>
<tr>
<td>③ 公開の閉塞</td>
<td>LBをSorry画面に切り替える</td>
<td>バックエンドへの迂回経路がないか</td>
</tr>
<tr>
<td>④ 修正適用</td>
<td>全対象ノードへ修正版を適用</td>
<td>修正済みのランタイムが稼働しているか</td>
</tr>
<tr>
<td>⑤ 安全性・正常性確認</td>
<td>侵害調査と業務動作の確認</td>
<td>セキュリティ上・業務上の問題がないか</td>
</tr>
<tr>
<td>⑥ 再公開</td>
<td>LB配下へ段階的に戻す</td>
<td>エラーや性能劣化が発生していないか</td>
</tr>
</tbody>
</table>
</div>
<h4><span id="toc17">①〜③ 影響を調査し、必要なら公開を止める</span></h4>
<p>構成管理台帳だけでなく実際の稼働環境と照合して、どのサーバーでPHPが動いているかを確認します。攻撃可能で修正まで安全を確保できなければ、LBでSorry画面に切り替えます。Sorry画面はPHPに依存しないLBの固定応答や静的コンテンツで返し、Web/APサーバーへの直接アクセス、管理用の別ポート、公開API、IPv6など、LBを迂回する経路も確認します。</p>
<h4><span id="toc18">④ パッチを適用し、実際の稼働状態を確認する</span></h4>
<p>見落としやすいのがこの段階です。パッケージを更新しても、PHP-FPMやApacheを再起動しなければ古いランタイムが動き続けます。Webサーバーが使うPHPとコマンドラインのPHPで、バージョンが異なることもあります。コンテナは修正版のイメージで置き換え、オートスケールの起動テンプレートも更新しなければ、後から増えたサーバーが修正前の状態で立ち上がります。ディストリビューションが修正をバックポートしている場合は、表示バージョンではなくベンダーのアドバイザリやパッケージの修正履歴で判断します。</p>
<h4><span id="toc19">⑤ セキュリティ確認と正常性確認を行う</span></h4>
<p>修正前に侵害を受けていなかったかも調べます。JPCERT/CCは、不自然に長い、または異常な形式のPHPSESSID Cookie、不審なmultipart/form-data形式のリクエストとその前後のメモリ上限エラーやHTTP 500、PHPワーカーの異常終了や頻繁な再起動の3点の確認を推奨しています。痕跡がないことは侵害がなかった証明にはならず、疑わしい兆候があれば証拠保全や再構築も検討します。</p>
<p data-pm-slice="1 1 []">パッチ適用後は、既存機能に不具合が生じていないかを確認するデグレード確認（無影響確認）が必要です。私が携わったシステムでは、この確認のために正常性確認スクリプトとテスト項目一覧を平時から作成・整備していました。今回のようなケースでも、それらを使ってDB接続、主要業務画面、外部連携、ログ出力や監視の動作を確認する想定です。ただし、すべてのケースで正常性確認スクリプトで対応できわけるではなく、事象事に適用可否を検討します。</p>
<h4><span id="toc20">⑥ LB配下へ段階的に再公開する</span></h4>
<p>修正済みのノードを1台ずつLB配下に戻し、エラー率、応答時間、CPU使用率、DB接続数を見ながら範囲を広げます。これは全対象ノードの安全を確保したうえでの段階的な復旧であり、未修正のサーバーを公開したまま順番にパッチを当てるという意味ではありません。</p>
<h3><span id="toc21">PHPだけに特別な対処をしているわけではない</span></h3>
<p>この流れはPHPに固有のものではありません。Javaのランタイムでも、Webサーバーでも、OSやRDBMSでも、影響を確認し、リスクを評価して対策を選び、安全と業務の両面を確かめて再開する考え方は共通です。差を生むのは、判断基準と確認手順を平時から持っているかどうかです。</p>
<p dir="ltr">こうした判断と準備は、システム基盤エンジニアの日常業務の延長にあります。平時に構成と手順を整え、稼働を保ち、いざというときには安全な状態へ戻す。基盤エンジニアの仕事の全体像は、次の記事で紹介しています。</p>

<a href="https://sys-univ.com/dev/system-infrastructure-engineer/" title="システム基盤・クラウドエンジニアの仕事｜整える、保つ、戻す" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">システム基盤・クラウドエンジニアの仕事｜整える、保つ、戻す</div><div class="blogcard-snippet internal-blogcard-snippet">システム基盤エンジニアの仕事内容を、インフラエンジニアとの違いから実務まで解説。サイジング、標準化、監視、可用性、バックアップ、AWS移行、障害対応を大規模SIの実例を交えて紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.17</div></div></div></div></a>
<h2><span id="toc22">脆弱性対応で本当に重要なのは、更新できる状態を維持すること</span></h2>
<h3><span id="toc23">緊急時に「すぐ更新できない」理由</span></h3>
<p>今回は、サポート終了バージョンへの対応も課題になりました。8.1以前は公式の修正版がなく、サポート中の版への移行にはアプリケーションやプラグインの互換性確認と改修が必要です。長く更新されていないシステムでは、設計資料が不足していたり、当時の担当者がいなかったり、保守契約が終わっていたりもします。IPAも今回の注意喚起で、こうした理由で更新が難しくなる場合があると指摘しています。パッチが出ても、安全に適用できるとは限らないのです。</p>
<p>こうした事態を避けるため、企業システムではOSやミドルウェアのサポート終了を見据え、計画的にバージョンアップやシステム更改を行います。重大な脆弱性が見つかってから更新方法を検討するのではなく、平時から更新可能な状態を維持しておくことが重要です。</p>
<p>保守終了を契機としたシステム更改については、システム更改で学ぶ、プログラミングだけではない仕事の全体像で、基盤設計からテスト、移行までの進め方を解説しています。</p>

<a href="https://sys-univ.com/dev/base2/" title="【システム開発とは何か】システム更改で学ぶ、プログラミングだけではない仕事の全体像" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-160x90.jpg 160w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-500x281.jpg 500w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-800x450.jpg 800w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-300x169.jpg 300w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-768x432.jpg 768w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-1536x864.jpg 1536w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-120x68.jpg 120w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-320x180.jpg 320w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f-376x212.jpg 376w, https://sys-univ.com/wp-content/uploads/2022/01/661447202f61355a29b111a9031b127f.jpg 1672w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【システム開発とは何か】システム更改で学ぶ、プログラミングだけではない仕事の全体像</div><div class="blogcard-snippet internal-blogcard-snippet">システム開発はプログラミングだけではありません。A銀行のクラウドリフトを例に、現行調査、基盤設計、データ移行、テスト、運用引継ぎ、ステークホルダーや責任共有モデルまで、初心者向けに解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.07.17</div></div></div></div></a>
<h3><span id="toc24">更新できる状態を維持することも運用設計</span></h3>
<p>迅速に動くには、平時から次の状態を保つ必要があります。使っているOSやミドルウェアの製品とバージョン、サポート期限を把握していること。パッチ適用時の影響範囲を確認でき、正常性確認手順が整っていること。サービスの停止と再開の判断基準と責任者が決まっていること。そして、更新後の監視と復旧の手順を用意していることです。</p>
<p>これらは脆弱性が見つかってから短期間で整えられるものではありません。正常性確認の手順も、機能追加や構成変更に合わせて更新し続けて初めて、緊急時に使えるものになります。</p>
<h3><span id="toc25">脆弱性対応とは、パッチを当てる作業ではない</span></h3>
<p>重大な脆弱性への緊急対応を「想定内」にできるのは、重大な脆弱性が見つかることを前提に、情報収集から対応基準、対象の特定、適用の要否、正常性確認、再開までを平時に準備しているからです。成立条件を確実に排除できるなら緊急パッチを見送る判断もあり、PHP2Shellのように攻撃リスクが高く修正まで安全を確保できなければ、一時停止も合理的な選択です。どちらも、脆弱性の特徴と実際のシステム構成を確かめたうえで下す判断です。</p>
<p>PHP2Shellが社会問題になった背景には、普及範囲の広さに加え、管理体制や更新のしやすさがシステムごとに異なるという事情がありました。これはPHPに限った話ではありません。</p>
<p><strong>脆弱性対応とは、単にパッチを当てる作業ではありません。影響を調査し、対策を選択し、安全に業務を継続・再開するための運用設計なのです。</strong></p>
<h2><span id="toc26">参考文献</span></h2>
<ol>
<li>IPA「PHPの脆弱性対策について（CVE-2026-109618、CVE-2026-109619：PHP2shell）」（2026年10月22日公開、10月27日更新） <a href="https://www.ipa.go.jp/security/security-alert/2026/alert20261022.html">https://www.ipa.go.jp/security/security-alert/2026/alert20261022.html</a></li>
<li>IPA「【事前準備のお願い】PHPのセキュリティリリース公開予定について」（2026年10月21日） <a href="https://www.ipa.go.jp/security/security-alert/2026/pre-alert20261021.html">https://www.ipa.go.jp/security/security-alert/2026/pre-alert20261021.html</a></li>
<li>PHP公式「Security advisory: Critical remote code execution vulnerabilities, update now」（2026年10月21日） <a href="https://www.php.net/archive/2026.php#2026-10-21-5">https://www.php.net/archive/2026.php#2026-10-21-5</a></li>
<li>PHP公式「Supported Versions」 <a href="https://www.php.net/supported-versions.php">https://www.php.net/supported-versions.php</a></li>
<li>JPCERT/CC「PHPにおける複数の脆弱性（CVE-2026-109618、CVE-2026-109619）に関する注意喚起」（2026年10月22日公開、10月29日更新） <a href="https://www.jpcert.or.jp/at/2026/at260033.html">https://www.jpcert.or.jp/at/2026/at260033.html</a></li>
<li>FIRST「Common Vulnerability Scoring System Version 4.0」 <a href="https://www.first.org/cvss/v4.0/">https://www.first.org/cvss/v4.0/</a></li>
<li>NIST「Guide to Enterprise Patch Management Planning, SP 800-40 Rev.4」 <a href="https://csrc.nist.gov/pubs/sp/800/40/r4/final">https://csrc.nist.gov/pubs/sp/800/40/r4/final</a></li>
<li>W3Techs「Usage statistics of PHP」 <a href="https://w3techs.com/technologies/details/pl-php">https://w3techs.com/technologies/details/pl-php</a></li>
<li>BASEプロダクトチームブログ「事業継続のためにPHPを使ったサービスを継続的に進化させていくこと」 <a href="https://devblog.thebase.in/entry/leverage_php">https://devblog.thebase.in/entry/leverage_php</a></li>
<li>ITmedia NEWS「高市総理『大至急、PHPパッチ適用を』Xで異例の要請」（2026年10月22日） <a href="https://www.itmedia.co.jp/news/article/2610/22/2000002483/">https://www.itmedia.co.jp/news/article/2610/22/2000002483/</a></li>
<li>Impress Watch「国内大手サービスで緊急メンテやサービス停止 PHP脆弱性で対策」（2026年10月21日） <a href="https://watch.impress.co.jp/docs/news/2150159.html">https://watch.impress.co.jp/docs/news/2150159.html</a></li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/dev/php2shell-vulnerability-response/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>OracleのLIKE検索でほぼ全件ヒット？全角アンダースコアの不具合とSQL改修・再発防止の実例</title>
		<link>https://sys-univ.com/incident/oracle-like-fullwidth-underscore/</link>
					<comments>https://sys-univ.com/incident/oracle-like-fullwidth-underscore/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 10:20:39 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[テクノロジー]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=3506</guid>

					<description><![CDATA[データベースの検索結果が想定より多いとき、SQLの書き方だけを疑っていないでしょうか。検索条件が正しく見えても、データ型や文字セット、データベースのリリースによって文字の解釈が変わることがあります。 ある処理で、全角アン [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">データベースの検索結果が想定より多いとき、SQLの書き方だけを疑っていないでしょうか。検索条件が正しく見えても、データ型や文字セット、データベースのリリースによって文字の解釈が変わることがあります。</p>


<p class="wp-block-paragraph">ある処理で、全角アンダースコア「＿」を含むデータを探したところ、意図しない大量のレコードが検索対象になる事象が発生しました。調査では、公開されていたサポート情報と実機の動作が食い違い、最終的にOracle側の不具合と確認されました。しかし、製品側に修正があるからといって、パッチ適用がプロジェクトの最適解とは限りません。</p>


<p class="wp-block-paragraph">本記事では、<strong>事象の把握→原因の切り分け→対策の比較→実施→効果確認→再発防止</strong>の過程を紹介します。あわせて、Oracle Database 19cの公式仕様に基づく現在の書き方と、読者自身が確認するための検証SQLを示します。</p>


<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>先に結論：Oracle 19cでのLIKE検索</strong></p>


<ul class="wp-block-list">
	<li>ワイルドカードは半角の<code>%</code>（0文字以上）と<code>_</code>（1文字）。全角の<code>％</code>と<code>＿</code>は通常の文字として扱うのが公式仕様です。</li>


	<li>利用者が入力した半角<code>%</code>・<code>_</code>を文字として探すときは、<code>ESCAPE</code>句で明示的にエスケープします。バインド変数だけではワイルドカード化を防げません。</li>


	<li>過去の案件で採用した<code>LIKEC</code>への一律変更は、19cでの一般的な推奨規約ではありません。照合順序・データ型も含めて、<strong>実際に使用するDB環境で検証して判断します</strong>。</li>
</ul>


<p class="wp-block-paragraph">※障害事例は特定リリースの記録ですが、Oracle 19cの説明・SQL例は公式仕様に基づいており、筆者は19c実機での再現・効果検証を実施していません。利用するリリース、文字セット、データ型、照合順序で読者自身が検証してください。</p>
</blockquote>



  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">1. 事象発生：全角アンダースコアの検索で想定外の大量ヒット</a><ol><li><a href="#toc2" tabindex="0">何を検索したかったのか</a></li><li><a href="#toc3" tabindex="0">半角・全角の違いは目視では分かりにくい</a></li></ol></li><li><a href="#toc4" tabindex="0">2. 現状把握・原因調査：仕様、データ型、実機結果を突き合わせる</a><ol><li><a href="#toc5" tabindex="0">まず再現条件を小さくする</a></li><li><a href="#toc6" tabindex="0">サポート文書と実測結果が一致しなかった</a></li></ol></li><li><a href="#toc7" tabindex="0">3. 対策の立案・評価：ORA-01424と将来互換性まで比較する</a><ol><li><a href="#toc8" tabindex="0">対策を「直せるか」ではなく「全体コスト」で比べる</a></li><li><a href="#toc9" tabindex="0">ORA-01424を生んだのはどの書き方か</a></li><li><a href="#toc10" tabindex="0">なぜLIKECをSQL規約として採用したのか――保守サポートと技術的な認識をそろえる</a></li><li><a href="#toc11" tabindex="0">今回パッチを見送り、SQL規約と運用回避を選んだ理由</a></li></ol></li><li><a href="#toc12" tabindex="0">4. 対策の実施：変更範囲を絞り、SQL規約と運用を整える</a><ol><li><a href="#toc13" tabindex="0">改修対象と運用対象を分けて展開する</a></li><li><a href="#toc14" tabindex="0">GLの役割は、技術評価と業務上の判断をつなぐこと</a></li></ol></li><li><a href="#toc15" tabindex="0">5. 効果の確認：検索結果の正しさと将来互換性を確認する</a><ol><li><a href="#toc16" tabindex="0">SQLの実行可否・検索結果・将来互換性を確認する</a></li></ol></li><li><a href="#toc17" tabindex="0">6. 歯止め：個別対処をプロジェクト全体のルールにする</a><ol><li><a href="#toc18" tabindex="0">SQL規約に判断結果を反映する</a></li><li><a href="#toc19" tabindex="0">再発防止は「注意喚起」で終わらせない</a></li></ol></li><li><a href="#toc20" tabindex="0">7. Oracle 19cではどう書くか：LIKE・ESCAPE・照合順序</a><ol><li><a href="#toc21" tabindex="0">Oracle 19cの公式仕様では全角は通常の文字</a></li><li><a href="#toc22" tabindex="0">入力値のワイルドカードはバインド変数だけでは防げない</a></li><li><a href="#toc23" tabindex="0">実機で確認するSQL：VARCHAR2とNVARCHAR2を比較</a></li><li><a href="#toc24" tabindex="0">照合順序によって文字の一致判定が変わる場合がある</a></li></ol></li><li><a href="#toc25" tabindex="0">8. まとめ：サポートと根拠をそろえ、説明できる対策を選ぶ</a><ol><li><a href="#toc26" tabindex="0">参考資料</a></li></ol></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">1. 事象発生：全角アンダースコアの検索で想定外の大量ヒット</span></h2>


<h3 class="wp-block-heading"><span id="toc2">何を検索したかったのか</span></h3>


<p class="wp-block-paragraph">アプリケーションでは、データに含まれる全角アンダースコア「＿」を、<strong>文字そのもの</strong>として検索したいという要件がありました。ところが、問題が発生したOracle Database 11.2.0.1環境では、次のような検索が想定外の結果になりました。</p>


<pre class="wp-block-code"><code>-- 過去の障害を説明するために匿名化したSQL
-- 両端の % は半角、中央の ＿ は全角
SELECT *
FROM TEST
WHERE EFG LIKE '%＿%';
</code></pre>


<p class="wp-block-paragraph">本来は「全角アンダースコア（＿）を含む行」だけを検索するはずでした。ところが、当時のOracle環境では、全角＿が「任意の1文字」を表すワイルドカードとして扱われる不具合がありました。</p>
<p>この結果、<code>LIKE '%＿%'</code> という条件で、全角＿を含まない1文字以上の値まで一致し、ほぼ全件がヒットしてしまいました。</p>
<p><strong>問題は、検索結果が誤るだけでなく、不要なデータまで検索対象となり、処理負荷も増大することです。</strong> 実際、この案件でも性能問題をきっかけに調査を開始しました。</p>


<h3 class="wp-block-heading"><span id="toc3">半角・全角の違いは目視では分かりにくい</span></h3>


<figure class="wp-block-table">
<table class="has-fixed-layout">
<thead>
<tr>
<th>文字</th>
<th>表示</th>
<th>本来の役割（19cの標準仕様）</th>
</tr>
</thead>
<tbody>
<tr>
<td>半角パーセント</td>
<td><code>%</code></td>
<td>0文字以上に一致するワイルドカード</td>
</tr>
<tr>
<td>半角アンダースコア</td>
<td><code>_</code></td>
<td>ちょうど1文字に一致するワイルドカード</td>
</tr>
<tr>
<td>全角パーセント</td>
<td><code>％</code></td>
<td>通常の文字</td>
</tr>
<tr>
<td>全角アンダースコア</td>
<td><code>＿</code></td>
<td>通常の文字</td>
</tr>
</tbody>
</table>
</figure>


<p class="wp-block-paragraph">SQLのレビュー画面では、特に半角<code>_</code>と全角<code>＿</code>を見落としやすくなります。また、問題の本質は「全角文字が常にワイルドカードになる」ことではありません。過去の検証記録では、<strong>パターンに半角の<code>%</code>や<code>_</code>が混在したとき、全角<code>％</code>・<code>＿</code>がワイルドカードとして動作する現象</strong>が問題となりました。</p>


<h2 class="wp-block-heading"><span id="toc4">2. 現状把握・原因調査：仕様、データ型、実機結果を突き合わせる</span></h2>


<h3 class="wp-block-heading"><span id="toc5">まず再現条件を小さくする</span></h3>


<p class="wp-block-paragraph">障害対応では、いきなり本番SQLを広範囲に修正するのではなく、現象を小さな表と短いSQLで再現します。この案件でも、<code>CHAR</code>、<code>NCHAR</code>、<code>NVARCHAR2</code>、<code>VARCHAR2</code>を使い、半角・全角のアンダースコアを格納したテストデータで挙動を確認しました。</p>


<p class="wp-block-paragraph">調査の観点は、次の4つに分けられます。</p>


<figure class="wp-block-table">
<table class="has-fixed-layout">
<thead>
<tr>
<th>確認項目</th>
<th>確認の目的</th>
<th>具体例</th>
</tr>
</thead>
<tbody>
<tr>
<td>検索文字</td>
<td>半角・全角の混同がないか</td>
<td><code>%</code>と<code>％</code>、<code>_</code>と<code>＿</code>を区別</td>
</tr>
<tr>
<td>データ型</td>
<td>列と検索パターンの変換があるか</td>
<td><code>VARCHAR2</code>、<code>NVARCHAR2</code>など</td>
</tr>
<tr>
<td>文字セット</td>
<td>各国語キャラクタセットの条件</td>
<td><code>NLS_NCHAR_CHARACTERSET</code>を確認</td>
</tr>
<tr>
<td>SQLの種類</td>
<td>比較方式とESCAPEの影響</td>
<td><code>LIKE</code>と<code>LIKEC</code>を比較</td>
</tr>
</tbody>
</table>
</figure>


<p class="wp-block-paragraph">各国語キャラクタセットは、例えば次のSQLで確認できます。</p>


<pre class="wp-block-code"><code>SELECT parameter, value
FROM NLS_DATABASE_PARAMETERS
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
</code></pre>


<p class="wp-block-paragraph">過去のサポート調査では、各国語キャラクタセットが固定幅かどうかも論点になりました。再現性を評価するときは、実際の環境で確認した文字セット名と、対象列の型を記録します。</p>


<h3 class="wp-block-heading"><span id="toc6">サポート文書と実測結果が一致しなかった</span></h3>


<p class="wp-block-paragraph">当時のサポート情報には、特定の<code>NCHAR</code>・<code>NVARCHAR2</code>環境では、全角の<code>％</code>をワイルドカードとして扱わないという説明がありました。しかし、検証環境では半角記号との組合せなどにより、説明と一致しない結果が得られました。</p>


<p class="wp-block-paragraph">サポート窓口への初期問い合わせでは、特定リリースの「仕様」とする説明が提示されました。しかし、当時のサポート文書では全角記号をワイルドカードとして扱わないと説明されている一方、手元の実機では半角記号が混じると一致範囲が広がりました。<strong>私は、仕様の説明だけでは今回のSQL実行結果を説明できないと考えました。</strong> そこでSQL、データ型、再現条件、エラーを具体的に提示し、継続調査を依頼しました。その後、Oracle側から<strong>製品の不具合に起因する事象と考えられる</strong>との回答があり、11.2.0.4で修正済みと報告されました。</p>


<p class="wp-block-paragraph">ここで重要なのは「メーカーの回答を疑う」という姿勢ではありません。<strong>文書の記述と実測が異なる場合に、同じ条件で再現できる証拠をそろえ、技術的な説明がつくまで調べること</strong>です。技術的な事実を確定させると、対策を比較する土台ができます。</p>


<h2 class="wp-block-heading"><span id="toc7">3. 対策の立案・評価：ORA-01424と将来互換性まで比較する</span></h2>


<h3 class="wp-block-heading"><span id="toc8">対策を「直せるか」ではなく「全体コスト」で比べる</span></h3>


<p class="wp-block-paragraph">原因が製品不具合だと分かると、パッチ適用が第一候補に見えます。しかし、稼働中システムのパッチ適用では、問題の検索処理以外の業務機能にも影響しないかを確認する必要があります。今回の案件では、パッチの適用作業そのものより、<strong>広範囲の影響調査・回帰テスト・リリース調整にかかる工数</strong>が大きいと評価しました。</p>


<p class="wp-block-paragraph">複数の業務グループを集めてアクション会議を開催し、方式・基盤側が技術評価・再現検証を主導、業務側には影響範囲と運用上の回避可否の確認を依頼しました。GLとして、技術的な正しさに加え、PMと業務側が費用・リスク・運用制約を含めて選択できるよう整理したのです。</p>


<figure class="wp-block-table">
<table class="has-fixed-layout">
<thead>
<tr>
<th>対策候補</th>
<th>長所</th>
<th>案件での評価・採用範囲</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A. パッチセット適用</strong></td>
<td>製品不具合そのものの修正が期待できる</td>
<td>DB全体の影響調査・回帰テストが大きい。今回の障害対応を目的とする適用は見送る</td>
</tr>
<tr>
<td><strong>B. <code>LIKE</code>＋全角記号の<code>ESCAPE</code></strong></td>
<td>一見、修正量を限定できる</td>
<td>11.2.0.1の再現SQLですでに<code>ORA-01424</code>。有効な回避策にならない</td>
</tr>
<tr>
<td><strong>C. <code>LIKEC</code>への変更とエスケープ方式の整理</strong></td>
<td>旧環境では<code>LIKEC</code>＋全角エスケープが動作し、保守サポートもSQL書き換えを回避策として提示。原因と対策候補について技術的な認識をそろえられた</td>
<td><strong>新規・改修SQLの記述方針として採用</strong>。将来の修正済みリリースで問題になる全角エスケープは規約で禁止。既存処理の残存リスクには運用回避を併用</td>
</tr>
<tr>
<td><strong>D. 運用回避</strong></td>
<td>大量の既存SQL改修を避け、限定的な対象データ・業務だけで対応できる</td>
<td><strong>改修工数が大きく、対象データが少ない既存機能で採用</strong>。回避手順と影響範囲を業務側と共有し、SQL規約と組み合わせて案件として対応</td>
</tr>
</tbody>
</table>
</figure>


<p class="wp-block-paragraph">これは特定案件での費用・リスク評価です。パッチにセキュリティ修正が含まれる場合、サポート要件がある場合などは、別の結論になることがあります。</p>


<h3 class="wp-block-heading"><span id="toc9">ORA-01424を生んだのはどの書き方か</span></h3>


<p class="wp-block-paragraph">実機確認で明らかになったのは、<strong>「全角記号をエスケープする」という方針自体が、リリースの違いによって成立しなくなる</strong>ことでした。</p>


<pre class="wp-block-code"><code>-- 旧リリース（11.2.0.1）では ORA-01424 を確認
SELECT * FROM TEST WHERE EFG LIKE '%\＿%' ESCAPE '\';

-- 同じ旧リリースで実行できた、LIKEC＋全角エスケープ
SELECT * FROM TEST WHERE EFG LIKEC '%\＿%' ESCAPE '\';

-- ただし上のLIKEC文は11.2.0.4の検証環境では ORA-01424
</code></pre>


<figure class="wp-block-table">
<table class="has-fixed-layout">
<thead>
<tr>
<th>SQL方式・パターン</th>
<th>11.2.0.1での記録</th>
<th>11.2.0.4での記録・仕様</th>
<th>判断</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>LIKE '%\＿%' ESCAPE '\'</code></td>
<td><code>ORA-01424</code></td>
<td>全角記号はリテラルとなり、同じエスケープは無効</td>
<td>旧環境の対策にはできない</td>
</tr>
<tr>
<td><code>LIKEC '%\＿%' ESCAPE '\'</code></td>
<td>実行できた</td>
<td><code>ORA-01424</code>を実機確認</td>
<td>将来互換性がない</td>
</tr>
<tr>
<td><code>LIKEC '%＿%'</code>（全角をエスケープしない）</td>
<td>半角・全角が混在する旧環境の検索条件では、SQL記述の統一だけでリスクをなくせない</td>
<td>全角<code>＿</code>を通常文字として扱う仕様</td>
<td><strong>新規・改修SQLの規約として採用</strong>。旧環境で影響を受ける既存処理は運用回避と組み合わせ、案件の対応目的を達成</td>
</tr>
<tr>
<td><code>LIKE '%＿%'</code>（全角をエスケープしない）</td>
<td>半角<code>%</code>との組合せで想定外にヒット</td>
<td>全角<code>＿</code>を通常文字として扱う仕様</td>
<td>修正済みリリースでは基本形</td>
</tr>
</tbody>
</table>
</figure>


<p class="wp-block-paragraph"><code>ORA-01424</code>が発生するのは、<code>ESCAPE '\'</code>に指定したエスケープ文字の次に、リテラル化の対象となる半角<code>%</code>・<code>_</code>やエスケープ文字自身ではなく、通常文字である全角<code>＿</code>が続くためです。<strong>修正前に成立した「全角記号のエスケープ」が、修正後には無効な指定になる</strong>ことを理解する必要があります。</p>


<p class="wp-block-paragraph">対策を採用する前に、<strong>修正対象の現行環境だけでなく、将来のアップグレード先でも同じSQLが成立するか</strong>を確認したことが、二度の改修を避けるうえで重要でした。</p>


<h3 class="wp-block-heading"><span id="toc10">なぜLIKECをSQL規約として採用したのか――保守サポートと技術的な認識をそろえる</span></h3>


<p class="wp-block-paragraph">今回重視したのは、<code>LIKE</code>と<code>LIKEC</code>のどちらが一般的に優れているかではありません。調査では、旧環境の<code>NCHAR</code>・<code>NVARCHAR2</code>列に対し、<code>LIKE</code>に全角エスケープを付けると<code>ORA-01424</code>になる一方、<code>LIKEC</code>なら実行できる組合せを確認しました。保守サポートからも<code>LIKEC</code>への書き換えが回避策として提示され、<strong>原因、成立する回避方法、リリースによる挙動の違いについて、サポートと技術的な認識をそろえることができました。</strong></p>


<p class="wp-block-paragraph">ただし、将来のアップグレード後には、全角記号をエスケープした<code>LIKEC</code>が<code>ORA-01424</code>になることも実機で確認しました。そこでプロジェクトのSQL規約では、<strong>「パターンマッチングには<code>LIKEC</code>を使い、半角<code>%</code>・<code>_</code>を文字として探す場合にエスケープする。全角<code>％</code>・<code>＿</code>はエスケープしない」</strong>という方針を定めました。</p>


<p class="wp-block-paragraph">この規約は、旧環境に存在した全角記号の問題をすべてSQLだけで解消するという意味ではありません。今回の対応目的を、<strong>新規・改修SQLの記述を統一すること、影響のある既存機能のリスクを抑えながら業務を継続すること、将来のアップグレード時に同じ箇所を再改修しないこと</strong>と定め、改修量が大きい一方で対象データが限定的な部分には運用回避を併用しました。</p>


<p class="wp-block-paragraph"><strong>この対策で目的を達成できることについて、保守サポートから得た技術的根拠を持ち、PMや業務側に説明して実施方針の合意につなげられたことが重要です。</strong> 自分たちの推測だけではなく、問い合わせ結果と実機検証に基づいて判断したことは、後から対応理由を説明する際にも役立ちます。保守サポートが確認したのは製品動作と回避策に関する技術的見解であり、改修・運用回避の適用範囲や工数の判断はプロジェクト側の責任で決めました。</p>


<h3 class="wp-block-heading"><span id="toc11">今回パッチを見送り、SQL規約と運用回避を選んだ理由</span></h3>


<p class="wp-block-paragraph">今回の障害への個別対処としてパッチを当てることは選択しませんでした。製品修正を適用すれば問題箇所は直っても、影響調査を対象SQLだけで済ませられず、調査・試験の総コストが大きかったためです。</p>


<p class="wp-block-paragraph">一方、SQL修正であれば対象機能を絞って検証できます。ただし、既存SQLの改修箇所が膨大なのに、問題となるデータや利用場面が少ない場合は、改修・試験の工数が効果に見合いません。そこで<strong>影響の大きさと対象データの量、運用で吸収できる負担を比較し、必要なSQL修正と運用回避を使い分ける</strong>方針を選びました。新規・改修SQLには<code>LIKEC</code>の規約を適用し、既存機能のうち費用対効果が見合わない範囲は運用面で対処します。</p>


<h2 class="wp-block-heading"><span id="toc12">4. 対策の実施：変更範囲を絞り、SQL規約と運用を整える</span></h2>


<h3 class="wp-block-heading"><span id="toc13">改修対象と運用対象を分けて展開する</span></h3>


<p class="wp-block-paragraph">SQL規約を改訂し、パターンマッチングには<code>LIKEC</code>を利用すること、半角の<code>%</code>と<code>_</code>をリテラルとして検索するときはエスケープすること、全角の<code>％</code>と<code>＿</code>にはエスケープを付けないことを定めました。新規・改修SQLではこの方針を使い、既存機能については改修の費用対効果と業務影響を見て対応方法を選びました。</p>


<p class="wp-block-paragraph">SQL改修が膨大でも、対象データが限られ、現場で無理なく回避できるなら、運用対応の方が合理的な場合があります。運用回避を選んだ機能については、対象条件と対処手順を業務側に周知する必要があります。</p>


<h3 class="wp-block-heading"><span id="toc14">GLの役割は、技術評価と業務上の判断をつなぐこと</span></h3>


<p class="wp-block-paragraph">今回、複数の業務グループを集めたアクション会議で、影響調査と対応の方向性を整理しました。方式・基盤側がSQLの再現検証と対策評価を主導し、業務側には対象機能や対象データ、運用回避の可否を確認してもらいました。</p>


<p class="wp-block-paragraph">PMへの説明では、パッチ適用の作業費だけでなく、DB全体の影響調査・回帰テスト・変更管理の総コストと、SQL改修後の将来互換性を比較しました。さらに、保守サポートに確認した技術的な内容を対策の根拠として示し、業務側とは修正する範囲と運用回避する範囲を調整しました。<strong>技術的に可能な対策と、プロジェクトとして選ぶべき対策は必ずしも同じではありません。</strong> GLには、製品側の技術的見解を確認するだけでなく、PM・業務側の合意形成を通じて実行可能な対策へ落とし込む役割があります。</p>
<p>今回のように、データベースで発生した問題が必ずしもDB側の設定だけで解決するとは限りません。SQLの実装や業務要件にも踏み込み、アプリケーション担当者や保守サポートと連携して原因を切り分けることも、DBAの重要な仕事です。</p>
<p>DBAが担う物理設計、性能管理、障害対応、バックアップ・復旧などの役割については、次の記事で詳しく解説しています。</p>

<a href="https://sys-univ.com/dev/database-engineer-dba/" title="データベースエンジニア（DBA）の仕事｜止めない、失わない、遅くさせない" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-160x90.jpg 160w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-500x281.jpg 500w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-800x450.jpg 800w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-300x169.jpg 300w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-768x432.jpg 768w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-1536x864.jpg 1536w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-120x68.jpg 120w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-320x180.jpg 320w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384-376x212.jpg 376w, https://sys-univ.com/wp-content/uploads/2026/08/251be8c60a42d58dcec6615bfa7aa384.jpg 1672w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">データベースエンジニア（DBA）の仕事｜止めない、失わない、遅くさせない</div><div class="blogcard-snippet internal-blogcard-snippet">データベースエンジニア（DBA）は何をする職種なのか。Oracle DBAの実務経験をもとに、物理設計・構築、性能と容量管理、権限・監査、監視、バックアップ、障害復旧、データ移行まで、構築後も続く仕事と責任をわかりやすく解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.03</div></div></div></div></a>


<h2 class="wp-block-heading"><span id="toc15">5. 効果の確認：検索結果の正しさと将来互換性を確認する</span></h2>


<h3 class="wp-block-heading"><span id="toc16">SQLの実行可否・検索結果・将来互換性を確認する</span></h3>


<p class="wp-block-paragraph">SQLの検証では、エラーが出ないだけでは合格にできません。「全角<code>＿</code>を含む行だけを返す」という要件を満たすか、含まない行が混ざらないかまで確認します。さらに、同じ検索処理が将来のアップグレード後にも成立するかを調べます。</p>


<figure class="wp-block-table">
<table class="has-fixed-layout">
<thead>
<tr>
<th>検証観点</th>
<th>確認内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>事象の再現</td>
<td>旧リリースの<code>LIKE '%＿%'</code>で、全角<code>＿</code>を含まない値も検索対象となる</td>
</tr>
<tr>
<td>SQLの実行可否</td>
<td><code>LIKE '%\＿%' ESCAPE '\'</code>では旧環境で<code>ORA-01424</code>、<code>LIKEC '%\＿%' ESCAPE '\'</code>では旧環境で実行可能</td>
</tr>
<tr>
<td>将来互換性</td>
<td>修正済みリリースでは<code>LIKEC</code>＋全角エスケープが<code>ORA-01424</code>となる</td>
</tr>
<tr>
<td>文字の組み合わせ</td>
<td>全角<code>＿</code>・<code>％</code>と半角<code>_</code>・<code>%</code>を混在させ、意図しない一致がないか確認する</td>
</tr>
<tr>
<td>列型と環境条件</td>
<td><code>VARCHAR2</code>・<code>NVARCHAR2</code>、文字セット、照合順序を記録する</td>
</tr>
<tr>
<td>運用回避の成立</td>
<td>改修しない部分について、対象データと回避手順が実際の業務で扱えるかを確認する</td>
</tr>
<tr>
<td>性能への影響</td>
<td>ヒット件数、実行計画、I/O、応答時間を確認する</td>
</tr>
</tbody>
</table>
</figure>


<p class="wp-block-paragraph"><strong>実行できるSQLと、業務要件どおりの結果を返すSQLは別です。</strong> この区別が、原因調査でも、対策評価でも重要でした。</p>


<p class="wp-block-paragraph">次章以降の規約・テスト項目に反映する際は、全角と半角を混ぜた入力、エスケープ文字、NULLや空文字なども含め、同じ不具合を再び見落とさないようにします。現行Oracle向けの具体的なSQL例は第7章で紹介します。</p>


<h2 class="wp-block-heading"><span id="toc17">6. 歯止め：個別対処をプロジェクト全体のルールにする</span></h2>


<h3 class="wp-block-heading"><span id="toc18">SQL規約に判断結果を反映する</span></h3>


<p class="wp-block-paragraph">実案件では、SQL規約に「パターンマッチングにおけるLIKECの利用」を新設し、設計・コーディング時の確認基準としてプロジェクトに展開しました。</p>


<p class="wp-block-paragraph">重要なのは、<strong>調査担当者だけが知っている注意点を、ほかの開発メンバーも実践できるルールに変えた</strong>ことです。規約、レビュー観点、テストデータまで揃えてこそ、障害対応が再発防止につながります。</p>


<p class="wp-block-paragraph">当時の規約改訂は、その案件の環境と将来のリリース変更を考慮したものです。現在のOracle 19c向けの規約としては、そのままコピーせず、次節に示すように<code>LIKE</code>を原則としたうえで、必要な例外条件を整理します。</p>


<h3 class="wp-block-heading"><span id="toc19">再発防止は「注意喚起」で終わらせない</span></h3>


<p class="wp-block-paragraph">プロジェクト内へ周知するだけでなく、SQLレビューで確認する項目と、テストで使う文字の組合せを具体化します。例えば、検索条件に利用者入力が含まれる処理では、半角<code>%</code>・<code>_</code>・エスケープ文字、全角<code>％</code>・<code>＿</code>、NULLや空文字をテストデータに含めます。</p>


<p class="wp-block-paragraph">修正箇所だけでなく、<strong>SQLの作り方とレビュー観点を変えること</strong>が歯止めになります。既存の機能が大きく、全面改修が現実的でない場合には、運用制約を明示し、将来の改修時に見直す対象として管理することも必要です。</p>


<h2 class="wp-block-heading"><span id="toc20">7. Oracle 19cではどう書くか：LIKE・ESCAPE・照合順序</span></h2>


<h3 class="wp-block-heading"><span id="toc21">Oracle 19cの公式仕様では全角は通常の文字</span></h3>


<p class="wp-block-paragraph">Oracle Database 19cのSQL言語リファレンスでは、<code>LIKE</code>のワイルドカードとして認識するのはASCII相当の半角<code>%</code>と<code>_</code>で、<strong>全角の<code>％</code>と<code>＿</code>は通常の文字として扱う</strong>と説明されています。また、Oracleはほとんどの場合に<code>LIKE</code>を推奨し、<code>LIKEC</code>はUnicodeの完全な文字単位で比較する必要がある場合の選択肢と位置付けています。</p>


<p class="wp-block-paragraph">そのため、<strong>19cで旧案件のSQL規約をそのまま移植し、すべての<code>LIKE</code>を<code>LIKEC</code>へ変更する必要はありません</strong>。適切な演算子は検索要件に基づいて選択します。</p>


<figure class="wp-block-table">
<table class="has-fixed-layout">
<thead>
<tr>
<th>検索要件</th>
<th>SQLの考え方</th>
</tr>
</thead>
<tbody>
<tr>
<td>全角<code>＿</code>を含む値を探す</td>
<td>原則として<code>LIKE '%＿%'</code></td>
</tr>
<tr>
<td>半角<code>_</code>を文字として探す</td>
<td><code>LIKE '%\_%' ESCAPE '\'</code></td>
</tr>
<tr>
<td>半角<code>%</code>を文字として探す</td>
<td><code>LIKE '%\%%' ESCAPE '\'</code></td>
</tr>
<tr>
<td>利用者入力を部分一致検索する</td>
<td>入力中の<code>\</code>・<code>%</code>・<code>_</code>をエスケープし、バインド変数で渡す</td>
</tr>
<tr>
<td>Unicodeの複合文字を1文字として評価する</td>
<td>要件に応じて<code>LIKEC</code>を検討</td>
</tr>
</tbody>
</table>
</figure>


<p class="wp-block-paragraph">適用時は列のデータ型・照合順序・入力値の取り扱いを確認します。</p>


<h3 class="wp-block-heading"><span id="toc22">入力値のワイルドカードはバインド変数だけでは防げない</span></h3>


<p class="wp-block-paragraph">現行システムで起こりやすいのは、検索欄に利用者が入力した<code>%</code>や<code>_</code>がそのままワイルドカードとして解釈され、想定より広い範囲に一致してしまう問題です。</p>


<p class="wp-block-paragraph">例えば次のSQLは、SQLインジェクションを防ぐ目的でバインド変数を使用していても、<strong><code>:keyword</code>中のワイルドカードが有効なまま</strong>です。</p>


<pre class="wp-block-code"><code>-- バインド変数を使っていても、入力中の % や _ はワイルドカードとして働く
SELECT *
FROM TEST
WHERE EFG LIKE '%' || :keyword || '%';
</code></pre>


<p class="wp-block-paragraph">利用者入力を<strong>通常の文字列として部分一致検索したい</strong>場合は、先にエスケープ文字自体を二重化し、その後<code>%</code>と<code>_</code>をエスケープします。次は説明用のSQLです。</p>


<pre class="wp-block-code"><code>-- :keyword を1か所でバインドするSQL例
-- 未入力はNULLとして扱い、検索対象としない
WITH input_keyword AS (
    SELECT :keyword AS keyword FROM dual
)
SELECT t.*
FROM TEST t
CROSS JOIN input_keyword k
WHERE k.keyword IS NOT NULL
  AND t.EFG LIKE
      '%' ||
      REPLACE(
        REPLACE(
          REPLACE(k.keyword, '\', '\\'),
          '%', '\%'
        ),
        '_', '\_'
      ) || '%'
      ESCAPE '\';
</code></pre>


<p class="wp-block-paragraph"><code>REPLACE</code>は、<strong>エスケープ文字→<code>%</code>→<code>_</code>の順序</strong>で適用します。逆順にすると、新たに挿入したエスケープ文字が再度処理され、意図しない検索パターンになる可能性があります。</p>


<p class="wp-block-paragraph">Oracleは空文字列をNULLとして扱うため、未入力を検出する条件として<code>LENGTH(:keyword) &gt; 0</code>を追加する必要はありません。未入力で全件表示する仕様の場合は別途分岐してください。また、上の例ではバインド変数はSQL中の1か所です。実運用ではアプリケーション側で文字列をエスケープしてから単一のバインド変数として渡す方法も選べます。</p>


<p class="wp-block-paragraph">データ型が<code>NVARCHAR2</code>の場合は、文字列リテラルとバインド値の型変換も検証してください。また、検索語にSQL構文を連結するのではなく、値をバインドして渡す方針は維持します。</p>


<h3 class="wp-block-heading"><span id="toc23">実機で確認するSQL：VARCHAR2とNVARCHAR2を比較</span></h3>


<p class="wp-block-paragraph">以下は読者のOracle 19c環境で試せる検証手順です。<strong>テスト専用スキーマで作成し、DBの文字セット・セッション設定も記録</strong>してください。全角・半角の字形が入力時に変換されていないかにも注意します。</p>


<pre class="wp-block-code"><code>-- 検証用テーブル（業務データは使用しない）
CREATE TABLE LIKE_TEST (
    ID NUMBER PRIMARY KEY,
    TXT_V VARCHAR2(40 CHAR),
    TXT_N NVARCHAR2(40)
);

INSERT INTO LIKE_TEST VALUES (1, '東京＿本店', N'東京＿本店');
INSERT INTO LIKE_TEST VALUES (2, '東京_本店',  N'東京_本店');
INSERT INTO LIKE_TEST VALUES (3, '東京％本店', N'東京％本店');
INSERT INTO LIKE_TEST VALUES (4, '東京%本店',  N'東京%本店');
INSERT INTO LIKE_TEST VALUES (5, '東京本店',   N'東京本店');
INSERT INTO LIKE_TEST VALUES (6, NULL, NULL);
COMMIT;

-- ① 全角＿を含む値の検索：VARCHAR2／NVARCHAR2で比較
SELECT ID, TXT_V FROM LIKE_TEST WHERE TXT_V LIKE '%＿%' ORDER BY ID;
SELECT ID, TXT_N FROM LIKE_TEST WHERE TXT_N LIKE N'%＿%' ORDER BY ID;

-- ② 半角_はESCAPEを付け、文字として検索
SELECT ID, TXT_V FROM LIKE_TEST WHERE TXT_V LIKE '%\_%' ESCAPE '\' ORDER BY ID;
SELECT ID, TXT_N FROM LIKE_TEST WHERE TXT_N LIKE N'%\_%' ESCAPE '\' ORDER BY ID;

-- ③ 全角＿にESCAPEを付けるとどうなるか（エラー確認用）
SELECT ID, TXT_V FROM LIKE_TEST WHERE TXT_V LIKE '%\＿%' ESCAPE '\' ORDER BY ID;
SELECT ID, TXT_N FROM LIKE_TEST WHERE TXT_N LIKE N'%\＿%' ESCAPE '\' ORDER BY ID;

-- ④ LIKECを使用した全角＿の検索
SELECT ID, TXT_V FROM LIKE_TEST WHERE TXT_V LIKEC '%＿%' ORDER BY ID;
SELECT ID, TXT_N FROM LIKE_TEST WHERE TXT_N LIKEC N'%＿%' ORDER BY ID;

-- 確認終了後、必要な場合のみ実行
-- DROP TABLE LIKE_TEST PURGE;
</code></pre>


<p class="wp-block-paragraph">公式仕様上、①と④では全角<code>＿</code>を通常文字として扱い、②では半角<code>_</code>をエスケープし、③は無効なエスケープ指定となることが想定されます。<strong>実際の結果は照合順序・文字セットを含めて検証し、条件ごとの一致行・エラー番号を記録</strong>してください。必要に応じて、後述する照合順序の条件も記録してください。</p>


<h3 class="wp-block-heading"><span id="toc24">照合順序によって文字の一致判定が変わる場合がある</span></h3>


<p class="wp-block-paragraph">Oracle 19cで全角<code>＿</code>をワイルドカードとして扱わないことと、全角・半角の文字が比較上同じと見なされるかは別の問題です。<code>LIKE</code>の一致判定は、列・式の照合順序（collation）の影響を受けます。大文字・小文字、アクセント、文字幅など、区別したい属性がある場合は、対象DBの照合設定と実際の検索結果を確認してください。</p>


<pre class="wp-block-code"><code>-- セッションの比較設定を記録する
SELECT parameter, value
FROM NLS_SESSION_PARAMETERS
WHERE parameter IN ('NLS_COMP', 'NLS_SORT');
</code></pre>


<p class="wp-block-paragraph"><code>NLS_COMP</code>や<code>NLS_SORT</code>に加え、列・式で指定された照合順序が評価に影響する場合もあります。検索結果の差を調査するときは、SQLだけでなく、これらの環境条件を合わせて記録することが重要です。</p>


<p class="wp-block-paragraph">検索パターンの先頭に<code>%</code>を置く部分一致検索は、通常のB-tree索引の範囲検索を効率よく利用しにくくなります。大量データを対象にする場合は、実行計画やI/Oを確認し、必要に応じて検索方式・索引設計を見直します。</p>


<h2 class="wp-block-heading"><span id="toc25">8. まとめ：サポートと根拠をそろえ、説明できる対策を選ぶ</span></h2>


<p class="wp-block-paragraph">今回の事例で重要だったのは、Oracleに不具合があったという事実だけではありません。検索結果の異常から出発し、再現条件を切り分け、サポート文書と実機の矛盾を根拠とともに提示して調査を依頼しました。</p>


<p class="wp-block-paragraph">不具合を修正するパッチが存在しても、稼働中のシステムでは影響調査や回帰テスト、展開の負担まで含めて判断しなければなりません。今回の案件では、パッチ適用を見送り、<strong>新規・改修SQLの規約整備と、改修量に比べ対象データが少ない既存機能での運用回避を組み合わせる</strong>方針を選びました。さらに、旧環境で有効なエスケープ方式がアップグレード先では<code>ORA-01424</code>になることを検証し、将来の保守も考慮した規約としました。</p>


<p class="wp-block-paragraph">こうした対策を選ぶうえで大きかったのは、<strong>保守サポートと技術的な認識をそろえ、その回答と実機検証を根拠にPM・業務側へ説明し、実施方針の合意を得られたこと</strong>です。製品の動作についてはサポートに確認し、どの範囲を改修して何を運用で回避するかはプロジェクトで決める。その責任分界と判断根拠を明確にしたことで、対応を実行に移すことができました。</p>


<p class="wp-block-paragraph"><strong>障害対応の本質は、技術的な解決策を見つけることだけではありません。品質・コスト・リスクを比較し、ベンダーと関係者の技術的な認識をそろえ、後から理由を説明できる対策を選ぶことです。</strong> この進め方こそが、別の障害に直面したときにも再利用できる実務上のノウハウだと考えます。</p>


<p class="wp-block-paragraph">なお、現在のOracle 19cでは、全角記号を通常文字として扱う仕様が明記されています。個々のシステムでは、利用者入力のワイルドカード化、文字セット、照合順序、性能面も含め、対象環境で検証して最終判断してください。</p>


<hr class="wp-block-separator has-alpha-channel-opacity" />

<h3 class="wp-block-heading"><span id="toc26">参考資料</span></h3>


<ul class="wp-block-list">
	<li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Pattern-matching-Conditions.html">Oracle Database 19c SQL言語リファレンス：Pattern-matching Conditions</a> — LIKE、LIKEC、ESCAPE、全角記号の扱い</li>


	<li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/nlspg/linguistic-sorting-and-matching.html">Oracle Database 19c Globalization Support Guide：Linguistic Sorting and Matching</a> — NLS_COMP、NLS_SORT、照合順序</li>
</ul>

]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/oracle-like-fullwidth-underscore/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ECS/FargateでDockerfileのchownが効かない｜非rootコンテナがPermission deniedになる理由</title>
		<link>https://sys-univ.com/incident/ecs-fargate-permission-denied/</link>
					<comments>https://sys-univ.com/incident/ecs-fargate-permission-denied/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Fri, 14 Aug 2026 01:18:51 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[トラブル]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=3094</guid>

					<description><![CDATA[はじめに ECS/Fargateでコンテナを非rootユーザーとして実行したところ、ログ出力先のディレクトリでPermission deniedが発生したことがありました。 Dockerfileでは、ログ出力先のディレク [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><span style="font-size: 18px;"><strong>はじめに</strong></span></p>
<p>ECS/Fargateでコンテナを非rootユーザーとして実行したところ、ログ出力先のディレクトリで<code>Permission denied</code>が発生したことがありました。</p>
<p>Dockerfileでは、ログ出力先のディレクトリを作成し、アプリケーションを実行するユーザーへ<code>chown</code>していました。Dockerイメージだけを見ると、書き込みできるように設定されています。</p>
<p>問題が起きたのは、アプリケーションコンテナとFluent Bitコンテナでログ用のVolumeを共有する構成にしたときでした。</p>
<p>原因を調べていくと、Dockerfileの設定が常に無効になるという単純な話ではありませんでした。Dockerfile、ECSタスク定義、Volumeを個別に確認するだけではなく、<strong>それらを組み合わせた実行時の最終状態まで設計対象にできていたか</strong>という問題に行き着きました。</p>
<p>この記事では、実際に発生した事象と採用した対策を、AWS公式ドキュメントで確認できる仕様と照らし合わせて整理します。採用しなかった対策候補との違いも明確にしながら、設計段階で見落とした点と、事前のPoCで確認すべきだった内容を振り返ります。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">ECS/FargateでPermission deniedが発生した</a></li><li><a href="#toc2" tabindex="0">Dockerfileでchownしたのに、なぜ書き込めなかったのか</a><ol><li><a href="#toc3" tabindex="0">DockerfileのVOLUMEとcontainerPathが一致する場合</a></li><li><a href="#toc4" tabindex="0">実効ユーザーもDockerfileだけで確認しない</a></li></ol></li><li><a href="#toc5" tabindex="0">対策はchownの方法だけで考えない</a><ol><li><a href="#toc6" tabindex="0">共有Volume自体をなくせないか</a></li><li><a href="#toc7" tabindex="0">VOLUMEディレクティブを利用する方法</a></li><li><a href="#toc8" tabindex="0">補足：configuredAtLaunchはbind mountの設定ではない</a></li><li><a href="#toc9" tabindex="0">権限設定用コンテナを先行して実行する</a></li><li><a href="#toc10" tabindex="0">rootユーザーで実行する</a></li><li><a href="#toc11" tabindex="0">技術的に動く対策と、プロジェクトで採用できる対策は違う</a></li></ol></li><li><a href="#toc12" tabindex="0">なぜ設計段階で気づけなかったのか</a><ol><li><a href="#toc13" tabindex="0">「担当者が知らなかった」で終わらせない</a></li></ol></li><li><a href="#toc14" tabindex="0">事前PoCでは、ここまで確認すべきだった</a></li><li><a href="#toc15" tabindex="0">今回の事象から得た3つの学び</a></li><li><a href="#toc16" tabindex="0">参考にしたAWS公式ドキュメント</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">ECS/FargateでPermission deniedが発生した</span></h2>
<p>今回の構成を単純化すると、アプリケーションがファイルへログを書き込み、同じVolumeをマウントしたFluent Bitがそのログを読み取る構成でした。</p>
<pre><code class="language-text">Application Container
非rootユーザー
        │
        │ ログ書き込み
        ↓
    Shared Volume
        │
        │ ログ読み込み
        ↓
Fluent Bit Container
</code></pre>
<p>ECSのタスク定義では、Volumeを定義し、アプリケーションコンテナとFluent Bitコンテナの双方へマウントしていました。</p>
<p>本記事では、タスク定義でボリューム名を定義した空のデータVolumeを、AWS公式ドキュメントに合わせて<strong>bind mount</strong>と呼びます。AWS公式でも、bind mountの用途として、1つ以上のコンテナにマウントする空のデータVolumeが示されています。Fargateでは、bind mountにタスクへ割り当てられたエフェメラルストレージが利用されます。</p>
<p>詳細は、<a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/bind-mounts.html">AWS公式「Amazon ECSでのバインドマウントの使用」</a>と<a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/fargate-task-storage.html">AWS公式「Amazon ECS向けのFargateタスクエフェメラルストレージ」</a>で確認できます。</p>
<p>アプリケーションコンテナは非rootユーザーで動作させていました。Dockerfileでは、概念的には次のようにログ出力先を作成し、所有者を変更しています。</p>
<pre><code class="language-dockerfile">RUN mkdir -p /app/logs
RUN chown appuser:appgroup /app/logs

USER appuser
</code></pre>
<p>タスク定義側の<code>user</code>による上書きはなく、実行ユーザーはDockerfileの<code>USER</code>で指定した非rootユーザーでした。</p>
<p>このDockerイメージだけを見ると、<code>appuser</code>が<code>/app/logs</code>へ書き込めるように見えます。</p>
<p>ところがECS/Fargate上でタスクを起動すると、アプリケーションがログを書き込む際に<code>Permission denied</code>が発生しました。</p>
<h2><span id="toc2">Dockerfileでchownしたのに、なぜ書き込めなかったのか</span></h2>
<p>問題のポイントは、<strong>Dockerfileで<code>chown</code>したディレクトリと、ECS/Fargate上でアプリケーションが実際に書き込むディレクトリが、Volumeマウント後は同じものではなかったこと</strong>です。</p>
<p>Dockerイメージ内では、<code>/app/logs</code>の所有者を<code>appuser</code>へ変更していました。</p>
<pre class="wp-block-code"><code>Docker Image
    │
    └─ /app/logs
         owner = appuser</code></pre>
<p>この状態だけを見れば、<code>appuser</code>は<code>/app/logs</code>へ書き込めるように見えます。</p>
<p>ECSで同じ<code>/app/logs</code>へVolumeをマウントすると、イメージ内のディレクトリはマウントによって覆い隠されます。実行中のコンテナから見えるのは、Dockerfileで<code>chown</code>したイメージ側の<code>/app/logs</code>ではなく、<strong>Volume側の<code>/app/logs</code></strong>です。</p>
<pre class="wp-block-code"><code>Docker Image
/app/logs
owner = appuser
        │
        │ ECS Task起動
        ↓
Volumeを /app/logs へmount
        │
        ↓
イメージ側の /app/logs は隠蔽
        │
        ↓
コンテナから見える /app/logs
＝ Volume側</code></pre>
<p>Dockerfileで設定したディレクトリが削除されたわけではありません。同じパスへVolumeをマウントしたことで、イメージ側のディレクトリが実行中のコンテナから見えなくなっています。</p>
<p><strong>Dockerfileで<code>chown</code>していても、Volumeマウント後の<code>/app/logs</code>が同じ所有者・権限になるとは限りません。</strong></p>
<p>今回見落としていたのは、この<strong>「イメージ作成時の権限」と「Volumeマウント後の実効権限」の違い</strong>でした。</p>
<h3><span id="toc3">DockerfileのVOLUMEとcontainerPathが一致する場合</span></h3>
<p>ここまでだけを見ると、「VolumeをマウントするとDockerfile側の権限設定は使われない」と考えたくなります。</p>
<p>Amazon ECSには、もう一つ重要な仕様があります。</p>
<p>Dockerfileの<code>VOLUME</code>で指定した絶対パスと、タスク定義の<code>containerPath</code>が一致する場合、ECSはそのパス内のデータをデータVolumeへコピーします。</p>
<p>AWS公式ドキュメントには、非rootユーザー向けに対象ディレクトリを<code>chown</code>し、<code>USER</code>を指定した後に<code>VOLUME</code>を宣言する例も掲載されています。この説明の中では、既定のVolume権限を<code>0755</code>、所有者を<code>root</code>とし、Dockerfileでカスタマイズできることも示されています。</p>
<p>詳細は、<a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/bind-mounts.html">AWS公式「Amazon ECSでのバインドマウントの使用」</a>を参照してください。</p>
<p>概念的には次のような記述です。</p>
<pre class="wp-block-code"><code>RUN mkdir -p /app/logs
RUN chown appuser:appgroup /app/logs

USER appuser
VOLUME ["/app/logs"]</code></pre>
<p>今回使用していたDockerfileには、<strong>ログ出力先を<code>VOLUME</code>として宣言する記述はありませんでした。</strong></p>
<pre class="wp-block-code"><code>Dockerfile
/app/logs を appuser に chown
        │
        ↓
ECSで同じパスへVolumeをmount
        │
        ↓
イメージ側の /app/logs は隠蔽
        │
        ↓
VOLUME宣言なし
        │
        ↓
Volumeマウント後の権限で
書き込み可否が決まる</code></pre>
<p class="PDq2pG_selectionAnchorContainer" data-start="308" data-end="485">今回の構成では、Dockerfileで<code data-start="327" data-end="334">chown</code>した<code data-start="336" data-end="347">/app/logs</code>へVolumeをマウントしたことで、イメージ側のディレクトリは隠蔽されました。また、Dockerfileに対象パスの<code data-start="405" data-end="413">VOLUME</code>宣言がなく、<code data-start="419" data-end="427">VOLUME</code>と<code data-start="428" data-end="443">containerPath</code>を一致させてイメージ側の状態をVolumeへ引き継ぐ仕組みも利用していませんでした。</p>
<p data-start="490" data-end="566">当時は、この<strong data-start="496" data-end="547">DockerfileとECS Volumeを組み合わせた後に、実行時にどのような状態になるのか</strong>を設計観点として持っていませんでした。</p>
<p data-start="571" data-end="712"><code data-start="571" data-end="579">VOLUME</code>宣言がなかったことだけで、Permission deniedの原因をすべて説明できるわけではありません。実際の書き込み可否は、Volumeマウント後のowner、group、modeと、アプリケーションの実効UID/GID、書き込み対象パスの組み合わせで決まります。</p>
<p>今回の問題で重要だったのは、<strong>Dockerfileで<code>chown</code>したという設定だけを見て書き込み可能と判断し、Volumeマウント後にどの所有者・権限になるのかを確認していなかったこと</strong>です。</p>
<p>今回の案件では<code>VOLUME</code>を利用する方法は採用していないため、ここではAWS公式仕様から確認できる対策候補の一つとして扱います。</p>
<h3 data-section-id="ouun3s" data-start="2343" data-end="2372"><span id="toc4">実効ユーザーもDockerfileだけで確認しない</span></h3>
<p data-start="2374" data-end="2434">ファイルやディレクトリの権限とあわせて確認する必要があるのが、<strong data-start="2405" data-end="2431">コンテナを実際にどのユーザーで実行しているか</strong>です。</p>
<p data-start="2436" data-end="2529">ECSでは、Dockerfileの<code data-start="2453" data-end="2459">USER</code>とは別に、タスク定義の<code data-start="2470" data-end="2476">user</code>でも実行ユーザーを指定できます。このパラメータはDockerの<code data-start="2507" data-end="2513">User</code>や<code data-start="2514" data-end="2522">--user</code>に対応します。</p>
<p data-start="2531" data-end="2591">今回のタスク定義では<code data-start="2541" data-end="2547">user</code>を指定しておらず、Dockerfileの<code data-start="2567" data-end="2573">USER</code>を上書きする設定はありませんでした。</p>
<p data-start="2593" data-end="2652">設計レビューで確認すべきなのは、「Dockerfileに<code data-start="2621" data-end="2635">USER appuser</code>と書いてある」ことではありません。</p>
<p data-start="2654" data-end="2731"><strong data-start="2654" data-end="2717">ECS上で最終的にどのUID/GIDでプロセスが動き、そのユーザーがVolumeマウント後のパスへ必要な操作をできるか</strong>まで確認する必要があります。</p>
<p data-start="2733" data-end="2814">Volumeの権限と同じく、Dockerfileやタスク定義を個別に見るだけでは不十分です。設計対象にすべきなのは、それらを組み合わせた後の実行時の最終状態です。</p>
<p data-start="2816" data-end="2977"><code data-start="2816" data-end="2822">user</code>パラメータの仕様は、<a class="decorated-link" href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html" target="_new" data-start="2832" data-end="2969">AWS公式「FargateでのAmazon ECSタスク定義パラメータ」</a>で確認できます。</p>
<h2><span id="toc5">対策はchownの方法だけで考えない</span></h2>
<p>Permission deniedが発生すると、<code>chmod</code>や<code>chown</code>の方法から考えたくなります。</p>
<p>今回の構成を設計の観点から見直すと、その前に確認すべきことがあります。</p>
<p><strong>アプリケーションコンテナとFluent Bitの間に、そもそも共有Volumeが必要なのか。</strong></p>
<p>権限をどう合わせるかだけではなく、権限調整が必要になる境界そのものをなくせないかを最初に検討します。</p>
<h3><span id="toc6">共有Volume自体をなくせないか</span></h3>
<p>今回の構成は次のようになっていました。</p>
<pre><code class="language-text">Application
    ↓ file
Shared Volume
    ↓ file
Fluent Bit
</code></pre>
<p>ログ出力要件が許せば、アプリケーションのログをファイルへ出力せず、<code>awsfirelens</code>ログドライバ経由でFluent Bitへ渡す構成も考えられます。</p>
<p>FireLensでは、アプリケーションコンテナに<code>awsfirelens</code>ログドライバを設定し、Fluent BitまたはFluentdをログルーターとして利用できます。</p>
<p>詳細は、<a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/firelens-taskdef.html">AWS公式「Amazon ECSタスク定義の例：FireLensにログをルーティングする」</a>を参照してください。</p>
<pre><code class="language-text">Application
    ↓ awsfirelens
Fluent Bit
</code></pre>
<p>この構成に変更できれば、アプリケーションとFluent Bitの間でログファイルを共有するVolumeをなくせる可能性があります。Volumeに付随するowner、group、mode、UID/GID、マウント後の権限といった設計項目も減らせます。</p>
<p>実案件でも、ログ出力方式そのものを変更して共有Volumeをなくす案を検討しました。既存のログ出力方式を変更するとAP側での改修と再テストが必要になるため、今回は共有Volumeを残したうえで権限設定方法を変更する判断としました。</p>
<p><strong>設計として上位の選択肢を検討しても、変更影響やプロジェクト条件によって採用できないことがあります。</strong></p>
<p>重要なのは、「権限エラーをどう直すか」から始めるのではなく、「その権限設計自体をなくせないか」を一度確認したうえで、案件条件に合った方法を選ぶことです。</p>
<h3><span id="toc7">VOLUMEディレクティブを利用する方法</span></h3>
<p>共有Volumeを残す場合には、前述したDockerfileの<code>VOLUME</code>と<code>containerPath</code>の仕様を利用する方法も候補になります。</p>
<p>この方法ではDockerfile、すなわちコンテナイメージそのものを変更します。ECS上の課題を解決する目的で<code>VOLUME</code>を追加しても、同じイメージを別の環境で実行した場合の挙動にも影響します。</p>
<p>今回の環境ではこの方法を追加検証していないため、AWS公式仕様から確認できる対策候補としての紹介に留めます。</p>
<h3><span id="toc8">補足：configuredAtLaunchはbind mountの設定ではない</span></h3>
<p>対策を調べる過程では、ECSのVolumeに関する情報を複数確認しました。その中で紛らわしかったのが<code>configuredAtLaunch</code>です。</p>
<p>名称からはVolumeの初期設定に使えるようにも見えますが、<code>configuredAtLaunch=true</code>は、ECSのデプロイ時にAmazon EBS Volumeを構成するための設定です。今回利用していたbind mountの権限を変更するためのオプションではありません。</p>
<p><a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/configure-ebs-volume.html">AWS公式「Amazon ECSのデプロイ時にAmazon EBSボリューム設定を指定する」</a>でも、<code>configuredAtLaunch</code>を<code>true</code>に設定したタスク定義に対して、デプロイ時にAmazon EBS Volumeを構成する仕組みとして説明されています。</p>
<p><strong>同じ「Volume」という言葉で扱われていても、bind mount、EBS、EFSでは仕様も設定方法も異なります。目にした情報をそのまま設計判断に使うのではなく、自分が利用しているVolume方式を特定したうえで、該当する公式ドキュメントを確認する必要があります。</strong></p>
<h3><span id="toc9">権限設定用コンテナを先行して実行する</span></h3>
<p>別の方法として、Volumeの所有者や権限を設定するコンテナを先に実行し、正常終了した後にアプリケーションコンテナを起動する構成があります。</p>
<p>ECSでは<code>dependsOn</code>でコンテナ間の起動依存関係を設定できます。<code>SUCCESS</code>を指定すると、依存先コンテナが終了コード0で完了するまで後続コンテナを開始しません。<code>SUCCESS</code>と<code>COMPLETE</code>の依存先にはessential containerを指定できません。</p>
<p>詳細は、<a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html">AWS公式「FargateでのAmazon ECSタスク定義パラメータ」</a>を参照してください。</p>
<pre><code class="language-text">Permission Setting Container
        │
        │ Volumeの所有者・権限を設定
        │ exit 0
        ↓
Application Container
        ↓
Fluent Bit Container
</code></pre>
<p class="PDq2pG_selectionAnchorContainer" data-start="131" data-end="212">権限設定用コンテナには、共有Volumeへ必要な所有者・権限を設定できる権限を持たせます。アプリケーションコンテナ自体は従来どおり非rootユーザーで実行します。</p>
<p data-start="217" data-end="269">この方法であれば、アプリケーションイメージを変更せず、タスク定義を中心とした基盤側の変更で対応できます。</p>
<p data-start="274" data-end="446"><strong data-start="274" data-end="446">なお、権限設定用コンテナでVolumeの初期権限を整えても、その後アプリケーションが生成するファイルを別コンテナから読めるとは限りません。TomcatとFluent BitでVolumeを共有した際に実際に発生したPermission deniedと、UID/GID・setgid・umaskを含む権限設計について、続編で整理しました。</strong></p>

<a href="https://sys-univ.com/dev/ecs-fargate-fluent-bit-permission-denied/" title="Fluent BitがPermission deniedでログを読めない｜ECS/Fargate共有VolumeのUID/GID設計" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/08/c93b625ff36561072a4ad9fa2e52e6a8-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/08/c93b625ff36561072a4ad9fa2e52e6a8-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/08/c93b625ff36561072a4ad9fa2e52e6a8-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/08/c93b625ff36561072a4ad9fa2e52e6a8-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/08/c93b625ff36561072a4ad9fa2e52e6a8-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Fluent BitがPermission deniedでログを読めない｜ECS/Fargate共有VolumeのUID/GID設計</div><div class="blogcard-snippet internal-blogcard-snippet">ECS/FargateでTomcatとFluent Bitが共有Volumeを利用する構成でPermission deniedが発生。Fluent BitのUID/GID、setgid、umask、read-onlyマウントなど、Dockerコンテナ間でログを共有する際の権限設計を実例から解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.24</div></div></div></div></a>
<h3><span id="toc10">rootユーザーで実行する</span></h3>
<p>アプリケーションコンテナ自体をrootユーザーで実行する方法もあります。</p>
<p>権限問題は回避しやすくなりますが、非root実行を前提としていたセキュリティ設計との整合を確認する必要があります。動作するかどうかだけではなく、なぜ非rootユーザーで実行する設計にしていたのかまで戻って判断する必要があります。</p>
<h3><span id="toc11">技術的に動く対策と、プロジェクトで採用できる対策は違う</span></h3>
<p>今回検討した方法を、変更対象まで含めて整理すると次のようになります。</p>
<table>
<thead>
<tr>
<th>対策</th>
<th>主な変更対象</th>
<th>実務上の論点</th>
</tr>
</thead>
<tbody>
<tr>
<td>共有Volumeをなくす</td>
<td>アプリケーション／ログ出力設定／タスク定義</td>
<td>既存のログ出力方式を変更できるか</td>
</tr>
<tr>
<td><code>VOLUME</code>を利用</td>
<td>Dockerfile／コンテナイメージ</td>
<td>AP側成果物の変更と再テストが必要</td>
</tr>
<tr>
<td>権限設定用コンテナ</td>
<td>タスク定義</td>
<td>基盤側で完結しやすいが構成要素が増える</td>
</tr>
<tr>
<td>rootで実行</td>
<td>実行ユーザー／セキュリティ設計</td>
<td>非root要件との整合が必要</td>
</tr>
</tbody>
</table>
<p><strong>最終的には、権限設定用コンテナを先行して実行する構成を採用しました。</strong></p>
<p>アプリケーション側を修正したりログ出力仕様を変更したりする場合、AP側での改修とテストが必要になります。権限設定用コンテナの追加であれば、タスク定義を管理する基盤側で変更を完結でき、既存のコンテナイメージにも影響を与えません。</p>
<p><strong>変更範囲を基盤側に限定できることから、この方式を採用しました。</strong> この構成への変更後は、非rootユーザーで実行するアプリケーションからログを正常に書き込めるようになり、Permission deniedは解消しました。</p>
<p>技術的に成立する対策と、プロジェクトとして採用しやすい対策は同じとは限りません。変更主体、責任分界、変更影響、追加試験の範囲まで含めて対策を決める必要があります。</p>
<h2><span id="toc12">なぜ設計段階で気づけなかったのか</span></h2>
<p>今回の問題で重要なのは、ECSのVolume仕様を知っていたかどうかだけではありません。</p>
<p>結果として、Dockerfileで設定した権限と、ECSがVolumeをマウントした後の実効権限との接続部分を、設計時に十分確認できていませんでした。</p>
<p>Dockerfileだけを見れば、確認対象は次の範囲です。</p>
<pre><code class="language-text">Dockerfile
 ├ mkdir
 ├ chown
 └ USER
</code></pre>
<p>実際には、その後ろまで設計する必要があります。</p>
<pre><code class="language-text">Docker Image
      ↓
ECS Task Definition
      ↓
Volume生成
      ↓
containerPathへmount
      ↓
実効UID/GID
      ↓
Applicationからwrite
      ↓
Fluent Bitからread
</code></pre>
<p><strong>「Dockerfileで対象ディレクトリをchownしたこと」と、「Volumeをマウントした実行環境でアプリケーションユーザーが書き込めること」は同じではありません。</strong></p>
<p>前者は設定内容です。設計で最終的に保証したいのは後者です。</p>
<h3><span id="toc13">「担当者が知らなかった」で終わらせない</span></h3>
<p>今回のECS Volumeの仕様を知っている担当者であれば、設計段階で問題に気づけた可能性があります。</p>
<p>原因を「担当者が仕様を知らなかった」で終わらせても、次の案件で同じ問題を防ぐ仕組みにはなりません。</p>
<p>クラウドでは、自分たちがDockerfileや設定ファイルへ直接記述するものだけでなく、クラウドサービスが実行時に生成、マウント、変更するものがあります。必要なのは、それらを含めた<strong>実行時の最終状態を設計する観点</strong>です。</p>
<p>今回であれば、設計レビューでは次のような項目を確認すべきでした。</p>
<table>
<thead>
<tr>
<th>設計項目</th>
<th>確認する内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>Volume方式</td>
<td>bind mount、EBS、EFSなど、どの方式を利用するか</td>
</tr>
<tr>
<td>Volume生成</td>
<td>誰が、いつ生成するか</td>
</tr>
<tr>
<td><code>containerPath</code></td>
<td>どのパスへマウントするか</td>
</tr>
<tr>
<td>Dockerfile <code>VOLUME</code></td>
<td>定義の有無と<code>containerPath</code>との関係</td>
</tr>
<tr>
<td>実効UID/GID</td>
<td>Dockerfileの<code>USER</code>、タスク定義の<code>user</code>を踏まえて誰が実行するか</td>
</tr>
<tr>
<td>Application側権限</td>
<td>誰が、どのパスへwriteするか</td>
</tr>
<tr>
<td>Fluent Bit側権限</td>
<td>誰が、どのパスをreadするか</td>
</tr>
<tr>
<td>owner/group/mode</td>
<td>Volumeマウント後にどうなるべきか</td>
</tr>
<tr>
<td>起動順</td>
<td>権限設定が必要な場合、いつ実施するか</td>
</tr>
<tr>
<td>Volumeライフサイクル</td>
<td>タスク停止・再作成時にデータや設定がどうなるか</td>
</tr>
<tr>
<td>変更主体</td>
<td>Dockerfile、タスク定義、ログ設定の誰が変更するか</td>
</tr>
</tbody>
</table>
<p>Fargateで利用するbind mountはタスクのエフェメラルストレージ上にあり、bind mountを使用するすべてのコンテナが停止するとデータは削除されます。今回のようなFargateタスクでは、タスク停止時のライフサイクルまで含めて設計する必要があります。</p>
<p>詳細は、<a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/bind-mounts.html">AWS公式「Amazon ECSでのバインドマウントの使用」</a>を参照してください。</p>
<p><strong>設計書に「Dockerfileでchownする」と書くだけでは足りません。Volumeをマウントした後に、どのUID/GIDが、どのパスへ、どの権限でアクセスできるのかを定義する必要があります。</strong></p>
<p>ここまで書いて、初めて実行時の権限設計になります。</p>
<p>この考え方は、ECSだけに限りません。基本設計で決めた方式を、構築・テストできる状態までどう落とすかについては、次の記事で詳しく整理しています。</p>
<ul>
<li><a href="https://sys-univ.com/dev/basic-design-infrastructure/">基本設計で決めること｜画面設計だけでは終わらない基盤SEの設計工程</a></li>
<li><a href="https://sys-univ.com/dev/detailed-design-overview/">【前編】詳細設計で決めること｜基本設計を「構築・テスト・運用できる形」に落とし込む工程</a></li>
</ul>
<h2><span id="toc14">事前PoCでは、ここまで確認すべきだった</span></h2>
<p>今回の問題は、設計段階のPoCで発見できた可能性があります。</p>
<p>ECSでコンテナが起動することだけを確認するPoCでは足りません。</p>
<p>今回のPermission deniedを検出するだけなら、大掛かりな試験は必要ありませんでした。本番と同じ非rootユーザーとVolume構成でタスクを起動し、次の範囲を確認すれば、書き込み権限の問題を設計段階で検出できた可能性があります。</p>
<pre><code class="language-text">ECS Task起動
      ↓
実効UID/GIDを確認
      ↓
Volume mount後のowner/group/modeを確認
      ↓
Applicationからファイル作成
      ↓
Applicationからディレクトリ作成
</code></pre>
<p>これが、今回の問題を発見するために必要だった<strong>最低限のPoC</strong>です。</p>
<p>ログ機構全体の成立性まで確認するのであれば、その先にFluent Bitからの読み取り、ログ転送、Task再作成後の動作まで確認します。</p>
<pre><code class="language-text">Applicationからwrite
      ↓
Fluent Bitからread
      ↓
ログ転送
      ↓
Task再作成後も成立するか
</code></pre>
<p>設計レビュー表とPoCで似た項目を確認するのには理由があります。</p>
<p><strong>設計では、実行時に成立すべき状態を定義する。PoCでは、その状態が実際の環境で成立することを確認する。</strong></p>
<p>今回なら、設計では「非rootのアプリケーションユーザーがVolumeマウント後のログ出力先へwriteできる」と定義します。PoCでは、本番相当のユーザーとVolume構成で実際にファイルを作成して確認します。</p>
<p>PoCは「AWSのサービスが使えるか」を試すだけの工程ではありません。</p>
<p><strong>本番と同じ境界を通したときに、設計したシステムが成立するかを確認する工程です。</strong></p>
<p>クラウドリフトでも、AWSサービス単体の機能確認だけを行い、オンプレミスからクラウドへ移した後の実際の処理や運用まで通さなければ、問題が後工程で表面化します。今回のVolume権限も規模は小さいものの、構造は同じでした。</p>
<p>クラウドリフトでPoCに何を含めるべきかは、次の記事で詳しく整理しています。</p>
<ul style="list-style-type: disc;">
<li><a href="https://sys-univ.com/dev/cloudlift/">クラウドリフトの失敗は構築前に始まっている｜PoC不足が手戻り・コスト超過・納期遅延を招く理由</a></li>
<li><a href="https://sys-univ.com/dev/cloudlift-poc-risk-1/">クラウドリフトPoCで「動いた」は確認できた。しかし業務では使えなかった｜10の設計リスク① 可用性・性能・ストレージ・バックアップ・監視</a></li>
</ul>
<h2><span id="toc15">今回の事象から得た3つの学び</span></h2>
<p>一つ目は、<strong>Dockerfileは設定であって、実行時の最終状態ではない</strong>ことです。</p>
<p>Dockerfileで<code>USER</code>や<code>chown</code>を指定しても、それだけでECS上の実効ユーザーやVolumeマウント後の権限は確定しません。設計で確認するべきなのは、各設定をECS上で組み合わせた後の最終状態です。</p>
<p>二つ目は、<strong>設計で抜けやすいのはコンポーネント単体ではなく、その接続部分である</strong>ことです。</p>
<p>Dockerfileの設定もECSのVolume定義も、それぞれ単体で存在しています。今回確認できていなかったのは、DockerイメージとECS Volumeを接続した後に、どのユーザーがどのファイルシステムへアクセスするのかという実行時の状態でした。</p>
<p>三つ目は、<strong>PoCでは本番と同じ境界を通す必要がある</strong>ことです。</p>
<p>コンテナが起動したことだけでは、システムとして成立したことにはなりません。本番と同じUID/GID、Volume、マウントポイント、サイドカーを含めて実際の処理を通し、設計した状態が成立することを確認する必要があります。</p>
<p>今回の事象を振り返ると、</p>
<p><strong>「Dockerfileでchownした」ではなく、「Volumeをマウントした後に、必要なユーザーが必要な操作をできる」まで確認して初めて権限設計は完了する</strong></p>
<p>ということになります。</p>
<p>クラウドでは、自分たちが直接構築・設定したものだけを見るのでは足りません。クラウドサービスが実行時に生成、変更、接続するものまで含めて最終状態を設計し、不確実性が残る境界は事前PoCで実際に通す。</p>
<p>今回のPermission deniedは小さな権限エラーでしたが、クラウド設計とPoCで何を確認するべきかを改めて考えるきっかけになりました。</p>
<h2><span id="toc16">参考にしたAWS公式ドキュメント</span></h2>
<ul>
<li>
<p><a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/bind-mounts.html">Amazon ECSでのバインドマウントの使用</a></p>
</li>
<li>
<p><a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/fargate-task-storage.html">Amazon ECS向けのFargateタスクエフェメラルストレージ</a></p>
</li>
<li>
<p><a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html">FargateでのAmazon ECSタスク定義パラメータ</a></p>
</li>
<li>
<p><a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/configure-ebs-volume.html">Amazon ECSのデプロイ時にAmazon EBSボリューム設定を指定する</a></p>
</li>
<li>
<p><a href="https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/firelens-taskdef.html">Amazon ECSタスク定義の例：FireLensにログをルーティングする</a></p>
</li>
</ul>
<hr />
<p><span style="font-size: 18px;"><strong>関連記事</strong></span></p>
<p class="PDq2pG_selectionAnchorContainer" data-start="49" data-end="112">ECS/Fargateの権限問題を、設計レビューで何を確認するかという観点を、運用設計や要件定義の工程まで広げて確認したい方は、以下の記事も参考にしてください。</p>
<ul data-start="114" data-end="193">
<li data-section-id="hata0n" data-start="114" data-end="193"><strong>運用設計とは？運用設計書の目次サンプルと項目一覧｜基盤SE視点</strong><br />
ログ、監視、ジョブ、バックアップ、障害対応など、本番運用を成立させるために設計しておくべき項目を整理しています。</li>
</ul>

<a href="https://sys-univ.com/dev/opedesign/" title="運用設計とは？運用設計書の目次サンプルと項目一覧｜システム基盤エンジニア視点" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-160x90.jpg 160w, https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-120x68.jpg 120w, https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-320x180.jpg 320w, https://sys-univ.com/wp-content/uploads/2026/07/7a689f13e1c38b90b6e6b1584b241588-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">運用設計とは？運用設計書の目次サンプルと項目一覧｜システム基盤エンジニア視点</div><div class="blogcard-snippet internal-blogcard-snippet">運用設計とは何かをシステム基盤エンジニアの実務目線で解説します。運用設計書の目次サンプルと検討項目一覧を示し、監視・ログ・バックアップ・ジョブ管理、誰がやるのか、要件定義・基本設計との関係、処理方式設計との双方向連携を整理します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.14</div></div></div></div></a>
<ul data-start="231" data-end="312">
<li data-section-id="x4krsd" data-start="231" data-end="312"><strong>要件定義とは何をする工程か｜RFP・見積前提から認識差を潰す実務</strong><br />
RFPや提案内容を前提に、スコープや責任分界を確定し、設計・構築・テストできる水準まで具体化する実務を解説しています。</li>
</ul>

<a href="https://sys-univ.com/dev/requirements-definition/" title="要件定義とは何をする工程か｜RFP・見積前提から認識差を潰す実務" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-500x281.png 500w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-800x450.png 800w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-300x169.png 300w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-768x432.png 768w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-1536x864.png 1536w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a-376x212.png 376w, https://sys-univ.com/wp-content/uploads/2026/06/2d222665bad7a62379b769bded1c226a.png 1672w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">要件定義とは何をする工程か｜RFP・見積前提から認識差を潰す実務</div><div class="blogcard-snippet internal-blogcard-snippet">要件定義とは何をする工程なのか。RFP、質問回答、提案書、見積前提から認識差を潰し、スコープや責任分界を確定する実務を、大規模SIの具体的な失敗事例とともに解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.12</div></div></div></div></a>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/ecs-fargate-permission-denied/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【AWS】別AZで起動したWindowsが通信不能に｜原因はVPCではなく「OS内のルート情報」だった</title>
		<link>https://sys-univ.com/incident/addroute/</link>
					<comments>https://sys-univ.com/incident/addroute/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Sun, 12 Jul 2026 03:00:28 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[AWS]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=1493</guid>

					<description><![CDATA[はじめに セキュリティグループも見た。 NACLも見た。 VPCルートテーブルも見た。 それでも通信できない。 そんなとき、原因はAWSコンソールの中ではなく、OSの中にあるかもしれません。 今回扱うのは、EC2を別AZ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p id="520c1fbf-2ede-41b1-994c-13ebd9a6950e"><strong>はじめに</strong></p>
<p>セキュリティグループも見た。<br />
NACLも見た。<br />
VPCルートテーブルも見た。</p>
<p id="bdf24a40-c78c-4282-a5dd-f17d3711dca3">それでも通信できない。</p>
<p id="54740cae-ca78-4bfe-a5b6-705cfb958d64">そんなとき、原因はAWSコンソールの中ではなく、OSの中にあるかもしれません。</p>
<p id="e309d140-47b7-4e48-9bfa-f53bd87488d2">今回扱うのは、EC2を別AZで起動した際に、Windows ServerのOS内ルート情報が更新されず、通信できなくなった事象です。</p>
<p id="2443481b-b38c-4cd5-9218-cd644f43373a">この記事では、単なるルート設定の話ではなく、EC2Launch、User Data、AMI再利用、DR設計で見落としやすい「起動後のOS状態」について整理します。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">EC2は起動した。でも通信できない</a></li><li><a href="#toc2" tabindex="0">AZ移動後、Windowsサーバが通信できない</a></li><li><a href="#toc3" tabindex="0">原因はEC2Launchの起動時処理だった</a></li><li><a href="#toc4" tabindex="0">対策は「OS起動ごとに必要な処理を実行させる」こと</a></li><li><a href="#toc5" tabindex="0">AWS側の設定だけ見ても足りない</a></li><li><a href="#toc6" tabindex="0">これはルーティングだけの話ではない</a></li><li><a href="#toc7" tabindex="0">なぜクラウドはOS設定を書き換えるのか</a></li><li><a href="#toc8" tabindex="0">DR設計では「起動できる」だけでは足りない</a></li><li><a href="#toc9" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 id="c8671a81-fd99-4eed-8b0b-16236561ffb3" tabindex="-1"><span id="toc1">EC2は起動した。でも通信できない</span></h2>
<p id="ac9bf7a0-d792-4e16-b53c-53a92e61f89b">EC2インスタンスを別AZで起動した。</p>
<p id="56009cfd-145a-4a49-a20c-ec797d51d345">インスタンスの起動は成功している。<br />
OSも上がっている。<br />
しかし、通信できない。</p>
<p id="33d27af2-9d34-4b3e-9f5d-007a1e39d3ed">このような事象が起きると、まずAWS側の設定を疑うと思います。</p>
<p id="f122f626-784b-427d-b739-6aa4455103b4">セキュリティグループがおかしいのか。<br />
NACLで止められているのか。<br />
サブネットのルートテーブルが間違っているのか。</p>
<p id="6fd185d9-7227-4a8d-b05b-3524bf620ee8">もちろん、それらは確認すべきです。</p>
<p id="97be70f4-ab23-4f38-b041-1e5864d48c7c">しかし、今回の原因はそこではありませんでした。</p>
<p id="7128f477-a6cd-4887-831f-b67500912c9c">問題は、Windows OS内のルーティング情報が、移動先AZに合わせて更新されていなかったことでした。</p>
<h2 id="a3a5eaa4-c886-4635-bde5-7da292d728fd" tabindex="-1"><span id="toc2">AZ移動後、Windowsサーバが通信できない</span></h2>
<p id="8be28339-3a1a-4d0a-9219-76da3f8698d7">今回の事象は、AZ障害時の切替を想定した環境で発生しました。</p>
<p id="59bb9556-58f5-43f8-88c8-322329457d7e">通常時は、あるAZでWindows ServerのEC2インスタンスを稼働させています。</p>
<p id="da117454-26d7-4584-bed8-181589631070">障害時には、別AZでインスタンスを起動し、業務を継続する想定でした。</p>
<p id="99a6c266-c60f-4a74-b71f-f4ec02836cc9">構成としては、クラウドではよくある考え方です。</p>
<figure id="c4b2b1e1-5f67-43f6-bc8a-0236391e1678">
<div style="width: 630px" class="wp-caption aligncenter"><a href="https://assets.st-note.com/img/1780473466-Rbf2paQvm8dgSjYeAcN19LlP.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide" src="https://assets.st-note.com/img/1780473466-Rbf2paQvm8dgSjYeAcN19LlP.png?width=1200" alt="画像" width="620" height="439" data-modal="true" /></a><p class="wp-caption-text">図　別AZでEC2を起動できても、起動後に通信できるとは限らない</p></div><br />
</figure>
<p id="c1be95ca-8ac6-4547-b9ff-57afc1258861">ただし、この構成で注意すべきなのは、「別AZでEC2が起動できること」と「起動後に業務通信が成立すること」は別問題だという点です。</p>
<p id="f2598e8d-5c12-42cd-88f0-be155b8b78ff">今回も、インスタンスの起動自体は成功していました。</p>
<p id="695718a0-cbf9-4a6e-b4eb-866039f64326">OSも起動していました。</p>
<p id="f8eacf54-fb85-415b-a364-3dbabf6d0731">ところが、正常なネットワーク通信ができませんでした。</p>
<p id="d3d10523-d178-4f61-bfa1-e114d517222b">AWS側の設定だけを見れば、サブネット、セキュリティグループ、NACL、VPCルートテーブルを疑いたくなります。</p>
<p id="1df1b1ab-d696-4ef8-a1a8-acb0c2d8ea39">しかし、調査していくと、問題はWindows OS内部のルーティング情報にありました。</p>
<p id="66ba10a6-bae5-4343-ae15-8c486fa08344">移動先AZで必要となるルート情報が、OS起動時に追加されていなかったのです。</p>
<p id="dfc6dca6-adf2-4a12-9188-a28a1c22db3d">ここで重要なのは、VPCのルートテーブルではなく、Windows OS内のルート情報だという点です。</p>
<p id="33322f9d-1790-43cf-aa11-e1863b2d4044">では、なぜOS内にルート情報が必要になるのでしょうか。</p>
<p id="8c305441-a343-4c47-8ae7-007810946f97">たとえば、次のような構成を考えてみます。</p>
<p id="4cdbe14f-e1d8-4b46-bd7e-6fbd6f755d0c">通常の業務通信は、デフォルトゲートウェイから出す。<br />
一方で、監視サーバ向けのセグメント 172.16.10.0/24 には、2枚目のNIC、つまり別ENI側の経路を使って通信させる。</p>
<p id="98542b5a-80a3-47db-9711-5d897318ef13">この場合、Windows OS内には、</p>
<div class="code-block-container">
<pre id="46d69c23-cf13-40a2-8ebb-c072fbf2aee7" data-name="preCode"><code class="hljs" data-name="code">172.16.10.0/24 は、2枚目のNIC側の経路へ向ける
</code></pre>
<div class="a-button__inner" data-v-00506f85="">というスタティックルートが必要になります。</div>
</div>
<p id="558bd618-473e-4872-b4f1-c98941fdd35e">VPCルートテーブルが正しくても、Windows OS内にこのルートがなければ、監視サーバ向けの通信は期待した経路に流れません。</p>
<p id="d28e64a9-5ed9-4074-811c-634190aecfa4">EC2はクラウド上の仮想サーバです。</p>
<p id="6420f64d-4848-4fcc-b51d-885a1590558c">しかし、サーバである以上、OSの中にもネットワーク設定があります。</p>
<p id="287de988-c449-45bd-933f-f4daa1edf4b4">クラウド側の設定だけでは、通信は完結しません。</p>
<p id="714591fe-82e4-43d5-a195-bcbebdccdcce">さらに、別AZで起動すると、通常は起動先のサブネットも変わります。</p>
<p id="c67abc63-67e0-435e-b423-e1903ea6e1af">サブネットやENI構成が変われば、OS内のスタティックルートで前提にしていたネクストホップ（次に経由するルーターやゲートウェイのIPアドレス）　　やインターフェースが、移動先の環境と合わなくなることがあります。</p>
<p id="2e61561a-0f65-42b6-b5b9-713341bd8895">しかし、AMIを取得した時点のOS内ルート情報には、旧環境を前提にした経路が残っている場合があります。</p>
<p id="b24f9cda-53c0-47b5-8c77-eb1426745f06">そのまま別AZで起動すると、ルートのエントリは存在しているのに、実際には期待した経路へ到達できない。</p>
<p id="6c8da315-1f88-4c00-b62e-8e52f9d0880a">これが、</p>
<p id="de020489-a57e-4e8b-849d-4db0decf00a5">「設定した覚えはあるのに通信できない」</p>
<p id="04d9981e-06be-48eb-9e9c-eba36d62f716">という事象の正体です。</p>
<h2 id="99877098-61b6-496c-848d-5dd548e51304" tabindex="-1"><span id="toc3">原因はEC2Launchの起動時処理だった</span></h2>
<p id="b48b74a5-65a3-4e18-9b13-bda3220b0a70">原因は、Windows Serverの起動時に動く初期化処理でした。</p>
<p id="18317afc-79f3-4f82-a242-aed5963f82af">Windows Server 2012 R2以前では、EC2Configというサービスが使われていました。</p>
<p id="ac3131f8-dfdc-4399-a5dd-b3c6834e78d7">一方、Windows Server 2016 / 2019では、EC2Launch v1が使われる構成があります。</p>
<p id="8d0a940b-bc2d-4b5d-a36f-27b49ffb694b">ここで見落としやすいのは、</p>
<p id="48da3542-dbca-4370-9abe-edd7ecdc348a">「Windows Serverなら、起動時に毎回同じ初期化処理が走る」</p>
<p id="858ea04d-9c9a-43ba-9a03-e9bc1e26eca1">とは限らないことです。</p>
<p id="4c1c9119-37e9-4b70-8d94-a8cb3f4e45f8">今回のポイントはここです。</p>
<p id="041b0076-981e-4bad-9489-1765f91126a6">AMIを取得する前のインスタンスで、すでに初回起動時の処理が終わっている。<br />
その状態をAMIとして固める。<br />
そのAMIから別AZで起動する。<br />
しかし、OSや初期化エージェントの状態としては、必要な処理が「初回起動時のみ実行済み」と扱われる。<br />
その結果、別AZで起動したときに、ルート追加処理が走らない。</p>
<p id="41cc4ac3-908f-4b8b-8fb7-18b291af7f98">このような流れになると、EC2自体は起動しているのに、OS内のルート情報が移動先AZに合わないまま残ります。</p>
<p id="290b3c4f-ad31-4814-be17-76c2d6054a39">その結果、サーバは起動したのに通信できない、という状態になります。</p>
<p id="41d6073d-d6ec-47c3-81a0-db5ec5d68053">若手SEがここで学ぶべきなのは、OSの設定そのものだけではありません。</p>
<p id="0db4176e-26e0-42cc-a8c0-ea7c85ded38a">「その設定は、いつ、どの仕組みによって入るのか」</p>
<p id="89352f38-55e4-4543-9e66-648f12fbfa74">を見る必要があるということです。</p>
<p id="46863647-a47d-4a45-b7a0-99eb63d5563a"><strong>EC2Config、EC2Launch v1、EC2Launch v2をざっくり押さえる</strong></p>
<p id="c6e08fd5-bcb1-42c3-b0f4-69a1e9e4bb19">細かい仕様をすべて暗記する必要はありません。</p>
<p id="618b2056-2e7a-4003-8d36-db5d1f9e9707">ただ、Windows EC2の初期化エージェントには世代差があることは押さえておくべきです。</p>
<div class="code-block-container">
<pre id="215f7c23-ee25-42a0-b706-21d6c14f0329" data-name="preCode"><code class="hljs" data-name="code">Windows Server 2012 R2以前
  → EC2Config

Windows Server 2016 / 2019の一部AMI
  → EC2Launch v1

Windows Server 2022 / 2025、
一部のWindows Server 2016 / 2019 AMI
  → EC2Launch v2
</code></pre>
<div class="a-button__inner" data-v-00506f85="">現在は、EC2Launch v2への移行が進んでいます。</div>
</div>
<p id="0cbdd46c-2d54-4c1c-ad7b-25048e174389">EC2Launch v2では、「どのタスクを、どのステージで、どの頻度で実行するか」を管理する考え方になります。</p>
<p id="56e59873-f8b1-4f9e-9428-6c2b298e2a85">見るべきポイントは、バージョン名そのものではありません。</p>
<p id="8916d201-98b3-4ee3-84a0-3fcde6a88e2b">実務では、以下を確認します。</p>
<div class="code-block-container">
<pre id="4bbbaade-a532-4ed3-b45d-9601e4422c4f" data-name="preCode"><code class="hljs" data-name="code">・対象OSは何か
・EC2Config、EC2Launch v1、EC2Launch v2のどれか
・User Dataは初回だけか、毎回か
・起動時タスクは有効か
・タスクの実行頻度は once か always か
・初期化処理のログにエラーは出ていないか
</code></pre>
<div class="a-button__inner" data-v-00506f85="">特にEC2Launch v2では、User Dataもタスクとして扱われるため、実行頻度が once なのか always なのかを確認する必要があります。</div>
</div>
<p id="2434891b-d0f2-4600-897d-a014256aabb0">ここを確認しないままDR設計や移行設計を進めると、机上では成立しているのに、切替時に通信できないサーバが立ち上がることがあります。</p>
<p id="48dd7e54-4fbf-4684-a2c2-b8a735faddc2">なお、EC2Launch v2には agent-config.yml などの設定ファイルがありますが、この記事では詳細な設定手順までは踏み込みません。</p>
<p id="9236ab5f-5d3b-4392-b644-d9a4dd5b615e">ここで重要なのは、ファイル名を暗記することではなく、起動時に実行されるタスクと実行頻度を確認する、という考え方です。</p>
<p id="5e6fb7ed-ef69-4bb7-8d94-1a669b884a22"><strong>なぜ永続ルートではなく、起動ごとの処理なのか</strong></p>
<p id="13927e36-ea3c-4e62-a312-d57257a46815">ここで、こう思う人もいるかもしれません。</p>
<p id="3666f2cf-9f9e-4b60-b988-7b15a9961709">「Windowsなら route add -p で永続ルートにすればよいのでは？」</p>
<p id="50f1ad2d-7685-4627-b4dc-4491a3121ad9">たしかに、固定的な経路であれば、それで済む場合もあります。</p>
<p id="09e30b34-392f-4089-854c-8e0a56a90a7f">route add -p は、Windowsで再起動後も残るルートを登録する方法です。</p>
<p id="c1bc12c6-6759-4387-abd1-f8ece513f74f">しかし、クラウド移行やAZ切替では、単純な永続ルートだけでは不十分な場合があります。</p>
<p id="b16c09d2-221c-457a-b387-e34f7e44bcc1">なぜなら、起動先のAZ、サブネット、ENI構成、ゲートウェイ、経路設計によって、追加すべきルートが変わることがあるからです。</p>
<p id="672a0c0f-57b1-4f93-8326-28f5d4815a21">AMIに固定ルートを焼き込んでしまうと、元のAZでは正しくても、別AZでは古い経路を引きずる可能性があります。</p>
<p id="defa0de7-9de4-4b96-b717-63719bece69d">たとえば、元の環境では `10.0.1.1` 側を通る前提でOS内にルートを持っていたとします。</p>
<p id="2f1e7c26-126f-41ab-b46d-65fd68a70832">しかし、別AZで起動した後は、サブネットやENI構成が変わり、`10.0.2.1` 側を通すべき構成になっているかもしれません。</p>
<p id="f6adfcbc-97ec-40c2-a19c-850f7dd3340a">このとき、OS内に旧環境のルートが残ったままだと、設定は存在しているのに、移動先環境では正しい経路に通信が流れません。</p>
<p id="c0f012db-e45f-4526-a8e7-84fc922b3805">一方、起動ごとのスクリプトでルートを追加する方式なら、起動先の環境に合わせて必要なルートを入れ直す設計にできます。</p>
<p id="fdfd37e4-556b-491d-9966-08f4b296a18b">もちろん、その分だけスクリプト設計は慎重に行う必要があります。</p>
<p id="272f33d3-2e68-4fcd-a812-c24db7c26af6">特に重要なのが、冪等性です。</p>
<p id="c66f034f-4e56-426a-9401-23e0235104a5">冪等性とは<strong>「同じ処理を何度実行しても、結果が壊れず同じ状態に収まる性質のこと」</strong>です。</p>
<p id="83472d99-91b3-472a-b240-2ea13f788f0d">起動のたびに実行される処理は、何度実行しても壊れないように作る必要があります。</p>
<p id="4c7ca025-bd64-4f21-bcc9-fd6f6cd9f7eb">たとえば、同じルートを毎回追加しようとしてエラーになる。<br />
既存設定を無条件で上書きしてしまう。<br />
途中で失敗したときに中途半端な状態が残る。</p>
<p id="595cc8a9-9868-46e0-bb64-254f2601bf48">こうした作りになっていると、初期化処理そのものが新しい障害原因になります。</p>
<h2 id="ffb4b76d-d9d7-4cd8-ac35-4ea4923847d2" tabindex="-1"><span id="toc4">対策は「OS起動ごとに必要な処理を実行させる」こと</span></h2>
<p id="b99140a8-5071-4048-ba68-94bf2247b63a">今回の対策は、OS起動ごとに必要なルート追加処理が実行されるようにすることでした。</p>
<p id="d9074ce8-8323-4a49-98dc-1ddfdc458a6d">EC2Launch v1の場合、単に「起動すれば自動で全部整う」と考えるのではなく、起動時に必要な処理が実行される状態になっているかを確認する必要があります。</p>
<p id="2ca816d6-31b8-44a9-bf5b-239ca6df67de">たとえば、今回のようなルート追加であれば、User DataからEC2Launchのモジュールを読み込み、`Add-Routes` を呼び出す方法があります。</p>
<div class="code-block-container">
<pre id="3c15d7d2-f4b4-4fbd-bff8-b73d09d6d9da" data-name="preCode"><code class="hljs ruby" data-name="code">Import-Module (Join-Path $env<span class="hljs-symbol">:ProgramData</span> <span class="hljs-string">'Amazon\EC2-Windows\Launch\Module\Ec2Launch.psd1'</span>)
Add-Routes</code></pre>
<div class="a-button__inner" data-v-00506f85="">さらに、User Dataを起動ごとに実行したい場合は、persist を有効にします。</div>
</div>
<div class="code-block-container">
<pre id="fc69529c-b693-4730-9298-0452a352f91e" data-name="preCode"><code class="hljs javascript" data-name="code">&lt;persist&gt;<span class="hljs-literal">true</span>&lt;<span class="hljs-regexp">/persist&gt;</span></code></pre>
<div class="a-button__inner" data-v-00506f85="">これにより、インスタンス起動時にUser Dataの処理が繰り返し実行され、移動先環境に合わせたルート追加処理を走らせることができます。</div>
</div>
<p id="ebfe3831-d78c-4893-bf03-78d06e21cb52">重要なのは、コマンドそのものを暗記することではありません。</p>
<p id="cce9e892-0477-43e2-920e-934e57f50d92">タスクスケジューラ、User Data、EC2Launchのどの仕組みによって、起動時の処理を実行させているのかを理解することです。</p>
<p id="f01fcead-b950-40a8-bbd7-63ae65fbff3b">EC2Launch v2では、この種の起動時タスクの扱いが整理されており、同じ問題が起きにくい構成になっています。</p>
<p id="49cb7bbc-6b39-4a46-b3b3-d1077715a9ee">ただし、実際の挙動は、AMIの世代、EC2Launchのバージョン、User Data、タスクの実行頻度に依存します。</p>
<p id="454bb55a-a98e-48f6-a49f-b2ba01163394">そのため、v2だから確認不要、とは考えない方が安全です。</p>
<p id="9546e064-917d-45a0-98e6-6e575ffea0c9">環境によって確認ポイントは変わります。</p>
<p id="a1d6843a-1495-48f5-ae71-174cb79e8f15">しかし、共通する考え方は同じです。</p>
<p id="fe9f05a2-93ed-42d5-afce-876646e15a59">「起動時に、必要なOS設定が、確実に反映される状態になっているか」</p>
<p id="5f4a3331-5b6a-4ff0-991c-3d41e67d7027">ここを確認する必要があります。</p>
<h2 id="a646f83e-76e1-4a3d-9fdf-5207130cc22e" tabindex="-1"><span id="toc5">AWS側の設定だけ見ても足りない</span></h2>
<p id="9cd7c1d7-ec90-419e-8ba4-2800e2e09d7c">若手SEにとって、EC2の通信不可というと、どうしてもAWS側の設定に目が行きます。</p>
<p id="eb2369b5-f961-4003-9a70-46c60b5bba5a">それ自体は間違いではありません。</p>
<p id="1cf8e9b7-0c39-4958-8d5e-1c4dd771fbd5">実際、通信不可の原因として、セキュリティグループ、NACL、VPCルートテーブル、サブネット、ENI、DNS設定などはよくあります。</p>
<p id="bb05981f-4562-4edd-b493-22f488800052">しかし、それだけでは足りません。</p>
<p id="8b8feb07-8fb6-4dc9-9b56-1ebcca31342c">今回のように、OS内部の設定が原因になることもあります。</p>
<p id="70f08156-abe7-412c-8fd0-8122ff77b59c">今回の切り分けは、3つの層で見ると整理しやすくなります。</p>
<div class="code-block-container">
<pre id="b657639a-00e7-41bc-a6c0-708533387c30" data-name="preCode"><code class="hljs" data-name="code">AWSインフラ層
  → セキュリティグループ、NACL、VPCルートテーブルを見る

初期化エージェント層
  → EC2LaunchやUser Dataが期待どおり実行されたかを見る

OS設定層
  → Windowsのルーティングテーブルが移動先環境に合っているかを見る
</code></pre>
<div class="a-button__inner" data-v-00506f85="">今回の原因は、AWSインフラ層ではなく、初期化エージェント層とOS設定層の間にありました。</div>
</div>
<p id="008ff45d-0f6d-4718-876c-921dbe2ac2e2">EC2の通信確認では、AWS側の設定、クラウド初期化処理、OS内部の設定を一連の流れとして見る必要があります。</p>
<figure id="34ae7188-7c91-481f-b108-8c5b3bed636f">
<div style="width: 630px" class="wp-caption aligncenter"><a href="https://assets.st-note.com/img/1780473510-jpmDS8wUoYf6e4PZRXhbilrK.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide" src="https://assets.st-note.com/img/1780473510-jpmDS8wUoYf6e4PZRXhbilrK.png?width=1200" alt="画像" width="620" height="439" data-modal="true" /></a><p class="wp-caption-text">図　AWS側の設定だけ見ても足りない</p></div><figcaption></figcaption></figure>
<p id="b7610046-233b-42f1-bfec-c32ee4771b31">この図で言いたいのは、EC2が起動した時点で確認が終わるわけではない、ということです。</p>
<p id="e8bd6263-71e5-47d2-bd61-a81e6efae9c3">AWS側の設定が正しく、インスタンスが起動していても、その後に動く初期化処理やOS内部の設定が想定どおりでなければ、業務通信は成立しません。</p>
<p id="a433a55b-2556-4ce8-bcff-6360b67c154c">サーバが起動していることと、業務通信が成立していることは別です。</p>
<p id="944bd7c5-1a7c-4b0b-a392-5a53b6845d77">ここを混同すると、DRテストや移行リハーサルで痛い目を見ます。</p>
<h2 id="88eefb7d-79fc-49c6-a6f2-2becfa26dfe3" tabindex="-1"><span id="toc6">これはルーティングだけの話ではない</span></h2>
<p id="b497ca4f-e0f8-4987-8d88-7c06627610d7">今回の事象は、Windows Serverのルーティング情報が更新されなかった、という個別トラブルに見えます。</p>
<p id="b5187475-b14b-4be9-930e-2fc920563bba">しかし、これはルーティングだけの話ではありません。</p>
<p id="c8fd7ac7-e7f6-473b-a32b-382e493bb8c0">以前扱ったような、MTU設定が戻る、SSHでログインできない、OS起動後に想定した設定になっていない、といった事象にも共通する構造があります。</p>
<p id="e48a4680-2290-4c0f-b16d-332b33aa3e16">共通しているのは、初期化エージェントがOS設定を書き換える、または書き換えないことで、起動後のOS状態が想定とずれる点です。</p>
<p id="e0ca0382-7430-4122-a56e-d4da26079a32">ある設定は、初期化エージェントによって上書きされます。</p>
<p id="7f3b890b-44f6-43bf-9d76-02ffedd1bcc3">別の設定は、初期化エージェントが実行されないために更新されません。</p>
<p id="a72179eb-5b83-4733-9aa9-a9bcd559fad8">つまり、</p>
<p id="9e46566e-43e3-496b-a39f-cf69a57d9efe">「書き換えられて困る」</p>
<p id="cc4dbf88-fc42-4ff6-af57-eba774015879">場合もあれば、</p>
<p id="5868f75e-2a3d-411e-ab45-1ab4d8565d1c">「書き換えてほしいのに書き換わらない」</p>
<p id="bfe239b1-65a2-4b53-9f94-a1f495208493">場合もあります。</p>
<p id="53112035-682e-4cf2-90b3-f101574ce9dd">どちらも、クラウド初期化処理がOS設定に関与していることを理解していないと、原因にたどり着きにくくなります。</p>
<h2 id="dcdadf47-4d5e-4dce-a98a-1a1492e0fc38" tabindex="-1"><span id="toc7">なぜクラウドはOS設定を書き換えるのか</span></h2>
<p id="bbeff4ac-5424-42b8-ab0a-6a307b935a90">では、なぜクラウド環境では、起動時にOS設定へ手を入れるのでしょうか。</p>
<p id="58d5f910-b76e-487d-ab97-293c79dbb820">理由は大きく3つあります。</p>
<p id="b6c55e9e-0fe0-4c4d-92ca-22e64e4833c0">1つ目は、セキュリティです。</p>
<p id="fcb37893-80de-4380-b1e7-cd7ae76ff846">クラウド環境では、インターネットや社内ネットワークから到達可能なサーバを短時間で作成できます。</p>
<p id="6d53b24d-3481-46ab-a6b0-f532e7144bf0">そのため、初期状態をできるだけ安全側に寄せる必要があります。</p>
<p id="84296913-9871-4a5a-90fb-eddaba2fa80f">SSHのパスワード認証を無効にし、公開鍵認証を前提にするような考え方は、その典型です。</p>
<p id="84a5be44-9c7f-41ff-9c54-5f29122d3230">パスワード総当たり攻撃の入口を減らすためです。</p>
<p id="c708c9e1-ca21-4ac9-bb86-ad5a74f9ef80">これは、クラウド環境におけるベストプラクティスに寄せた挙動と考えると理解しやすいです。</p>
<p id="edea57d0-7873-44a6-b2ab-05acc0a6add7">2つ目は、クラウド環境に合わせてOSを自動適応させるためです。</p>
<p id="7ce72a7a-dc57-464e-bdad-25fb05d79ced">EC2インスタンスは、起動時にインスタンスメタデータ、User Data、ネットワーク情報などを利用します。</p>
<p id="4ac540b9-3bf1-4074-b261-717feb53e0d3">OSは、起動した場所、割り当てられたIP、ホスト名、初期化スクリプトなどをもとに、クラウド上で動ける状態に整えられます。</p>
<p id="0a9081b5-8ac6-4e2f-8a59-715d9edf847d">3つ目は、AMIを再利用するためです。</p>
<p id="6c15de6b-8039-46ad-8a09-0a0693308b8d">AMIは、ある時点のOS状態を固めたものです。</p>
<p id="5ad2e64b-b093-46e1-acc2-736f84bd576c">しかし、そのAMIから起動されるインスタンスは、元の環境と同じとは限りません。</p>
<p id="b6bfb5bd-75c8-4069-8c9f-647670e014e4">別AZかもしれません。<br />
別サブネットかもしれません。<br />
別IPかもしれません。<br />
別用途のサーバとして起動されるかもしれません。</p>
<p id="378eaf36-6e37-457d-8b0f-10597b76aa4f">そのため、AMIに残っているOS設定をそのまま信じるだけでは危険です。</p>
<p id="8969a507-91c0-4c74-937f-a00445e05ca1">クラウドでは、起動時にメタデータやUser Dataを参照し、起動先の環境に合わせて初期化する仕組みが用意されています。</p>
<p id="7edb6bb8-fc76-4064-b0aa-3622d63f9413">ただし、その初期化処理が「いつ」「どの条件で」「何を」実行するかは、OS、エージェント、設定によって変わります。</p>
<p id="0af63280-b917-4939-b3ef-073b2b8886e0">ここを理解していないと、</p>
<div class="code-block-container">
<pre id="b0ac7176-e1d2-44f3-ba45-16fbbeb48224" data-name="preCode"><code class="hljs" data-name="code">設定したはずなのに戻った
自動で入ると思っていたのに入らなかった
AMIから起動したら前の状態を引きずった
</code></pre>
<div class="a-button__inner" data-v-00506f85="">という事象が起こります。</div>
</div>
<h2 id="b7c0ad2b-c423-4958-afa9-7e572f0397e9" tabindex="-1"><span id="toc8">DR設計では「起動できる」だけでは足りない</span></h2>
<p id="afc653c5-4207-47b0-a738-535870392c7b">今回の話は、DR設計やAZ障害時の切替設計にも直結します。</p>
<p id="c2c4b579-673b-495e-98fe-3a17340222b6">DR設計では、次のような確認をしがちです。</p>
<div class="code-block-container">
<pre id="f4c89edf-77dc-429b-b9c6-b920af551280" data-name="preCode"><code class="hljs" data-name="code">・別AZでEC2が起動できる
・AMIからインスタンスを作成できる
・EBSを付け替えられる
・IPやDNSを切り替えられる
</code></pre>
<div class="a-button__inner" data-v-00506f85="">もちろん、これらは重要です。</div>
</div>
<p id="ddc3a103-b93b-45fb-8caa-0dbc7eab78a4">しかし、これだけでは不十分です。</p>
<p id="1fdcd319-d5ff-4c51-b638-4167d25baded">本当に確認すべきなのは、起動後に業務通信が成立するかです。</p>
<p id="2c4f0a7c-ae0a-4b07-8ca2-214a0f14de29">実務では、少なくとも以下を確認した方がよいです。</p>
<div class="code-block-container">
<pre id="8c663d5a-3d2d-470a-9c70-75d2c24301ff" data-name="preCode"><code class="hljs" data-name="code">・OS内のルート情報は正しいか
・DNS名前解決はできるか
・ADや認証基盤へ到達できるか
・業務アプリの接続先へ通信できるか
・監視、バックアップ、ジョブ管理エージェントは動くか
・User Dataや起動時スクリプトは期待どおり実行されたか
・初期化処理のログにエラーは出ていないか
</code></pre>
<div class="a-button__inner" data-v-00506f85="">DRテストで見るべきなのは、インスタンスの起動成功ではありません。</div>
</div>
<p id="379cbc44-b2bc-41a5-9ea6-7e07a84e199d">業務として使える状態になったかどうかです。</p>
<p id="fbff3646-bde5-4ded-8371-a0b34e6dd069">ここを間違えると、テストでは成功したように見えても、本番障害時に通信できないサーバが立ち上がることになります。</p>
<h2 id="83a8c398-c306-41d8-80e1-51081f7e5856" tabindex="-1"><span id="toc9">まとめ</span></h2>
<p id="34fed3d6-cb18-4f15-bdf5-a17a80deb49f">今回は、EC2を別AZで起動した際に、Windows Serverのルーティング情報が更新されず、通信できなくなった事象を扱いました。</p>
<p id="44c32348-a128-4031-8d0a-ecb02e906184">原因は、AWS側のセキュリティグループやVPCルートテーブルではなく、OS内部のルート情報でした。</p>
<p id="86459391-867b-46b3-91ce-30bc7f9c85f9">そして、その背景には、EC2Config、EC2Launch、EC2Launch v2といったクラウド初期化エージェントの挙動差がありました。</p>
<p id="48b161c5-54db-4119-9265-4b695fe8f2ba">クラウドでは、サーバを起動するだけなら簡単です。</p>
<p id="0c7a2496-9c90-4c6b-ad64-66cf3d3315f0">しかし、起動したサーバが業務として使える状態になっているかは、別の問題です。</p>
<p id="0b4034bf-072e-4182-a173-6b62449b2431">若手SEは、EC2が起動したかどうかだけで安心してはいけません。</p>
<p id="7a7fab07-c8c1-4567-9597-8d002965293a">見るべきなのは、起動後に、どの設定が、どのタイミングで、どの仕組みによって反映されるのかです。</p>
<p id="a76a836c-421f-499b-b667-c3be5c8485ce">サーバは起動した。<br />
でも通信できない。</p>
<p id="3441d922-79bb-40c4-b038-e0ea5edd8f60">その原因は、AWS側ではなく、OSの中にあるかもしれません。</p>
<hr id="fd9b46d7-9522-49ac-8bb8-743c2079c671" />
<p id="bad0c73b-5e79-4e8d-8a38-c9d8c1a681bc"><strong>関連記事</strong></p>
<p>今回のようなトラブルは、AWSやOSの設定だけを個別に見るのではなく、切替後にシステム全体が業務として使える状態になっているかまで確認する必要があります。</p>
<p><strong>システム基盤・クラウドエンジニアの仕事</strong><br />
サーバー、OS、監視、バックアップ、可用性、クラウドなどを横断し、<br />
システムを「整える・保つ・戻す」ための基盤設計・運用・障害対応を解説しています。</p>

<a href="https://sys-univ.com/dev/system-infrastructure-engineer/" title="システム基盤・クラウドエンジニアの仕事｜整える、保つ、戻す" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/08/769693434e6531947a35f1606041df3d-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">システム基盤・クラウドエンジニアの仕事｜整える、保つ、戻す</div><div class="blogcard-snippet internal-blogcard-snippet">システム基盤エンジニアの仕事内容を、インフラエンジニアとの違いから実務まで解説。サイジング、標準化、監視、可用性、バックアップ、AWS移行、障害対応を大規模SIの実例を交えて紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.17</div></div></div></div></a>
<p><strong>詳細設計とは何を決める工程か｜パラメータ表で終わらせないための設計の考え方</strong><br />
基本設計で決めた内容を、構築・テスト・運用できる具体的な設定や手順へどう落とし込むかを整理しています。</p>

<a href="https://sys-univ.com/dev/detailed-design-overview/" title="【全3回・第1部】詳細設計とは何を決める工程か｜パラメータ表で終わらせないための設計の考え方" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【全3回・第1部】詳細設計とは何を決める工程か｜パラメータ表で終わらせないための設計の考え方</div><div class="blogcard-snippet internal-blogcard-snippet">詳細設計とは、基本設計で決めた方式を構築・テスト・運用できる粒度に落とし込む工程です。OS、ミドルウェア、DB、ジョブ、監視、バックアップなどを、単なるパラメータ表ではなく品質保証ストーリーとして設計する考え方を基盤SEの目線で解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.20</div></div></div></div></a>
<p><strong>シリーズ全体は「実務で使えるシステム開発方法論」マガジンにまとめています。</strong></p>

<a rel="noopener" href="https://note.com/k_s7906/m/mc19593a012e2" title="実務で使えるシステム開発方法論｜ナギ ＠ 氷河期SEの知見録｜note" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://sys-univ.com/wp-content/uploads/cocoon-resources/blog-card-cache/0f32eea23c3fec6193dcd0147c80e86d.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">実務で使えるシステム開発方法論｜ナギ ＠ 氷河期SEの知見録｜note</div><div class="blogcard-snippet external-blogcard-snippet">要件定義、基本設計、詳細設計、テスト、移行、運用保守まで、システム開発の流れを実務目線で体系化するマガジンです。教科書には書かれにくい、設計漏れ、手戻り、品質保証、運用で詰まるポイントを、現場経験に基づいて整理します。若手SEだけでなく、開ReadMore...</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://note.com/k_s7906/m/mc19593a012e2" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">note.com</div></div></div></div></a>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/addroute/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>EC2を止めただけなのに再作成？Auto Scaling運用の落とし穴｜クラウドの自動化は、作業者の意図までは読んでくれない</title>
		<link>https://sys-univ.com/incident/ec2autoscaling/</link>
					<comments>https://sys-univ.com/incident/ec2autoscaling/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Thu, 06 Aug 2026 12:06:17 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[AWS]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=1510</guid>

					<description><![CDATA[AWSを使っていると、EC2を一時的に停止・起動したい場面があります。 たとえば、検証作業、メンテナンス、OS設定変更、ミドルウェア設定変更、不要時間帯の停止などです。 単体のEC2であれば、停止して、起動する。それだけ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p id="d4dcfd93-906c-4bb8-93a4-2f8b0a294955">AWSを使っていると、EC2を一時的に停止・起動したい場面があります。</p>
<p id="4a994136-f88d-4179-87c3-23a198235f36">たとえば、検証作業、メンテナンス、OS設定変更、ミドルウェア設定変更、不要時間帯の停止などです。</p>
<p id="933c34dc-d328-49f9-93a9-12cd30ebfe47">単体のEC2であれば、停止して、起動する。それだけです。</p>
<p id="8fc23f98-e07e-4268-ba5f-0cbf714c8827">しかし、そのEC2がAuto Scaling Group配下のインスタンスだった場合、話は少し変わります。</p>
<p id="6db2ebfa-c75b-495f-b44a-0d3720da0961">Auto Scaling Groupは、単にEC2をまとめて管理する仕組みではありません。指定された台数を維持するために、インスタンスの状態を監視し、異常と判断した場合には新しいインスタンスに置き換える仕組みです。</p>
<figure id="18c62ac1-b3e0-46c9-828f-4f78deb1d30f">
<p><a href="https://assets.st-note.com/img/1780102175-dzpUTNAZfmIv8uabFtkV530Q.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide aligncenter" src="https://assets.st-note.com/img/1780102175-dzpUTNAZfmIv8uabFtkV530Q.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a></p><figcaption></figcaption></figure>
<p id="6c273a4c-d9fe-4874-b809-408f0946f496">ここで、現場で起こりがちな事故があります。</p>
<p id="d12cb694-0048-442b-b96f-e5feae352937">Auto Scaling対象のEC2を停止・起動したところ、意図せずインスタンスが再作成されてしまう。</p>
<p id="a16493a2-3e66-4b5b-9d3d-33f6d311b077">作業者としては「既存のEC2を一時停止して、また起動しただけ」のつもりです。しかしAuto Scaling側から見ると「正常ではないインスタンスがいる。希望台数を維持する必要がある」という判断になることがあります。そして結果として新しいEC2が起動され、元のEC2が置き換えられてしまう。</p>
<p id="75b0473e-f47e-40ad-8ad5-5d37e3bd7276">これが、Auto Scaling配下のEC2停止・起動で起こる落とし穴です。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">クラウドでも、過去の落とし穴が消えているとは限らない</a></li><li><a href="#toc2" tabindex="0">HealthCheckとReplaceUnhealthyの違い</a></li><li><a href="#toc3" tabindex="0">「ヘルスチェック猶予期間があるから大丈夫」ではない</a></li><li><a href="#toc4" tabindex="0">どう対策すべきか</a></li><li><a href="#toc5" tabindex="0">事前にどうチェックすべきか</a></li><li><a href="#toc6" tabindex="0">これは運用設計の問題である</a></li><li><a href="#toc7" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 id="df4826ab-8688-41e5-8e0f-d9b7f182337b" tabindex="-1"><span id="toc1">クラウドでも、過去の落とし穴が消えているとは限らない</span></h2>
<p id="626b903b-3062-4620-8151-82228931dab2">実はこれ、かなり昔に経験した事象です。</p>
<p id="85e056ea-6a41-4ef0-a863-30398713abb4">Auto Scaling配下のEC2を停止・起動したところ、意図せずインスタンスが再作成されてしまった。</p>
<p id="ecd93a97-7534-4d6e-ae64-ecc7789167af">当時は、「そんな動きをするのか」と思いました。</p>
<p id="bcc293fd-c0ae-4c44-a0bf-a7c1c148284c">ただ、クラウドサービスは日々進化します。</p>
<p id="9557d3b7-a169-4f1e-ba38-b5bc08cf2a91">昔の事故事例を、今もそのまま起こる前提で語るのは危険です。</p>
<p id="36be8f4c-af7d-4b63-bbbb-06076abbd421">一方で、過去に起きた事故や落とし穴が、現在では完全に解消されているとも限りません。</p>
<p id="5ad3abee-c096-4522-8f17-b51ad653f3a8">特に、Auto Scaling、ヘルスチェック、自動復旧、フェイルオーバーのような仕組みは、クラウドサービスの基本的な設計思想に関わります。</p>
<p id="fdc6cfd5-dfbd-482e-bdd4-63dc633a0118">そのため、昔の事例であっても、今の仕様ではどうなっているのかを確認することが大切です。</p>
<p id="bf800540-9b76-4ff6-8268-94ad607e9db2">今回の事象も、現在の<a rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/ec2-auto-scaling-health-checks.html" target="_blank">AWS公式ドキュメント</a>で確認できます。</p>
<figure id="15d36664-c7a3-4e26-91c3-d27e2e18f5b8">
<blockquote>
<p id="31ba7614-03dd-4e72-99cb-e45726fedb6f">ヘルスチェック猶予期間中であっても、Amazon EC2 Auto ScalingがインスタンスをEC2の running 状態ではないと検出した場合、そのインスタンスを即座に Unhealthy とマークして置き換える</p>
</blockquote><figcaption><a rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/ec2-auto-scaling-health-checks.html" target="_blank">AWS公式ドキュメント</a></figcaption></figure>
<figure id="29b279e6-f19a-4931-8e5c-7177650a190d"><a href="https://assets.st-note.com/img/1780102574-fbZvws2oIGc37XH5ngNykQmB.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide aligncenter" src="https://assets.st-note.com/img/1780102574-fbZvws2oIGc37XH5ngNykQmB.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="3acad24b-b1d1-446a-b71b-061137923a4c">つまり、Auto Scaling Group配下のEC2を停止するという行為は、今でも単体EC2の停止とは意味が違います。</p>
<p id="62606795-0736-42c2-9686-0bbbe328687b">単体EC2なら、停止はただの停止です。</p>
<p id="905dc497-98c6-4668-a34d-0f47782bc308"><strong>しかしAuto Scaling Group配下では「本来動いているべきインスタンスが、正常な状態ではない」と判断される可能性があります。</strong></p>
<p id="42406c04-0f71-404f-8d98-6b17f32804fc">これはAWSのバグというより、Auto Scalingが希望台数を維持するための仕様です。</p>
<p id="a76869a2-e2d6-4abf-8a75-0ccf3c79ac28">問題は、作業者の意図とAuto Scalingの判断がずれることです。</p>
<h2 id="9cc1386c-8e73-4f2c-b2ed-5af316b4114e" tabindex="-1"><span id="toc2">HealthCheckとReplaceUnhealthyの違い</span></h2>
<p id="d2652342-04e2-4e50-b486-2a5959085fde">Auto Scalingには複数の内部プロセスがあります。今回特に関係するのがHealthCheckとReplaceUnhealthyです。</p>
<p id="adc7df10-249e-4f03-9e3b-d140efffef7d">HealthCheckはインスタンスの正常性を確認し、ReplaceUnhealthyは、異常と判断されたインスタンスを置き換えるプロセスです。</p>
<p id="cd59abbc-d7a6-4cad-864b-e3b3d5086588">AWS公式ドキュメントでは、以下のとおり説明されています。</p>
<figure id="17437a21-b535-460e-b68b-03679f492880">
<blockquote>
<p id="7274444e-1a58-42e3-bfab-d89192fcfa46">・ReplaceUnhealthyを停止すると異常とマークされたインスタンスの置き換えは止まるが、EC2やELBのヘルスチェックに失敗したインスタンスは引き続き異常とマークされる<br />
・ReplaceUnhealthyを再開すると、停止中に異常とマークされていたインスタンスが置き換えられる</p>
</blockquote><figcaption><a rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/understand-how-suspending-processes-affects-other-processes.html" target="_blank">（AWS公式ドキュメント）</a></figcaption></figure>
<figure id="dfedd44e-9b2c-4949-a6df-1f12740c54e0"><a href="https://assets.st-note.com/img/1780102595-brECIa6Jpk20uUj8mY1nqzQe.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide aligncenter" src="https://assets.st-note.com/img/1780102595-brECIa6Jpk20uUj8mY1nqzQe.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="6108d3c7-3c5e-4050-8920-8ecf8f28bb3d">つまり、ReplaceUnhealthyを止めていたとしても、その間にインスタンスが異常扱いになっていると、再開した瞬間に置き換えが走る可能性があります。</p>
<p id="d5890be3-b293-4680-b676-fc83ab2c3b4d">作業者としては「作業が終わったから戻そう」という感覚です。しかしAuto Scaling側では「このインスタンスはすでに異常とマークされています。プロセスが再開されたので置き換えます」という動きになる可能性があります。だから、単にプロセスを戻すのではなく、戻す前の状態確認が必要になります。</p>
<h2 id="157e5bf6-f6fb-46fd-970c-5eb08bae93a6" tabindex="-1"><span id="toc3">「ヘルスチェック猶予期間があるから大丈夫」ではない</span></h2>
<p id="0d11176c-12af-4a64-ae76-39d6417ad2f8">ヘルスチェック猶予期間は、新しく起動したインスタンスがInServiceになってから、Auto Scalingがヘルスチェックの評価を始めるまでの待ち時間です<a rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/health-check-grace-period.html" target="_blank">（AWS公式ドキュメント）</a>。</p>
<p id="7d5cea67-6b34-44fd-b3b7-63760745c30c">これだけを見ると「猶予期間を長くしておけば安全では？」と思うかもしれません。しかしここに落とし穴があります。</p>
<p id="f8c9b724-2b6b-4398-9dd8-d3c617d2856b">ヘルスチェック猶予期間は、アプリケーションの起動待ちには役立ちます。しかし、Auto Scaling Group内のインスタンスを停止した場合に、それを安全に見逃してくれる仕組みではありません。ここを勘違いすると危険です。</p>
<h2 id="5a6b3705-7a7c-4c6b-9bbc-36193c615743" tabindex="-1"><span id="toc4">どう対策すべきか</span></h2>
<p id="6fc76cc5-10fa-4d58-a9f4-710dbe2d2768">対策として重要なのは、EC2を起動した直後にAuto Scalingのヘルスチェックや置き換えプロセスを機械的に戻さないことです。</p>
<p id="b7ccb40b-a086-4b1b-9f0f-bcc16631f50d">「EC2起動後、5分待ってからヘルスチェックを有効化する」という運用は実務上よく見ます。ただし、5分という数字そのものが本質ではありません。本質は「Auto Scalingが正常と判断できる状態になってから戻す」ことです。</p>
<figure id="04c6cc47-e3a0-405b-b115-c6d7555e9e18"><a href="https://assets.st-note.com/img/1780102941-MWyU9tAB81TgDq7r5IOuXQP0.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide aligncenter" src="https://assets.st-note.com/img/1780102941-MWyU9tAB81TgDq7r5IOuXQP0.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="54f17e97-08d7-4fe3-8aa5-ab8bd53d75ba">戻す前に確認すべきことは次のとおりです。</p>
<ul id="6c77152f-9408-44a9-9757-ebdfcf12f8b4">
<li>
<p id="2d532c37-2f58-4c86-aa62-f5a19b150253">EC2のステータスチェックが正常であること</p>
</li>
<li>
<p id="305e05db-c118-4244-9e89-744023ad1a18">OSが正常に起動していること</p>
</li>
<li>
<p id="a5602b8f-803f-4011-a8a0-210d1d492ed4">ミドルウェアが起動していること</p>
</li>
<li>
<p id="9bd17dd0-37cb-4bd7-95a9-7da271204ea1">アプリケーションが正常応答していること</p>
</li>
<li>
<p id="0db5e50d-80d8-45f4-84bb-6e29ca4e3609">ELBまたはターゲットグループでHealthyになっていること</p>
</li>
<li>
<p id="e08b0909-a04e-4b87-84dc-039e7857fb45">Auto Scaling Activityに異常な置き換え履歴がないこと</p>
</li>
</ul>
<p id="754950cd-db31-4f40-9716-94986bf483f8">手順書には「起動後5分待つ」だけでなく、「何を確認できたら次の操作に進んでよいのか」を書く必要があります。</p>
<h2 id="026a6714-b19b-4c9a-b547-e86eead48224" tabindex="-1"><span id="toc5">事前にどうチェックすべきか</span></h2>
<p id="6867611f-7ab9-4613-b203-08b63489a806">このような事象を防ぐために、作業前に確認すべき点は大きく4つあります。</p>
<p id="0e764eeb-9724-4aa1-8914-dc4107cc4525"><strong>1. 対象EC2がAuto Scaling Group配下か確認する</strong></p>
<p id="a0388558-f896-437c-950b-702c78daf7fb">EC2一覧だけを見ていると、普通のEC2に見えます。しかしタグやAuto Scaling Group名を見ると、ASG管理対象であることがあります。少なくとも以下を確認してください。</p>
<ul id="4fcbf8b2-2c74-4612-9591-d7133b9337d2">
<li>
<p id="03fd93b8-c9f3-4c6a-af02-9db2a8487eeb">対象EC2はAuto Scaling Group配下か</p>
</li>
<li>
<p id="a1ccfdf4-2a60-4bf3-bfd6-cfb18b406058">Desired Capacityはいくつか</p>
</li>
<li>
<p id="5e84155e-4af4-4ade-906b-ac70088c7aac">対象インスタンスを停止した場合、希望台数維持のために補充されるか</p>
</li>
<li>
<p id="c5b494ce-c951-4d53-ac27-7638d6c27f73">再作成された場合、元の状態を再現できるか</p>
</li>
</ul>
<p id="19d2e60e-b389-42cd-8517-bd302a9521d9">特に危険なのは、手作業で設定変更されたEC2がAuto Scalingで再作成されるケースです。再作成されたEC2は起動テンプレートやAMIに基づいて作られるため、手作業で入れた設定が消える可能性があります。</p>
<p id="84a03266-e4af-4b56-92a3-e4fcda1cc2b3"><strong>2. どのAuto Scalingプロセスを止めるべきか確認する</strong></p>
<p id="28b65146-5443-4cff-aa41-58ee63989fc5">HealthCheckとReplaceUnhealthyは意味が違います。状況に応じて、どちらを止めるのか、Standbyを使うのかを判断する必要があります。スケジュールスケーリングやスケーリングポリシーの影響も確認してください。</p>
<ul id="8192c481-2c1f-4584-bc94-9a53ac26c093">
<li>
<p id="87d23782-2a3c-4407-9003-b48b7e23e2f8">プロセスの一時停止・再開：<a rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-suspend-resume-processes.htmlperiod.html" target="_blank">（AWS公式ドキュメント）</a></p>
</li>
<li>
<p id="23fb0902-658e-4e7e-8ddc-bd4f4acb0ac5">Standby機能：<a rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-enter-exit-standby.html" target="_blank">（AWS公式ドキュメント）</a></p>
</li>
</ul>
<p id="8b9d283b-811c-401a-8c27-fccc1498769b"><strong>3. ヘルスチェック猶予期間と起動時間を確認する</strong></p>
<p id="da6adb04-c65c-476b-b092-86e28eca784d">EC2起動からステータスチェック正常化まで何分かかるか、アプリケーションが正常応答するまで何分かかるか、ELBがHealthyになるまで何分かかるか。これらがヘルスチェック猶予期間と整合しているかを確認してください。</p>
<p id="b0ac5c7c-b5e9-43ff-bf64-5f4728316fcb"><strong>4. 手順書に「戻し条件」を書く</strong></p>
<p id="b25ac4f8-1a95-4e2c-9015-abc8f8a11b91">運用手順書でよくあるのは、操作手順は書いてあるが戻し条件が曖昧なケースです。「EC2起動後、Auto Scalingのヘルスチェックを有効化する」だけでは危険です。上で挙げた確認項目をすべて満たしたことを確認してから戻す、と明記する必要があります。</p>
<p id="40b3a2bc-4c6b-423e-b390-48c1a2ec4f45">運用手順で大事なのは操作そのものではありません。次の操作に進んでよい条件を明確にすることです。</p>
<h2 id="9fcbbd3d-45ce-42a8-88a9-1eabe31ff27e" tabindex="-1"><span id="toc6">これは運用設計の問題である</span></h2>
<p id="34afaae9-a3be-4cc6-bdaf-7a625ce0ad1f">今回の話は、AWSのAuto Scalingという個別サービスの話に見えます。しかし実際には運用設計の問題です。</p>
<p id="ee9e5628-7efe-4465-8853-58caaf3af681">Auto Scalingを使うなら、設計時点で少なくとも以下を決めておく必要があります。</p>
<ul id="83dc4274-32bd-409c-8a32-aeb904ab5602">
<li>
<p id="3b4c86fc-199a-4c99-ae35-248178ac6fc6">インスタンスを手動停止してよいのか</p>
</li>
<li>
<p id="72f74f0b-0421-402f-9fc4-be13407cd5f5">メンテナンス時はStandbyに入れるのか</p>
</li>
<li>
<p id="26dc3371-3aec-4640-b7da-b5c7fe2b81a3">HealthCheckやReplaceUnhealthyを一時停止するのか</p>
</li>
<li>
<p id="516eb7bc-ba83-4de5-89c8-0b2546a7c4ef">どの条件を満たしたらAuto Scalingのプロセスを戻してよいのか</p>
</li>
<li>
<p id="8e7b3d1e-759e-47dd-881b-930fbbc870f9">再作成された場合、設定やデータは失われないのか</p>
</li>
<li>
<p id="a36aaf38-4a28-417a-8b8f-194986da96d5">手作業で変更した内容はAMI、起動テンプレート、IaCに反映されているのか</p>
</li>
</ul>
<p id="ea6df4dd-4341-4913-9005-1684ea9ec4c1">これらは、運用当日に作業者がその場で判断するものではありません。設計書、運用設計書、作業手順書、チェックリストに落としておくべき内容です。</p>
<p id="45424004-72e2-4355-84bf-b9f808522c3a">クラウドでは、ひとつの操作に対して裏側で複数の自動化機能が反応します。作業対象のサーバだけを見ていると危険です。周辺にある自動制御の仕組みまで含めて、作業手順を考える必要があります。</p>
<p id="fa0083de-5303-4ee9-a1ed-aa03f8037fe1">これはバックアップ保存期限の設計と同じ構図です。「5日保存」と書いてあっても5営業日分なのか5世代なのかを確認しないと復旧時に認識違いが起きます。Auto Scalingも同様で、「EC2を停止・起動する」とだけ書くのではなく、その操作に対してAuto Scaling、ELB、CloudWatchがどう反応するのかまで設計しておく必要があります。</p>
<p id="d06837a9-5b44-48e2-9453-4a4f00f6426e">設計で決めるべきことを曖昧にしたまま運用に渡すと、作業時に現場が迷います。Auto Scalingの事故は、そのことを教えてくれる典型例です。</p>
<h2 id="d702d3ad-c722-493a-afd2-621153425573" tabindex="-1"><span id="toc7">まとめ</span></h2>
<p>Auto Scaling対象のEC2を停止・起動する場合、単体EC2と同じ感覚で作業してはいけません。</p>
<p>停止中にインスタンスがUnhealthyと判定され、起動直後にプロセスを戻した瞬間に置き換えが始まることがあります。ヘルスチェックの猶予期間を長くしても、停止中に発生する置き換えそのものを防げるわけではありません。「起動後5分待つ」といった運用ルールも、環境や処理時間に依存する暫定的な対処であり、設計上の判断基準にはなりません。</p>
<p>重要なのは、<strong>Auto Scalingがインスタンスを正常と判断できる状態まで復旧したことを確認してから、通常運用へ戻すこと</strong>です。さらに、その正常性を何で確認するのかを設計時点で明確にし、運用手順書へ落としておく必要があります。</p>
<p>クラウドの自動化は便利ですが、作業者が「いまはメンテナンス中だから置き換えてほしくない」と考えていることまでは判断してくれません。正常時の構成だけでなく、メンテナンス時、障害時、復旧時に各サービスがどのように振る舞うのかまで含めて設計することが、クラウド環境では重要になります。</p>
<hr />
<p><strong><span style="font-size: 20px;">関連記事</span></strong></p>
<p>こうした<strong>正常時だけでなく、障害時・復旧時・運用時の振る舞いまで設計する考え方</strong>については、以下の記事でも整理しています。</p>
<ul>
<li data-start="473" data-end="565"><strong data-start="473" data-end="516">詳細設計で決めること｜基本設計を「構築・テスト・運用できる形」に落とし込む工程<br />
</strong>基本設計で決めた方式を、実際に構築できる設定値や設計内容まで具体化する工程を解説しています。</li>
</ul>

<a href="https://sys-univ.com/dev/detailed-design-overview/" title="【全3回・第1部】詳細設計とは何を決める工程か｜パラメータ表で終わらせないための設計の考え方" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/06/a6c056b838ba24669f57a7e23dae134f-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【全3回・第1部】詳細設計とは何を決める工程か｜パラメータ表で終わらせないための設計の考え方</div><div class="blogcard-snippet internal-blogcard-snippet">詳細設計とは、基本設計で決めた方式を構築・テスト・運用できる粒度に落とし込む工程です。OS、ミドルウェア、DB、ジョブ、監視、バックアップなどを、単なるパラメータ表ではなく品質保証ストーリーとして設計する考え方を基盤SEの目線で解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.20</div></div></div></div></a>
<ul>
<li><strong>実務で使えるシステム開発方法論</strong><br />
システム開発の各工程で何を検討し、どのように設計へ落とし込むのかについては、以下のマガジンにまとめています。</li>
</ul>

<a rel="noopener" href="https://note.com/k_s7906/m/mc19593a012e2" title="実務で使えるシステム開発方法論｜ナギ ＠ 氷河期SEの知見録｜note" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://sys-univ.com/wp-content/uploads/cocoon-resources/blog-card-cache/0f32eea23c3fec6193dcd0147c80e86d.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">実務で使えるシステム開発方法論｜ナギ ＠ 氷河期SEの知見録｜note</div><div class="blogcard-snippet external-blogcard-snippet">要件定義、基本設計、詳細設計、テスト、移行、運用保守まで、システム開発の流れを実務目線で体系化するマガジンです。教科書には書かれにくい、設計漏れ、手戻り、品質保証、運用で詰まるポイントを、現場経験に基づいて整理します。若手SEだけでなく、開ReadMore...</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://note.com/k_s7906/m/mc19593a012e2" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">note.com</div></div></div></div></a>
<p>&nbsp;</p>
<div id="gtx-trans" style="position: absolute; left: 3px; top: 5991.03px;">
<div class="gtx-trans-icon"> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/ec2autoscaling/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ECS/FargateでEFSが127.0.0.1にマウントされる｜NFSの接続先がlocalhostになる理由</title>
		<link>https://sys-univ.com/incident/ecs-fargate-efs-localhost-mount/</link>
					<comments>https://sys-univ.com/incident/ecs-fargate-efs-localhost-mount/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Fri, 14 Aug 2026 09:16:06 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[トラブル]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=3109</guid>

					<description><![CDATA[ECS/FargateのタスクからEFSをマウントしている環境で、コンテナ内からマウント情報を確認すると、EFSのDNS名でもマウントターゲットのIPアドレスでもなく、127.0.0.1が表示されることがあります。 私が [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">ECS/FargateのタスクからEFSをマウントしている環境で、コンテナ内からマウント情報を確認すると、EFSのDNS名でもマウントターゲットのIPアドレスでもなく、<code>127.0.0.1</code>が表示されることがあります。</p>


<p class="wp-block-paragraph">私が確認した環境でも、タスク定義にはEFSボリュームを定義しており、アプリケーションからEFS上のファイルを正常に読み書きできているにもかかわらず、マウント元はlocalhostになっていました。</p>


<p class="wp-block-paragraph">EFSへ接続しているはずなのに、なぜ接続先が<code>127.0.0.1</code>なのか。クロスアカウントでEFSを利用していることが原因なのか、Fargate特有の動作なのか、マウント情報だけでは分かりませんでした。</p>


<p class="wp-block-paragraph">結論から書くと、これはEFSの転送時暗号化（TLS）で使われる仕組みによるものです。</p>


<p class="wp-block-paragraph">NFSクライアントはEFSへ直接接続するのではなく、ローカルで待ち受けるプロキシへ接続します。そのプロキシがEFSとのTLS通信を担当するため、NFSクライアントから見た接続先として<code>127.0.0.1</code>が表示されます。</p>


<p class="wp-block-paragraph">この記事では、実際に確認した<code>127.0.0.1</code>という表示を起点に、EFSの転送時暗号化でどのような通信経路が作られるのか、AWSサポートがEC2基盤のECSタスクで確認したログも交えて整理します。</p>



  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-12" checked><label class="toc-title" for="toc-checkbox-12">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">EFSをマウントしているのに127.0.0.1が表示された</a></li><li><a href="#toc2" tabindex="0">NFSクライアントはローカルポートへ接続している</a></li><li><a href="#toc3" tabindex="0">なぜTLS通信ではlocalhostを経由するのか</a></li><li><a href="#toc4" tabindex="0">今回なぜ転送時暗号化が有効になっていたのか</a></li><li><a href="#toc5" tabindex="0">EC2基盤のmount.logではefs-proxyの起動を確認できる</a></li><li><a href="#toc6" tabindex="0">Fargateではどこまで確認できるのか</a></li><li><a href="#toc7" tabindex="0">127.0.0.1が見えたとき、何を切り分けるのか</a></li><li><a href="#toc8" tabindex="0">設定値と実行時の状態は同じではない</a></li><li><a href="#toc9" tabindex="0">まとめ</a></li><li><a href="#toc10" tabindex="0">参考文献</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">EFSをマウントしているのに127.0.0.1が表示された</span></h2>


<p class="wp-block-paragraph">今回確認したのは、ECS/Fargateから別AWSアカウントのEFSを利用する構成です。</p>


<pre class="wp-block-code"><code>AWSアカウントA

ECS / Fargate
      │
      │ EFSマウント
      ▼

AWSアカウントB

EFS
</code></pre>


<p class="wp-block-paragraph">タスク定義にはEFSボリュームを定義し、コンテナの所定のディレクトリへマウントしていました。アプリケーションからEFS上のファイルを読み書きできているため、EFSへの接続自体は成立しています。</p>


<p class="wp-block-paragraph">ところが、コンテナ内からマウント状態を確認すると、次のように表示されました。</p>


<pre class="wp-block-code"><code>127.0.0.1:/ on /mnt/xxxx type nfs4 (...,port=2xxxx,...,addr=127.0.0.1)
</code></pre>


<p class="wp-block-paragraph">通常のNFSマウントをイメージすると、接続先にはEFSのDNS名やマウントターゲットが見えるように思えます。実際に表示されているのは<code>127.0.0.1</code>、コンテナから見たlocalhostです。</p>


<p class="wp-block-paragraph">この結果だけを見ると、「EFSではなくローカルのファイルシステムを見ているのではないか」「クロスアカウントEFSだから特殊なマウントになっているのではないか」と考えたくなります。</p>


<p class="wp-block-paragraph">原因はクロスアカウント構成そのものではありませんでした。</p>


<h2 class="wp-block-heading"><span id="toc2">NFSクライアントはローカルポートへ接続している</span></h2>


<p class="PDq2pG_selectionAnchorContainer wp-block-paragraph" data-start="340" data-end="370">EFSへの通信経路は、転送時暗号化の有無によって変わります。</p>
<p data-start="375" data-end="477">転送時暗号化を利用しない場合、NFSクライアントはEFSマウントターゲットへ直接NFS通信を行います。転送時暗号化を有効にすると、NFSクライアントとEFSの間に、TLS通信を担当するプロキシが入ります。</p>

<div id="attachment_3118" style="width: 510px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3118" class="wp-image-3118 size-medium" src="https://sys-univ.com/wp-content/uploads/2026/08/ae435e52fa548a61c0e0f87cd872ece0-500x274.png" alt="" width="500" height="274" srcset="https://sys-univ.com/wp-content/uploads/2026/08/ae435e52fa548a61c0e0f87cd872ece0-500x274.png 500w, https://sys-univ.com/wp-content/uploads/2026/08/ae435e52fa548a61c0e0f87cd872ece0-800x439.png 800w, https://sys-univ.com/wp-content/uploads/2026/08/ae435e52fa548a61c0e0f87cd872ece0-300x165.png 300w, https://sys-univ.com/wp-content/uploads/2026/08/ae435e52fa548a61c0e0f87cd872ece0-768x421.png 768w, https://sys-univ.com/wp-content/uploads/2026/08/ae435e52fa548a61c0e0f87cd872ece0-1536x843.png 1536w, https://sys-univ.com/wp-content/uploads/2026/08/ae435e52fa548a61c0e0f87cd872ece0.png 1693w" sizes="(max-width: 500px) 100vw, 500px" /><p id="caption-attachment-3118" class="wp-caption-text">図：EFSの転送時暗号化なし／ありで変わる通信経路</p></div>




<p class="PDq2pG_selectionAnchorContainer wp-block-paragraph" data-start="534" data-end="658">転送時暗号化を有効にした場合、NFSクライアントから見た接続先はEFSではなく、ローカルで待ち受けているプロキシです。NFSクライアントは<code data-start="603" data-end="614">127.0.0.1</code>のローカルポートへ接続し、<code data-start="627" data-end="638">efs-proxy</code>がその通信をTLSでEFSへ中継します。</p>
<p data-start="663" data-end="776">このため、<code data-start="668" data-end="675">mount</code>などで確認したマウント情報には、EFSのDNS名ではなく<code data-start="703" data-end="714">127.0.0.1</code>が現れます。<code data-start="720" data-end="731">127.0.0.1</code>はEFSそのものを示しているのではなく、NFSクライアントから見たローカル側の接続先です。</p>
<p data-start="781" data-end="898">AWSのEFSドキュメントでも、EFS mount helperを使用して転送時暗号化を行う場合、NFSクライアントはローカルポートへマウントするよう構成され、マウント情報では<code data-start="869" data-end="880">127.0.0.1</code>として見えることが説明されています。</p>


<p class="wp-block-paragraph"><a href="https://docs.aws.amazon.com/efs/latest/ug/encryption-in-transit.html">Encrypting data in transit &#8211; Amazon Elastic File System</a></p>


<p class="wp-block-paragraph"><code data-start="1037" data-end="1048">127.0.0.1</code>が表示されたこと自体は、EFSへの接続異常を示しているわけではありません。</p>


<h2 class="wp-block-heading"><span id="toc3">なぜTLS通信ではlocalhostを経由するのか</span></h2>


<p class="wp-block-paragraph">NFSクライアントからEFSへの通信をTLSで暗号化するには、NFS通信とTLS通信の間を仲介するコンポーネントが必要になります。</p>


<p class="wp-block-paragraph">EFSでは<code>amazon-efs-utils</code>に含まれるEFS mount helperが、このマウント処理を支援します。現在の<code>amazon-efs-utils</code>では<code>efs-proxy</code>が利用され、2.0.0より前のバージョンでは<code>stunnel</code>が利用されていました。</p>


<p class="wp-block-paragraph">古いEFSの記事では<code data-start="851" data-end="860">stunnel</code>、比較的新しい記事では<code data-start="871" data-end="882">efs-proxy</code>という名前が出てくることがありますが、これは<code data-start="904" data-end="922">amazon-efs-utils</code>のバージョンによる違いです。<code data-start="936" data-end="954">amazon-efs-utils</code> 2.0.0以降では、従来の<code data-start="968" data-end="977">stunnel</code>に代わって、性能を改善した<code data-start="990" data-end="1001">efs-proxy</code>が利用されています。</p>


<h2 class="wp-block-heading"><span id="toc4">今回なぜ転送時暗号化が有効になっていたのか</span></h2>


<p class="wp-block-paragraph">ここまでの仕組みは、EFSの転送時暗号化を利用していることが前提です。</p>


<p class="wp-block-paragraph">ECSのタスク定義では、EFSボリュームの<code>transitEncryption</code>によって転送時暗号化を指定します。<code>transitEncryption</code>を省略した場合の既定値は<code>DISABLED</code>です。</p>


<p class="wp-block-paragraph">IAM認可またはEFS Access Pointを利用する構成では、<code>transitEncryption</code>を明示的に有効にする必要があります。自動的にTLSが有効になるわけではありません。</p>


<p class="wp-block-paragraph">たとえばIAM認可を利用する場合、タスク定義の<code>volumes</code>内の該当部分は次のような設定になります。</p>


<pre class="wp-block-code"><code>{
  "efsVolumeConfiguration": {
    "fileSystemId": "fs-xxxxxxxx",
    "transitEncryption": "ENABLED",
    "authorizationConfig": {
      "iam": "ENABLED"
    }
  }
}
</code></pre>


<p class="wp-block-paragraph">IAM認可と転送時暗号化の関係や、<code>transitEncryption</code>の既定値についてはAWSのECSドキュメントでも確認できます。</p>


<p class="wp-block-paragraph"><a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specify-efs-config.html">Specify an Amazon EFS file system in an Amazon ECS task definition</a></p>


<p class="wp-block-paragraph">EFSを利用している環境で<code>127.0.0.1</code>が表示された場合、クロスアカウント構成かどうかだけを見るのではなく、タスク定義の<code>transitEncryption</code>や<code>authorizationConfig</code>を確認する必要があります。</p>


<p class="wp-block-paragraph">今回見えていた<code>127.0.0.1</code>は、クロスアカウントだから発生したものではなく、EFSをTLSでマウントする通信経路の一部でした。</p>


<h2 class="wp-block-heading"><span id="toc5">EC2基盤のmount.logではefs-proxyの起動を確認できる</span></h2>


<p class="wp-block-paragraph">Fargateでは利用者がホストOSへログインできないため、EFSのマウント処理をホスト側から直接確認できません。</p>


<p class="wp-block-paragraph">AWSサポートへ問い合わせたところ、EC2基盤のECSタスクで同様のEFSマウントを確認した結果として、<code>/var/log/amazon/efs/mount.log</code>のログが提示されました。</p>


<p class="wp-block-paragraph">一部を簡略化すると、次のような内容です。</p>


<pre class="wp-block-code"><code>INFO - binding &lt;local port&gt;
INFO - Starting efs-proxy:
       nsenter --net=/proc/xxxx/ns/net ... /sbin/efs-proxy ...
INFO - Started efs-proxy, pid: &lt;pid&gt;
</code></pre>


<p class="PDq2pG_selectionAnchorContainer wp-block-paragraph" data-start="792" data-end="928">ログには、ローカルポートの確保、<code data-start="808" data-end="819">efs-proxy</code>の起動、指定されたネットワーク名前空間への切り替えが記録されています。<code data-start="854" data-end="870">nsenter --net=</code>が使われていることから、<code data-start="882" data-end="893">efs-proxy</code>は指定されたネットワーク名前空間内で起動されていることが確認できます。</p>
<p data-start="933" data-end="1043">これを通信経路と対応させると、<code data-start="948" data-end="955">mount</code>で見えていた<code data-start="961" data-end="972">127.0.0.1</code>と、<code data-start="974" data-end="985">mount.log</code>に記録されたローカルポートの確保、<code data-start="1002" data-end="1013">efs-proxy</code>の起動、EFSへのTLS接続が一つの流れとして理解できます。</p>

<div id="attachment_3120" style="width: 510px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3120" class="wp-image-3120 size-medium" src="https://sys-univ.com/wp-content/uploads/2026/08/2efdb592696b40b9291de1d418a79754-500x625.png" alt="" width="500" height="625" srcset="https://sys-univ.com/wp-content/uploads/2026/08/2efdb592696b40b9291de1d418a79754-500x625.png 500w, https://sys-univ.com/wp-content/uploads/2026/08/2efdb592696b40b9291de1d418a79754-800x1000.png 800w, https://sys-univ.com/wp-content/uploads/2026/08/2efdb592696b40b9291de1d418a79754-300x375.png 300w, https://sys-univ.com/wp-content/uploads/2026/08/2efdb592696b40b9291de1d418a79754-768x960.png 768w, https://sys-univ.com/wp-content/uploads/2026/08/2efdb592696b40b9291de1d418a79754.png 1122w" sizes="(max-width: 500px) 100vw, 500px" /><p id="caption-attachment-3120" class="wp-caption-text">図：EC2基盤のmount.logとefs-proxyによる通信経路の対応</p></div>



<p class="wp-block-paragraph">EC2基盤では、<code data-start="1118" data-end="1129">127.0.0.1</code>というマウント表示が単なるlocalhostを示しているのではなく、その先で<code data-start="1167" data-end="1178">efs-proxy</code>を介してEFSへ接続するためのローカルエンドポイントであることを、ログと通信経路を対応させて確認できます。</p>


<h2 class="wp-block-heading"><span id="toc6">Fargateではどこまで確認できるのか</span></h2>


<p class="wp-block-paragraph">FargateではホストOSがAWSによって管理されているため、利用者が<code>mount.log</code>やホスト側のプロセス一覧を直接確認することはできません。</p>


<p class="wp-block-paragraph">FargateでEFSボリュームを利用すると、AWSはEFSボリュームを管理するための<code>aws-fargate-supervisor</code>というsupervisorコンテナを作成します。</p>


<p class="wp-block-paragraph">このコンテナは、タスクメタデータエンドポイント バージョン4（Task Metadata v4）から確認できるほか、CloudWatch Container Insightsでも<code>aws-fargate-supervisor</code>というコンテナ名で確認できます。</p>


<p class="wp-block-paragraph"><code>aws-fargate-supervisor</code>はタスクに割り当てられたCPUとメモリを少量使用します。EFSを利用するFargateタスクでは、アプリケーションコンテナ以外にもEFSボリューム管理のためのリソースが消費されることになります。</p>


<p class="wp-block-paragraph">この仕様はAWSのECSドキュメントに記載されています。</p>


<p class="wp-block-paragraph"><a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html">Amazon EFS volumes &#8211; Amazon Elastic Container Service</a></p>


<p class="wp-block-paragraph">ここで注意したいのは、<code>aws-fargate-supervisor</code>と<code>efs-proxy</code>を同じものとして扱わないことです。</p>


<p class="wp-block-paragraph">AWS公式ドキュメントでは、<code>aws-fargate-supervisor</code>がEFSボリュームの管理を担当することまでは説明されていますが、supervisorコンテナと<code>efs-proxy</code>の具体的な関係までは明示されていません。</p>


<p class="wp-block-paragraph">今回、FargateタスクではEFSのマウント元が<code>127.0.0.1</code>として表示されました。EFSの公式仕様では、TLSマウント時にNFSクライアントをローカルポートへ接続する方式が説明され、EC2基盤で確認されたログでは実際に<code>efs-proxy</code>が起動しています。</p>


<p class="wp-block-paragraph">これらからFargateでも同様の通信方式が使われていると考えられますが、Fargate内部でEC2基盤とまったく同じプロセス起動シーケンスが実行されているところまで、今回直接確認したわけではありません。</p>


<h2 class="wp-block-heading"><span id="toc7">127.0.0.1が見えたとき、何を切り分けるのか</span></h2>


<p class="wp-block-paragraph"><code>mount</code>の結果に<code>127.0.0.1</code>が表示されても、それだけでEFSへの接続障害とは判断できません。転送時暗号化を利用している場合、localhostは正常な通信経路の一部だからです。</p>


<p class="wp-block-paragraph">アプリケーションからEFS上のファイルを正常に読み書きできているのであれば、<code>127.0.0.1</code>を理由にネットワーク障害を疑う必要はありません。</p>


<p class="wp-block-paragraph">EFSをマウントできない、あるいはアクセス時にエラーになる場合は、localhostより先の経路を確認します。主な確認対象は次のとおりです。</p>


<ul class="wp-block-list">
	<li>ECSタスクとEFSマウントターゲット間のセキュリティグループ</li>


	<li>NFS（TCP/2049）の通信可否</li>


	<li>利用するAZのEFSマウントターゲット</li>


	<li>IAM認可</li>


	<li>EFSファイルシステムポリシー</li>


	<li>Access Pointを利用している場合はその設定</li>
</ul>


<p class="wp-block-paragraph">EC2基盤であれば、<code>/var/log/amazon/efs/mount.log</code>も有力な調査材料になります。Fargateではホスト側の<code>mount.log</code>を直接確認できないため、タスクの停止理由やECSのイベント、EFS側のネットワーク・認可設定など、利用者から確認できる範囲で切り分けます。</p>


<p class="wp-block-paragraph">ここで重要なのは、</p>


<p class="wp-block-paragraph"><strong><code>127.0.0.1</code>という表示だけでは、EFSへの到達性が正常か異常かは判断できない</strong></p>


<p class="wp-block-paragraph">ということです。</p>


<h2 class="wp-block-heading"><span id="toc8">設定値と実行時の状態は同じではない</span></h2>


<p class="wp-block-paragraph">今回の調査で改めて感じたのは、マネージドサービスでは設定として見えているものと、その設定を実現するために内部で動いている処理が同じ粒度ではないということです。</p>


<p class="wp-block-paragraph">ECSのタスク定義には、EFSのファイルシステムIDやマウント先、転送時暗号化、認可方式などを設定します。そこに「127.0.0.1へNFSマウントする」「efs-proxyを起動する」と書くわけではありません。</p>


<p class="wp-block-paragraph">利用者が指定した設定を実現するため、基盤側では別の処理が動きます。通常はそこまで意識する必要がないこと自体がFargateの利点ですが、障害調査では、この隠蔽が逆に分かりにくさにつながることがあります。</p>


<p class="wp-block-paragraph">タスク定義ではEFSを指定しているのに、実行時には<code>127.0.0.1</code>が見える。設定だけを見ていれば、この二つが同じEFSマウントを表しているとは直感的に理解しにくいからです。</p>


<p class="wp-block-paragraph">以前、ECS/Fargateで非rootコンテナを動かした際にも、Dockerfileで<code data-start="343" data-end="350">chown</code>したディレクトリと、ECSがボリュームをマウントした後の実行時状態が異なることで、<code data-start="391" data-end="410">Permission denied</code>が発生しました。<br data-start="418" data-end="421" />
この事象については、以下の記事で実際の原因と切り分けを整理しています。</p>

<a href="https://sys-univ.com/incident/ecs-fargate-permission-denied/" title="ECS/FargateでDockerfileのchownが効かない｜非rootコンテナがPermission deniedになる理由" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://sys-univ.com/wp-content/uploads/2026/08/5f2272883f1f19f228ad9dc0e58a281b-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/08/5f2272883f1f19f228ad9dc0e58a281b-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/08/5f2272883f1f19f228ad9dc0e58a281b-240x135.png 240w, https://sys-univ.com/wp-content/uploads/2026/08/5f2272883f1f19f228ad9dc0e58a281b-640x360.png 640w, https://sys-univ.com/wp-content/uploads/2026/08/5f2272883f1f19f228ad9dc0e58a281b-752x423.png 752w" sizes="(max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">ECS/FargateでDockerfileのchownが効かない｜非rootコンテナがPermission deniedになる理由</div><div class="blogcard-snippet internal-blogcard-snippet">ECS/Fargateで非rootコンテナを実行した際、Dockerfileでchown済みのログディレクトリがPermission deniedになった実例をもとに、空のデータVolume（Empty Volume）とbind mount、VOLUMEの仕様、対策、設計レビュー、事前PoCで確認すべき点を解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.14</div></div></div></div></a>


<p class="wp-block-paragraph">今回も問題の種類は違いますが、見るべきポイントは似ています。</p>


<p class="wp-block-paragraph"><strong>設定ファイルに何を書いたかだけではなく、その設定によって実行時にどのような状態が作られるのかを見る。</strong></p>


<p class="wp-block-paragraph">Fargateのように基盤側が隠蔽されているサービスほど、この視点が障害調査や設計レビューで重要になります。</p>
<p>この違いを設計書や設定値だけで確認するには限界があります。</p>
<p>特にクラウド移行では、本番相当の構成で実際に動かし、設計時の想定と実行時の状態に差がないかをPoCで確認することが重要です。PoCで何を確認すべきか、確認不足が後工程でどのような手戻りにつながるのかは、以下の記事で整理しています。</p>

<a href="https://sys-univ.com/dev/cloudlift/" title="【第1回】クラウドリフトの失敗は構築前に始まっている｜PoC不足が手戻り・コスト超過・納期遅延を招く理由" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【第1回】クラウドリフトの失敗は構築前に始まっている｜PoC不足が手戻り・コスト超過・納期遅延を招く理由</div><div class="blogcard-snippet internal-blogcard-snippet">クラウド移行（AWSへのクラウドリフト）で起きる手戻り・コスト超過・納期遅延は、構築中ではなくPoC不足から始まります。Auto Scaling、EFS/EBS、RDS、監視、バックアップ、ライセンスなど10の設計リスクを現場目線で整理します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.20</div></div></div></div></a>


<h2 class="wp-block-heading"><span id="toc9">まとめ</span></h2>


<p class="wp-block-paragraph">ECS/FargateからEFSをマウントしているにもかかわらず、マウント情報に<code>127.0.0.1</code>が表示されるのは、EFSの転送時暗号化で利用される通信方式によるものです。</p>


<p class="wp-block-paragraph">NFSクライアントはEFSへ直接接続せず、ローカルポートで待ち受けるプロキシへ接続します。現在の<code>amazon-efs-utils</code>では<code>efs-proxy</code>がEFSとのTLS通信を担当するため、NFSクライアントから見た接続先としてlocalhostが表示されます。</p>


<p class="wp-block-paragraph"><code>127.0.0.1</code>が見えたこと自体はEFSへの接続障害を意味しません。マウントやアクセスに問題がある場合は、localhostという表示ではなく、EFSまでのネットワーク経路やIAM認可、ファイルシステムポリシーなどを切り分ける必要があります。</p>


<p class="wp-block-paragraph">設定として書いた内容と、それを実現するために実行時に作られる状態は、別に確認する必要があります。</p>


<h2 class="wp-block-heading"><span id="toc10">参考文献</span></h2>


<ul class="wp-block-list">
	<li><a href="https://docs.aws.amazon.com/efs/latest/ug/encryption-in-transit.html">Encrypting data in transit &#8211; Amazon Elastic File System</a></li>


	<li><a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specify-efs-config.html">Specify an Amazon EFS file system in an Amazon ECS task definition</a></li>


	<li><a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html">Amazon EFS volumes &#8211; Amazon Elastic Container Service</a></li>


	<li><a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_EFSVolumeConfiguration.html">EFSVolumeConfiguration &#8211; Amazon Elastic Container Service</a></li>


	<li><a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_EFSAuthorizationConfig.html">EFSAuthorizationConfig &#8211; Amazon Elastic Container Service</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/ecs-fargate-efs-localhost-mount/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CloudWatch Logsのログエクスポートが失敗した話｜「ジョブは動く」と「運用で回る」は別物</title>
		<link>https://sys-univ.com/incident/cloudwatch-logs-export-concurrency/</link>
					<comments>https://sys-univ.com/incident/cloudwatch-logs-export-concurrency/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Mon, 22 Jun 2026 05:32:22 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[AWS]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=2728</guid>

					<description><![CDATA[ログエクスポートのジョブは、正しく書いてある。 IAMも問題ない。 S3バケットも存在する。 ロググループも存在する。 なのに、本番運用で失敗する。 そういうことがあります。 今回起きたのは、CloudWatch Log [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">ログエクスポートのジョブは、正しく書いてある。<br />
IAMも問題ない。<br />
S3バケットも存在する。<br />
ロググループも存在する。</p>


<p class="wp-block-paragraph">なのに、本番運用で失敗する。</p>


<p class="wp-block-paragraph">そういうことがあります。</p>


<p class="wp-block-paragraph">今回起きたのは、CloudWatch Logsのログエクスポートジョブが、日次処理でエラーになるという事象です。</p>


<p class="wp-block-paragraph">CloudWatch Logsのログを、定期的にS3へエクスポートする。</p>


<p class="wp-block-paragraph">AWSを使ったシステムでは、よくある運用設計です。</p>


<p class="wp-block-paragraph">ログをCloudWatch Logsに集約し、一定期間ごとにS3へ退避する。<br />
監査、障害調査、保存期間、コスト、運用保守を考えると、自然な構成に見えます。</p>


<p class="wp-block-paragraph">しかし、今回の本質は、ジョブの実装ミスではありませんでした。</p>


<p class="wp-block-paragraph">問題は、AWSサービスの制約を、運用ジョブ設計とテスト設計に織り込めていなかったことです。</p>


<p class="wp-block-paragraph">CloudWatch Logsのログエクスポートは、ジョブを作れば好きなだけ並列に流せるものではありません。</p>


<p class="wp-block-paragraph">ここを知らないと、単体では正常に動いていたジョブが、本番運用で突然失敗します。</p>



  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-14" checked><label class="toc-title" for="toc-checkbox-14">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">起きたこと</a></li><li><a href="#toc2" tabindex="0">何が問題だったのか</a></li><li><a href="#toc3" tabindex="0">原因</a></li><li><a href="#toc4" tabindex="0">打った対策と運用の設計観点</a><ol><li><a href="#toc5" tabindex="0">補足：そもそもExportTaskでよかったのか</a></li></ol></li><li><a href="#toc6" tabindex="0">テスト工程で見るべきだったこと</a></li><li><a href="#toc7" tabindex="0">クラウドでも設計は省けない</a></li><li><a href="#toc8" tabindex="0">再発防止として見るべきこと</a></li><li><a href="#toc9" tabindex="0">若手SEに伝えたいこと</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">起きたこと</span></h2>


<p class="wp-block-paragraph">あるシステムで、日次ジョブとしてCloudWatch Logsのログエクスポートを実行していました。</p>


<p class="wp-block-paragraph">処理内容はシンプルです。</p>


<p class="wp-block-paragraph">CloudWatch Logsに出力されたログを、一定期間ごとにS3へエクスポートする。<br />
S3側に保存しておけば、長期保管、調査、監査対応にも使える。<br />
CloudWatch Logs側の保持期間も適切に管理できる。</p>


<p class="wp-block-paragraph">よくある構成です。</p>


<p class="wp-block-paragraph">ところが、日次ジョブで実行しているログエクスポートがエラーになりました。</p>


<p class="wp-block-paragraph">確認すると、ロググループは存在している。<br />
S3バケットも存在している。<br />
IAMロールも大きく間違っていない。<br />
以前は同じ処理が動いていた。</p>


<p class="wp-block-paragraph">にもかかわらず、ジョブが失敗する。</p>


<p class="wp-block-paragraph">この時点で、最初に疑うのは個別設定です。</p>


<p class="wp-block-paragraph">権限が足りないのではないか。<br />
出力先バケットのポリシーが変わったのではないか。<br />
ロググループ名が間違っているのではないか。<br />
対象期間の指定がおかしいのではないか。<br />
Lambdaやシェルの実装に不備があるのではないか。</p>


<p class="wp-block-paragraph">もちろん、それらの確認は必要です。</p>


<p class="wp-block-paragraph">しかし、調べていくと、原因はもっと上位の設計にありました。</p>


<h2 class="wp-block-heading"><span id="toc2">何が問題だったのか</span></h2>


<p class="wp-block-paragraph">問題は、CloudWatch Logsのログエクスポートには、AWS側の制約があるという点です。</p>


<p class="wp-block-paragraph">CloudWatch Logsのログエクスポートでは、CreateExportTaskを使って、ロググループのログをS3へ出力します。</p>


<p class="wp-block-paragraph">このExportTaskには制約があります。</p>


<p class="wp-block-paragraph"><strong>1つのAWSアカウント、1つのリージョンにつき、アクティブなExportTaskは1つしか持てません。</strong></p>


<p class="wp-block-paragraph">ここでいうアクティブとは、実行中または保留中の状態です。</p>


<p class="wp-block-paragraph">つまり、あるログエクスポートタスクがまだ実行中、または開始待ちの状態で残っている場合、同じアカウント・同じリージョン内で次のエクスポートタスクを作成しようとしても失敗する可能性があります。</p>


<p class="wp-block-paragraph">これはAWS公式ドキュメントにも記載されているCloudWatch Logsのクォータです。</p>


<p class="wp-block-paragraph">これが盲点でした。</p>


<p class="wp-block-paragraph">1つのシステムだけを見ていると、この問題は見えにくいです。</p>


<p class="wp-block-paragraph">1つのロググループを対象にしている。<br />
手動で1回だけ実行する。<br />
単体テストで1回だけエクスポートする。</p>


<p class="wp-block-paragraph">この条件なら、正常に見えます。</p>


<p class="wp-block-paragraph">しかし、同じAWSアカウントの同一リージョンの中に複数システムが存在し、それぞれが日次でCloudWatch Logsのエクスポートを実行していると、話が変わります。</p>


<p class="wp-block-paragraph">Aシステムのログエクスポートが実行中。<br />
そのタイミングで、Bシステムのログエクスポートが起動する。<br />
さらに、Cシステムのログエクスポートも同じ時間帯に起動する。</p>


<p class="wp-block-paragraph">それぞれのジョブは、単体で見れば正しい。</p>


<p class="wp-block-paragraph">しかし、アカウント全体で見ると、同時に実行できない処理が重なっている。</p>


<p class="wp-block-paragraph">これでは失敗します。</p>


<p class="wp-block-paragraph">ジョブの中身が間違っていなくても、AWSサービスの制約に引っかかるからです。</p>


<figure id="fc5fa595-aa7a-4582-8171-4bcc58b3e682" class="wp-block-image"><a href="https://assets.st-note.com/img/1780546651-v1RoMmfjWIxeOiyX02qCnFH5.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85"><img decoding="async" src="https://assets.st-note.com/img/1780546651-v1RoMmfjWIxeOiyX02qCnFH5.png?width=1200" alt="画像" /></a>
<figcaption class="wp-element-caption">　　　　　　　　　　　　　　　　　　　　　　　複数システムが同一AWSアカウント／同一リージョンで競合する</figcaption>
</figure>


<p class="wp-block-paragraph">個別には正しい。<br />
しかし、共通のAWSアカウント／リージョン側で競合する。</p>


<p class="wp-block-paragraph">今回の問題は、まさにここでした。</p>


<h2 class="wp-block-heading"><span id="toc3">原因</span></h2>


<p class="wp-block-paragraph">「AWSの制約でした」で終わらせてはいけません。</p>


<p class="wp-block-paragraph">それは調べれば分かる話です。</p>


<p class="wp-block-paragraph">実務で問うべき原因は、もう一段深いところにあります。</p>


<p class="wp-block-paragraph">それは、AWSサービスの制約を、設計時点でジョブ設計・スケジュール設計・テスト設計に落とせていなかったことです。</p>


<p class="wp-block-paragraph">AWSの制約そのものは障害ではありません。<br />
AWSが壊れていたわけではありません。<br />
CloudWatch Logsが異常だったわけでもありません。</p>


<p class="wp-block-paragraph">仕様どおりに動いていただけです。</p>


<p class="wp-block-paragraph">問題は、その仕様を使う側が、運用条件に織り込めていなかったことです。</p>


<p class="wp-block-paragraph">特に、複数システムを1つのAWSアカウントに載せる場合、各システムが独立してジョブを設計すると、こういう問題が起きます。</p>


<p class="wp-block-paragraph">Aシステムの担当者は、Aシステムのログエクスポートだけを見る。<br />
Bシステムの担当者は、Bシステムのログエクスポートだけを見る。<br />
Cシステムの担当者は、Cシステムのログエクスポートだけを見る。</p>


<p class="wp-block-paragraph">個別に見ると、それぞれの設計は間違っていない。</p>


<p class="wp-block-paragraph">しかし、アカウント全体で見ると、同時実行できないジョブが同じ時間帯に並んでいる。</p>


<p class="wp-block-paragraph">この状態では、本番運用で失敗します。</p>


<h2 class="wp-block-heading"><span id="toc4">打った対策と運用の設計観点</span></h2>


<p class="wp-block-paragraph">対策を考えるときに、単純に「エラーになったらリトライすればよい」と考えるのは危険です。</p>


<p class="wp-block-paragraph">もちろん、リトライは必要です。</p>


<p class="wp-block-paragraph">しかし、何も考えずにリトライを入れると、別のシステムのExportTaskがまだ完了していない状態で、同じ失敗を繰り返すだけになります。</p>


<p class="wp-block-paragraph">今回考えるべき対策は、少なくとも次の3つです。</p>


<p class="wp-block-paragraph"><strong>1つ目は、ログエクスポートジョブの実行時間をずらすことです</strong>。</p>


<p class="wp-block-paragraph">同じAWSアカウント・同一リージョン内で複数システムがCloudWatch Logsのエクスポートを行う場合、各ジョブの起動時刻を重ねないようにする必要があります。</p>


<p class="wp-block-paragraph">たとえば、以下のように時間帯を分けます。</p>


<pre class="wp-block-code"><code>変更前：
01:00 Aシステム ログエクスポート
01:00 Bシステム ログエクスポート
01:00 Cシステム ログエクスポート

変更後：
01:00 Aシステム ログエクスポート
02:00 Bシステム ログエクスポート
03:00 Cシステム ログエクスポート
</code></pre>



<p class="wp-block-paragraph">ただし、これは最低限の対策です。</p>


<p class="wp-block-paragraph"><strong>2つ目は、ExportTaskの状態を確認してから、次のタスクを作成することです。</strong></p>


<p class="wp-block-paragraph">ログ量が多い日には、前のエクスポート処理が想定より長引くことがあります。<br />
障害や遅延により、前日のタスクが残っていることもあります。<br />
単純に時刻をずらしただけでは、処理時間の変動に対応できません。</p>


<p class="wp-block-paragraph">そのため、既存のExportTaskの状態を確認し、実行中または保留中のタスクがある場合は、待機する、スキップする、後続へ回す、といった制御が必要になります。</p>


<p class="wp-block-paragraph">処理の流れとしては、以下のような形です。</p>


<pre class="wp-block-code"><code>1. 既存のExportTaskを確認する
2. RUNNINGまたはPENDINGのタスクがあれば待機する
3. 一定時間待っても完了しなければスキップまたは異常終了する
4. 実行可能な状態であれば新しいExportTaskを作成する
5. 作成したタスクIDを記録する
6. 完了状態を確認する
7. 失敗時はリトライまたは運用通知する
</code></pre>



<figure id="42c49159-1326-4192-85fb-5c00695ec2f4" class="wp-block-image"><a href="https://assets.st-note.com/img/1780546820-6ReMw4cFhZBqD0yVdpuX2Glz.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85"><img decoding="async" src="https://assets.st-note.com/img/1780546820-6ReMw4cFhZBqD0yVdpuX2Glz.png?width=1200" alt="画像" /></a>
<figcaption class="wp-element-caption">　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　ExportTask作成前のガード処理フロー</figcaption>
</figure>


<p class="wp-block-paragraph">ここで重要なのは、ジョブの成功条件を「APIを呼べたこと」にしないことです。</p>


<p class="wp-block-paragraph">CreateExportTaskを呼び出せた。<br />
タスクIDが返ってきた。<br />
だから成功。</p>


<p class="wp-block-paragraph">これだけでは不十分です。</p>


<p class="wp-block-paragraph">運用上は、実際にエクスポートが完了し、S3に期待したログが出力されていることまで確認する必要があります。</p>


<p class="wp-block-paragraph"><strong>3つ目は、失敗時の運用を決めておくことです。</strong></p>


<p class="wp-block-paragraph">エクスポートに失敗した場合、翌日にまとめて再実行するのか。<br />
対象期間を分割して再実行するのか。<br />
失敗したロググループだけを再実行するのか。<br />
運用担当者にアラートを出すのか。<br />
一定回数までは自動リトライするのか。<br />
リトライしても失敗した場合、誰が判断するのか。</p>


<p class="wp-block-paragraph">ここまで決めて、初めて運用ジョブの設計になります。</p>


<p class="wp-block-paragraph">「毎日1時にジョブを起動する」だけでは、設計として足りません。</p>


<p class="wp-block-paragraph">「その時間に実行してよい状態か」<br />
「実行できなかった場合にどう扱うか」<br />
「ログ欠損や二重出力をどう防ぐか」</p>


<p class="wp-block-paragraph">ここまで考える必要があります。</p>


<p class="wp-block-paragraph">失敗時の設計観点は、最低でも次のように整理します。</p>


<pre class="wp-block-code"><code>・リトライ回数
・リトライ間隔
・再実行対象期間
・二重出力の扱い
・ログ欠損時の対応
・通知先
・運用手順書への記載
</code></pre>



<p class="wp-block-paragraph">ジョブは、処理を起動するだけではありません。</p>


<p class="wp-block-paragraph">失敗したときに、運用担当者が判断できる状態にしておくところまで含めて、ジョブ設計です。</p>


<h3 class="wp-block-heading"><span id="toc5">補足：そもそもExportTaskでよかったのか</span></h3>


<p class="wp-block-paragraph">ここまでの対策は、CloudWatch LogsのExportTaskを使い続ける前提の話です。</p>


<p class="wp-block-paragraph">しかし、設計としては、そもそもS3へ日次エクスポートする方式でよかったのか、という確認も必要です。</p>


<p class="wp-block-paragraph">障害調査や一時的なログ検索が目的であれば、CloudWatch Logs Insightsで足りるケースもあります。<br />
CloudWatch Logsにログを保持し、必要なときに検索・分析できれば、必ずしもS3へエクスポートしなくてよい場合があります。</p>


<p class="wp-block-paragraph">一方で、長期保管、監査対応、CloudWatch Logsの保持期間外の保存、S3を前提にしたログ管理が必要であれば、S3への保存は必要になります。</p>


<p class="wp-block-paragraph">その場合も、日次のExportTaskだけが選択肢ではありません。</p>


<p class="wp-block-paragraph">リアルタイム性が必要な場合や、ExportTaskの同時実行制約を避けたい場合は、CloudWatch LogsのサブスクリプションフィルターからAmazon Data Firehoseへ連携し、Firehose経由でS3へ配信する構成も検討対象になります。</p>


<p class="wp-block-paragraph">つまり、対策は「ExportTaskの起動時間をずらす」だけではありません。</p>


<p class="wp-block-paragraph">ログの用途、保存期間、検索頻度、監査要件、リアルタイム性、コスト、運用負荷を踏まえて、そもそものログ保存方式を選ぶ必要があります。</p>


<p class="wp-block-paragraph">今回のようなトラブルは、単にジョブを直すだけでなく、ログ運用方式そのものを見直すきっかけにもなります。</p>


<h2 class="wp-block-heading"><span id="toc6">テスト工程で見るべきだったこと</span></h2>


<p class="wp-block-paragraph">今回の話で重要なのは、設計だけではありません。</p>


<p class="wp-block-paragraph">テスト工程でも、見方を間違えるとこの問題は見逃されます。</p>


<p class="wp-block-paragraph">単体テストでは、CloudWatch LogsからS3へエクスポートできるかを確認します。</p>


<p class="wp-block-paragraph">これは必要です。</p>


<p class="wp-block-paragraph">ロググループを指定する。<br />
対象期間を指定する。<br />
S3バケットに出力される。<br />
IAMロールで実行できる。<br />
エラー時にログが出る。</p>


<p class="wp-block-paragraph">ここまでは確認します。</p>


<p class="wp-block-paragraph">しかし、単体テストで1回エクスポートが成功しても、本番運用で問題なく回ることは保証できません。</p>


<p class="wp-block-paragraph">結合テストでは、ジョブスケジューラから起動できるか、LambdaやシェルからAWS APIを呼べるか、S3に出力されるか、異常時に通知されるかを確認します。</p>


<p class="wp-block-paragraph">これも必要です。</p>


<p class="wp-block-paragraph">しかし、それでもまだ足りません。</p>


<p class="wp-block-paragraph">システムテストや運用テストでは、実際の運用に近い条件で確認する必要があります。</p>


<p class="wp-block-paragraph">たとえば、次のような観点です。</p>


<pre class="wp-block-code"><code>・同じAWSアカウント内に複数システムが存在する
・同一リージョン内で複数のログエクスポートジョブが日次で動く
・ログ量が多い日にExportTaskの完了が遅れる
・前日のExportTaskが残っている状態で翌日のジョブが起動する
・他システムのExportTask実行中に自システムのジョブが起動する
・失敗した場合に再実行すると対象期間が重複する
・スキップした場合にログ欠損が起きる
・運用担当者が失敗に気づける
・通知を受けた担当者が、何を見て判断すればよいか分かる
</code></pre>



<p class="wp-block-paragraph">ここまで見ないと、運用ジョブとしての品質は確認できません。</p>


<p class="wp-block-paragraph">「1回エクスポートできた」ことと、<br />
「毎日、運用として成立する」ことは別です。</p>


<p class="wp-block-paragraph">これは、テスト工程で非常に重要な考え方です。</p>


<p class="wp-block-paragraph">機能確認だけなら、1回エクスポートできれば合格に見えます。</p>


<p class="wp-block-paragraph">しかし、運用確認として見るなら、複数システム、複数ジョブ、ログ量増加、遅延、再実行、通知、手順まで確認しなければいけません。</p>


<p class="wp-block-paragraph">テスト工程は、単に「作ったものが動くか」を見る工程ではありません。</p>


<p class="wp-block-paragraph">設計した運用が、実際の条件で破綻しないかを確認する工程です。</p>


<h2 class="wp-block-heading"><span id="toc7">クラウドでも設計は省けない</span></h2>


<p class="wp-block-paragraph">今回の気づきは、CloudWatch LogsのExportTask制約そのものではありません。</p>


<p class="wp-block-paragraph">それは調べれば分かります。</p>


<p class="wp-block-paragraph">本当の気づきは、クラウドサービスを使う場合、設計対象は自分たちが作った処理だけではないということです。</p>


<p class="wp-block-paragraph">AWSのマネージドサービスを使うと、OSやミドルウェアを自分たちで管理しなくてよい部分が増えます。</p>


<p class="wp-block-paragraph">それは大きなメリットです。</p>


<p class="wp-block-paragraph">しかし、その代わりに、サービスごとの仕様、クォータ、非同期処理、状態遷移、リトライ設計、料金体系を理解する必要があります。</p>


<p class="wp-block-paragraph">CloudWatch Logsのエクスポートも同じです。</p>


<p class="wp-block-paragraph">画面上は簡単に見えます。<br />
APIも用意されています。<br />
S3へ出力できるので、仕組みとしてはシンプルに見えます。</p>


<p class="wp-block-paragraph">しかし、実運用では、同時実行数、処理時間、ログ量、再実行、監視、通知まで考える必要があります。</p>


<p class="wp-block-paragraph">クラウドだから簡単になる部分はあります。</p>


<p class="wp-block-paragraph">しかし、クラウドだから設計しなくてよい、という話ではありません。</p>


<p class="wp-block-paragraph">むしろ、クラウドサービスの仕様を知らないまま設計すると、オンプレとは別の形で詰まります。</p>


<p class="wp-block-paragraph">オンプレでは、サーバ、ディスク、ネットワーク、ジョブスケジューラ、ミドルウェアの制約を見ていました。</p>


<p class="wp-block-paragraph">クラウドでは、そこにAWSサービスごとの制約が加わります。</p>


<p class="wp-block-paragraph">サービスを使うだけなら簡単です。</p>


<p class="wp-block-paragraph">しかし、業務システムとして運用するなら、サービスの制約まで含めて設計する必要があります。</p>


<h2 class="wp-block-heading"><span id="toc8">再発防止として見るべきこと</span></h2>


<p class="wp-block-paragraph">同じ問題を繰り返さないためには、個別ジョブを修正するだけでは不十分です。<br />
<br />
今回のような問題は、担当者がCloudWatch LogsのExportTask制約を知っていれば防げます。<br />
しかし、知らない人が設計すれば、また同じことが起きます。<br />
<br />
だからこそ、個人の知識や注意力に頼るのではなく、設計レビューやテスト計画の観点として残しておく必要があります。<br />
<br />
以下は、設計レビューやテスト計画にそのまま転用できる形で整理したチェックリストです。</p>


<pre class="wp-block-code"><code>・使用するAWSサービスのクォータを確認したか
・アカウント単位、リージョン単位の制約を確認したか
・同一アカウント内の他システムと競合しないか
・同一リージョン内で競合するジョブがないか
・同時実行できない処理を並列に起動していないか
・ジョブの起動時刻だけでなく、完了時刻も考慮したか
・処理時間が長引いた場合の後続影響を確認したか
・前回処理が残っている場合の動作を決めたか
・リトライ時に二重処理やログ欠損が起きないか
・スキップ時にどのように検知するか決めたか
・失敗時に誰が、どの通知で、何を見て判断するか
・運用手順書に再実行方法を記載したか
・運用テストで複数システム同時稼働を確認したか
</code></pre>



<p class="wp-block-paragraph">このような観点を、設計レビューやテスト計画に入れておく。</p>


<p class="wp-block-paragraph">それが再発防止のために見るべきことです。</p>


<p class="wp-block-paragraph">今回のような問題は、担当者個人の注意力だけに頼ると再発します。</p>


<p class="wp-block-paragraph">CloudWatch LogsのExportTask制約を知っている人がいれば防げる。<br />
知らない人が設計するとまた起きる。</p>


<p class="wp-block-paragraph">それでは、組織として弱いです。</p>


<p class="wp-block-paragraph">だから、レビュー観点にする。<br />
テスト観点にする。<br />
運用設計のチェックリストにする。</p>


<p class="wp-block-paragraph">これが、実務では必要になります。</p>


<h2 class="wp-block-heading"><span id="toc9">若手SEに伝えたいこと</span></h2>


<p class="wp-block-paragraph">若手SEのうちは、どうしても「処理が動くか」に意識が向きます。</p>


<p class="wp-block-paragraph">コマンドが成功した。<br />
APIが通った。<br />
S3にファイルが出た。<br />
ジョブが正常終了した。</p>


<p class="wp-block-paragraph">もちろん、それは大事です。</p>


<p class="wp-block-paragraph">しかし、実務ではそれだけでは足りません。</p>


<p class="wp-block-paragraph">本番では、他のシステムも動いています。<br />
他のジョブも動いています。<br />
ログ量も日によって変わります。<br />
AWSサービス側の制約もあります。<br />
障害時には再実行もあります。</p>


<p class="wp-block-paragraph">だから、設計では「単体で動くか」だけでなく、「運用全体の中で成立するか」を見なければいけません。</p>


<p class="wp-block-paragraph">CloudWatch Logsのログエクスポート失敗は、小さなトラブルに見えるかもしれません。</p>


<p class="wp-block-paragraph">しかし、ここには大事な教訓があります。</p>


<p class="wp-block-paragraph"><strong>ジョブは、処理単体ではなく、運用全体で設計する。</strong></p>


<p class="wp-block-paragraph">そして、</p>


<p class="wp-block-paragraph"><strong>テストは、機能確認ではなく、運用で破綻しないことを確認する工程である。</strong></p>


<p class="wp-block-paragraph">この視点がないと、クラウドでもオンプレでも、同じように運用で詰まります。</p>


<p class="wp-block-paragraph">AWSを使うこと自体は難しくありません。</p>


<p class="wp-block-paragraph">しかし、AWSを使って業務システムを安定運用するには、サービス仕様、制約、ジョブ設計、監視、再実行、テスト工程までつなげて考える必要があります。</p>


<p class="wp-block-paragraph">「1回動いたから大丈夫」</p>


<p class="wp-block-paragraph">この考え方が、本番運用では一番危ないです。</p>


<p class="wp-block-paragraph">単体で動くことと、運用で回ることは違います。</p>


<p class="wp-block-paragraph">この違いを理解しているかどうかが、実務のSEとしてかなり大きな差になります。</p>
<p>今回の話は、単なるCloudWatch Logsの制約の話ではなく、<br />
「ジョブ単体では動く」ことと、<br />
「本番運用で毎日回る」ことは別物である、という話でもあります。</p>
<hr />
<p>このあたりは、以下の記事でも詳しく書いています。</p>
<p><a rel="nofollow" href="https://sys-univ.com/dev/detailed-design-overview/" target="_blank">【前編】詳細設計で決めること｜基本設計を「構築・テスト・運用できる形」に落とし込む工程</a></p>
<p id="11509699-b6e2-4cb5-af51-af3ef3bd772d">シリーズ全体は<a rel="nofollow noopener" href="https://note.com/k_s7906/m/mc19593a012e2" target="_blank">「実務で使えるシステム開発方法論」マガジン</a>にまとめています。</p>]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/cloudwatch-logs-export-concurrency/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>EBSは見えているのにマウントできない？｜AMIコピーで起きた落とし穴</title>
		<link>https://sys-univ.com/incident/mounterr/</link>
					<comments>https://sys-univ.com/incident/mounterr/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Sun, 12 Jul 2026 00:39:50 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[AWS]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=1419</guid>

					<description><![CDATA[クラウドリフトで見落としやすい「OSの中身」の落とし穴 クラウドリフトでは、既存サーバをAMI化し、そこからEC2を作成することがあります。 オンプレミスのサーバ更改でいえば、既存環境を複製して、新しい環境で起動するよう [&#8230;]]]></description>
										<content:encoded><![CDATA[<p id="a1e6ad44-4f19-4776-be9c-78e79bfa35c0">クラウドリフトで見落としやすい「OSの中身」の落とし穴</p>
<p id="5bae012d-11d8-447f-aec2-1c8454a897e6">クラウドリフトでは、既存サーバをAMI化し、そこからEC2を作成することがあります。</p>
<p id="0f4d4361-539e-4f99-a412-1bda26287b4f">オンプレミスのサーバ更改でいえば、既存環境を複製して、新しい環境で起動するようなイメージです。</p>
<p id="8a5fc594-7a14-4ffc-b3db-56197693f049">一見すると、とても便利です。</p>
<p id="5b4c18d2-e5d0-47a5-a856-b9aba1e902f3">OS、ミドルウェア、設定ファイル、アプリケーション、ディレクトリ構成などを、元の環境に近い状態で再現できます。</p>
<p id="253c98c4-6fb9-4b80-beee-70ba70401f2e">そのため、クラウド移行では、</p>
<figure id="c0bfd809-9abd-419e-9a59-245c2fe7e76a">
<blockquote>
<p id="ad199ffd-0f5f-4db0-8251-0a032d30f0db">AMIを作って、そこからEC2を起動すればよい</p>
</blockquote><figcaption></figcaption></figure>
<p id="25c1a0a8-3400-434b-8848-23f93e874849">と思いがちです。</p>
<p id="0b2562c2-abfb-4087-9dbd-866fbc46efb7">しかし、ここに落とし穴があります。</p>
<p id="cea98c1b-d0ae-4855-a174-5375e13881c2">EC2は起動できる。<br />
EBSボリュームも作成できる。<br />
別のEC2へアタッチもできる。</p>
<p id="692a0622-8f6a-4552-8db1-56ec721e6311">それなのに、<strong>OS上で期待どおりにマウントできない</strong>ことがあります。</p>
<p id="f6eb5652-b17e-4236-b9b6-59bfd9ce1a45">今回扱うのは、AMIコピーやスナップショットから復元したEBSを、既存EC2にアタッチしてデータ復旧しようとしたときに起きたトラブルです。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-16" checked><label class="toc-title" for="toc-checkbox-16">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">何が起きたのか</a></li><li><a href="#toc2" tabindex="0">原因は「EBSが壊れていた」ではない</a></li><li><a href="#toc3" tabindex="0">なぜ LVM2_member になるのか</a></li><li><a href="#toc4" tabindex="0">UUIDの競合も見落としやすい</a></li><li><a href="#toc5" tabindex="0">どう対処したのか</a></li><li><a href="#toc6" tabindex="0">クラウドリフトでは「コピーできた」と「運用できる」は違う</a></li><li><a href="#toc7" tabindex="0">事前にどうチェックすべきだったのか</a></li><li><a href="#toc8" tabindex="0">これは詳細設計・運用設計の問題である</a></li><li><a href="#toc9" tabindex="0">まとめ</a></li><li><a href="#toc10" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2 id="414c7bdc-a5bc-48cb-a43e-48917cba516f" tabindex="-1"><span id="toc1">何が起きたのか</span></h2>
<p id="83e513a6-f7a7-4b01-a421-7300150b76d7">過去のAMIバックアップからデータを復旧したい場面がありました。</p>
<p id="79a2cdba-036d-44f8-b669-668a09e091c9">やろうとしたことは、よくある復旧作業です。</p>
<ol id="3baa4c1a-d82b-4800-b621-57499f15ce22">
<li>
<p id="50d6fb79-eca5-48d8-b829-2a36b6e9d8b1">過去のAMIまたはスナップショットからEBSを復元する</p>
</li>
<li>
<p id="6430f0ba-8678-408e-abdb-b296f6addc6c">復元したEBSを既存のEC2にアタッチする</p>
</li>
<li>
<p id="4527d5a3-3595-45b5-9ceb-41b7a8bd5a74">OS上でマウントする</p>
</li>
<li>
<p id="8d8f47e2-180f-4aca-bc61-db3cf61231ed">必要なファイルを取り出す</p>
</li>
</ol>
<p id="50b88b81-b8b8-4de0-8062-73ef442ccfa9">クラウド環境では、障害調査や復旧作業でよく出てくる手順です。</p>
<p id="631bae24-d1b3-42ae-bb39-97f0d79cc578">EBSはAWS上では問題なく作成できました。<br />
既存EC2へのアタッチもできました。<br />
OS上でもディスクとして見えていました。</p>
<p id="62147b04-85f4-4ea3-b7af-5eb250a6c834">ところが、いざマウントしようとすると失敗しました。</p>
<p id="b7bd9f90-19be-47d5-a8df-2d620b1180c1">たとえば、以下のようにデバイスを直接指定してマウントしようとします。</p>
<div class="code-block-container">
<pre id="c92b023f-b3a8-4ee9-a6f8-a3951c9e9074" data-name="preCode"><code class="hljs" data-name="code">mount /dev/xvdf2 /mnt
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="8ec9c17e-1778-4399-9391-a9d58eb7ec73">すると、次のようなエラーになります。</p>
<div class="code-block-container">
<pre id="ce325d02-3cfe-4b28-8396-4d50c2516c79" data-name="preCode"><code class="hljs go" data-name="code">mount: /mnt: unknown filesystem <span class="hljs-keyword">type</span> <span class="hljs-string">'LVM2_member'</span>
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="592f90c5-2f78-43bf-a106-ec11831ddd2b">ここが今回のポイントです。</p>
<p id="32d1a255-5273-4fa9-9da5-03fca1dc2cb3">OSから見ると、/dev/xvdf2 はそのままマウントできるXFSやext系のファイルシステムではありませんでした。</p>
<p id="0eab71d0-9610-45d2-96ea-f56815123dd0">LVM2_member として認識されています。</p>
<p id="e9de1ede-27cf-45dd-9d3d-a9ab4546c616">つまり、直接マウントしようとしていた対象は、ファイルシステムそのものではなく、LVMの物理ボリュームとして扱われる領域だったということです。</p>
<h2 id="fed3e22e-3306-4e22-8cdb-af1928f423e9" tabindex="-1"><span id="toc2">原因は「EBSが壊れていた」ではない</span></h2>
<p id="20b7b4e6-1c24-4425-a6c2-2108deacb823">この手のエラーを見ると、最初はこう考えがちです。</p>
<p id="2472c018-5650-49ec-b4de-30e1c6acfdd6">EBSの復元に失敗したのではないか。<br />
スナップショットが壊れているのではないか。<br />
デバイス名を間違えたのではないか。</p>
<p id="551eab3f-2239-48e2-ba39-41857fafb4db">もちろん、それらも確認すべきです。</p>
<p id="7884c2e3-cd9c-4776-9711-90c42058b683">しかし今回の本質は、EBSそのものが壊れていたことではありません。</p>
<p id="71ee1879-39f3-430d-ab9d-e55de71bbcbe">原因は二つあります。</p>
<p id="79ff95b7-42c6-4a4f-8936-28dec6067ae0">一つ目は、直接マウントしようとした対象が LVM2_member だったことです。</p>
<p id="bc32686e-6562-46d6-9b7a-3559eb1f1e04">二つ目は、同じAMIを元にしたインスタンス同士で、ディスクやボリューム管理情報の識別子が競合したことです。</p>
<p id="453736d5-8282-45cd-acad-7c6e8bc25f0d">AMIからEC2を作ると、OSの中身も含めて複製されます。</p>
<p id="9c7ca32f-e4b0-46eb-a7da-30c22f39b48f">ファイルシステムのUUID、LVMのボリューム情報、/etc/fstab の記述、デバイス構成の前提なども、元の環境を引き継ぎます。</p>
<p id="c063e770-2c75-4046-b123-05d35ab75088">そのため、同じAMIを元にしたEC2に、同じ系統のAMIやスナップショットから復元したEBSをアタッチすると、OSから見た識別情報が競合することがあります。</p>
<p id="a67206cc-058e-47a6-8da6-eb30ed25368c">作業者としては、</p>
<figure id="708f8bc2-e5ce-4b74-8f78-f7552d7e8c3d">
<blockquote>
<p id="310cb1be-8f9b-41b5-b4e1-e4c722dfe9a1">復元したEBSを別EC2に付けて、中身を見たいだけ</p>
</blockquote><figcaption></figcaption></figure>
<p id="57747afe-4914-48fb-aa2d-0232229039d7">です。</p>
<p id="43efb1e5-333a-4503-b613-785ce1c75233">しかしOS側から見ると、同じような識別情報を持つボリュームが複数見えている状態になります。</p>
<p id="9a01c816-4b00-462d-90f2-2875937ccef4">AWS上ではEBSがアタッチできていても、OS上で安全にマウントできるとは限りません。</p>
<p id="ac470be3-3505-4344-90e8-8f2f6370fc5d">ここを取り違えると、復旧作業で詰まります。</p>
<p id="dd4b159c-ce07-4338-8a7c-3c1087314ae1">これはAWSの不具合というより、Linuxのディスク管理、UUID、LVM、fstab の仕組みに基づく動作です。</p>
<p id="5a53b042-3f26-4151-ba96-23be6f41b96d">EBSはクラウド上のブロックストレージですが、最終的にそれをどう認識し、どうマウントするかはOS側の話になります。</p>
<h2 id="a4aed584-69a7-42dd-aa26-4c28142cf83d" tabindex="-1"><span id="toc3">なぜ LVM2_member になるのか</span></h2>
<p id="672514c9-616e-44c6-89e7-a7cfce8995b4">Linuxでは、ディスク上に直接ファイルシステムが作られている場合もあれば、LVMを使ってボリューム管理している場合もあります。</p>
<p id="77f547cc-7783-423d-81b1-478d276dc156">単純な構成であれば、パーティションにXFSなどのファイルシステムがあり、そのパーティションを直接マウントできます。</p>
<p id="271aed7a-743f-43cf-bc6b-1635e44673ff">一方、LVMを使っている場合、物理ディスクやパーティションは、まずLVMの物理ボリュームとして扱われます。</p>
<p id="8ec62288-c9d9-4098-8d13-62badf4cbce8">その上にボリュームグループがあり、さらに論理ボリュームが作られ、その論理ボリューム上にファイルシステムがあります。</p>
<p id="cf4ee645-7f28-41a7-8f35-61f0e20989e7">つまり、LVM構成では、次のような階層になります。</p>
<figure id="14c53725-13ce-471d-b272-527ca51d0f3e"><a href="https://assets.st-note.com/img/1780366499-KXh7a8PEBNZzrn0VC1iHDvTQ.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide" src="https://assets.st-note.com/img/1780366499-KXh7a8PEBNZzrn0VC1iHDvTQ.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="22945179-05c0-411c-ac3e-cf1037cd1b82">この場合、LVMの物理ボリュームを直接 mount しても、ファイルシステムとして認識できません。</p>
<p id="015f3933-44ce-4cc4-8583-16e0b9b0cc00">そのため、</p>
<div class="code-block-container">
<pre id="bcfb7f4f-7635-4799-bd92-c7840aa2874a" data-name="preCode"><code class="hljs go" data-name="code">unknown filesystem <span class="hljs-keyword">type</span> <span class="hljs-string">'LVM2_member'</span>
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="a8483dc4-fc29-40c9-b27c-1034fed56c27">となります。</p>
<p id="608d9f49-b8d9-4d76-92aa-8e96ce3449de">これは、OSが対象を見失っているというより、</p>
<figure id="8362bb38-f116-49f4-a4e9-53cd9171b0bf">
<blockquote>
<p id="def357b4-c6c4-4129-935d-0e29f18037ef">そこは直接マウントする場所ではない</p>
</blockquote><figcaption></figcaption></figure>
<p id="3e412f14-23c9-463f-b345-e46817e604d0">という意味に近いです。</p>
<p id="75361438-f9e3-4333-b838-309af55efc0a">たとえば、blkid で見ると、対象パーティションが次のように見えることがあります。</p>
<div class="code-block-container">
<pre id="6f77bb35-c71d-4195-98bc-224ec6664268" data-name="preCode"><code class="hljs" data-name="code">blkid /dev/xvdf2
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<div class="code-block-container">
<pre id="07b8dff8-2610-4cb9-9471-a9ceb3a6c59c" data-name="preCode"><code class="hljs javascript" data-name="code">/dev/xvdf2: UUID=<span class="hljs-string">"xxxxx"</span> TYPE=<span class="hljs-string">"LVM2_member"</span>
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="a574d4f1-928a-4402-8f4f-b7950f82769e">この状態で /dev/xvdf2 を直接 mount しても、XFSやext系のファイルシステムとしては扱えません。</p>
<h2 id="26a4b4d3-005b-4e44-b67d-689195d8c6c1" tabindex="-1"><span id="toc4">UUIDの競合も見落としやすい</span></h2>
<p id="689a59f6-caff-49d3-a7e0-4a937c38c836">もう一つ重要なのがUUIDです。</p>
<p id="7edad6da-0ad4-4109-8b08-5c1490b8b718">Linuxでは、ディスクやパーティションを /dev/xvdf、/dev/xvdf1、/dev/nvme1n1p1 のようなデバイス名で扱うことがあります。</p>
<p id="717e2029-69cc-48d7-9e4d-0bbfebf668da">しかし、クラウド環境ではデバイス名だけを信じると危険です。</p>
<p id="e3c99943-2288-48e0-aae5-95e54df118a4">AWSコンソール上で指定したデバイス名と、OS上で見えるデバイス名が直感どおり一致しないことがあります。</p>
<p id="9e36146b-1360-495e-9c34-a4ab6b6914dc">さらに、AMIやスナップショットから復元したボリュームでは、ファイルシステムUUIDやLVM関連の識別情報が元の環境と同じまま残ることがあります。</p>
<p id="9dc411d1-bb5f-4745-9b6c-78ac3bf1c1f1">そのため、同じAMI由来のボリュームを同じ系統のEC2にアタッチすると、UUIDやボリューム管理情報が競合し、どのボリュームをマウントすべきかが分かりにくくなります。</p>
<p id="87d931f4-e2ab-481c-9081-ff41fe206058">ここで必要なのは、勘でデバイス名を指定することではありません。</p>
<p id="7e668a3f-11d0-46a9-a4aa-ec2af63927c8">OSが実際にどう認識しているかを確認することです。</p>
<p id="72e56501-0323-4c92-af40-d3da4cc4c485">たとえば、以下のようなコマンドで確認します。</p>
<div class="code-block-container">
<pre id="708ca8af-4980-4737-a4bc-34017d7e9dbd" data-name="preCode"><code class="hljs cs" data-name="code">lsblk
blkid
ls -l /dev/disk/<span class="hljs-keyword">by</span>-uuid
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="a9125f5a-ba9f-4911-b98b-194f7ae372f3">これらを使って、次の情報を確認します。</p>
<ul id="a032dfba-aa02-4746-a876-d07ed4318aba">
<li>
<p id="a1b29c82-c15a-4f8c-bd0d-66e4c83f5a0d">どのデバイスが追加ボリュームなのか</p>
</li>
<li>
<p id="d429215e-b3f1-412b-9e9d-5d1789cb7a55">どのパーティションにファイルシステムがあるのか</p>
</li>
<li>
<p id="e40a9827-de2e-4962-9ce6-00389ba5a2e7">LVM2_member として見えているのか</p>
</li>
<li>
<p id="c43cc4c4-eb48-4c81-b94b-b52b4a7cce2d">どのUUIDがどのデバイスに対応しているのか</p>
</li>
<li>
<p id="85e8a6f1-0d0b-421e-94b2-4d55d4ca530a">既存ボリュームと識別情報が競合していないか</p>
</li>
</ul>
<h2 id="b997a2a8-ae89-435a-985d-a5214967a05f" tabindex="-1"><span id="toc5">どう対処したのか</span></h2>
<p id="666c6141-74d9-4566-befb-76cb746ac81a">今回の対処の核心は、同じAMI由来ではない作業用EC2を用意し、そこに復元EBSをアタッチしてマウントするという点です。</p>
<p id="51ccd583-a8d2-4557-b7cb-bca78401e2a4">狙いは、同じAMI由来のOSボリュームと復元ボリュームを同じEC2上に同居させることで起きる、UUIDやLVM関連の識別情報の競合を避けることです。</p>
<p id="e415073c-88f0-4401-912e-a167394b7702">ここでいう「別のEC2を用意する」とは、LVM2_member が自動的にマウントできるようになる、という意味ではありません。</p>
<p id="f4068b75-60fc-4de8-9c08-9507d61c3534">そのうえで、OS上で lsblk、blkid、/dev/disk/by-uuid を確認し、どの領域が直接マウントできるファイルシステムなのか、どの領域が LVM2_member なのかを切り分けました。</p>
<p id="b9113960-cbce-4650-845c-fa51adb754a9">LVM構成を維持したまま確認したい場合は、pvscan、vgscan、vgchange -ay でボリュームグループを有効化する方法や、複製されたLVMボリュームを別物として扱う vgimportclone を使う方法もあります。</p>
<p id="1f5e2114-ef0f-4fa1-a27a-243b09da5e2f">また、既存EC2上で対応せざるを得ない場合は、mount -o nouuid で一時的に参照する方法もあります。</p>
<p id="24673cb2-d344-4085-a6ae-43561bec33a5">ただし、これらは環境と目的によって適否が分かれます。</p>
<p id="c48a3b10-47df-4bca-bb42-8a217041d4af">今回は復旧対象のファイルを一時的に安全に取り出すことが目的だったため、作業用EC2を用意し、UUIDで対処する方針を採りました。</p>
<p id="31d342fe-62bb-49cc-98b1-154d5cea5042">具体的な手順は以下のとおりです。</p>
<p id="b2f1f4f3-bc8c-4cd6-ad22-aca6f1d87877">まず、/dev/disk/by-uuid でUUIDとデバイスの対応を確認します。</p>
<div class="code-block-container">
<pre id="e4f8f0b6-f2b8-46b0-9654-bcece5b6e262" data-name="preCode"><code class="hljs cs" data-name="code">ls -l /dev/disk/<span class="hljs-keyword">by</span>-uuid
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="26dc8e02-4c0a-4915-b7d6-4111c7f71948">たとえば、以下のように表示されます。</p>
<div class="code-block-container">
<pre id="359dd71a-8a9d-4ab9-96af-906ad7f9f5f5" data-name="preCode"><code class="hljs rust" data-name="code">lrwxrwxrwx. <span class="hljs-number">1</span> root root <span class="hljs-number">11</span> Feb <span class="hljs-number">16</span> <span class="hljs-number">07</span>:<span class="hljs-number">47</span> <span class="hljs-number">1</span>c5999b9-<span class="hljs-number">594</span>d-<span class="hljs-number">40</span>aa-<span class="hljs-number">84</span>d2-<span class="hljs-number">167</span>a92a977c5 -&gt; ../../xvdf1
lrwxrwxrwx. <span class="hljs-number">1</span> root root <span class="hljs-number">11</span> Feb <span class="hljs-number">16</span> <span class="hljs-number">07</span>:<span class="hljs-number">46</span> <span class="hljs-number">949779</span>ce-<span class="hljs-number">46</span>aa-<span class="hljs-number">434e-8</span>eb0-<span class="hljs-number">852514</span>a5d69e -&gt; ../../xvda2
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="8869707f-5133-4273-8903-8d3e5f546d38">この例では、xvdf1 がアタッチした復元ボリューム、xvda2 が既存のルートボリュームとして見えています。</p>
<p id="7e6a94f1-f9ae-485f-8bf8-a4ef90f080df">次に、/etc/fstab にマウント先を追記します。</p>
<div class="code-block-container">
<pre id="8355ab36-e2b2-4dfb-a1f5-84add2ee3fce" data-name="preCode"><code class="hljs python" data-name="code"><span class="hljs-comment"># fstab.new（変更後）</span>
UUID=<span class="hljs-number">949779</span>ce<span class="hljs-number">-46</span>aa<span class="hljs-number">-434e-8</span>eb0<span class="hljs-number">-852514</span>a5d69e /      xfs  defaults  <span class="hljs-number">0</span> <span class="hljs-number">0</span>
UUID=<span class="hljs-number">1</span>c5999b9<span class="hljs-number">-594</span>d<span class="hljs-number">-40</span>aa<span class="hljs-number">-84</span>d2<span class="hljs-number">-167</span>a92a977c5 /mnt   xfs  defaults  <span class="hljs-number">1</span> <span class="hljs-number">1</span>
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="d78fc159-03e8-4959-bbd3-b4951170b691">そのうえで、マウントを実行します。</p>
<div class="code-block-container">
<pre id="3c32c6af-8e5b-4b77-9c79-f34b551e58fe" data-name="preCode"><code class="hljs" data-name="code">mount -a
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="e9fca54b-c82c-448b-9ea0-065d7f3de357">最後に、マウント先の中身を確認して、意図したボリュームであることを確認します。</p>
<div class="code-block-container">
<pre id="4547096c-fe42-426d-8d4c-c0afb123174d" data-name="preCode"><code class="hljs" data-name="code">cat /mnt/etc/hostname
</code></pre>
<div class="a-button__inner" data-v-00506f85=""><span data-v-80ab2cbc=""><span class="visually-hidden" data-v-80ab2cbc="">copy</span><i class="a-icon a-icon--copy a-icon--size_small" aria-hidden="true" data-v-80ab2cbc=""></i></span></div>
</div>
<p id="a0a82999-6a29-4b1b-a0cf-e9ebdf52f0cf">この確認により、単にマウントできたかどうかだけでなく、本当に目的のボリュームを参照できているかを確認できます。</p>
<h2 id="6208d713-e896-4031-acac-20309dbb5c35" tabindex="-1"><span id="toc6">クラウドリフトでは「コピーできた」と「運用できる」は違う</span></h2>
<p id="131b5e7e-859f-46dc-9b1f-3306f5261e63">クラウドリフトでよくある誤解があります。</p>
<p id="f8374eb4-8704-4a40-82e9-5a947a068cb4">AMIを作れた。<br />
EC2が起動した。<br />
EBSもアタッチできた。<br />
だから移行できている。</p>
<p id="2e57ffb6-78fd-4a27-a2a2-65acade18f9b">もちろん、これらは重要です。</p>
<p id="c1bb99fa-598d-4dd5-aef1-cb9fa92cd782">しかし、それだけでは十分ではありません。</p>
<p id="676ad1ad-5c35-4f7c-83a5-6dc9b9123dbf">本当に確認すべきなのは、移行後に必要な運用作業ができるかです。</p>
<p id="091e10e8-6bee-40a1-a813-442bca8c25c0">たとえば、障害時に旧ボリュームを別EC2にアタッチして中身を確認できるか。<br />
/etc/fstab の記述は移行後の構成に合っているか。<br />
デバイス名だけに依存せず、UUIDで対象を識別できるか。<br />
LVM構成なら、LVMとして認識・有効化できるか。</p>
<p id="794f564c-c66d-41ef-bb76-493af0aeeb8a">こうした確認が抜けると、本番障害時に困ります。</p>
<p id="10005680-c934-4d0e-8fcc-354150ee526d">通常時は問題なく動いているように見えても、いざ障害調査や復旧作業をしようとしたときに、</p>
<figure id="d8cc0b90-1acb-4866-b1e3-c98f0f16f07e">
<blockquote>
<p id="e106d497-8ba4-4463-9eeb-aeffcd9b95ea">そのボリューム、どうやって安全にマウントするんだっけ？</p>
</blockquote><figcaption></figcaption></figure>
<p id="560075f5-50c6-4d94-95b9-fd4d1729b782">となります。</p>
<p id="cdebfed4-ae0a-4c45-976d-5cdab26fe4e7">クラウドリフトでは、このような運用時の確認観点が後回しになりがちです。</p>
<h2 id="6572f61e-f250-4c18-94c7-c78da40127df" tabindex="-1"><span id="toc7">事前にどうチェックすべきだったのか</span></h2>
<p id="2072a0e2-d447-4323-afcd-2c87005efdd5">チェックリストとして最小限に絞るなら、見るべきポイントは次の4つです。</p>
<p id="ccb4c119-4084-4e47-a2da-b340fd85904e"><strong>1. OSのディスク構成を確認する</strong></p>
<p id="812fa0db-b6cc-44ac-993d-402afac34547">ルートボリュームはどれか。<br />
追加ボリュームはどれか。<br />
パーティション構成はどうなっているか。<br />
ファイルシステムは何か。<br />
LVMを使っているか。<br />
UUIDは何か。<br />
/etc/fstab はどう書かれているか。</p>
<p id="5368a0b5-b01e-480f-9049-93b34db6189a">クラウドリフトでは、EC2を起動できるかだけでなく、移行後のOS内部構成まで確認する必要があります。</p>
<p id="fbf9ae99-a096-4dc5-8a33-b891547d0ad8"><strong>2. LVM構成か、直接マウント可能なファイルシステムかを確認する</strong></p>
<p id="5e5971d4-2692-4907-a04b-b8606d49bbf5">lsblk や blkid で、対象がXFSなどのファイルシステムなのか、LVM2_member なのかを確認します。</p>
<p id="22f3238f-f20b-4bb9-98a6-e2bd8e1c6f5c">LVM2_member であれば、直接 mount する対象ではありません。</p>
<p id="4d71b12b-8f00-4480-95c3-67bae970063a">LVMとして認識させるのか、UUIDでマウント対象を指定するのかを、OS構成に応じて判断する必要があります。</p>
<p id="b362c53c-7ce0-4ddd-99fb-bde831af1b45"><strong>3. UUIDの対応を確認する</strong></p>
<p id="892683a4-fd84-47ae-b71c-a2249f2b2688">/dev/disk/by-uuid を確認し、どのUUIDがどのデバイスを指しているかを確認します。</p>
<p id="ea96fd2a-8b06-48e1-828f-760f46f63c33">同じAMI由来のボリュームを扱う場合は、UUIDやボリューム管理情報の競合に注意します。</p>
<p id="c7319392-c623-4f76-9d94-6a493832ef25">デバイス名だけで判断せず、UUID、ファイルシステム、マウント先の対応を確認します。</p>
<p id="764f2ef0-8e08-4a57-8b60-35dede0681ed"><strong>4. 復旧手順として事前に試す</strong></p>
<p id="a02a0c99-2479-44a1-842a-ec6986454df6">設計書や手順書に「EBSをアタッチしてマウントする」と書いてあっても、本当にできるとは限りません。</p>
<p id="c764d621-b952-4ed8-b564-29beaa5ec230">別EC2にEBSをアタッチする。<br />
OS上でデバイスを確認する。<br />
UUIDを確認する。<br />
必要に応じてLVM構成を確認する。<br />
マウントして中身を確認する。<br />
作業後にアンマウントする。</p>
<p id="0460b0d6-1013-4cb0-9dbb-1bb4c3d1a604">ここまで一度試しておくべきです。</p>
<p id="d658cbd9-d3af-46ff-a29a-8fc313f8f72d">復旧手順は、障害が起きてから初めて実行するものではありません。</p>
<h2 id="e89b4753-2b76-4af1-8654-d9607a740da5" tabindex="-1"><span id="toc8">これは詳細設計・運用設計の問題である</span></h2>
<p id="c3526da0-b4da-4227-b09d-5e4afec7cb38">今回の話は、EBSをマウントできなかったという作業トラブルに見えます。</p>
<p id="2472d9ce-f61f-4a48-8b05-5167457cb3d9">しかし、本質は詳細設計・運用設計の問題です。</p>
<p id="85e764f7-5cb9-490b-ae35-a66031a97d8f">クラウドリフトでAMIやEBSを扱うなら、設計時点で少なくとも以下を決めておく必要があります。</p>
<ul id="0fab29ce-b512-472c-bcd3-e50a784ee55a">
<li>
<p id="c8906514-3e3e-4319-a624-698d4247b8ef">移行後のEBS構成</p>
</li>
<li>
<p id="8b552771-95e5-430d-888a-32402063bcc2">OS上のデバイス認識</p>
</li>
<li>
<p id="953cb954-2037-4f8d-9120-5b5335ba99ce">LVMを使っているかどうか</p>
</li>
<li>
<p id="0dbb4c0a-bedf-460b-8552-35754fdbf588">ルートボリュームと追加ボリュームの識別方法</p>
</li>
<li>
<p id="bbf047d6-e8a1-40bf-ba71-59214de941bf">UUIDの確認方法</p>
</li>
<li>
<p id="e0ea04b2-78d1-4551-97fc-cf350c22c33d">/etc/fstab の記述方針</p>
</li>
<li>
<p id="73f56f0d-8d81-4fd3-9f21-638eb98c3907">障害時に別EC2へアタッチして確認する手順</p>
</li>
<li>
<p id="5faec238-17b9-483a-add6-91d7898705bf">マウント確認後に何を見て正常と判断するか</p>
</li>
</ul>
<p id="4e426197-6e97-4291-b0dd-4b95941ef85c">これらは、運用当日に作業者が感覚で判断するものではありません。</p>
<p id="e9f05549-8148-41e8-bae5-f6530515b2e1">設計書、運用設計書、作業手順書、復旧手順書に落としておくべき内容です。</p>
<p id="fa5deb12-cc91-4327-9cad-6a09242e01a6">特に、構築担当者と運用担当者が分かれているプロジェクトでは、この問題が起きやすくなります。</p>
<p id="eb4d0293-835d-45b9-a0f0-a52494d30f21">構築担当者は、「AMIからEC2は起動した」「EBSも作成できた」と考える。</p>
<p id="cbf393af-2939-4569-aaff-c2f164722d77">一方、運用担当者は障害時に、「復元したEBSをどのEC2にアタッチし、どのUUIDを見て、どのディレクトリにマウントし、何を確認すればよいのか」で迷う。</p>
<p id="4edd882f-9241-4945-bc80-b98566232aa8">この間を埋めるのが、詳細設計と運用設計です。</p>
<p id="07a452dc-efb2-47fe-8749-d4e96f099eb2">「EC2が起動した」ことと、「運用できる」ことは違います。</p>
<p id="c03290de-d6f9-4222-ace8-68aca6f3e741">「EBSがアタッチされた」ことと、「安全にマウントできる」ことも違います。</p>
<p id="a4d43ed0-29d3-4f29-9043-64668b232e82">この違いを設計で潰しておくことが重要です。</p>
<h2 id="3c1b1450-15d2-4ed2-b6cd-a7a7d3a71742" tabindex="-1"><span id="toc9">まとめ</span></h2>
<p id="f9d41e86-77a3-4595-a6f5-771e32b69383">AMIコピーやスナップショット復元で作成したEBSは、AWS上でアタッチできていても、OS上でそのまま期待どおりにマウントできるとは限りません。</p>
<p id="e7f1120b-bad5-41da-ab10-fac37b3b861a">今回の事象では、直接マウントしようとした対象が LVM2_member であり、さらに同じAMI由来のボリューム識別情報が競合していたことが問題でした。</p>
<p id="805bf3dc-dfa3-4499-85bf-d51a3ebb72f0">対処の核心は、同じAMI由来ではない作業用EC2を用意して、そこに復元EBSをアタッチすることです。</p>
<p id="bfb599b7-b4cc-42be-8539-92b5f82ba2a2">そのうえで、/dev/disk/by-uuid を確認し、実際にマウント対象となるファイルシステムのUUIDを指定してマウントしました。</p>
<p id="612aa3dd-57c9-4453-a143-a50c5f6a9168">作業前には、lsblk、blkid、/dev/disk/by-uuid で、OSが対象ボリュームをどう認識しているかを必ず確認します。</p>
<p id="bfccd2b2-407d-4447-a024-53495eac2874">デバイス名だけで判断せず、UUID、ファイルシステム、マウント先の対応を確認してから作業に入ることが重要です。</p>
<p id="67abcff9-e007-4cb2-9363-d54157ad71fe">クラウドリフトで本当に大事なのは、サーバをクラウド上で起動することだけではありません。</p>
<p id="c3c4f85c-3d21-4d85-a8c3-e018751ffbcc">移行後に、調査できること。<br />
復旧できること。<br />
運用できること。</p>
<p id="87929eb3-5e48-4028-9c8e-1f076dc5682d">ここまで確認して初めて、クラウドリフトは現場で使えるものになります。</p>
<h2 id="1afa7894-18d3-4452-b1ac-563924439116" tabindex="-1"><span id="toc10">関連記事</span></h2>
<p>この考え方については、以下の記事でも整理しています。</p>
<p><a href="https://sys-univ.com/dev/detailed-design-overview/">【前編】詳細設計で決めること｜基本設計を「構築・テスト・運用できる形」に落とし込む工程</a></p>
<p id="11509699-b6e2-4cb5-af51-af3ef3bd772d">シリーズ全体は<a rel="nofollow noopener" href="https://note.com/k_s7906/m/mc19593a012e2" target="_blank">「実務で使えるシステム開発方法論」マガジン</a>にまとめています。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/mounterr/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>RHELで使えた設定方法が、Amazon Linuxでは使えなかった｜MTU設定に見る、OS差分と永続化確認の落とし穴</title>
		<link>https://sys-univ.com/incident/mtusetting/</link>
					<comments>https://sys-univ.com/incident/mtusetting/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Sun, 12 Jul 2026 05:10:47 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[AWS]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=1475</guid>

					<description><![CDATA[構築作業が終わり、確認コマンドでも想定どおりの値になっている。 「これで設定完了です」 そう報告したあと、OSを再起動したら設定が戻っていた。 クラウド環境でインスタンスを再作成したら、同じ設定が入っていなかった。 イン [&#8230;]]]></description>
										<content:encoded><![CDATA[<p id="aec80593-f0fa-4915-810d-3119e89cea6f">構築作業が終わり、確認コマンドでも想定どおりの値になっている。</p>
<p id="c11efdeb-ff6c-493c-ae23-d5efdb1984de">「これで設定完了です」</p>
<p id="449f078f-76b2-4940-be7d-f73dc20dc82c">そう報告したあと、OSを再起動したら設定が戻っていた。<br />
クラウド環境でインスタンスを再作成したら、同じ設定が入っていなかった。</p>
<p id="c8df7210-8dbc-44d7-a07c-75203f2fb6fe">インフラ構築では、こういうことが起きます。</p>
<p id="62ef42e3-bf5c-4a1f-91d3-dad6916da403">特に危ないのは、作業直後には正しく見えるケースです。</p>
<p id="cc8e3c02-bdc7-4fc2-a237-147c98379ddb">コマンドを実行した。<br />
設定値も変わった。<br />
疎通もできた。</p>
<p id="1a0c8037-932a-4551-8d0c-fcc8c875d8a2">だから大丈夫だと思っていた。</p>
<p id="621740dd-f3dc-45b7-bf0b-4b26ba007a8a"><strong>しかし、再起動後、AMI化後、インスタンス再作成後、DHCP更新後に設定が戻る。<br />
</strong><br />
本番運用でこれが起きると、単なる作業ミスでは済まなくなります。</p>
<p id="dcf0ac41-a8a5-469a-a64e-2976e4b0f375">今回は、<strong>MTU設定</strong>を題材にします。</p>
<p id="e16d71fc-2b3f-4eb7-bbea-7b29cb4d9217">MTUとは、ネットワークで一度に送れるパケットサイズの上限です。</p>
<p id="5a3eab60-bddf-4b07-a204-eab600e92de8">通常のWebシステムでは、普段あまり意識しないかもしれません。<br />
しかし、クラウド環境、VPN、Direct Connect、閉域接続、ジャンボフレーム、オンプレからクラウドへの移行などが絡むと、MTUは設計・構築・試験で確認すべき項目になります。</p>
<p id="a997677c-1592-4ba7-834b-b49912909b5d">今回のトラブルは、次のようなものでした。</p>
<p id="e8027bc1-1de3-445b-830c-dc74ba451537">RHEL7の環境では、NetworkManager を使ってMTUを設定していた。<br />
ところが、Amazon Linux 2の環境では、同じように設定しようとしても、RHEL7と同じ前提では作業できなかった。</p>
<p id="dd7cf0d2-dfd9-4565-bda9-48e59176d865">つまり、<strong>RHELで使っていた設定手順を、そのままAmazon Linux 2に横展開できなかった</strong>のです。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-18" checked><label class="toc-title" for="toc-checkbox-18">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">何が起きたのか</a></li><li><a href="#toc2" tabindex="0">問題は「MTUの設定方法を知らなかったこと」ではない</a></li><li><a href="#toc3" tabindex="0">なぜこういうことが起きるのか</a></li><li><a href="#toc4" tabindex="0">RHEL7ではNetworkManager、Amazon Linux 2では別の見方が必要だった</a></li><li><a href="#toc5" tabindex="0">一番怖いのは、設定できたように見えてしまうこと</a></li><li><a href="#toc6" tabindex="0">設定確認は「今」だけで終わらせない</a></li><li><a href="#toc7" tabindex="0">このトラブルを防ぐための確認観点</a></li><li><a href="#toc8" tabindex="0">詳細設計と構築手順では「設定値」だけでなく「反映と確認」まで書く</a></li><li><a href="#toc9" tabindex="0">試験項目では「今の設定値」だけを見ない</a></li><li><a href="#toc10" tabindex="0">レビューでは設定値ではなく、設定が残る仕組みを見る</a></li><li><a href="#toc11" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 id="b63cb731-5120-4545-ac30-026aaeff5bbb" tabindex="-1"><span id="toc1">何が起きたのか</span></h2>
<p id="a93f3eff-8ff2-446f-9592-d913a3f6afe0">ある環境で、ネットワークインターフェースのMTU値をカスタマイズする必要がありました。</p>
<p id="4c7e4a88-e238-4714-b48e-7a3f3094e61f">RHEL7の環境では、次のように nmcli を使って設定していました。</p>
<div class="code-block-container">
<pre id="e88d6e43-2fe1-44af-b402-4ac4ab28b9b7" data-name="preCode"><code class="hljs swift" data-name="code">nmcli <span class="hljs-built_in">c</span> modify <span class="hljs-string">"My favorite connection"</span> ethernet.mtu <span class="hljs-number">1600</span>
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="61add955-6eba-488d-9c7a-8d2a588a9c03">nmcli は、NetworkManagerを操作するためのコマンドです。</p>
<p id="1ec68c27-aedc-4e82-b9bb-77ac8518a4c3">NetworkManagerが管理している接続設定に対して、MTU値などを変更できます。</p>
<p id="2aa32fd6-fd5a-4187-b883-d3d2ad091f63">この場合、設定内容は結果的に以下のようなファイルにも反映されます。</p>
<div class="code-block-container">
<pre id="3d63a0c4-bfbe-45a7-bc30-12fbf5650c44" data-name="preCode"><code class="hljs" data-name="code">/etc/sysconfig/network-scripts/ifcfg-XXXX
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="5b838b50-8cab-435d-9e10-c3e6c71ac56f">そのため、RHEL7で構築経験がある人からすると、</p>
<p id="eebd7c6a-b32f-446b-aaa8-2c1a57679ca5">「MTUを変えるなら、nmcli で設定すればよい」</p>
<p id="82b1e9dc-27ad-445e-b4bd-83b3860baff0">という感覚になりがちです。</p>
<p id="3b684b64-4cae-4953-ab11-6c188bd25dea">しかし、今回のAmazon Linux 2環境では、同じ前提が成り立ちませんでした。</p>
<p id="b2f2c27e-9403-41e8-9af6-a14517ed119e">RHEL7と同じように NetworkManager.service を前提にした構成ではなく、nmcli 前提の手順をそのまま使うことができなかったのです。</p>
<h2 id="d4d44757-45e9-4e64-b1e3-fbf8c1c1b6df" tabindex="-1"><span id="toc2">問題は「MTUの設定方法を知らなかったこと」ではない</span></h2>
<p id="37f3fd70-c536-4834-be02-34d4e668a2db">ここで大事なのは、</p>
<p id="ba727c03-febc-4a8b-a051-358b180955a6">「Amazon Linux 2では、このファイルを編集しましょう」</p>
<p id="a66ee79b-995c-4725-b007-d05a67824c94">という単純な話ではありません。</p>
<p id="03d640ea-6d21-4679-b8f9-f43c69f5b6dc">本質的な問題は、<strong>OSが変わったにもかかわらず、ネットワーク設定の管理方式が同じだと思い込んだこと</strong>です。</p>
<p id="bc0bee59-c43b-4766-b533-bcba73c41ef4">Linuxといっても、すべてが同じではありません。</p>
<p id="f31113ce-4670-4a50-b578-608c6a9bfdee">RHEL、CentOS、Amazon Linux、Ubuntu、Oracle Linuxなど、ディストリビューションが違えば、設定ファイルの場所、サービス管理の考え方、ネットワーク設定の反映方法、標準で有効になっているサービスが変わることがあります。</p>
<p id="ad8fe594-ffbe-468c-987f-3a6fb14cd817">さらに、同じRHEL系に見えても、バージョンやクラウドイメージの作りによって、デフォルト構成が違うこともあります。</p>
<p id="fd138906-917c-4857-bb22-f7e8444a603d">つまり、</p>
<p id="55c8774a-a64f-4069-87e4-4aa7806428bc">「前の案件で動いた」<br />
「RHELではこうだった」<br />
「Linuxだから同じだろう」</p>
<p id="e5e0eeb6-b8a9-4f18-98b5-159e05462f20">という判断は、インフラ構築では危険です。</p>
<h2 id="81dd49bb-c588-461f-aec4-28ed1a7762f8" tabindex="-1"><span id="toc3">なぜこういうことが起きるのか</span></h2>
<p id="4f4d4c8e-7dc4-480b-85b5-76d00e6ff2c7">オンプレミス環境のLinuxと、クラウド環境のLinuxでは、サーバの作られ方が違います。</p>
<p id="df0891d4-3c72-4d68-99c5-da9d9ecf06bd">オンプレミスでは、OSをインストールし、ネットワーク設定を作り込み、固定的なサーバとして長期間運用することが多くあります。</p>
<p id="eba446bc-d7f6-4d7f-a4cf-a59bdf96c088">一方、クラウド環境では、AMIなどのイメージからインスタンスを起動し、起動時にIPアドレス、ホスト名、鍵情報、ネットワーク関連の初期設定などが自動的に構成されることがあります。</p>
<p id="411a1f97-d122-4020-8dbb-0c416d5b5cbe">Amazon Linux 2のようなクラウド向けのOSイメージでは、オンプレミスのRHEL環境と同じ管理サービス構成になっているとは限りません。</p>
<p id="75a5a556-7d48-41d6-972d-37fdccee9b5e">そのため、NetworkManagerだけでなく、network service、DHCP、cloud-init、AMI作成時の状態など、複数の仕組みが関係する場合があります。</p>
<p id="d1f38bba-cd91-4fe7-97d5-440eb17e23cd">今回の環境では、RHEL7で使っていたNetworkManager前提の設定手順を、そのまま使える構成ではありませんでした。</p>
<p id="3bb2e7af-3c12-4a86-a4b4-37aa188a55bc">見るべきポイントは、</p>
<p id="abf9247e-9521-4fe0-b324-53037ba7fa67">「どのOSか」</p>
<p id="69ff822c-21be-4efe-899f-aebce59fee3c">だけではありません。</p>
<p id="d8f5311a-1dba-4df3-81d3-1a0429ae8e55">より正確には、</p>
<p id="caea0fe4-faa3-439b-be65-a2ce0bb90d21">「そのOSイメージでは、ネットワーク設定を何が管理しているのか」</p>
<p id="72aaabc9-2727-45f1-a0bb-c63a435470b4">です。</p>
<p id="9ac4a5ec-260a-4bbc-b6d9-3cb5267007fa">ここを確認せずに手順を横展開すると、設定が反映されない、再起動後に戻る、別インスタンスでは挙動が違う、というトラブルにつながります。</p>
<p id="98d50e7e-b7de-4f85-b6fd-aae1c3efedcc">なお、Amazon Linux 2023では、さらに事情が変わります。</p>
<p id="4ccd5dd9-598d-4311-8199-38c902d9fce5">AWS公式ドキュメントでは、AL2023では `systemd-networkd` がネットワークインターフェースを管理し、AL2で使われていた `dhclient` から変更されていると説明されています。</p>
<p id="56615450-c388-4c2f-bb60-e3f8fa8f8bb1">つまり、Amazon Linux 2で確認した手順も、Amazon Linux 2023にそのまま横展開できるとは限りません。</p>
<h2 id="431a1056-2710-429a-b3a5-c882c9e34308" tabindex="-1"><span id="toc4">RHEL7ではNetworkManager、Amazon Linux 2では別の見方が必要だった</span></h2>
<p id="ef9c712f-4b0c-4dcc-9f97-92bce0c8a7ea">今回の差分を簡単に整理すると、以下のようになります。</p>
<figure id="1e3252c4-535b-43c6-a6f4-150bde55b7b8"><a href="https://assets.st-note.com/img/1780964845-vz9RTZ6Vsj5e4PpuntySLHmE.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide" src="https://assets.st-note.com/img/1780964845-vz9RTZ6Vsj5e4PpuntySLHmE.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="269b6f88-c1b6-427b-97af-11e6ff7b3ed9">RHEL7では、NetworkManagerがネットワーク設定の中心になっている環境があります。</p>
<p id="04bcdb31-e8e6-4888-9216-f3d824a4f426">その場合、nmcli で接続プロファイルを変更することが自然な方法になります。</p>
<p id="002b70a7-6afa-4a8b-a4de-66a04809161d">一方で、Amazon Linux 2では、環境によってはNetworkManagerを前提にできません。</p>
<p id="3b04325d-4a03-46b7-bc1c-563fc989c800">そのため、インターフェース設定ファイルやDHCPクライアント設定、起動時にネットワーク設定へ関わる仕組みを確認する必要があります。</p>
<p id="a42d013c-69dd-4d65-a750-2e81fa23bbe1">たとえば、インターフェース側では以下のような設定ファイルを確認します。</p>
<div class="code-block-container">
<pre id="d10850bf-e4a2-42d6-9edd-948aedecbbc1" data-name="preCode"><code class="hljs" data-name="code">/etc/sysconfig/network-scripts/ifcfg-eth0
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="282114ac-77c2-461e-b722-144fda9d80d5">MTU値を指定する場合、環境に応じて次のような設定を追加・変更します。</p>
<div class="code-block-container">
<pre id="a4dc8d95-1739-449a-85ab-ecb0ed543f0b" data-name="preCode"><code class="hljs" data-name="code">MTU=1600
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="4d780b00-8318-4fac-93d9-63e97d482eec">さらに、DHCPでネットワーク設定を取得している場合は、DHCPクライアント側の設定も確認対象になります。</p>
<div class="code-block-container">
<pre id="4899517a-e9c4-46fd-853c-3859d0147938" data-name="preCode"><code class="hljs" data-name="code">/etc/dhcp/dhclient.conf
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="46110550-e96f-4c2d-bff3-15fc2bbf7a01">ここで出てくるコマンドやファイルパスを、すべて丸暗記する必要はありません。</p>
<p id="54410ff8-e443-4d3b-8800-1726d85c29a3">大事なのは、個別のコマンドを覚えることではなく、</p>
<p id="78e6ce8a-e6b5-4faf-8e7e-22824eaa13e8">「誰がネットワーク設定を管理しているのか」<br />
「どこに書けば再起動後も残るのか」<br />
「何に上書きされる可能性があるのか」</p>
<p id="d2f48d67-8712-4c1d-8dba-3012b973b4ac">という構造を押さえることです。</p>
<figure id="749c37c5-cdd9-42bc-9729-e4babe7fac2a" data-align="center"><a href="https://assets.st-note.com/img/1780621641-carLuhgPyj5CT2ApKYS4knql.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide" src="https://assets.st-note.com/img/1780621641-carLuhgPyj5CT2ApKYS4knql.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="88a98c40-fbd4-4476-bbc5-721c44db9290">この図で見てほしいのは、設定値の違いではありません。</p>
<p id="3baf05ab-296b-415f-943f-f0ce13f9577a">同じMTU設定でも、RHEL7ではNetworkManager経由、Amazon Linux 2では設定ファイルやDHCP関連の確認が中心になる、という<strong>設定経路の違い</strong>です。</p>
<h2 id="9c190c47-2b87-4a38-b3e1-9e9d09fee8fd" tabindex="-1"><span id="toc5">一番怖いのは、設定できたように見えてしまうこと</span></h2>
<p id="d178ebba-f9f7-434d-b59f-c3b3e6c0f230">この手のトラブルで怖いのは、最初から完全に失敗してくれるとは限らないことです。</p>
<p id="1f3ebb15-8085-4755-a926-d7aa6e89c59e">コマンドが存在しない。<br />
サービスが存在しない。<br />
設定ファイルが見つからない。</p>
<p id="bae35c12-c208-4855-8c33-263e423f2660">ここまで分かりやすく失敗してくれれば、まだよいです。</p>
<p id="0fd89c9c-f73e-459f-8f99-8d120fe6fe86">問題は、<strong>設定したつもりになっているケース</strong>です。</p>
<p id="c5f5f33f-4bfa-4ab4-b6a5-e7ef5897d7c1">たとえば、次のようなコマンドで確認したとします。</p>
<div class="code-block-container">
<pre id="ee2984fe-cb7f-4812-a97a-573bfa5a6900" data-name="preCode"><code class="hljs" data-name="code">ip link show eth0
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="5539e4f4-dc96-4c3c-9edc-5f2f874c3806">その時点では、MTUが変わっているように見える。</p>
<p id="d73eb59a-06e2-4bd0-a505-b8bcaa56366d">しかし、ネットワークサービスを再起動すると戻る。<br />
OSを再起動すると戻る。<br />
AMIから再作成すると戻る。<br />
DHCP更新後に戻る。<br />
別のインスタンスでは挙動が違う。</p>
<p id="2028e23f-e87b-443a-b6bb-7ae61838d795">この場合、作業者の感覚としては、</p>
<p id="b0de435d-b7fe-4676-a5e1-c30a04f55f21">「設定したのに戻った」<br />
「なぜか環境によって違う」<br />
「手順通りにやったのに再現しない」</p>
<p id="97f8458d-8222-4c17-a380-57f36d92a33f">となります。</p>
<p id="0e16f2e8-2331-4f6a-811c-e9bb5056f049">しかし、原因はシンプルです。</p>
<p id="d8329e15-f81d-4d07-8800-e50d44ff31f0"><strong>その設定が、永続化される場所に入っていなかった。</strong><br />
または、<br />
<strong>永続化したつもりの設定が、別の仕組みに上書きされていた。</strong></p>
<p id="30b53f24-d2bd-4492-858a-57afec7086ff">作業直後に設定値が変わることと、運用中もその設定が維持されることは、別の話です。</p>
<h2 id="ce3c3ec8-b7b3-461b-b972-66653b5e9be9" tabindex="-1"><span id="toc6">設定確認は「今」だけで終わらせない</span></h2>
<p id="0e7550a2-b192-4ad9-90a7-25567d176c84">MTU設定後に ip link show eth0 で確認することは必要です。</p>
<p id="64c23201-0e2c-4293-8987-6e1abc777f0d">しかし、それは「今そうなっている」ことを見ているだけです。</p>
<p id="d1ca4136-3744-4069-8f0d-b1e9cd11adf1">インフラ構築では、設定直後だけでなく、network再起動後、OS再起動後、AMI化・再作成後、DHCP更新後まで確認します。</p>
<ul id="49768f84-3f60-4e34-a276-599ce2a85a9e">
<li>
<p id="a6a94918-e1c5-4d68-88e4-76cf2652d703">設定直後にMTUが変わっているか</p>
</li>
<li>
<p id="1723accc-9679-47ae-ae2e-0d5fa9e5e521">network再起動後も維持されるか</p>
</li>
<li>
<p id="d2bc8525-d577-4673-ae15-9c5e9b64cbd9">OS再起動後も維持されるか</p>
</li>
<li>
<p id="0c528687-6ab9-44bc-8311-b993d710f241">AMI化・再作成後も維持されるか</p>
</li>
<li>
<p id="38a638ee-61ad-4366-98a5-c19057da24d2">DHCP更新後に戻らないか</p>
</li>
</ul>
<figure id="6c3037b6-b6ce-482c-8db9-b90146745f90" data-align="center"><a href="https://assets.st-note.com/img/1780621751-QXH3kKSWs6iNpnxMfJDPVGoI.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide" src="https://assets.st-note.com/img/1780621751-QXH3kKSWs6iNpnxMfJDPVGoI.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="2435e595-df32-40ae-9afc-e5619f94d396">この図で伝えたいのは、「今変わっているか」だけでなく、<strong>戻らないか</strong>まで見る必要がある、ということです。</p>
<h2 id="90825d49-519a-4f4a-83ec-19b6b861a997" tabindex="-1"><span id="toc7">このトラブルを防ぐための確認観点</span></h2>
<p id="494fa3c5-ea03-4ce1-b199-8adfd835fcc6"><strong>1. ネットワーク設定の管理方式を確認する</strong></p>
<p id="b208e563-57e2-4b28-8be7-4aed8b3e7740">対象OSでネットワーク設定を何が管理しているかを最初に確認します。</p>
<div class="code-block-container">
<pre id="dc300757-dc37-42f9-8619-c2bcede29ce0" data-name="preCode"><code class="hljs" data-name="code">systemctl status NetworkManager
systemctl status network
ls -l /etc/sysconfig/network-scripts/
cat /etc/sysconfig/network-scripts/ifcfg-eth0
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="b6874985-2c55-4da2-beec-7bcd4dafb404">見るべきなのは、コマンドが使えるかどうかだけではありません。</p>
<p id="eb65fd43-ecae-455c-8d6a-a5f4d520530f">そのサービスがOS起動時に使われているか。<br />
対象インターフェースを管理しているか。<br />
設定ファイルの内容と実際の状態が合っているか。</p>
<p id="424fd0ac-ea6d-496d-859c-fa46e0ec03f2">ここまで確認します。</p>
<p id="ec210bcf-b497-401a-81bd-53c043906d17"><strong>2. 一時設定と永続設定を分ける</strong></p>
<p id="758511c3-82fe-44d0-9075-f73a1738f1eb">MTUは、一時的に変更するだけなら次のようなコマンドでも変更できます。</p>
<div class="code-block-container">
<pre id="66a1ec71-88b1-4027-9687-9aac86cfb05e" data-name="preCode"><code class="hljs javascript" data-name="code">ip link <span class="hljs-keyword">set</span> dev eth0 mtu 1600
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="efd571ed-f67e-4f7f-ac44-a2d6f36739a7">しかし、これは基本的に一時的な変更です。</p>
<p id="b5cfb3c5-87e8-4d43-af3f-ae209bc41db4">OS再起動後に維持されるかは別問題です。</p>
<p id="30d124c1-eeee-4ff1-b555-49037e267ae3">一時設定で確認するのか。<br />
永続設定として設計するのか。</p>
<p id="8cb51758-74fb-42eb-91e6-5c88c9e22c92">ここを混同すると、構築時は動いていたのに、本番運用で戻るということが起きます。</p>
<p id="95e891d3-bf24-4db4-8344-68c635af0a4f"><strong>3. DHCPやcloud-initによる上書きを確認する</strong></p>
<p id="aef6ab87-d9cf-4ee5-975b-654510914963">クラウド環境では、OSが起動した後に、DHCPやcloud-initなどがネットワーク設定に関わることがあります。</p>
<p id="34b8a460-6023-4f29-8d6a-19bdd5dfd47d">そのため、設定ファイルに値を書いただけでは不十分な場合があります。</p>
<p id="80396ac6-651d-4129-9e85-a54ca60ba36f">確認すべきことは、たとえば次のような点です。</p>
<ul id="86475a68-aad1-4511-a882-20a06a16f0fc">
<li>
<p id="9a781b7c-8960-442b-b9f2-303b220d9264">DHCPで取得した設定によりMTUが上書きされないか</p>
</li>
<li>
<p id="fa75f086-c3fb-462c-b057-aef7ae4f4828">dhclient.conf で明示的な設定が必要か</p>
</li>
<li>
<p id="63d26f57-2f47-4979-aebb-c97f50e9d1ae">cloud-initが起動時にネットワーク設定を生成・変更していないか</p>
</li>
<li>
<p id="0829283f-4a97-449b-923e-ef17bf4e45f9">AMI化した後、別インスタンスで同じ設定が再現されるか</p>
</li>
</ul>
<p id="aa2f3916-8648-4278-bc62-b053912b72b5">さらに対策として、手作業で変更した内容を、AMI作成手順、構築手順、構成管理、または自動構築の仕組みに反映しておく必要があります。</p>
<h2 id="3f333a38-ffb2-487b-80e2-7e95b91a50a7" tabindex="-1"><span id="toc8">詳細設計と構築手順では「設定値」だけでなく「反映と確認」まで書く</span></h2>
<p id="31e43114-d0ba-4bf8-904b-f6d1634be3b1">詳細設計書に、</p>
<figure id="d7d1210c-2ebf-4bf4-9705-63f773ffd98f">
<blockquote>
<p id="8f7cb816-0620-4ca2-988e-62b0f6db185c">MTUを1600に設定する</p>
</blockquote><figcaption></figcaption></figure>
<p id="dde411c9-9eda-4c74-8167-e9d611214817">とだけ書いてあったとします。</p>
<p id="c1b65f39-848e-434c-b2f1-739c919ec657">設定値だけでは、構築する側は判断できません。<br />
少なくとも次の情報が必要です。</p>
<div class="code-block-container">
<pre id="de5c32bb-2c50-465a-b383-ec97ee6969b2" data-name="preCode"><code class="hljs" data-name="code">対象OS：
  Amazon Linux 2

対象インターフェース：
  eth0

設定値：
  MTU=1600

設定箇所：
  /etc/sysconfig/network-scripts/ifcfg-eth0

DHCP設定：
  /etc/dhcp/dhclient.conf の更新要否を確認

反映方法：
  networkサービス再起動、またはOS再起動

確認方法：
  ip link show eth0
  ping疎通
  必要に応じてパケットサイズ指定で疎通確認

永続化確認：
  OS再起動後もMTU値が維持されること
  AMI化・再作成後もMTU値が維持されること
  DHCP更新後にMTU値が戻らないこと
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<p id="5bf20dac-924d-46e0-bbf1-656395df921b">これくらい書いて、ようやく構築・試験できる設計になります。</p>
<p id="cd861f7b-ba17-415e-912f-62a8fa49282d">構築手順書に落とす場合も同じです。</p>
<p id="879c304e-ebc5-44d0-a1be-c08be6796864">手順書には、設定コマンドだけでなく、変更前確認、変更後確認、再起動後確認、必要に応じてAMI化・再作成後の確認まで含める必要があります。</p>
<p id="52b7b141-4d0b-4656-9492-b0cd533c3aab">たとえば、作業の流れとしては次のようになります。</p>
<div class="code-block-container">
<pre id="ca595290-f71c-4dea-bb1c-b8e546bcb1bf" data-name="preCode"><code class="hljs" data-name="code">1. 現在のMTU値を確認する
2. 対象インターフェースを確認する
3. ネットワーク設定の管理方式を確認する
4. 設定ファイルやDHCP設定を修正する
5. network再起動またはOS再起動で反映する
6. MTU値を確認する
7. OS再起動後に再確認する
8. 必要に応じてAMI化・再作成後に再確認する
</code></pre>
<div class="a-button__inner" data-v-00506f85=""> </div>
</div>
<h2 id="b49759d3-9c19-41be-b20a-7d78d2c1c44e" tabindex="-1"><span id="toc9">試験項目では「今の設定値」だけを見ない</span></h2>
<p id="824e8aca-54b5-457e-9b57-661df5d110f7">ip link show eth0 だけでは「今の状態」しか分かりません。<br />
実務では次の観点まで確認します。</p>
<figure id="a1001a90-43f7-43fa-b9c1-884357164964" data-align="center"><a href="https://assets.st-note.com/img/1780622118-0H7rql89SgVGFEKXPO6oyjsw.png?width=2000&amp;height=2000&amp;fit=bounds&amp;quality=85" aria-label="画像を拡大表示"><img loading="lazy" decoding="async" class="is-slide" src="https://assets.st-note.com/img/1780622118-0H7rql89SgVGFEKXPO6oyjsw.png?width=1200" alt="画像" width="620" height="465" data-modal="true" /></a><figcaption></figcaption></figure>
<p id="c9004c73-04cf-4a54-8873-fd1fad2d3c08">特にクラウド環境では、AMI化・再作成後の確認が重要です。</p>
<p id="ebd62679-178b-4ada-8803-469f2fac026a">Auto Scalingや障害復旧で新しいインスタンスが起動したときに設定が戻るなら、構築時に確認できていても運用には耐えません。</p>
<h2 id="f4ba7c9d-70a7-4344-be1d-8ea775b83681" tabindex="-1"><span id="toc10">レビューでは設定値ではなく、設定が残る仕組みを見る</span></h2>
<p id="b693d8c3-d935-4789-a7a2-e647ad2e7466">MTU設定の設計書や手順書をレビューするなら、次のような観点で見ます。</p>
<ul id="e97a01fa-d576-46d6-a3b5-d42158300c34">
<li>
<p id="83c97e2a-0ab5-45e0-b8d9-a8e2c35555fa">対象OS・バージョン・対象インターフェースが明記されているか</p>
</li>
<li>
<p id="f4e6c4b5-7f9e-4503-98e5-31f334ba7fab">設定箇所と反映方法が明記されているか</p>
</li>
<li>
<p id="1d1b063b-122d-4d88-ae1b-4247f244ef3b">NetworkManager前提か、network service前提かが明記されているか</p>
</li>
<li>
<p id="0a80f59a-6ae2-48b5-ba95-4d76aa5f2bab">DHCP・cloud-initの影響を確認しているか</p>
</li>
<li>
<p id="0d5ada20-d55a-431d-8dde-40f899f4e704">OS再起動後の確認があるか</p>
</li>
<li>
<p id="990a9110-6c12-433a-a43f-e438c68f741b">AMI化・再作成後の確認があるか</p>
</li>
</ul>
<p id="b46ccb60-64e3-452e-85de-309e0c9fdbb0">「MTU=1600と書いてあるからOK」では、このトラブルは防げません。<br />
設定値ではなく、設定が残る仕組みまで見ることがレビューのポイントです。</p>
<h2 id="c7dea103-5b0c-40c2-b418-d2c949f8d3ef" tabindex="-1"><span id="toc11">まとめ</span></h2>
<p id="9cf4b455-b3d0-467e-b15c-c695fa8d8c10">今回のトラブルは、RHEL7とAmazon Linux 2でMTU設定方法が違っていた、という事例です。</p>
<p id="8abd743e-9ad3-4441-98f5-506bc66efdd6">ただし、学ぶべきことは「Amazon Linux 2ではこのファイルを編集する」という単純な話ではありません。</p>
<p id="fb55b832-b66e-4de1-98a6-f4ad6035c65a">重要なのは、以下です。</p>
<ul id="22fff5b1-e13f-47b4-a832-ff9046aba507">
<li>
<p id="3a58c13e-3bed-49b9-b3f1-826aa08c71d9">OSが変われば、設定の管理方式も変わる</p>
</li>
<li>
<p id="e3855094-0351-45b4-973e-2d97280b8e3f">コマンドではなく、管理している仕組みを見る</p>
</li>
<li>
<p id="6a843259-feeb-4ed0-84aa-38bbcab8641d">設定直後だけでなく、再起動後・再作成後も確認する</p>
</li>
<li>
<p id="c58ef937-90ed-40ba-b465-275e97e78a79">詳細設計では、設定値だけでなく設定箇所・反映方法・確認方法まで書く</p>
</li>
<li>
<p id="b8b9307e-5b21-456e-aa44-1bf2b610133c">クラウド環境では、AMI化・再作成後も同じ設定になるかを見る</p>
</li>
</ul>
<p id="7a67735c-d585-4821-8ff9-a44c2df2cc30">コマンドを知っていること以上に、その設定がどの仕組みに管理され、再起動後も維持されるのかを確認できること。</p>
<p id="1c2313cc-ebc1-4407-8607-1142f7fadaf2">この視点が、インフラ構築の品質を分けます。</p>
<p id="b7c3e600-282f-43c9-8c22-15a4035e8224"><strong>関連記事</strong></p>
<p id="a74373b3-48ac-4d9e-bfc4-77c788da1cac">今回の記事で扱った「設定値だけでなく、設定箇所・反映方法・確認方法・永続化確認まで設計に落とす」という考え方は、以下の記事でも整理しています。</p>
<p><a rel="nofollow" href="https://sys-univ.com/dev/detailed-design-overview/" target="_blank">【前編】詳細設計で決めること｜基本設計を「構築・テスト・運用できる形」に落とし込む工程</a></p>
<p id="977be368-4c93-44ea-9dfc-2cb25d028cce">シリーズ全体は<a rel="nofollow noopener" href="https://note.com/k_s7906/m/mc19593a012e2" target="_blank">「実務で使えるシステム開発方法論」マガジン</a>にまとめています。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/incident/mtusetting/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Oracle 19c更改後に実行計画が変わる――パーティション削除時の統計情報更新と影響調査漏れ</title>
		<link>https://sys-univ.com/dev/oracle-19c-partition-statistics-execution-plan/</link>
					<comments>https://sys-univ.com/dev/oracle-19c-partition-statistics-execution-plan/#respond</comments>
		
		<dc:creator><![CDATA[ナギ]]></dc:creator>
		<pubDate>Wed, 22 Jul 2026 03:16:41 +0000</pubDate>
				<category><![CDATA[トラブル]]></category>
		<category><![CDATA[システム開発]]></category>
		<guid isPermaLink="false">https://sys-univ.com/?p=2887</guid>

					<description><![CDATA[はじめに Oracle Databaseを19cへ更改した後、最初の年次処理を終えた直後から、一部SQLの性能が急激に悪化し、夜間バッチの処理時間へ影響が及びました。 SQLもアプリケーションも変えていません。統計収集ジ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><strong>はじめに</strong></p>


<p class="wp-block-paragraph">Oracle Databaseを19cへ更改した後、最初の年次処理を終えた直後から、一部SQLの性能が急激に悪化し、夜間バッチの処理時間へ影響が及びました。</p>


<p class="wp-block-paragraph">SQLもアプリケーションも変えていません。統計収集ジョブも実行していません。それにもかかわらず、実行計画だけが変わっていました。</p>


<p class="wp-block-paragraph">原因は、Oracle 19cで追加された、パーティションメンテナンス時に統計情報が更新される仕様でした。従来から実施していたパーティション削除を契機として表統計の一部だけが更新され、実行計画が変化した結果、SQL性能が悪化していました。</p>


<p class="wp-block-paragraph">この障害の本質は、Oracleの仕様そのものではありません。非互換情報の確認だけでは捉えられない「新機能による内部動作の変更」が、更改時の影響調査から漏れていたことです。同じ構図の見落としは、OracleでもAWSでもLinuxでも起こり得ます。</p>


<p class="wp-block-paragraph">本記事では、この事例を題材に、原因調査で確認した証跡、対策の設計判断、更改プロジェクトとして追加すべき影響調査と試験の観点を整理します。</p>



  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-20" checked><label class="toc-title" for="toc-checkbox-20">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">発端は更改後最初の年次処理だった</a></li><li><a href="#toc2" tabindex="0">Oracle 19cへの更改で顕在化した統計情報の更新</a></li><li><a href="#toc3" tabindex="0">なぜデータを削除した後にSQLが遅くなるのか</a></li><li><a href="#toc4" tabindex="0">調査で確認した証跡</a><ol><li><a href="#toc5" tabindex="0">AWRでSQL性能の変化を確認する</a></li><li><a href="#toc6" tabindex="0">実行計画が変わっていないかを確認する</a></li><li><a href="#toc7" tabindex="0">統計情報はいつ変わったのか</a></li><li><a href="#toc8" tabindex="0">時系列で整理すると原因が見えてくる</a></li></ol></li><li><a href="#toc9" tabindex="0">問題はOracleではなく影響調査の範囲だった</a></li><li><a href="#toc10" tabindex="0">技術的な対策は一つではない</a><ol><li><a href="#toc11" tabindex="0">パーティションメンテナンス後に統計情報を再収集する</a></li><li><a href="#toc12" tabindex="0">実行計画そのものを安定させる</a></li><li><a href="#toc13" tabindex="0">Oracle内部動作を変更する方法もある</a></li><li><a href="#toc14" tabindex="0">更改設計として考えるべきこと</a></li></ol></li><li><a href="#toc15" tabindex="0">更改プロジェクトで追加すべき試験と運用</a></li><li><a href="#toc16" tabindex="0">非互換情報の外側にある変更を見る</a></li><li><a href="#toc17" tabindex="0">まとめ</a></li><li><a href="#toc18" tabindex="0">参考資料</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">発端は更改後最初の年次処理だった</span></h2>


<p class="wp-block-paragraph">ある基幹システムでは、Oracle Databaseの更改後、最初の年次処理として保存期間を超えたデータをパーティション削除で整理していました。旧環境から長年継続している定期メンテナンスで、SQL、アプリケーション、運用手順のいずれにも性能へ影響するような変更は加えていません。</p>


<p class="wp-block-paragraph">年次処理が終了した直後から、一部SQLの応答が悪化し始めました。</p>


<p class="wp-block-paragraph">最初に疑ったのは、アプリケーション側の変更です。変更履歴を確認しても、性能劣化につながる修正は見つかりません。次に疑ったのは統計情報ですが、運用担当者が対象表へ統計収集を実行した記録もありませんでした。</p>


<p class="wp-block-paragraph">処理内容もSQLも統計収集も、利用者側は何も変えていない。それでも更改後の環境では、SQLの性能特性だけが変わっていました。</p>


<p class="wp-block-paragraph">この時点で、利用者側の変更を探す調査は行き詰まりました。残る可能性は、旧バージョンと19cの間で、Oracle内部の動作そのものが変わっていることです。調査の焦点を、アプリケーションからOracleの内部動作へ切り替えました。</p>


<h2 class="wp-block-heading"><span id="toc2">Oracle 19cへの更改で顕在化した統計情報の更新</span></h2>


<p class="wp-block-paragraph">調査を進めた結果、パーティションメンテナンス時にOracleが統計情報を更新する動作が関係していることが分かりました。</p>


<p class="wp-block-paragraph">この動作は、My Oracle Supportの次の文書でも、Oracle Database 19cにおけるパーティション表の統計情報変更として整理されています。</p>


<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>Partitioned Table Statistics Changed After Truncate Partition or Drop Partition Operation</strong><br />
<strong>MOS Doc ID 2970098.1</strong></p>
</blockquote>


<p class="wp-block-paragraph">Oracle Database 19cのSQL Tuning Guideにも、パーティションメンテナンスに伴う統計情報の処理が「Online Statistics Gathering for Partition Maintenance Operations」として記載されています。</p>


<p class="wp-block-paragraph">ここで区別しなければならないのは、すべてのパーティション操作で同じ統計収集処理が実行されるわけではないことです。</p>


<p class="wp-block-paragraph">パーティションメンテナンスには、次のような操作があります。</p>


<ul id="187f0994-efd6-4b79-aa41-dd56ffe3ff65" class="wp-block-list">
	<li>DROP PARTITION</li>


	<li>TRUNCATE PARTITION</li>


	<li>MOVE PARTITION</li>


	<li>MERGE PARTITION</li>


	<li>COALESCE PARTITION</li>


	<li>SPLIT PARTITION</li>
</ul>


<p class="wp-block-paragraph">MOVE PARTITIONやMERGE PARTITIONなど、データの移動やダイレクトパス書き込みを伴う処理では、操作内容に応じてオンライン統計収集が行われる場合があります。</p>


<p class="wp-block-paragraph">本事例で問題となったDROP PARTITIONでは、DBMS_STATS.GATHER_TABLE_STATSに相当する全統計収集が実行されたわけではありません。パーティション削除に合わせて、グローバル表統計のNUM_ROWSやBLOCKSなどがOracle内部で更新されました。</p>


<p class="wp-block-paragraph">運用担当者が統計収集ジョブを実行していなくても、統計情報の一部はパーティション操作によって変化します。</p>


<p class="wp-block-paragraph">「統計情報を収集していない」という運用上の認識と、「統計情報が変化していない」というデータベース上の事実は同じではありません。</p>


<p class="wp-block-paragraph">この違いを認識していなければ、性能劣化の調査でアプリケーション、SQL、負荷状況だけを追い続け、実行計画を変化させた統計情報の更新を見落とすことになります。</p>


<h2 class="wp-block-heading"><span id="toc3">なぜデータを削除した後にSQLが遅くなるのか</span></h2>


<p class="wp-block-paragraph">この動作は旧環境では発生しておらず、19cへの更改後に初めて顕在化しました。</p>


<p class="wp-block-paragraph">データを削除すれば処理対象が減るため、SQLも速くなるように思えます。</p>


<p class="wp-block-paragraph">今回の事象では、パーティション削除後にSQL性能が悪化しました。</p>


<p class="wp-block-paragraph">原因を理解するには、Oracleのオプティマイザが利用する統計情報を、表統計とカラム統計に分けて考える必要があります。</p>


<p class="wp-block-paragraph">表統計には、表全体の規模を示す情報が含まれます。代表的な項目はNUM_ROWS、BLOCKS、AVG_ROW_LENです。</p>


<p class="wp-block-paragraph">カラム統計には、列の値がどのように分布しているかを示す情報が含まれます。代表的な項目には、個別値数を示すNDV、LOW_VALUE、HIGH_VALUE、NULL数、ヒストグラムなどがあります。</p>


<p class="wp-block-paragraph">DROP PARTITIONを実行すると、削除されたパーティションを反映して、表全体の行数やブロック数を示す統計が更新されます。カラム統計やヒストグラムまで、同じタイミングで整合した状態へ再収集されるわけではありません。</p>


<p class="wp-block-paragraph">この状態では、オプティマイザが参照する統計情報に異なる時点の情報が混在します。</p>


<p class="wp-block-paragraph">表統計は、パーティション削除後の表が以前より小さくなったことを示しています。カラム統計は、削除前の値分布を前提とした状態で残っています。</p>


<p class="wp-block-paragraph">オプティマイザは、表統計とカラム統計を使って、検索条件へ該当する行数を推定します。両者の前提が一致していなければ、カーディナリティ推定が実際のデータ分布から外れる可能性があります。</p>


<p class="wp-block-paragraph">カーディナリティ推定が変わると、索引を使うか全表走査を選ぶか、Nested LoopsとHash Joinのどちらを使うか、どの表を駆動表とするかといった判断も変わります。結合順序や並列実行の選択まで変化することがあります。</p>


<p class="wp-block-paragraph">本件では、統計情報が更新されたという事実だけで性能が悪化したのではありません。</p>


<p class="wp-block-paragraph">表統計の一部だけが更新され、既存のカラム統計との前提が一致しない状態が次回の統計収集まで残った結果、<strong>カーディナリティ推定が変化し、従来とは異なる実行計画が選択</strong>されました。</p>


<p class="wp-block-paragraph">たとえば本件では、パーティション削除後にNUM_ROWSが大幅に減少した統計を基に、オプティマイザが従来とは異なるアクセスパスを選択したと推定されます。統計上は小さく見える表に対してIndex Range ScanよりFull Table Scanのコストが低いと判断されたり、結合方式がNested LoopsからHash Joinへ変わったりすることで、実業務データの実際の件数との乖離が性能劣化として現れます。</p>


<p class="wp-block-paragraph">統計情報の更新は、常に性能改善を意味するものではありません。どの統計が、どの単位で、どの範囲まで更新されたのかを確認しなければ、オプティマイザが参照している情報の状態を正しく把握できません。</p>


<h2 class="wp-block-heading"><span id="toc4">調査で確認した証跡</span></h2>


<p class="wp-block-paragraph">性能障害を説明するには、「パーティションを削除した」「統計情報が変わった」「SQLが遅くなった」という個別の事実だけでは十分ではありません。</p>


<p class="wp-block-paragraph">重要なのは、それらの出来事が<strong>同じ時間軸で発生していること</strong>を確認することです。</p>


<p class="wp-block-paragraph">今回の調査では、AWR、実行計画、統計情報の更新時刻を組み合わせ、原因と結果を時系列で整理しました。</p>


<h3 class="wp-block-heading"><span id="toc5">AWRでSQL性能の変化を確認する</span></h3>


<p class="wp-block-paragraph">最初に確認したのは、AWRに記録されたSQL性能の変化です。</p>


<p class="wp-block-paragraph">年次処理の終了後から対象SQLの負荷が増加しており、単純に実行回数が増えたのではなく、1回当たりの処理コストそのものが悪化していました。</p>


<p class="wp-block-paragraph">主に確認した項目は次のとおりです。</p>


<ul id="00373a11-2ca9-49a2-81b5-a47e0d9d0f7a" class="wp-block-list">
	<li>Elapsed Time</li>


	<li>CPU Time</li>


	<li>Buffer Gets</li>


	<li>Disk Reads</li>


	<li>Executions</li>


	<li>Rows Processed</li>
</ul>


<p class="wp-block-paragraph">これらは合計値だけでは判断できません。</p>


<p class="wp-block-paragraph">たとえばElapsed Timeが増加していても、単純に実行回数が増えただけであれば異常とは言えません。</p>


<ul id="04074422-6e2a-4076-ab92-03dc3135bc26" class="wp-block-list">
	<li>1実行当たりのElapsed Time</li>


	<li>1実行当たりのBuffer Gets</li>
</ul>


<p class="wp-block-paragraph">まで確認し、SQLそのものの性能が変化したことを確認しました。</p>


<h3 class="wp-block-heading"><span id="toc6">実行計画が変わっていないかを確認する</span></h3>


<p class="wp-block-paragraph">次に確認したのは実行計画です。</p>


<p class="wp-block-paragraph">AWRやDBA_HIST_SQLSTAT、DBA_HIST_SQL_PLANを調査すると、対象SQLでは性能悪化前後でPLAN_HASH_VALUEが変化していました。</p>


<p class="wp-block-paragraph">PLAN_HASH_VALUEが変わるということは、少なくともOracleが異なる実行計画を選択したことを意味します。</p>


<p class="wp-block-paragraph">もちろん、PLAN_HASH_VALUEだけでは原因を断定できません。</p>


<p class="wp-block-paragraph">実際には、</p>


<ul id="decc2bc5-d8f9-4394-9cd5-44850c084795" class="wp-block-list">
	<li>アクセスパス</li>


	<li>結合方式</li>


	<li>結合順序</li>


	<li>推定行数（Cardinality）</li>


	<li>実際の処理行数</li>
</ul>


<p class="wp-block-paragraph">まで確認し、オプティマイザがどの判断を変更したのかを追跡しました。</p>


<h3 class="wp-block-heading"><span id="toc7">統計情報はいつ変わったのか</span></h3>


<p class="wp-block-paragraph">最後に、統計情報そのものを確認しました。</p>


<p class="wp-block-paragraph">DBA_TAB_STATISTICSを見ると、パーティション削除を実施した時刻を境に、対象表の統計情報が更新されていました。</p>


<p class="wp-block-paragraph">確認した主な項目は次の三つです。</p>


<ul id="4d38f674-8ecb-4588-a2f3-bc769e7f94b7" class="wp-block-list">
	<li>NUM_ROWS</li>


	<li>BLOCKS</li>


	<li>LAST_ANALYZED</li>
</ul>


<p class="wp-block-paragraph">運用では統計収集ジョブを実行していないにもかかわらず、これらの値はパーティション削除のタイミングで変化していました。</p>


<p class="wp-block-paragraph">さらに、DBA_TAB_COL_STATISTICSやヒストグラム関連ビューも確認したところ、カラム統計は従来の状態を保持していました。</p>


<ul id="5448d9a1-9549-4b2b-9214-a85c9fb1f9fe" class="wp-block-list">
	<li>表統計は更新されている</li>


	<li>カラム統計は更新されていない</li>
</ul>


<p class="wp-block-paragraph">という状態になっていたことが分かります。</p>


<p class="wp-block-paragraph">この結果は、前章で説明した「表統計とカラム統計の前提が一致しない状態」が実際に発生していたことを裏付ける証拠となりました。</p>


<h3 class="wp-block-heading"><span id="toc8">時系列で整理すると原因が見えてくる</span></h3>


<p class="wp-block-paragraph">今回の調査結果を時系列で整理すると、次の流れになります。</p>


<pre class="wp-block-code"><code>年次処理でDROP PARTITION
        ↓
Oracle内部で表統計の一部が更新
        ↓
表統計とカラム統計の前提が一致しない
        ↓
オプティマイザのカーディナリティ推定が変化
        ↓
実行計画が変更される
        ↓
PLAN_HASH_VALUEの変化として観測される
        ↓
Elapsed Time・Buffer Getsが増加</code></pre>


<p class="wp-block-paragraph">この流れは、一つのビューだけを見て導いたものではありません。</p>


<p class="wp-block-paragraph">パーティション操作の実施時刻、統計情報の更新時刻、実行計画の変化、AWRに記録された性能指標を同じ時間軸へ並べることで、初めて因果関係を説明できます。</p>


<p class="wp-block-paragraph">性能障害の調査では、「実行計画が変わった」「統計情報が更新された」という個別の事実だけを示しても説得力はありません。</p>


<p class="wp-block-paragraph"><strong>複数の証跡を時系列で結び付けて初めて、性能劣化の原因を論理的に説明できます。</strong></p>


<hr class="wp-block-separator has-alpha-channel-opacity" />

<h2 class="wp-block-heading"><span id="toc9">問題はOracleではなく影響調査の範囲だった</span></h2>


<p class="wp-block-paragraph">Oracleは仕様どおりに動作していました。</p>


<p class="wp-block-paragraph">本件の問題は、パーティションメンテナンスに伴う統計情報の更新を、更改時の影響調査対象として認識できていなかったことです。</p>


<p class="wp-block-paragraph">システム更改では、多くの場合、次のような項目を重点的に確認します。</p>


<ul id="24c5748d-c711-40c3-b988-ee36dfa03298" class="wp-block-list">
	<li>非互換情報</li>


	<li>廃止機能</li>


	<li>Deprecated機能</li>


	<li>初期化パラメータの変更</li>


	<li>サポート終了機能</li>


	<li>既知の不具合</li>


	<li>SQL構文やAPIの変更</li>
</ul>


<p class="wp-block-paragraph">これらは重要な確認項目です。</p>


<p class="wp-block-paragraph">新機能については「追加機能だから既存システムには影響しないだろう」と判断され、調査対象から外れてしまうことがあります。</p>


<p class="wp-block-paragraph">今回見落としていたのは、「従来のSQLが実行できなくなる非互換」ではありませんでした。</p>


<p class="wp-block-paragraph"><strong>従来と同じSQLが正常終了したまま、Oracle内部の統計情報管理だけが変わる仕様変更</strong>です。</p>


<p class="wp-block-paragraph">このような仕様変更は、機能試験だけでは見つかりません。</p>


<p class="wp-block-paragraph">SQLは正常終了し、処理結果も正しく、エラーログも出力されません。</p>


<p class="wp-block-paragraph">実行計画や統計情報まで確認して初めて、旧バージョンとの違いが見えてきます。</p>


<p class="wp-block-paragraph">更改プロジェクトでは「新機能だから影響はない」と考えるのではなく、<strong>既存処理の内部動作を変える仕様変更はないか</strong>という観点で調査することが重要になります。</p>
<p class="PDq2pG_selectionAnchorContainer" data-start="292" data-end="376">このような影響調査は、構築フェーズに入ってから始めるものではありません。クラウドリフトでは、PoCや基本設計の段階で「何を調査対象に含めるか」が品質を大きく左右します。</p>
<p data-start="381" data-end="414"><strong data-start="381" data-end="414">設計前に確認すべき観点は、次の記事で詳しく解説しています。</strong></p>

<a href="https://sys-univ.com/dev/cloudlift/" title="【第1回】クラウドリフトの失敗は構築前に始まっている｜PoC不足が手戻り・コスト超過・納期遅延を招く理由" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/08/34014ea8103fa5e3a36e14fd6df22125-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【第1回】クラウドリフトの失敗は構築前に始まっている｜PoC不足が手戻り・コスト超過・納期遅延を招く理由</div><div class="blogcard-snippet internal-blogcard-snippet">クラウド移行（AWSへのクラウドリフト）で起きる手戻り・コスト超過・納期遅延は、構築中ではなくPoC不足から始まります。Auto Scaling、EFS/EBS、RDS、監視、バックアップ、ライセンスなど10の設計リスクを現場目線で整理します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.20</div></div></div></div></a>


<h2 class="wp-block-heading"><span id="toc10">技術的な対策は一つではない</span></h2>


<p class="wp-block-paragraph">本件のような事象に対して、「統計情報の更新を止めればよい」と考えるのは適切ではありません。</p>


<p class="wp-block-paragraph">問題は、パーティション削除そのものではなく、統計情報の状態が変化した結果として実行計画が変わることです。</p>


<p class="wp-block-paragraph">更改設計では</p>


<ul id="6aa751f1-260b-45c2-af4d-b4c9ccd2d2b0" class="wp-block-list">
	<li>統計情報をどのように管理するか</li>


	<li>実行計画の変化をどこまで許容するか</li>


	<li>運用でどこまで吸収するか</li>
</ul>


<p class="wp-block-paragraph">という三つの観点から設計する必要があります。</p>


<h3 class="wp-block-heading"><span id="toc11">パーティションメンテナンス後に統計情報を再収集する</span></h3>


<p class="wp-block-paragraph">最も直接的な方法は、パーティション削除後にDBMS_STATS.GATHER_TABLE_STATSを実行し、表統計とカラム統計を同じ状態へ揃えることです。</p>


<p class="wp-block-paragraph">今回の事象では、表統計だけが更新され、カラム統計との前提が一致しない状態が残ったことが実行計画変更の要因でした。</p>


<p class="wp-block-paragraph">統計情報を再収集すれば、この不整合は解消されます。</p>


<p class="wp-block-paragraph">統計情報を取得すれば必ず性能が改善するとは限りません。</p>


<p class="wp-block-paragraph">表全体を再収集するのか、対象パーティションだけで十分なのか、インクリメンタル統計を利用するのかなど、システム特性に応じた設計は必要になります。</p>


<p class="wp-block-paragraph">重要なのは、「統計情報が更新されたこと」ではなく、「統計情報の整合性をどのように維持するか」という観点で設計することです。</p>


<h3 class="wp-block-heading"><span id="toc12">実行計画そのものを安定させる</span></h3>


<p class="wp-block-paragraph">統計情報を適切に管理しても、データ量や分布は時間とともに変化します。</p>


<p class="wp-block-paragraph">業務影響が極めて大きいSQLについては、統計情報だけに依存せず、SQL Plan Baselineなどを利用して実行計画を管理する方法もあります。</p>


<p class="wp-block-paragraph">SQL Plan Baselineは、統計情報の変化そのものを止める機能ではありません。</p>


<p class="wp-block-paragraph">その代わり、十分に検証された実行計画を維持することで、予期しない計画変更による性能劣化を防ぐ役割を持ちます。</p>


<p class="wp-block-paragraph">すべてのSQLを固定する運用は現実的ではありません。</p>


<p class="wp-block-paragraph">長時間バッチや業務影響の大きいSQLなど、対象を限定して利用することが重要です。</p>


<h3 class="wp-block-heading"><span id="toc13">Oracle内部動作を変更する方法もある</span></h3>


<p class="wp-block-paragraph">Oracleには、オンライン統計収集の動作そのものを抑止する方法も存在します。</p>


<p class="wp-block-paragraph">SQL単位で抑止するのであれば、公式ドキュメントに記載されているNO_GATHER_OPTIMIZER_STATISTICSヒントが利用できます。影響範囲を特定のSQLへ限定できるため、対象処理が明確な場合には検討しやすい選択肢です。</p>


<p class="wp-block-paragraph">データベース全体で抑止する方法としては、隠しパラメータである_optimizer_gather_stats_on_loadが公開されている技術情報でも言及されています。ただし、このパラメータはパーティションメンテナンス時の統計更新だけではなく、ダイレクトパスロード時を含むオンライン統計収集全体へ影響します。</p>


<p class="wp-block-paragraph">隠しパラメータは、公開パラメータと同じ感覚で変更できるものではありません。バージョンやRelease Updateによって挙動が異なる可能性があり、適用の可否は自環境の構成を踏まえてOracle Supportへ確認した上で判断すべきです。</p>


<p class="wp-block-paragraph">今回の事象だけを止めたつもりでも、別のバルクロード処理へ新たな影響を与えることも考えられます。抑止は最初に選ぶ対策ではなく、統計の再収集や実行計画の管理で解決できない場合の最後の選択肢として、影響範囲を十分に評価して使うべきものです。</p>


<h3 class="wp-block-heading"><span id="toc14">更改設計として考えるべきこと</span></h3>


<p class="wp-block-paragraph">この事例で重要なのは、「どの対策が正しいか」を決めることではありません。</p>


<p class="wp-block-paragraph">最適解はシステムによって異なることに対し、どのようなシステムでも共通する考え方があります。</p>


<p class="wp-block-paragraph">パーティションメンテナンスによって統計情報が変化するのであれば、その変化を前提とした運用を設計することです。</p>


<p class="wp-block-paragraph">統計情報を再収集するのか、SQL Plan Baselineで重要SQLを保護するのか、あるいはOracle内部動作まで変更するのか。</p>


<p class="wp-block-paragraph">その判断は、性能要件、バッチ時間、データ量、運用体制まで含めたシステム設計として決めるべき事項です。</p>


<h2 class="wp-block-heading"><span id="toc15">更改プロジェクトで追加すべき試験と運用</span></h2>


<p class="wp-block-paragraph">今回の教訓は、Oracleのチューニングだけでは終わりません。</p>


<p class="wp-block-paragraph">本質的な問題は、更改プロジェクトの影響調査にありました。</p>


<p class="wp-block-paragraph">多くの更改プロジェクトでは、オンライン処理や通常の日次バッチを中心に性能試験を実施します。</p>


<p class="wp-block-paragraph">年次や月次にしか実行されない処理は、試験対象から外れることがあります。</p>


<p class="wp-block-paragraph">パーティション削除や履歴データの整理、大量データのアーカイブなどは、その代表例です。</p>


<p class="wp-block-paragraph">こうした処理は実行頻度が低いため、問題があっても更改直後には表面化しません。</p>


<p class="wp-block-paragraph">今回のように、更改後最初の年次処理で初めて障害として顕在化することがあります。</p>


<p class="wp-block-paragraph">更改試験では、本番データを完全に再現できないことも少なくありません。</p>


<p class="wp-block-paragraph">その場合でも、DDLの実行、統計情報の変化、実行計画の変化までは十分検証できます。</p>


<p class="wp-block-paragraph">さらに、更改後最初の年次処理や月次処理は通常運用として扱うのではなく、重点監視期間として計画しておくことが重要です。</p>


<p class="wp-block-paragraph">SQLの実行時間だけを見るのではなく、PLAN_HASH_VALUE、統計情報の更新時刻、AWRの性能指標をあらかじめ比較できる状態にしておけば、異常が発生しても原因へたどり着くまでの時間を大幅に短縮できます。</p>


<p class="wp-block-paragraph">性能障害は、発生してから調査を始めるよりも、比較するための基準値を更改前から残しておく方がはるかに効率的です。</p>
<p class="PDq2pG_selectionAnchorContainer" data-start="969" data-end="1020">PoCでは性能確認だけではなく、「更改後に何を比較するか」という観点で証跡を残しておくことが重要です。</p>
<p data-start="1025" data-end="1058"><strong data-start="1025" data-end="1058">PoCで確認すべき項目は、次の記事で詳しく整理しています。</strong></p>

<a href="https://sys-univ.com/dev/cloudlift-poc-risk-1/" title="【第2回】クラウドリフトPoCの設計リスク｜可用性・性能・ストレージ・バックアップ・監視" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://sys-univ.com/wp-content/uploads/2026/06/ed4ffad86310a20a2bb16109c2a6c4ae-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://sys-univ.com/wp-content/uploads/2026/06/ed4ffad86310a20a2bb16109c2a6c4ae-160x90.png 160w, https://sys-univ.com/wp-content/uploads/2026/06/ed4ffad86310a20a2bb16109c2a6c4ae-120x68.png 120w, https://sys-univ.com/wp-content/uploads/2026/06/ed4ffad86310a20a2bb16109c2a6c4ae-320x180.png 320w, https://sys-univ.com/wp-content/uploads/2026/06/ed4ffad86310a20a2bb16109c2a6c4ae-376x212.png 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【第2回】クラウドリフトPoCの設計リスク｜可用性・性能・ストレージ・バックアップ・監視</div><div class="blogcard-snippet internal-blogcard-snippet">クラウドリフトPoCで「動いた」だけでは、構築・試験・運用まで成立するとは限りません。可用性・性能・ストレージ・バックアップ・監視の5領域について、PoCで確認すべき設計リスクと、見落とした場合の後工程への影響を実務例から整理します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://sys-univ.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">sys-univ.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.08.25</div></div></div></div></a>


<h2 class="wp-block-heading"><span id="toc16">非互換情報の外側にある変更を見る</span></h2>


<p class="wp-block-paragraph">この事例は、Oracle Databaseだけに当てはまる話ではありません。</p>


<p class="wp-block-paragraph">システム基盤の更改では、新しいバージョンへ移行するたびに、ベンダーは性能、運用性、セキュリティ、自動化を目的として既定動作を見直しています。</p>


<p class="wp-block-paragraph">たとえばAmazon RDSでは、エンジンのバージョンアップに伴って、デフォルトパラメータグループの既定値が変更されることがあります。アプリケーションを変更していなくても、データベース側の既定設定が変われば、性能や動作特性へ影響する可能性があります。</p>


<p class="wp-block-paragraph">VMware vSphereでも同様です。バージョンアップに伴ってTLSの既定設定が変更され、従来は接続できていた外部システムとの通信へ影響した事例があります。システムが故障したわけではなく、製品側の既定動作が変わったことが原因でした。</p>


<p class="wp-block-paragraph">Linuxでも、カーネル更新によってメモリ管理やネットワーク関連の既定動作が変更されることがあります。アプリケーションは従来どおり動作していても、OSの内部動作が変わることで性能特性が変化するケースは珍しくありません。</p>


<p class="wp-block-paragraph">これらに共通しているのは、「何も変更していないのに動作が変わった」のではないという点です。</p>


<p class="wp-block-paragraph"><strong>利用者は変更していなくても、ベンダーは変更しています。</strong></p>


<p class="wp-block-paragraph">更改プロジェクトでは、自分たちが修正したプログラムや設定だけに目が向きがちです。</p>


<p class="wp-block-paragraph">実際には、ベンダーが変更した既定動作の方が、既存システムへ大きな影響を与えることがあります。</p>


<p class="wp-block-paragraph">更改影響調査では「非互換情報」だけを見るのではなく、「既定動作は変わっていないか」という視点を同じ重みで持つ必要があります。</p>
<p class="PDq2pG_selectionAnchorContainer" data-start="657" data-end="700">本記事のように、更改後に初めて表面化した仕様変更や設計上の見落としは少なくありません。</p>
<p data-start="705" data-end="750">クラウドリフトやシステム更改で実際に発生したトラブル事例は、次のマガジンにまとめています。</p>

<a rel="noopener" href="https://note.com/k_s7906/m/m4570946c9f86" title="クラウド移行でハマる、AWS設計・運用の落とし穴｜ナギ ＠ 氷河期SEの知見録｜note" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://sys-univ.com/wp-content/uploads/cocoon-resources/blog-card-cache/4cda2f46e0e0c9711ce9cc4eda825fb8.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">クラウド移行でハマる、AWS設計・運用の落とし穴｜ナギ ＠ 氷河期SEの知見録｜note</div><div class="blogcard-snippet external-blogcard-snippet">AWSへのクラウド移行やDR設計で見落としやすい、設計・起動・再作成・運用の落とし穴を整理するマガジンです。EC2、AMI、cloud-init、EC2Launch、Auto Scaling、EBS、CloudWatch Logs、S3、AReadMore...</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://note.com/k_s7906/m/m4570946c9f86" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">note.com</div></div></div></div></a>


<h2 class="wp-block-heading"><span id="toc17">まとめ</span></h2>


<p class="wp-block-paragraph">今回の性能障害では、年次処理によるパーティション削除を契機として、Oracle内部で表統計の一部が更新されました。</p>


<p class="wp-block-paragraph">表統計だけが新しい状態となり、カラム統計との前提が一致しない状態が残った結果、オプティマイザのカーディナリティ推定が変化し、実行計画も変わりました。その結果として、SQL性能が低下しました。</p>


<p class="wp-block-paragraph">原因を特定できたのは、一つの情報だけを見て判断しなかったためです。</p>


<p class="wp-block-paragraph">AWRで性能変化を確認し、PLAN_HASH_VALUEで実行計画の変化を追跡し、DBA_TAB_STATISTICSで統計情報の更新時刻を確認しました。それぞれを同じ時間軸へ並べることで、初めて原因と結果を論理的に説明できました。</p>


<p class="wp-block-paragraph">Oracleは仕様どおりに動作していました。</p>


<p class="wp-block-paragraph">問題だったのは、パーティション削除に伴う統計情報の更新という仕様変更が、更改時の影響調査対象になっていなかったことです。</p>


<p class="wp-block-paragraph">更改プロジェクトで確認すべき対象は、非互換情報だけではありません。</p>


<p class="wp-block-paragraph">新機能、デフォルト設定、バックグラウンド処理、内部アルゴリズムなど、既存システムへ影響を与える可能性のある仕様変更まで含めて評価する必要があります。</p>


<p class="wp-block-paragraph">システム更改では、「正常終了した」ことだけでは十分とは言えません。</p>


<p class="wp-block-paragraph">同じSQLが正常終了していても、実行計画や性能特性まで従来と同じとは限りません。</p>


<p class="wp-block-paragraph">更改で本当に確認すべきなのは、プログラムが動くかではありません。</p>


<p class="wp-block-paragraph">設計時に置いていた前提が、バージョンアップ後も成立しているかです。</p>


<p class="wp-block-paragraph">システム更改の品質を左右するのは、コード変更量ではなく、前提条件の変化をどこまで洗い出せるかです。</p>


<h2 class="wp-block-heading"><span id="toc18">参考資料</span></h2>


<ul id="f146bb2b-5cdb-441b-8325-4f92b1091aac" class="wp-block-list">
	<li>Oracle Support, Partitioned Table Statistics Changed After Truncate Partition or Drop Partition Operation（MOS Doc ID 2970098.1）</li>


	<li>Oracle Database 19c SQL Tuning Guide（SQL Plan Management）</li>


	<li>Oracle Database 19c PL/SQL Packages and Types Reference（DBMS_STATS）</li>


	<li>Amazon RDS User Guide(DB parameter groups)</li>


	<li>VMware vSphere 8 Release Notes(Security and TLS changes)</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sys-univ.com/dev/oracle-19c-partition-statistics-execution-plan/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
