IaC(Infrastructure as Code) における Declarative vs. Imperative

Declarative vs. Imperative for IaC
===

IaC(Infrastructure as Code) を実現するツールでは、宣言的モデル(Declarative)と命令実行型モデル(Imperative)があります。このモデルの特徴やメリットデメリットなどから、実際の現場ではどのように扱うべきか考察してみます。

はじめに[Wikipedia](https://en.wikipedia.org/wiki/Infrastructure_as_code) の`IaC`記述内容と書籍「[Infrastructure as Code Kief Morris (著), 宮下 剛輔 (監修), 長尾 高弘  (翻訳)](https://www.amazon.co.jp/dp/4873117968/ref=cm_sw_em_r_mt_dp_U_1f5ZCb6ETF67B)」の定義などを整理してみたイメージ図を以下に示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80280/b28a0b8b-54ae-748a-2ace-264811f7715a.png)

図の説明

広義のIaC（一番大きな円）の中に、DeclarativeとImperative を定義しています。ツールによっては、両方の側面を持ったものがあるため集合の重なりをイメージしています。最近では、新しい概念として `Intelligent` というユーザの意図（システム環境に対する要求事項など）を指定するという考え方も出てきました。
IaC を実現するには、DevOps の概念が重要になってきます。このため、下支えするというイメージでDevOps要素を記載しています。

次にDeclarativeとImperativeを実現するためにツールの分類を点線の四角枠で表現しています。具体的なツール名をその特徴から配置しています。

* Infrastructure define tools (インフラストラクチャ定義ツール）
  * 狭義のIaC を指しています
* Server configuration tools (サーバー構成ツール)
  * Configuration as Code とも呼ばれるツール群です
* Container as a Service
  * 参考資料等には定義されていませんが、コンテナ運用する上での定義もコードであるため記載しています

図の上部の左向き矢印は、ソースコードの定義方法が「システムを構造で表現」する形態、右矢印方向は「システムを処理フローで表現」する形態となります。下図のようなイメージです。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80280/e477c9b6-03a6-b646-a9d4-cbfd65e935e4.png)


## Declarative Modelのメリット

ここでのDeclarative Modelツールの例は、Openstack Heat, AWS Cloudformation, Terraform をイメージしています。

* システムの定義について、完成形をイメージして作成できる。GUIがあるとさらに直観的にイメージしやすくなる
* 抽象度が高い定義を使うことで、インターオペラビリティ（[この記事参照](https://qiita.com/san-tak/items/0a05234774eca57c0029)）の価値を得られる
* プロビジョニングやデプロイの処理フロー(手順)を記述する必要がない

## Imperative Modelのメリット

ここでのImperative Modelツールの例は、Chef をイメージしています。

* 手順に沿って複雑な条件分岐を含めて処理内容を記述できる
* 従来の作業手順書(例えばExcel版手順書)からそのまま移行しやすい
* トラブル発生時の解析やデバッグがしやすい

## Declarative / Imperative 双方のメリット

IaCツールとして共通のメリットは以下になります。

* べき等性が確保できる
* 再現性（同じ構築結果を得ることができる）
* 再利用性（パラメータを変更することで、同様な構成を構築できる）

## Declarative / Imperative 双方の課題や克服すべきこと

* インフラに対してコードで制御するという壁が意外と高い（例えば総論賛成、各論反対という状況に陥る）
* ツールだけの導入では逆効果（構成管理、自動化、テストドリブンなども合わせてIaCとする必要があるため、それなりのスキルが必要）
* 本運用開始後の変更では工夫が必要（新規構築と同じ手順では変更できないことが多い）
* べき等性を実現するには、ツール側が用意している管理対象用の部品群(Ansible の場合はModule)の品揃えに大きく依存することになる。結果的にそのツールにロックインされがち。
* 流行り廃りが早い中、コード実装者とその運用者が異なり、結果的に「運用でカバー」が発生する場合あり（本見解の引用元：https://speakerdeck.com/opelab/20180524-ssmjp-deploy）

## Declarative / Imperative IaCツール活用の考え方

様々なDeclarative / Imperative で実装されたIaCツールがある中、どのように使い分けていくべきかを考えてみます。

#### ツールの選択について

  * 特定の基盤利用に特化する場合は、その専用ツールを利用する
  * ライフサイクルや要員スキルに合わせて使い分け
  * 技術変化を考慮し、一つのツールに固執しない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80280/ade0dcdd-e194-6b3f-9aeb-90f798f4c0f7.png)

システムを乗せる基盤（ダイナミックインフラストラクチャプラットフォーム≒クラウド基盤）だけを使う場合は、その基盤が用意している専用ツールを使うと利便性、親和性が高く運用しやすくなります。Openstackだけを使う場合はHeatを、AWSだけを使う場合は、Cloudformation を選択することになります。
複数のクラウド基盤を組み合わせて使うパターン（ハイブリッドクラウド、マルチクラウド）の場合は、一段抽象度をあげたツールを使用すると良いでしょう。抽象度をあげたツールの例としては、AnsibleやTerraform が該当します。

システムを構成する要素（VM, 仮想ネットワーク, OS, ミドルウェア, 業務アプリケーション, 業務データなど）は、その構築やインストール、配備を実施するタイミングが異なります（ライフサイクルが異なります）。すべてをまとめてコード化することも可能ですが、モノリシックなイメージとなりメンテナンス性が非常に悪くなります。このため、その構成要素を担当をするエンジニアや構成要素のライフサイクルに応じて、コード化する方が良いでしょう。機能や役割での分割ができて他への影響を局所化することができると思います。

使用するIaCツールをプロジェクトで選択する際、一般的にその選定をリードするメンバの思いが強く反映されることが多いと思います。選定をリードするメンバは様々なクライテリアから、それなりの（確固たる）意思でIaCツールを決めており、余程の対抗案を示さない限り使用するIaCツールを変えることはできないでしょう。しかし、未来永劫（もしくは２−３年後でも）同じツールが使える保証はなく、その頃には、選定をしたメンバは既に異動していない、ということもありえます。最低限なぜそのツールを選定したのか、記録を残すようにしたいものです。

#### ゴールを明確にする

Declarative / Imperative の考察から少し論点がずれますが、IaCツールを使うことはあくまで手段であり、そのゴールを明確にしていく必要があります。

  * 自動化へのマイルストーンを明確に（ステップアップ計画）
  * ツールを使うことを目的化しない
  * ドキュメントを整備する（ブラックボックス化しない）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80280/a7b41450-8da7-0bcb-9ab1-eca19c6f3f03.png)

自動化を実現するといっても、一朝一夕には実現できません。例えば、上記の図の「個別作業」をいきなりIaCツールへ持っていくことは、単に個人作業を移行しているだけとなってしまいます。ある一定期間はその個人は効率化するかもしれませんが、メンバ全員が勝手気ままに自動化すると全体的に見るとマイナス方向の結果となってしまいます。（IaCツールの学習と意味での効果はあるとは思いますが）
自動化を行うためのシステム設計を明確に実施し、その結果をドキュメント化して何をどのようにして実現しているのかをわかるようにしたいです。これは、作業を標準化する、という段階に当たります。

また、いまいまの人の運用をそのまま置き換えようとすると上手くいかないことが多いと思います。新しいクラウド基盤を使う場合は、その提供機能をよく調査した上でプロセスの見直しを行う必要があるでしょう。

さらに自動化を見据えた新しい管理手法も一緒に啓蒙していく必要がでしょう（が鶏と卵、だれがその事例を作るか？？という問題がありますが）。[Google SRE](https://landing.google.com/sre/) は、今後ある意味指針になると考えています。さらに脱線しますが、[Github Actions](https://github.com/features/actions) は、今後活用していく要素の一つだと思います。

#### 本運用後の変更をどう扱うのか

本番運用中にシステム構成変更を行う際、IaCツールをどのように活用していくか、ココが一番難易度が高い事項と考えています。

システム構築を実施したIaCツールのソースコードと運用開始後のシステムの状態にどうしても差分が出てくるためです。コード上の定義と実体との差異への対処として、AWS では、「ドリフト検出」を行い実体に更新があった場合、どう扱うかを決定する方式(Change Set)を採用しています[^1]。Terraform は、tfstate というファイルにインフラの状態を記録しています。変更の実行前にDRY RUNをしてチェックすることができます。このようなツールの特性を調査してコードと実体の状態の整合性を取る方法を理解しておく必要があります。

[^1]: [AWS Cloudformation Black belt オンラインセミナー資料より](https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-online-seminar-aws-cloudformation)

## まとめ

IaC(Infrastructure as Code) を実現するための宣言的モデル(Declarative)と命令実行型モデル(Imperative)の位置付けやそのメリット、課題、活用方法などを見てきました。どちらのモデルも特徴や価値があり、本文中で説明した以下のような考慮がポイントとなると思います。

* IaCツールの選択は、プロジェクトの使用する基盤や要員のスキルに合わせて、取捨選択すること。単純にハヤリに踊らされたり、ベンダーの言うことを鵜呑みにしたりせず、自ら調査検討を行って決めた方がいいと思います。
* IaCツールを使うことを目的化しないこと。往々にして目的と手段が逆転してしまうことがあります。ツールによって自動化する目的を明確にしましょう。
* DAY1(本番システムの新規構築)だけでなくDAY2(システム運用)もよく考えること。特に構成変更時にIaCツールのソースコードと実体との状態乖離をどのように扱っていくか留意が必要です。

## 参考にした Link

### 宣言型(Declarative)と命令型(Imperative)の比較をしている記事

* [Declarative vs. Imperative Models for Configuration Management: Which Is Really Better?](https://www.upguard.com/blog/articles/declarative-vs.-imperative-models-for-configuration-management)
  * 宣言型の例をPuppet、命令型の例をChef で比較
  * プログラマは命令型を好み、システム管理者は宣言型を好む、としている
* [Imperative versus Declarative Process Modeling Languages: An Empirical Investigation](https://www.researchgate.net/publication/220268095_Imperative_versus_Declarative_Process_Modeling_Languages_An_Empirical_Investigation)
  * デンマーク工科大学 などの著者の研究論文
  * 宣言型と命令型の言語を使用して、利便性を検証
  * 宣言型モデルは、それを活用できる参加者が命令型に比べて少ない
  * 命令型は、順序で処理をするので理解しやすい
  * 今後は、宣言型と命令型を同じくらい理解している参加者で検証を行う必要がある

* [CloudSlang](http://www.cloudslang.io/#/) - Open Source Software
  * Process-Base（命令型） のオーケストレータであることを特徴としてあげている（動的な動作を行うことがメリット）

* [Why is a Declarative Model Important for NetOps Automation?](https://f5.com/about-us/blog/articles/why-is-a-declarative-model-important-for-netops-automation-30211) - F5 Networks
  * 次の４つの利点からネットワークオートメーションでは、宣言型にメリットがある
     1. 人的ミスを減らす
     2. 技術的な難易度を下げる
     3. APIのバージョン変更の影響を受けない（ちょっと意味が分からない）
     4. 専門知識の習得を減らすことができる

* [Declarative vs. imperative: The DevOps automation debate](https://searchitoperations.techtarget.com/news/2240187079/Declarative-vs-imperative-The-DevOps-automation-debate)
  * 宣言型モデルは環境に微妙な変化があると壊れる可能性があると言う人もいる。Chefでは、if-then で宣言的定義も可能
  * 宣言型モデルは、システム構成の理解がしやすい

#### Infrastructure as Code

* [私は Infrastructure as Code をわかっていなかった](http://simplearchitect.hatenablog.com/entry/2016/02/18/165917)
* [Infrastructure as Codeを否定していた私がKubernetesに否定されるという話](https://www.orangeitems.com/entry/2018/12/04/000500)
* [アプリケーションリリース自動化とインフラ自動化](https://www.microfocus.com/ja-jp/media/white-paper/application_release_automation_vs_infrastructure_automation_wp_ja.pdf)

---

### 宣言型モデルを採用している実装（ソフトウェア）

##### AWS Cloudformation

* AWS CloudFormationで手動で行った変更が検出可能になりました！！！
  * https://dev.classmethod.jp/cloud/aws/cloudformation-support-drift-detection/

##### Openstack Heat

* Heat テンプレートの例 (IBM)
  * https://www.ibm.com/support/knowledgecenter/ja/SS4KMC_2.5.0/com.ibm.ico.doc_2.5/r_heat_template_examples.html
* 第2章 HEAT テンプレートの理解 (RedHat)
  * https://access.redhat.com/documentation/ja-jp/red_hat_openstack_platform/11/html/advanced_overcloud_customization/sect-understanding_heat_templates

##### Puppet

* 宣言型言語としてのPuppet
  * https://qiita.com/udzura/items/ab1406413cb5e765ba29

##### Terraform

* CloudFormationとTerraformの使用感〜2017年7月版〜
  * https://qiita.com/CkReal/items/1c6f02ce55167a511231

* Terraform vs. CloudFormation, Heat, etc.
  * https://www.terraform.io/intro/vs/cloudformation.html

##### Kuberbetes

* Kubernetes YAMLの壁
  * https://deeeet.com/writing/2018/01/10/kubernetes-yaml/
* Kubernetes流YAML職人になるために
  * https://qiita.com/bgpat/items/173f33ae2a9e21b24487

##### Ansible
* Ansibleのテスト事情
  * https://dev.classmethod.jp/server-side/ansible/testing/ 

##### DSC
* PowerShell Desired State Configuration（DSC）とは
  * https://www.atmarkit.co.jp/ait/articles/1405/22/news131.html 

### その他
* 宣言的Spinnaker設計 継続的デリバリーのさらに上にいく
  * https://www.1915keke.com/entry/2018/05/19/124103
* DevOpsとは何か？ そのツールと組織文化、アジャイルとの違い
  * https://www.buildinsider.net/enterprise/devops/01
* 宣言型デプロイツールの「正しい」使い方 (考え方編) 
  * https://speakerdeck.com/opelab/20180524-ssmjp-deploy

---

### インテントベースネットワーキング
* Cisco インテントベース ネットワーキング
  * https://www.cisco.com/c/ja_jp/solutions/intent-based-networking.html
* 「インテント・ベースド・ネットワーキング」とは何か、Apstraの場合 (@IT)
  * https://www.atmarkit.co.jp/ait/articles/1804/25/news041.html
* シスコ「インテントベースネットワーク」がいよいよ完成形に (ASCII)
  * http://ascii.jp/elem/000/001/703/1703927/

~~~ 'txt
「Code Intent」は、ビジネスオーナーとDevNet開発者をつなぐポータルとなる。
たとえば「店舗に新しいレジを導入したい」といったビジネス視点の意図（インテント）を書き込むと、
DevNetコミュニティの開発者がその解決策となるコードを提案してくれるというものだ。
~~~

### 参考書籍
* [Infrastructure as Code Kief Morris (著), 宮下 剛輔 (監修), 長尾 高弘  (翻訳)](https://www.amazon.co.jp/dp/4873117968/ref=cm_sw_em_r_mt_dp_U_1f5ZCb6ETF67B)
   * 9章 インフラストラクチャ定義のパターン
      * 定義（宣言的モデル）をどう作るのか
     * ビルドフォワードとリバースエンジニアリング
     * 既存の環境からリーバスできる（TerraForm, CloudFormation、Heat)
       * リバースは、本当に同じ環境が再構築できるかどうかは保証なし
     * 最良なのは、「ビルドフォワード」（一から設計してコード化）