Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

Immutable Infrastructure時代のConfiguration Management Toolの要件およびその実装について

本稿では、"Immutable Infrastructure"時代におけるconfiguration management tool(以下、CMT)の要件およびそれを満たすツールについて議論する。

背景の整理

"Immutable Infrastructure"とは、2013年6月、Trash Your Servers and Burn Your Code: Immutable Infrastructure and Disposable Components - Chad Fowlerにより提唱された概念だ。ある種のプログラミング言語における不変性がプログラムにおける厄介な問題を解決するように、サーバの状態を不変な(正確には、状態を変更しない)ものとすることで、成長し続けるソフトウェアにとって避けられない、時間の経過によりもたらされる種々の問題が、解決可能であるとする。

そもそもどのような流れでImmutable Infrastructureという考え方が現れたのか、それが解決するであろう問題の具体的な例については、下記文書に詳述されている。

3つのレイヤ

インフラ系技術の流れ - Gosuke Miyashitaは、インフラ系技術を下記3つのレイヤを成すものとして整理する。

  • Orchestration
  • Configuration
  • Bootstrapping

Immutable Infrastructureは、このうちOrchestrationおよびBootstrappingの革新により可能となるだろうものだ。具体的には、

  • Orchestration: Serfなどのクラスタ管理ツール
  • Bootstrapping: EC2(Auto Scalingも含む), Docker, Vagrant, Packerなど

一方、configurationのレイヤにおいては、現在のところ、目立った革新はない(DockerやPackerは、その一部にconfigurationを含むが、ツールと密結合することになる)。

CMTのこれまで

そもそも、ChefやPuppetなどのようなCMTがなぜ重要であるかについては、これまで様々に述べられているので、ここでは言及しない(詳しくは拙著『入門Puppet』を参照のこと)。それらのツールは、以下の特徴を持つ。

  1. 状態の構造化を支援する
  2. プラットフォーム間のポータビリティを担保する
  3. 冪等性を担保する

(1)は、いわゆる"Infrastructure as Code"において重要な特徴である。サーバの状態を構造化しなければ、設計のまずいコードがそうであるように、共有・レビュー可能とならない。

(2)は、設定コードの一般性を担保するためのものである。たとえば、Puppetにおけるpackageリソースは、プラットフォームに応じて実行されるコマンドが自動的に切り替わる。

(3)は、それらツールがmutableな状態を持つサーバに対してくりかえし適用することが前提であるために、要請される性質である。

configspec

インフラ系技術の流れ - Gosuke Miyashitaは、次のように予告している。

Chef や Puppet に変わって、Immutable Infrastructure に適した Configuration Management Tool が今後出てくると思う。よりシンプルで、実行順序がわかりやすく制御しやすいものが。

それでは、そうしたツールの要件とは、具体的にはなんであろうか。configspec という Immutable Infrastructure 用 Configuration Management Tool をつくってみた - Gosuke Miyashitaは、configspecについて以下のように述べる。

  • 冪等性とかどうでもいい *まっさらな状態からのセットアップでしか使わない
  • 依存関係とかどうでもいい
    • ファイル名順、上から書いた順で実行してく
  • 対象サーバに余分なものをインストールしたくない
    • 対象サーバに SSH さえできれば OK
  • シェルスクリプトよりは抽象度を高めたい

さらに、configspec で Dockerfile を生成できるようにした - Gosuke Miyashitaおよびconfigspec/serverspec でシェルスクリプトを生成できるようにした - Gosuke Miyashitaでは、広義のconfigurationレイヤでのポータビリティの確保が行われている。

この時代に即したCMTの要件

configspecは、上述のCMTに要請される特徴に対して、Immutable Infrastructureを前提とするアプローチをとっている。まず目につくのは、冪等性の切り捨てだ。一度作った後、サーバが変更されることがない == いつでも捨てられる/再作成可能な状態を保つ、ということであれば、冪等性は必要ない。これは、この時代のCMTにおける一番の要件である。

また、ポータビリティについてもChef/Puppetとは異なるアプローチをとっている。確かに、configspecはbe_installedマッチャにより、プラットフォームの違いにそったコマンドを実行する。だが、そこはあまり重要なところではない。configspecが担保するポータビリティは、CMT間のポータビリティだ。それは現在、Docker用の設定ファイルと、CMTとしては最もプリミティブなシェルスクリプトとの間で実現されている。

この他、冪等性が不要となったこの時代のツールとして、構造化手法についても変化を加えなければならない。

ChefやPuppetは、mutableな状態変更が前提となっているために、宣言的な構文を持っている。どういうことか。

package { 'httpd': }

packageが、ただ存在すればいいだけならことはさほど難しくはない。Chef/Puppetで管理されるシステムはmutableであるため、上述のpackageが存在しないことを記述するためには以下のように書く。

package { 'package':
  ensure => absent,
}

このような「状態」は、ensureで指定される以外にも多数ありうる。そのため、Chef/Puppetは宣言的な構文を採用している。

Immutable Infrastructureを前提とするCMTは、状態について考慮する必要がないため、その構文はもっとシンプルにすることができる。つまり、手続きを並べるだけでよい。

install 'httpd'
install 'git'
# ...

まとめると、以下の通りの要件を挙げられる。

  1. 状態の構造化を支援する。ただしそれは、シェルスクリプトよりはマシという程度でよい
  2. 一方で、行き過ぎた構造化を廃する(依存関係の管理等)
  3. プラットフォーム間はもとより、CMT間のポータビリティを担保する
  4. 冪等性を考慮しない
  5. 手続き的な記法を採用する

Syllabus

上述の考えに基づいて、Syllabusという新たなCMTを開発しはじめた。このツールが満たす要件は以下の通りである。

  • 冪等性について考慮しない
  • プラットフォーム間ポータビリティを担保する
  • リソース間の依存関係を管理しない
  • CMT間ポータビリティを担保する
  • 手続き的記法を採用する

configspecと違うところは、抽象化の手法(RSpecによるDSLと、独自DSLとの相違)と「手続き的記法を採用する」ぐらいだろう。ただ、そうした違いは開発プロセスにおいて大きな分水嶺にもなり得るとも思えるため、今回、オルターナティブを作成した(specinfra という serverspec/configspec に共通する処理を抜き出した gem をつくった - Gosuke Miyashitaでの私の発言は、そうした意図に基づく)。

以下に、Syllabusによる設定ファイルを示す(現在は、パッケージのインストールのみ対応)。

os_type 'Darwin'
path    '/path/to/bin'

install 'httpd'
install 'git'
# ...

この設定ファイルを元に、syllabusコマンドにいくつかの引数をわたすことで、設定の適用を実行する。

$ syllabus exec --file examples/mac.rb --type Exec

ポータビリティ確保の実装には、configspecのバックエンドを成すspecinfraを利用している。

まとめ

Immutable Infrastructureを可能にしたのは、OrchestrationおよびBootstrappingレイヤにおける革新である。一方で、Configurationレイヤにおいては、いまだ革新が現れていない。しかし、既存のツールが新しいアーキテクチャにそぐわないのは明らかである。

そのための要件として、configspecの実装を参考に、本稿では以下のように整理した。

  1. 状態の構造化を支援する。ただしそれは、シェルスクリプトよりはマシという程度でよい
  2. 一方で、行き過ぎた構造化を廃する(依存関係の管理等)
  3. プラットフォーム間はもとより、CMT間のポータビリティを担保する
  4. 冪等性を考慮しない
  5. 手続き的な記法を採用する

その上で、上述要件を満たすPoCとしての実装、Syllabusについて紹介した。