「Ansibleは冪等なのに、なぜサーバは壊れていくのか」 第0回:なぜAnsibleで管理しているのにサーバはずれていくのか


🗺️ 初めての方・シリーズの全体像を知りたい方はこちら

シリーズ全体については、以下のまとめブログで整理しています。

→ 「Ansibleは冪等なのに、なぜサーバは壊れていくのか」シリーズまとめブログ


📋 目次

  1. はじめに
  2. 構成ドリフトとは何か
  3. ドリフトが発生する主な経路
  4. 「Ansibleは実行されたときだけ状態を収束させる」という構造上の限界
  5. 冪等性シリーズで扱った問題との違い
  6. まとめ
  7. 次回予告
  8. 連載一覧:「Ansibleは冪等なのに、なぜサーバは壊れていくのか」

1. はじめに

「Ansibleで構成管理しているから、サーバの状態は把握できている」と思っていないでしょうか。

Playbookを整備し、冪等性を意識した設計にして、定期的に実行もしている。それでも実務を続けていると、こういう場面に出くわします。

  • 障害対応で緊急ログインして直接設定を変更したあと、そのまま戻し忘れていた
  • 久しぶりにPlaybookを流したら、想定外のchangedが大量に出た
  • サーバごとに微妙に設定が違っていて、いつからそうなっていたのか分からない
  • 「先週は問題なかったはず」のサーバが、いつの間にか違う状態になっていた

こうした問題に共通しているのは、「Playbookを実行している間だけ、サーバの状態を把握できている」という点です。実行と実行の間、サーバは無防備な時間を過ごしています。

正確に言うと、Ansibleは「実行された瞬間」の状態しか保証していません。実行していない時間に何が起きても、Ansible自身はそれを知りません。この「実行していない時間に起きるずれ」のことを、構成ドリフトと呼びます。

冪等性シリーズ では「Playbookの設計問題」を扱いました。shellモジュールが状態を観測しないこと、state: latestがdesired stateをリポジトリに委譲すること、lineinfileが部分パッチであること——これらはすべて「Playbookをどう書くか」という設計の話でした。

この ドリフトシリーズ が扱うのはその外側です。Playbookの設計がどれだけ正しくても、構成ドリフトという問題は別に存在します。このシリーズでは、その構造を具体的に掘り下げていきます。第0回は、そのための土台として「構成ドリフトとは何か」を整理します。


↑ 目次に戻る


2. 構成ドリフトとは何か

構成ドリフトとは、構成管理において、意図した状態(desired state)と実際の状態がずれていく現象を指します。これはAnsible固有の概念ではなく、Terraform・Chef・Puppetを含む構成管理全般、あるいは手動運用のサーバでも起こりうる、IT運用における一般的な現象です。

このシリーズでは、Ansibleの文脈に絞り、Playbookで定義したdesired stateと、実際のサーバの状態がずれていく現象として構成ドリフトを扱います。

ドリフトにはいくつかの特徴があります。

  • ある瞬間に突然発生するのではなく、時間をかけてじわじわと進む
  • 「Ansibleを実行したときは正しい状態だった」「いつの間にかずれていた」という形で運用現場に現れる
  • Ansibleの実行結果はchanged=0のまま通過するケースがある(このパターンは 第3回 で詳しく扱います)

厄介なのは、「Ansibleを使っているから大丈夫」という思い込みが、ドリフトの発見をむしろ遅らせる点です。Playbookを実行してokが並んでいても、それはPlaybookが管理している範囲について「今回は変更が不要だった」ことを示しているにすぎません。Playbookが管理していない部分でサーバの状態が変化していても、実行結果には現れません。


↑ 目次に戻る


3. ドリフトが発生する主な経路

ここでは、Ansibleで管理している環境を前提に、ドリフトが発生する主な経路を整理します。

経路 具体例
手動変更 障害対応でサーバに直接ログインして設定を変更した
Ansible以外のツールによる変更 別のスクリプトや構成管理ツールが同じファイルを書き換えた
パッケージの自動更新 セキュリティパッチが自動適用されてバージョンが変わった
ソフトウェアの自己書き換え アプリケーションが起動時に設定ファイルを更新する

これらに共通しているのは、「Ansibleの管理外で起きる変化」だという点です。

手動変更は、緊急対応や一時的な確認作業のつもりでログインし、そのまま変更が残ってしまうケースが典型です。次回(第1回)で詳しく扱います。

Ansible以外のツールによる変更は、複数のチームや複数の自動化ツールが同じサーバを触っている環境で起きやすくなります。Ansibleが把握していない変更が、Ansibleの管理対象と同じファイルに加えられることがあります。

パッケージの自動更新は、yum-cronやunattended-upgradesのような仕組みが有効になっている場合に発生します。Ansible側でバージョンを固定していても、OS側の自動更新機構がそれとは独立に動いていれば、パッケージのバージョンはAnsibleの実行とは無関係に変化します。

ソフトウェアの自己書き換えは、アプリケーション自身が起動時やランタイム中に設定ファイルを書き換えるケースです。Ansibleが投入した設定ファイルの内容を、アプリケーションが後から上書きすることがあります。

いずれの経路も、Ansibleが「知らないところで起きる変化」だという点で同じ構造を持っています。


↑ 目次に戻る


4. 「Ansibleは実行されたときだけ状態を収束させる」という構造上の限界

Ansibleはプッシュ型のツールです。実行されたときだけ、リモートノードの現在の状態を確認し、desired stateとの差分があれば修正します。

この構造には、次のような限界があります。

  • Playbookを実行した瞬間は、desired stateへ収束する
  • 次の実行までの間に何かが変化しても、Ansibleはそれを検知しない
  • 「Playbookを先週実行して成功した」は、「今もそのサーバが正しい状態にある」ことを意味しない

ここで、「Playbookを正しく書けばドリフトは防げる」という誤解を解いておきます。冪等性シリーズ で扱った設計原則——desired stateをPlaybook内に閉じる、バージョンを固定する、lineinfileではなくtemplateでファイル全体を管理する——をすべて実践していても、Ansibleが実行されていない時間に起きた変化には対応できません。

これはPlaybookの設計の問題ではありません。プッシュ型ツールとしての構造上の特性です。エージェント型のツールが継続的に状態を監視するのとは異なり、Ansibleは実行された瞬間だけを担当します。実行と実行の間は、いわば空白の時間です。この空白の時間の長さと、その間にサーバへ加えられる変化の量が、ドリフトの実質的な規模を決めます。


↑ 目次に戻る


5. 冪等性シリーズで扱った問題との違い

ここまでの内容を、冪等性シリーズ との比較で整理します。

観点 冪等性シリーズ ドリフトシリーズ
問題が起きる場所 Playbookの設計の中 Playbookの外・実行されていない時間
原因 shellモジュール・desired stateの定義・タスク依存など 手動変更・自動更新・他ツールの介入など
確認手段 2回実行・--check・Molecule 定期実行・ドリフト検知の仕組み(第2回 、 第3回 で扱います)
解決の方向 Playbookを正しく設計する ドリフトを検知して修正する仕組みを持つ

冪等性シリーズ の知識は、このシリーズでも前提として活きています。「壊れない設計」を実践した上で、さらに「ずれていないことを継続的に確認する」という次の問いに進むのが、このシリーズの位置づけです。

Playbookの設計とドリフトへの対応は、どちらか一方で足りるものではなく、両方が揃って初めて運用が成立します。


↑ 目次に戻る


6. まとめ

この回で整理した内容を確認します。

  • 構成ドリフトとは、Playbookで定義したdesired stateと実際のサーバの状態がずれていく現象である
  • ドリフトはPlaybookの設計問題ではなく、Ansibleが実行されていない時間に起きる変化の問題である
  • ドリフトの発生経路には、手動変更・他ツールによる変更・パッケージの自動更新・ソフトウェアの自己書き換えがある
  • Ansibleは実行されたときだけ状態を収束させるというプッシュ型ツールとしての構造上の限界が、ドリフトの根本的な原因である
  • 冪等性シリーズ の「壊れない設計」を実践していても、ドリフトへの対応にはならない。両者は別の問題である

↑ 目次に戻る


7. 次回予告

次回は、ドリフトの発生経路の中でもっとも頻繁に起きる「手動変更」を取り上げます。

障害対応や一時的な設定変更のつもりでサーバに直接ログインした結果、Ansibleの管理がどのように壊れていくのかを、templateモジュールとlineinfileモジュールの挙動の違いを交えながら整理します。

次回:第1回:なぜ手動変更はAnsibleの管理を壊すのか


📑 連載の移動 前の記事:【冪等性編】 第10回 | 次の記事:【構成ドリフト編】 第1回


🗺️ 初めての方・シリーズの全体像を知りたい方はこちら

シリーズ全体については、以下のまとめブログで整理しています。

→ 「Ansibleは冪等なのに、なぜサーバは壊れていくのか」シリーズまとめブログ


↑ 目次に戻る


8. 連載一覧:「Ansibleは冪等なのに、なぜサーバは壊れていくのか」

回 タイトル 内容(概要)
第0回 なぜAnsibleで管理しているのにサーバはずれていくのか 構成ドリフトを「Playbookで定義したdesired stateと実際のサーバの状態がずれていく現象」として定義し、冪等性シリーズとの違いを整理する。ドリフトが「Ansibleが実行されていない時間」に起きる問題であることを理解する。
第1回 なぜ手動変更はAnsibleの管理を壊すのか 障害対応や一時的な直接編集がドリフトを生む構造を、templateとlineinfileの挙動の違いを通して理解する。手動変更が「次にAnsibleが実行されるまで気づかれない」空白を作ることを整理する。
第2回 なぜdriftは--checkで検知できないのか --check/--diffモードをドリフト検知の手段として使う場合の限界を整理する。検知できるケースと検知できないケースを実機で切り分け、「--checkで問題が出ない=ドリフトがない」ではないことを理解する。
第3回 なぜドリフトは気づかれないまま進むのか changedが出ない「静かなドリフト」の構造を扱う。cronジョブやアプリケーションの自己書き換え、パッケージの自動更新など、Ansible管理外で起きる変化がPlaybook実行結果に現れない理由を理解する。
第4回 ドリフトを検知して修正する設計 シリーズの結論として、ドリフトを「防ぐ」「検知する」「修正する」の3つの設計パターンを整理する。定期実行・アラート化・自動修正フローなど、運用に組み込むための具体的な設計を扱う。

↑ 目次に戻る