構成管理ツールと手法に関するプレゼンテーションを先日視聴し、掘り下げる価値のあるアイデアが浮かびました。
Infrastructure as Codeによる構成管理ツールが不可欠で価値あるものだという点に異論はないでしょう。しかし同時に、これらのツールの使いづらさへの不満は決して小さくありません。もし既存の構成管理やInfrastructure as Codeの仕組みが、これほど混沌として使いにくいものでなくなったとしたら、どうでしょうか。それはどのような姿になるのでしょうか。

地図は領土ではない — 人はこの2つを混同しがちです
本記事では、よく使われる用語を新しい角度から捉え直すことで、システムのプロビジョニングと構成に対する新たな視点がDevOpsとソフトウェア開発全般にどのような恩恵をもたらすのかを探っていきます。
まずは、私たちを取り巻く状況を理解し、多くの人が抱える問題に向き合うための手がかりとなる用語から見ていきましょう。
用語の解説
運用 (Operations): ソフトウェアシステムを良好な動作状態に保ち、ユーザーのニーズに応え続けるための実践です。運用エンジニアは新しいコードを書くことにはあまり関心がなく、既存システム上で既存ソフトウェアがどう振る舞うかに主眼を置きます。
これら2つの用語をこのように定義したうえで、「フォワードエンジニアリング」が「リバースエンジニアリング」とどう違うのかを見ていきましょう。
フォワードエンジニアリング
フォワードエンジニアリングとは、システム内に存在すべきものをモデル化し、それに基づいてシステムを構築するアプローチです。FEではまずモデルを作成し、そのテンプレートをデプロイ・構成して運用に乗せるのが一般的な流れです。実際に出来上がるシステムは、モデルにほぼ忠実な姿になることが期待されます。
しかし実際には、宣言されたモデルに曖昧さが残り、当初の意図とは異なる予期せぬ振る舞いをシステムが見せることも少なくありません。これは特に初心者にとって、こうした手法を使いこなすうえで大きな壁となります。
さらに厄介なのは、システム自体が環境との相互作用によってモデルから乖離していくケースが頻繁にあることです。例えば、複数のコンポーネントが互いの設定を書き換えてしまったり、エンジニアによるアドホックな操作がシステムを少しずつズラしていったりするケースです。
フォワードエンジニアリングには、初期モデルに対するフィードバックという概念がそもそも組み込まれていません。モデルはまず「動かないもの」として固定され、その後にデプロイされます。後からシステムの挙動について得られるフィードバックは、将来のモデルやデプロイに反映していくことしかできないのです。
リバースエンジニアリング
リバースエンジニアリングとは、既存のシステムから部分的なモデルを起こし、それを足がかりにシステムへ手を加えていくアプローチです。最初に決まったモデルがあるわけではなく、システムの現在の状態から「どう動くべきか」を読み解いていきます。
こうしたシステムへの変更は、多くの場合、システム全体を完全には把握しないまま、対象システム上で直接アドホックに行われます。フィードバックは即座に返ってくるため、システムを理解するには「つついて反応を見る」ことが主な手段になります。
リバースエンジニアリングはどこで使われているでしょうか。セキュリティ専門家がREの手法で既存ソフトウェアを掘り下げ、セキュリティホールを探しているという話は耳にしたことがあるかもしれません。例えば、ネットワークサービスやメモリをスキャンしてシステムの異常な振る舞いを見つけ出し、それを突いてシステムを意図しない形で動作させる、といった使い方です。
リバースエンジニアリングの本質は、既存のシステムやソフトウェアを観察し、実際の挙動から本来の意図とのギャップを浮かび上がらせることにあります。
では、これらの考え方はDevOpsの世界のどこに見出せるでしょうか。
Infrastructure as Code
1993年にCFEngineの最初のバージョンがリリースされて以来、Infrastructure as Codeという発想はソフトウェアエンジニアリング業界で爆発的に広まってきました。当初はサーバーOSの中身をどう構成すべきかを宣言するところから始まり、すぐにクラウドリソースのレイアウトや構成を記述する用途へと発展しました。Puppet、Chef、Salt、Ansible、CloudFormation、Terraform、CDK、Pulumi、そして数多くの自社製ソリューションなど、年月を重ねるなかで様々な企業やツールが浮き沈みを繰り返してきました。
これらのツールに共通するのは、その多くが宣言的(declarative)であるという点です。宣言的なツールでは、物事が「どうあるべきか」を指定するだけで、そこに至るまでの手順を明示することはしません。近年では、より命令的(imperative)であることを謳うツールもいくつか登場していますが、それらも本質的には宣言的であり、コードを書くために使われる従来の命令型プログラミング言語とは異なります。
では、なぜこれらのツールの多くは宣言的なのでしょうか。
答えはシンプルで、これが地図・モデル・テンプレートを作成するうえで最も手軽な方法だからです。エンジニアは、物事がどう見えるべきか、各要素がどこに配置されるべきかを宣言すればよく、各要素を適切な形に整える面倒な作業はツール側に任せられます。これによって時間をかけた段階的な改善が可能になり、最終的にはより堅牢で安定したシステムにつながっていきます。
宣言的なInfrastructure as Codeツールに共通するもう1つの強みが、冪等性(idempotence)です。冪等性とは、ある操作を何度繰り返しても結果が変わらないことを指します。冪等なツールでシステムに何度変更を加えても、システムは最終的にテンプレートで宣言された状態に収束します。その後に同じテンプレートを再適用しても、システムには何の影響もありません。冪等性とは、モデルを何度でも適用でき、モデルとの差分があるときにのみシステムが変化するという性質のことです。
命令的なアプローチでは、まずモデルとシステムの差分をすべて洗い出し、各変更に必要な手順を一つひとつ実装していかなければなりません。宣言的なInfrastructure as Codeツールは、開発者がそうした操作をすべて自分で書かなくても、これを実現してくれます。
Infrastructure as Codeツールが普及し、不可欠な存在となっているのは、繰り返し使えるテンプレートによって何千時間もの工数を節約し、ほぼ同一のシステムを異なる環境に最小限の追加コストで複製できるからです。
Infrastructure as Codeは、モデルを段階的に磨き込んでいくことで、それに基づいた堅牢で安定したシステムを実現できると約束しています。
以前書いた複数システムの構成管理に関する記事では、ほぼ同一のシステムを複製することがソフトウェアビジネスにとってなぜ有益なのかを解説しています。
しかし! これらのツールはフォワードエンジニアリングの考え方に立脚しており、宣言的であるがゆえに、稼働中のシステムからフィードバックを受け取る仕組みを備えていません。このアプローチは長年にわたり、ユーザーから多くの問題や不満の声を生んできました。次にその中身を見ていきましょう。
フォワード一辺倒のInfrastructure as Codeが抱える問題
構成ドリフト(Configuration Drift)という言葉を聞いたことがあるでしょうか。これは、宣言されたモデルとシステムの実際の状態が一致しなくなった状態を指します。十分な回数の更新を経たシステムは、ほぼ間違いなく、それを生み出したモデルとは異なる姿になっていきます。
ドリフトは、開発者がモデルのコードを変更したのに、そのモデルから作られたすべてのシステムを更新しなかった場合や、エンジニアが探索的なアドホック操作でシステムに手を加えたのに、テンプレート側のコードに反映しなかった場合に発生します。これらの活動はどちらも欠かせません。前者は将来のデプロイに改善を取り込むために開発者が行い、後者は未知の問題を発見して対処するために運用エンジニアが行うものです。
もちろん構成ドリフトは、いつか踏み抜く地雷のような存在であり、だからこそ「構成ドリフトは避けるべき」と誰もが口にします。とはいえ、運用担当者にシステムの操作を一切禁じ、アドホックな探索を完全に封じるというのは現実的でしょうか。実は、そうしている企業も存在します。「稼働中の本番」システムには運用担当者も開発者も触れてはならない、というポリシーを掲げる組織です。そうしたポリシーがMTTR(平均復旧時間)に何をもたらすかは、想像に難くありません。個人的な経験から言えば、何らかの理由で「本番」システムが壊れて事態が悪化した瞬間、真っ先に窓から放り投げられるのがこのルールであり、状況を把握できる人なら誰でもただちにアドホックな探索を許される、という流れになります。
Infrastructure as Codeに惹かれて導入したエンジニアからは、既存システムをゼロからモデル化し直す作業負荷が大きすぎるという不満もよく聞かれます。これに対しては、必ずと言っていいほど誰かがツールを作っています。GoogleにはGCP Terraformerがあり、AWSには現在は提供終了となったAWS CloudFormerがあり、AzureもクラウドコンソールのあちこちにARMを散りばめています。需要が非常に高いため、お気に入りの構成管理言語向けにこの種のツールを作っている人は必ずどこかにいるのです。
しかし残念ながら、エンジニアがそうしたツールを一度使ってみると、たいてい失望することになります。出力されるのは意味の通らないノイズだらけか、よくても翌日には陳腐化している程度のものです。こうしたリバースエンジニアリングされたテンプレートに対してできる最善のことは、そこからスニペットをコピペして、別の場所で手書きしているテンプレートに貼り付けることくらいでしょう。
前進への改善案
本記事では2つの用語を定義し、フォワード一辺倒のエンジニアリングが実際のシステム運用において最適とは言えないこと、そして多くの場合、問題の発見と解決にはやはりリバースエンジニアリングが欠かせないことを説明してきました。
そこで提案したいのが、新しい世代のInfrastructure as Codeツールです。リバースエンジニアリングを中核に据え、稼働中のシステムからのフィードバックを取り込んで、それを生み出したモデルを更新できるツールです。運用担当者は、アドホックな変更をそのまま採用することも、却下して元のモデルで宣言された状態にシステムを戻すことも選べるようになります。
既存の業界標準ツールは、システム運用の現場で生じる問題の解決という点で、エンジニアを十分には支援できていません。確かにTerraformテンプレートを監査してミスや誤設定を通知してくれるツールはいくつもあります。こうした監査は有用ですが、本当に価値があるのは、かつてシステムを作るために使われたテンプレートではなく、稼働中の実際のシステムそのものを点検することなのです。
私の知る限り、運用エンジニアの日常業務にリバースエンジニアリングの実践をうまく統合できるツールは、まだ十分なものが存在しません。一方には監視・オブザーバビリティのツールが数多くあり、もう一方にはInfrastructure as Codeのツールが数多くある——その間には、大きなギャップが横たわっています。
このギャップを埋めるアイデアをお持ちですか? ぜひ教えてください!
カバー画像:UnsplashのTabea Schimpfによる作品。