誰かがコンソールで直した
一言でいうと
ドリフトは、コードが宣言した状態と、実際の状態が食い違うことです。IaCを導入した組織が実際に格闘している問題の大半が、ここにあります。
なぜ必要なのか
金曜の夜に障害が起きました。誰かがコンソールに入り、セキュリティグループにルールを1つ追加して、急場をしのぎました。正しい判断でした。
問題は月曜日です。別の人が無関係な変更をしようとplanを回すと、金曜日に追加したそのルールを削除すると出てきます。コードにはそのルールがないからです。知らずにapplyすると、障害が再発します。
これがドリフトです。そして、これはツールの欠陥ではなく、当然の動作です。宣言的なツールは、コードを真実として、実際をそこに合わせます。
ドリフトが生じる経路
| 経路 | 例 | 対応 |
|---|---|---|
| 緊急の手動変更 | 障害対応中のコンソール操作 | 事後のコード反映を手順に入れる |
| 他チームの変更 | セキュリティチームがポリシーを調整 | 所有権の境界を明確にする |
| 自動スケーリング | インスタンス数が絶えず変わる | ignore_changesで除外 |
| クラウドのデフォルト値 | 作成時に自動で付与されるタグ | コードに反映するか、無視 |
| 別のコードベース | 2つのリポジトリが同じリソースを管理 | 絶対に禁止: 所有者は1つ |
最後の項目が最も危険です。2つの状態ファイルが同じリソースを管理すると、互いを元に戻し続けます。リソースごとに所有者は必ず1つでなければなりません。
検知: planは診断ツール
planは、デプロイの直前にだけ回すものではありません。定期的に回して、ドリフトを検知するのがよい運用です。
# 아무 변경도 안 했는데 plan 에 diff 가 있다 = 드리프트
plan → 변경 없음 ✅ 코드와 실제가 일치
plan → 변경 있음 ⚠️ 조사 필요
CIで毎日planを回して、結果が空でなければ通知を送ります。こうすれば、金曜日の変更を、月曜日ではなく土曜日の朝に知ることができます。
解消: 3つの選択肢
ドリフトを見つけたときの答えは、3つのうちの1つです。
1. コードに吸収する: その変更が正しかったなら、コードに反映します。最もよくあり、たいてい正しい選択です。
2. 元に戻す: その変更が間違っていたなら、applyでコードの状態を強制します。ただし、なぜそのような変更があったのかを、先に確認する必要があります。
3. 管理対象から外す: オートスケーリングのように、もともと変わる値なら、ignore_changesでその属性だけを除外します。リソース全体を外すのではなく、属性単位に絞るのがコツです。
インポート: すでにあるものをコードの中へ
IaCの導入は、たいてい白紙から始まりません。すでに手で作ったリソースが数百個あり、それをコードに移す必要があります。
ここで絶対にしてはいけないこと: 削除して作り直すこと。運用中のリソースならダウンタイムで、データがあれば損失です。
代わりにインポートを使います。実際のリソースを状態ファイルに登録して、ツールが「これは自分が管理するものだ」と認識するようにします。
1. 자원의 실제 설정을 조사한다
2. 그와 똑같은 코드를 작성한다
3. import 로 상태에 등록한다
4. plan 을 돌려 '변경 없음' 이 나올 때까지 코드를 다듬는다
4つ目が核心です。planが空になってはじめて、インポートが終わりです。diffが残ったまま進むと、次のapplyのときに、そのリソースが変更されます。
状態ファイルを扱うとき
状態ファイルには、リソースの実際のID・属性・依存関係が入っています。認証情報が平文で入る場合もあります。
- リモートバックエンドに置いて、ロックを有効にします。2人が同時にapplyすると、状態が壊れます。
- バージョン管理を有効にします。誤ったapplyを元に戻せる唯一の手段です。
- gitにコミットしません。秘密情報が入る可能性があります。
- 手で編集しません。どうしても必要なら、ツールが提供する状態コマンドを使います。
現場での姿
- 新入社員が初めて
applyして、他人の手動変更を消してしまった → planを読んでいませんでした。 - オートスケーリンググループのサイズが、毎回diffとして出る →
ignore_changesがありません。 - 状態ファイルがローカルにあり、2人が互いに上書きした → リモートバックエンドとロックがありません。
次の理論で見ること
続く理論では、ドリフトへの対応を複数の環境に複製するとき、モジュールの境界をどこに置くべきかを見ます。吸収・元に戻す・除外のうち、どの決定を共通モジュールに入れ、どの決定を呼び出す側の環境に残すと、変更の爆発半径を減らせるのかを、結びつけて考えてみてください。