「うちのサーバー、本番と検証で微妙に挙動が違う気がするんだけど……」
オンプレ環境を長年運用してきたエンジニアなら、一度はこういう経験があるはずだ。yumで入れたパッケージのバージョンがサーバーごとにズレていたり、誰かが直接SSHして設定を書き換えたまま記録が残っていなかったり。気づけばサーバーごとに独自の「個性」が出来上がっていて、障害が起きたときに原因を特定しにくくなっている。
クラウド時代になってから、この問題を根本から解決する設計思想として注目されているのがイミュータブルインフラ(Immutable Infrastructure)だ。
この記事では、従来のミュータブルインフラ(Mutable Infrastructure)との違いを整理し、なぜイミュータブルが推奨されるのか、AWS・Azureでどう実装するかを現場目線で解説する。オンプレ時代の「サーバーを育てる」文化から移行しようとしているエンジニアに向けた実践ガイドだ。

ミュータブルインフラとは何か
ミュータブル(Mutable)とは「変更可能」という意味だ。ミュータブルインフラとは、稼働中のサーバーに直接SSHして設定変更・パッケージ更新・ファイル修正を行う、従来型の運用スタイルを指す。
オンプレ時代に当たり前だったやり方を振り返ると:
・本番サーバーにSSHして yum update や apt upgrade を実行する
・設定ファイルを直接 vi で編集してサービスをrestart
・「このサーバーだけ特別な設定が必要」という属人的な知識が溜まっていく
・古いサーバーを「ペット」のように大切に扱い、何年も同じインスタンスを使い続ける
この運用スタイルには長所もある。問題が起きたときに即座に手動で対処できるし、設定変更の粒度も細かい。しかしサーバー台数が増えてスケールするにつれ、後述する「設定ドリフト」という問題が深刻化する。
イミュータブルインフラとは何か
イミュータブル(Immutable)とは「変更不可」という意味だ。イミュータブルインフラでは、稼働中のサーバーには一切手を入れない。設定変更が必要なときは「新しいイメージ(AMIやコンテナイメージ)を作成し、古いインスタンスを破棄して新しいものに置き換える」という手順を取る。
比喩でいうと次のようになる:
・ミュータブル = 「ペット」:名前をつけて大切に育て、病気になれば治療する
・イミュータブル = 「家畜」:同じ仕様のものを必要な数だけ用意し、問題があれば交換する
この考え方は、コンテナの普及とともに急速に広まった。Dockerイメージはビルド後に変更できない(変更したければ新しいイメージを作る)という特性を持つため、コンテナネイティブな環境では自然とイミュータブルな運用になる。
設定ドリフトとは何か
ミュータブルインフラの最大の問題が設定ドリフト(Configuration Drift)だ。
運用を続けていくと、サーバー間の設定が少しずつズレていく。意図的な変更もあれば、深夜の緊急対応で誰かが直接手を入れたまま記録が残っていないケースもある。気づかないうちに「本番サーバーA」と「本番サーバーB」が異なる状態になる。
| ドリフトの発生原因 | 具体例 |
|---|---|
| 手動の設定変更 | 深夜障害対応でSSH直接編集、記録なし |
| パッケージ更新のタイミングズレ | サーバーAはnginx 1.24、サーバーBは1.26 |
| 環境間の差異蓄積 | 本番にだけ存在する設定ファイルや環境変数 |
| セキュリティパッチ適用漏れ | 古いインスタンスだけパッチが未適用のまま |
設定ドリフトが引き起こす問題は深刻だ。
・障害の再現が困難になる(「なぜかあのサーバーだけ動く」)
・スケールアウト時に「動くかどうか」が不確かになる
・セキュリティ監査の際に全台の実態把握ができない
・AnsibleやChefなどの構成管理ツールを使っても、直接変更された部分は検知しにくい
イミュータブルインフラはこの問題を構造的に防ぐ。稼働中のサーバーには触れないので、ドリフトが発生しようがない。
ミュータブルとイミュータブルの比較
| 比較項目 | ミュータブルインフラ | イミュータブルインフラ |
|---|---|---|
| 変更方法 | 稼働中サーバーを直接更新 | 新イメージをビルドして置き換え |
| 設定ドリフト | 発生しやすい | 構造的に防止できる |
| ロールバック | 複雑(元の状態に戻す手順が必要) | 容易(前バージョンのイメージに切り替えるだけ) |
| デプロイ速度(初回) | 軽量(差分のみ反映) | イメージビルド時間が必要 |
| 緊急障害対応 | SSH接続して即座に対処できる | 新しいインスタンスへの置き換えが基本 |
| 適合するシステム | 長期稼働の重厚なレガシーシステム | マイクロサービス・コンテナ環境 |
| 学習コスト | オンプレ経験者にはなじみやすい | CI/CDパイプラインの理解が必要 |
AWSでのイミュータブルインフラ実装パターン
AWSでイミュータブルインフラを実現する主な方法は3つある。
1. Amazon EC2 AMIベースのアプローチ(Packer活用)
アプリケーションの変更が必要になったら、設定済みのAMI(Amazon Machine Image)を新たにベイク(焼き込み)し、Auto Scalingグループを更新して古いインスタンスを置き換える。
Packer(HashiCorp製)を使うと、AMIのビルド手順をコードで定義できる。
# packer.pkr.hcl の例(Nginx入りAMIをビルド) source "amazon-ebs" "nginx" { ami_name = "nginx-app-{{timestamp}}" instance_type = "t3.micro" region = "ap-northeast-1" source_ami_filter { filters = { name = "amzn2-ami-hvm-*-x86_64-gp2" root-device-type = "ebs" virtualization-type = "hvm" } most_recent = true owners = ["amazon"] } ssh_username = "ec2-user" } build { sources = ["source.amazon-ebs.nginx"] provisioner "shell" { inline = [ "sudo yum install -y nginx", "sudo systemctl enable nginx", "sudo systemctl start nginx" ] } }
このAMIを使ってLaunch Templateを更新し、Auto ScalingグループのInstance Refreshを実行すれば、ダウンタイムなしで全インスタンスを新AMIに切り替えられる。
2. コンテナ(Amazon ECS / Amazon EKS)
最もイミュータブルな設計に適しているのがコンテナだ。DockerイメージはAmazon ECRにプッシュされ、ECSのタスク定義やKubernetesのDeploymentで「どのイメージを使うか」を宣言する。
変更時はイメージを新規ビルドしてECRにプッシュし、タスク定義を更新して新しいタスクをローリングデプロイする。既存のコンテナには一切手を入れない。コンテナとVMの違い・使い分けについては、コンテナ vs 仮想マシン(VM)の違いとは?も参照してほしい。
3. AWS Lambda(サーバーレス)
Lambda関数はデプロイパッケージ(またはコンテナイメージ)をそのまま実行する。稼働中の関数環境に変更を加える手段がなく、構造的にイミュータブルだ。バージョニング機能を使えば以前のデプロイに即座にロールバックできる。
CI/CDパイプラインと組み合わせることで、コードのコミットから新イメージのビルド・デプロイまでを自動化できる。CI/CDの基礎についてはCI/CDとは何か?を参照してほしい。
AzureでのイミュータブルインフラStateless実装パターン
1. Azure Compute Gallery(カスタムイメージ管理)
AWSのAMIに相当するのがAzureのカスタムイメージだ。Azure Compute Gallery(旧称Shared Image Gallery)を使えば、組織内で検証済みのベースイメージをバージョン管理・共有できる。Packerは Azure Buildersもサポートしており、コード化されたイメージビルドが可能だ。
2. Azure Kubernetes Service(AKS)/ Azure Container Instances
コンテナを使ったイミュータブル設計はAzureでも同様だ。Azure Container Registry(ACR)にイメージをプッシュし、AKSのDeploymentで宣言する。変更があれば新しいイメージをプッシュして、Deploymentを更新するだけだ。
3. Azure Virtual Machine Scale Sets(VMSS)
VMSSでOrchestration ModeをUniformに設定し、カスタムイメージを使ったローリングアップグレードポリシーを定義することで、イミュータブルな更新フローを実現できる。インスタンスへの直接SSH接続は禁止し、設定変更はすべて新イメージ経由とする運用ルールをセットで設けるのがポイントだ。
イミュータブルインフラ移行のロードマップ
いきなりすべてをイミュータブルに切り替えるのは現実的ではない。段階的な移行が有効だ。
フェーズ1: インフラのコード化(IaC)
まず現状の構成をTerraformやAWS CloudFormationでコードに落とす。これだけでも「何が正しい状態か」が文書化され、設定ドリフトを検知しやすくなる。IaCでのインフラ管理の詳細はTerraform実践設計入門が参考になる。
フェーズ2: 新規システムからイミュータブルで構築
既存のシステムはそのまま維持しつつ、新しいシステムや機能追加はコンテナやPackerベースのAMIで構築する。両者が共存する期間を設けながら、チームにノウハウを蓄積する。
フェーズ3: 既存システムのリプラットフォーム
移行のノウハウが溜まったタイミングで、既存システムのコンテナ化やAMI化を進める。AWS移行の6Rフレームワークで言えば、イミュータブルへの移行は「Replatform(プラットフォームの変更)」に相当する。
よくある誤解と注意点
【注意1】すべてをイミュータブルにする必要はない
データベースや永続ストレージはイミュータブルにできない。イミュータブル設計は主にアプリケーション層・Webサーバー層に適用するものだ。ステートフルなデータはRDSやS3など、別のマネージドサービスで管理する設計とセットで考えること。
【注意2】AMIビルド時間はパイプラインに組み込んで吸収する
イミュータブルインフラの弱点の一つが「変更のたびにイメージをビルドする時間がかかる」点だ。10分以上かかるケースもある。これはCI/CDパイプラインの中に組み込み、並行作業で吸収するよう設計する。
【注意3】コンテナイメージのレイヤーキャッシュを活用する
DockerfileのCOPYやRUNの順序を工夫してキャッシュを最大限活用すれば、ビルド時間を大幅に短縮できる。変更頻度の低いレイヤー(OSパッケージのインストール等)を先に書き、変更頻度の高いアプリコードを後に書くのが鉄則だ。
【注意4】緊急対応の例外ルールを明文化しておく
本番障害の緊急対応では、既存インスタンスにSSHして原因調査をせざるを得ない場面もある。「調査目的のSSH接続は許可するが、設定変更は禁止し修正はパイプライン経由で実施する」というルールをチームで合意しておくと、現実的な運用に落とし込める。

本記事のまとめ
ミュータブルとイミュータブルの違いをあらためて整理しよう。
・ミュータブルインフラ: 稼働中のサーバーを直接変更する。運用の初動コストは低いが、設定ドリフトが起きやすく長期的に管理コストが増大する
・イミュータブルインフラ: 変更が必要なら新しいイメージを作って置き換える。CI/CDとの組み合わせで設定ドリフトを構造的に防止できる
・設定ドリフト: 手動変更の積み重ねでサーバー間に差異が生まれる現象。障害再現の困難さやセキュリティリスクの原因になる
・移行のアプローチ: IaC導入→新規システムのイミュータブル化→既存システムのリプラットフォームの順で段階的に進める
クラウドネイティブ設計の12ファクターで謳われている「Dev/Prod Parity(開発・本番環境の等価性)」を実現するためにも、イミュータブルインフラは重要な設計原則の一つだ。詳しくはクラウドネイティブ設計の12ファクター入門を参照してほしい。
PR
イミュータブルインフラやコンテナ活用を含むクラウドネイティブ設計パターンを体系的に解説。AWSサービスとの組み合わせ方を実践的に学べる一冊。
