Webエンジニアなら知っておきたいIaCの歴史

はじめに

「Webエンジニアなら知っておきたい」ということで、今回はIaC(Infrastructure as Code)の歴史についてです。

IaCをやろうとすると、CloudFormation、Terraform、CDK、Pulumiと選択肢がたくさんあります。どれを使えばいいのか悩んだ経験がある方も多いのではないでしょうか。 なぜこんなにツールがあるのかというと、それぞれのツールが何かの課題を解決しようとして生まれたからです。 今回IaCがどのような課題を解決しようとしてきたのか流れを私なりに簡単に振り返ってみます。

IaC以前

さて、IaCですが、概ねクラウドサービスやDevOpsといった言葉が使われ出した頃から使われている概念だと思いますが、そこにつながる考え方はそれ以前にもあったと考えています。 ということで、IaCということが言われる以前の、インフラ周りのコードについてから振り返っていきたいと思います。

手順書とシェルスクリプトの時代

最初期のインフラ構築は手順書ベースでした。「このコマンドを打って、次にこのファイルを編集して……」という手順をドキュメントに書いて、人が順番に実行していくスタイルです。

当然ですが、人によって手順書の内容に不備があったり、手順書が古くなっていたりして、同じ環境を再現できない問題が起きます。 そこでシェルスクリプトにまとめる動きが出てきます。手順をコードにすることで「誰がやっても同じ結果になる」再現性を手に入れました。

ただ、シェルスクリプトには厄介な問題があります。2回実行すると壊れることがあるのです。「ユーザーを作成する」スクリプトを2回実行すれば「既に存在します」エラーになります。 途中で失敗したときにどこまで戻してやり直せばいいのか分からない。スクリプトが長くなるほど、この問題は深刻になっていきました。

これを自力で解決しようとすると、「ユーザーが既にいるなら何もしない」「パッケージが既に入っているならスキップする」といった分岐を全部書くことになります。本来やりたいことよりもエラーを避けるための条件分岐の方が長くなっていく。これを全リソースに対して自前で書き続けるのは現実的ではありませんでした。

目指したもの: 手順の再現性

構成管理ツールの時代(CFEngine / Puppet / Chef / Ansible)

「シェルスクリプトの複雑さをどうにかしたい」という課題に対して、1993年にMark BurgessがCFEngineと呼ばれるプロダクトを作りました。オスロ大学で50台ほどのワークステーションを管理していたBurgessは、シェルスクリプトやPerlスクリプトの複雑さと非ポータビリティに限界を感じていました。彼が目指したのは、よく使われる管理パターンを宣言的なドメイン固有言語に吸収して、設定そのものが自己文書化されている状態を作ることでした。

その後、CFEngineの影響を受けて、2000年代後半から2010年代前半にかけてPuppet(2005年)・Chef(2009年)・Ansible(2012年)が登場します。 これらのツールが持ち込んだ重要な概念が「冪等性(べきとうせい)」です。何度実行しても同じ結果になる。ユーザーが存在しなければ作る、既に存在していれば何もしない。これによって「2回実行すると壊れる」問題が解消されました。 そしてもうひとつ重要なのが「宣言的」な記述です。Ansibleのplaybookを例にすると、「nginxをインストールしろ」という手続きではなく「nginxがインストールされている状態」を書きます。ツールが現在の状態を確認して、足りなければ適用し、既に満たされていれば何もしない。この宣言的なアプローチが冪等性を自然に実現していました。

Puppetの作者Luke Kaniesは、システム管理者として複雑なITシステムの管理に日々苦労していた人です。当時の商用ツールは大企業の経営層に売ることに注力していて、現場のシステム管理者が日々の運用で繰り返し使えるものではなかった。Puppetは「現場で毎日使うもの」として設計されていて、だからこそ宣言的な記述、つまり「あるべき状態を書いておけば、あとはツールが面倒を見る」という考え方が中心に据えられています。 ただ、PuppetやChefは強力な反面、ツール自体のセットアップや学習に数日かかることもありました。Ansibleの作者Michael DeHaanはまさにそこに課題を感じていました。

If people aren't successful trying (your app/tool) out in about 30 minutes, they're going to move on. You have to make somebody successful within their lunch hour.

(30分で成功体験を得られなければ、人は次に行ってしまう。ランチタイムの間に使えるようにしないといけない。)

SSHベースでエージェント不要、30分で使い始められるシンプルさを目指して作られたのがAnsibleです。構成管理ツール自体の複雑さが新たな課題になっていた。ツールのためのツールが必要になる状態を解消したかったのです。 同じ時期に、宮下剛輔さんがServerspecを作っています。「サーバーがあるべき状態になっているか」を特定の構成管理ツールやOSに依存せずテストできるフレームワークで、テスト駆動開発の手法をインフラに持ち込んだものです。

目指したもの: 冪等性と宣言的な構成管理

IaCの登場

IaC以前のツールが管理していたのは「サーバーの中身」でした。OSの上にどのパッケージが入っているか、設定ファイルがどうなっているか、サービスが起動しているか。管理対象はあくまでサーバーの内側に閉じていたのです。 サーバーは誰かが手動で、あるいは別の仕組みで用意するものでした。Ansibleが管理するのはサーバーにSSHした後の世界です。「そのサーバーをどうやって作るか」「ネットワークをどう構成するか」は別の話だったのです。

「サーバーの中身」から「インフラそのもの」へ

ここに大きな変化をもたらしたのが、インフラの各レイヤーがソフトウェアで定義可能になっていった流れです。VMwareやXenによる仮想化でサーバーの作成・削除がソフトウェア操作になり、Software-Definedの考え方でネットワークやストレージもAPIで制御できるようになった。そしてクラウドサービスが、これらを「誰でもAPIで呼べるサービス」として提供しました。自前で仮想化基盤を持たなくても、インフラ全体をプログラマブルに扱える世界が生まれたのです。

2011年にCloudFormation、2014年にTerraformが登場します。

CloudFormationの設計思想は、Jeff Barrによる最初のアナウンスに明確に表れています。

AWS is programmable, so it should be possible to build even complex systems using repeatable processes. Because the templates are declarative, you need only specify what you want and CloudFormation will figure out the rest.

(AWSはプログラマブルなのだから、複雑なシステムであっても再現可能なプロセスで構築できるべきだ。テンプレートは宣言的で、何が欲しいかを指定すればCloudFormationが残りを考える。)

つまり、ユーザーはリソースの作成順序や依存関係の解決を自分で管理しなくていい。「何が欲しいか」だけ書けば、手順の順序は機械が考えてくれる世界を目指したのです。

Terraformも同じ方向を向いています。Mitchell Hashimotoは「インフラを安全かつ効率的に構築・結合・起動する」ことを目指してTerraformを作りました。物理サーバーからコンテナ、SaaSまで、あらゆるコンポーネントをひとつのツールで扱えることを設計の中心に据えています。

構成管理ツールも宣言的でしたが、管理対象が違います。

構成管理ツール CloudFormation / Terraform
管理対象 サーバーの中身(パッケージ、設定、サービス) インフラそのもの(ネットワーク、サーバー、DB、ストレージ)
前提 サーバーが既に存在する サーバーの存在自体を定義する
操作方法 SSH等でサーバーに接続して適用 クラウドAPIを通じて適用

CloudFormationやTerraformが実現したのは、インフラ全体を丸ごと再現可能な状態にすることです。テンプレートさえあれば同じ環境をいくつでも作れますし、変更はテンプレートの差分として見えるので、レビューもしやすくなります。「このインフラはどういう構成か」がコードを読めば分かる状態になりました。

クラウドのインフラもAWS CLIやSDKを使えば手続き的に構築できます。シェルスクリプトでaws ec2 run-instancesを並べていけば良いのです。でもそれでは、シェルスクリプト時代と同じ「2回実行すると壊れる」「途中で失敗したらどこまで戻す?」という問題が再び起きてしまいます。CloudFormation/Terraformが宣言型を選んだのは、同じ課題に対する答えとして自然な選択だったのだと思います。宣言的なアプローチは構成管理ツールの時代から存在していて、本当に変わったのは管理対象の範囲でした。

目指したもの: インフラそのものの宣言的管理と再現性

CDKと新しい発展

2019年にAWS CDKがGAになります。 宣言型IaCは強力でしたが、新たな課題も見えてきていました。CDKのGA発表ブログではこう書かれています。

Configuration files used to manage your infrastructure are traditionally implemented as YAML or JSON text files, but in this way you're missing most of the advantages of modern programming languages. Specifically with YAML, it can be very difficult to detect a file truncated while transferring to another system, or a missing line when copying and pasting from one template to another.

(インフラを管理する設定ファイルは従来YAMLやJSONで書かれてきたが、これでは現代のプログラミング言語の利点をほとんど活かせない。特にYAMLでは、転送時にファイルが切り詰められたことや、コピー&ペースト時に行が欠落したことを検出するのが非常に難しい。)

宣言するための記述形式そのものが課題になっていたのです。

CDKはプログラミング言語(TypeScript、Pythonなど)でインフラを定義できるツールです。条件分岐やループが書けるので、一見すると手続き型の時代に戻ったように見えるかもしれません。

でも実際には、CDKが最終的に出力するのはCloudFormationテンプレートです。宣言型の恩恵(差分検知、ドリフト検出、状態管理)はそのまま残っています。CDKが取り戻したのは「人間が間違えにくい記述方法」と「抽象化力」です。IDEの補完が効く、型チェックで誤りを事前に検出できる、よくあるパターンをコンストラクトとして再利用できる。GA発表ブログの例では、800行を超えるCloudFormation YAMLになる構成が、TypeScriptで数十行で書かれています。

目指したもの: 宣言型の恩恵を保ちつつ、人間が間違えにくい記述と抽象化力を取り戻す

まとめ

振り返ると、各時代のツールは前の時代の課題を解決しようとした結果として生まれています。

時代 代表的なツール 何を解決したか
シェルスクリプト bash 手順書の再現性の問題
構成管理ツール Puppet / Chef / Ansible スクリプトの冪等性の問題
インフラ全体のIaC CloudFormation / Terraform 管理対象を「サーバーの中身」から「インフラそのもの」に拡張
CDK AWS CDK 宣言型の記述力・抽象化力の限界

ツールは変わり続けますが、「再現性がほしい」「安全に変更したい」「あるべき状態を定義したい」という目指す方向は一貫しています。 また、IaCは課題を解決するたびに、ソフトウェア開発のプラクティスをインフラ管理に自然に取り込んで来ました。 コードにする、テストを書く、バージョン管理する、差分をレビューする、型で安全性を担保する。

「このツールは何の課題を解決しようとしているのか」という視点を持つ事で、IaCツールが自分たちが求めているツールなのかを判断する役に立つのではと思います。

参考