サイオステクノロジーの池田 透です。
弊社で開発中の1からアプリケーションを動かすためのデプロイメントツールDacraneを紹介します。
ぜひ、前回のDacraneの構想に関するブログもご覧ください。
今回はよりDacraneの具体的なインフラからアプリまでを統合する戦略について説明をしていきます。
通常の多くのアプリケーションはどのようにデプロイされるかを手順書を書いて管理します。これらを宣言的で自動的に管理しようとするのが、Dacraneということになります。そのため、環境構築手順書を書く代わりに、デプロイコードを書き、環境を構築したい方が、手順書を読むする代わりに書かれたコードを実行するコマンドを叩くような開発を目指しているということです。
Dacraneは非常にシンプルであり、CLIを叩くことでデプロイメントコードを読み込むことで、その通りにローカルPCやクラウド上にインフラストラクチャーとアプリケーションをデプロイするツールです。イメージとしてMakefile、Apache Antがインフラへ拡張されたツールであったり、TerraformやAWS CloudFormationがアプリケーションまで拡張されたようなツールという位置付けと考えていただくとイメージしやすいかと思います。
このイメージをもう少し正確に表したものが下図のDeployment as Code (DaC)の領域です。Deployment as Codeはこのような領域を指し示すために作った造語です。
DaCはインフラストラクチャーからアプケーションまでのレイヤーを横断して「そのアプリケーションのデプロイ方法を宣言的なコードで管理する」という考え方をします。よく似た概念であるInfrastructure as Code (IaC)はインフラストラクチャーをコードとして管理するという考え方ですが、DaCは最終的にアプリケーションが「動く」までを重要視します。
DacraneはこのDaC領域における実装です。Dacraneはアプリケーションを動かすための一連のプロセス全体を管理して面倒や複雑性を取り除き、シンプルで強力な手法を提供することを目標としています。
ではどのよういこの一連のプロセスをどのように統合して管理することができるでしょうか。このブログではその戦略について書いていきます。
Dacraneが目指すアプリ開発
インフラストラクチャーからアプリケーションまでのデプロイメントのプロセスを統合にするにあたって、単に順番に構築がされればよいということはなく、運用を考慮した複数の環境やアプリのビルドなどの関係や開発サイクルに耐えうる必要があります。では具体的にどのようなケースにおいて使える必要があるでしょうか。DacraneではThe Twelve-Factor Appの考え方をベースとして、次のようなベストプラクティスが実現できるような設計を目標としています。
- 環境の一致
- 開発、ステージング、本番環境を可能な限り一致させる。
- バージョン管理
- バーション管理されている実行可能なアプリケーションを複数のデプロイする。
- 環境依存変数の注入
- 環境依存する変数に対して抽象化し、インフラ・アプリが実行、構築されるときに環境依存する設定を注入する。
環境の一致
通常のシステム開発では本番/ステージング/開発環境のような同様の環境を独立して複数用意することが一般的です。このとき開発、ステージング、本番環境を可能な限り一致させるのが望ましいと言えます。なぜ、望ましいかと言えば、次のようなことが問題となるためです。
歴史的に、開発環境(開発者が直接変更するアプリケーションのローカルデプロイ)と本番環境(エンドユーザーからアクセスされるアプリケーションの実行中デプロイ)の間には大きなギャップがあった。(〜中略〜) バックエンドサービスの違いは、わずかな非互換性が顕在化し、開発環境やステージング環境では正常に動作してテストも通過するコードが本番環境でエラーを起こす事態を招くことを意味する。この種のエラーは継続的デプロイを妨げる摩擦を生む。この摩擦とそれに伴って継続的デプロイが妨げられることのコストは、アプリケーションのライフサイクルに渡ってトータルで考えると非常に高くつく。
(The Twelve-Factor App x.開発/本番一致より引用)
従来、環境構築/更新手順書やシステム構成図、パラメータシート等で同じになるように管理してきたわけです。このようなドキュメントには曖昧性がどうしても入りますし、多くのコストをかけなければすぐに古くなってしまいます。さらに人間が注意して環境を一致させるにも限界があり、どうしても意図しないところに差分が出てきてしまうことがあります。
Dacraneでは環境を一致させるような機能を提供したいと考えています。
バージョンの管理
バーション管理されている実行可能なアプリケーションを複数のデプロイするのが望ましいと言えます。これが環境ごとに異なるビルドが使われたり、ビルド方法が開発者によって異なってしまうと、依存関係の複雑化で管理が困難となってしまいます。
バージョン付けされたアプリケーションが複数の環境にデプロイされることで、デプロイされたアプリケーションを簡単にたどることができます。アプリケーションのビルドは環境とは独立して実施して、各環境に選択的にデプロイできるのが望ましいと言えます。
Dacraneではアプリケーションのビルドはどの環境にもデプロイできるように均質化されいて、各環境にデプロイ簡単にデプロイできるようにする機能を持たせたいと考えています。
環境依存変数の注入
環境によって異なる構成については変数として扱うのが望ましいと言えます。The Twelve Factor Appではアプリケーションのコードが環境と切り離されることが要求されています。さらにDacraneではインフラストラクチャーもコード化されていれば、同じく変数として扱われることが望ましいと考えています。
アプリケーションは主にインフラストラクチャーやアタッチされるサービスに対して、環境の影響を受けるためこの部分が変数となります。
インフラストラクチャーにおける変数は主に要件定義や設計によって与えられます。例えば、本番環境は高い性能要件や可用性を求められる一方でステージング環境はコスト削減のために最小構成が求められたりします。
このような要件がインフラストラクチャーにおける変数となります。そのため、マシンスペックや分散システムにおけるノードの数が抽象化の候補となります。
Dacraneのデプロイメントのコードも具体的な環境に依存することなく、デプロイコードを書き下せ、具体的な環境を構築する際に変数を注入する機能を持たせたいと考えています。
ベストプラクティスとDacraneの戦略
現在、これら3つのベストプラクティスに対応するためにモジュール機能の導入を試しています。
データ設計
Dacraneでは次の5つの要素を取り扱います。
- リソース
- クラウド等のリソースを作成・更新・削除する要素。
- データ
- データを取得する要素。
- モジュール
- 抽象化されたインフラ/アプリの定義する要素。リソースとデータを呼び出して定義する。他のモジュールの呼び出しも可能。
- インスタンス
- インフラやアプリの実体と1対1で紐づく状態データ。
- リソース実体
- クラウド上のインフラやデプロイされて稼働するアプリの実体。
リソースはDacraneでクラウド等のリソースを作成する最小の単位です。また、外部リソースの読み込みにはデータを使います。
これらのリソースやデータを組み合わせてできるのがモジュールです。モジュールはデプロイメントコードに記載されています。モジュールは関数のように引数をとることや他のモジュールも呼び出すことができます。
モジュールはdacrane applyで引数を与えられることでインスタンスになります。インスタンスはクラウド上のリソースやアプリケーションの実体と1対1で紐づくデータであり、インスタンスは構築されて破棄されるまで、常にリソースの実体と共に同期されて管理されます。
モジュール
モジュールはインフラやアプリの雛形であり、モジュールはdacraneにとって非常に中心的な概念です。モジュールはデプロイメントコードとして定義します。モジュールは下図のようにリソースやデータ、他のモジュールを用いて構成を定義します。モジュールは仮引数をとることができ、その仮引数を用いてモジュールを定義します。そのほかにも条件分岐や反復処理といった制御や式表現を使うこともできます。
最後に定義したモジュールはapplyコマンドから実引数と共に呼び出します。このとき、モジュールの式が評価されて、モジュールが具体化します。これを元にインスタンスが構築されます。
ベストプラクティスの実践方法
これらの機能を使うことによって、どのように運用の課題を解決するかみていきます。
環境一致
モジュールで抽象化された環境を定義し、インスタンスとして個別の環境を生成します。これによりインスタンス作成時に与えた引数以外には同じデプロイメントが実行されることを保証できます。複数の環境があって変更する場合もモジュールのみを変更して、それぞれのインスタンスに適用すればよく、更新によって環境の一致が取れなくなることも防ぐことができます。
バージョン管理
モジュールでビルドを定義し、インスタンスとしてアプリケーションのバージョンを管理します。これにより環境に依存せず、均質なビルドを実現することができます。インスタンス化されたアプケーションと環境からデプロイしたいバージョンを参照することで、簡単に複数のデプロイを作成することもできます。
環境依存変数の注入
インスタンス生成の引数と依存モジュールの指定を使って環境変数を注入します。これにより環境ごとにことなる変数を切り離されるので、依存するインフラに合わせてアプリケーションに環境変数を指定したり、設計や要件に合わせてインフラのスペックをそれぞれ決めることができます。あとから生じたプロジェクトの変化に応じて、新しい環境を作ることもできます。例えば、新しくジョインした開発者の開発環境や使い捨ての環境も容易に構築することができます。
簡単なシステム構成例
例えば、次のようなApp ServiceへのExpressのAPIをデプロイする場合を考えます。まず、開発したアプリケーションをローカルのDockerイメージとしてビルドします。このイメージを開発者のPC上にデプロイしテストします。その後、Azure Container Registry (ACR)にイメージをプッシュします。そのイメージを使ってAzure App Serviceにデプロイします。Azure App Serviceは本番とステージングの2環境を用意します。この2環境はほぼ同じ構成です。このとき、ACRとResource Groupは環境間で共有します。
Dacraneでモジュールを定義するには次のように分割します。まず、APIのイメージをビルドするためのAPIアプリモジュールを用意します。次にローカルPC上のモジュールとして1つ準備し、共通インフラで1モジュール、両方の環境のApp Serviceで1モジュールとして分割します。
次にモジュールとインスタンスの関係として書き換えたイメージを下図に示します。モジュールが抽象的なレイヤーとして存在し、環境に依存するものがインスタンスのレイヤーとして存在しているのがわかると思います。Dacraneでは環境をこのように整理することでデプロイを管理します。クラウドAPIサービスは2環境をインスタンスとして構築することで同等の環境を作ることができます。また、APIアプリは1つのバージョンをインスタンスとして扱うことで管理されて、Docker ContainerにもApp Serviceにもデプロイできます。
ご覧いただいてわかる通り、モジュールとして抽象化されているので、新しい環境を簡単に作成することもできます。新しいバージョンを作成しても依存先(青い矢印)を切り替えるだけで簡単に変更できます。
これによりインフラからアプリまでの一連のデプロイが統合されました。
ここまでの説明とデモをYouTubeで公開していますので、ぜひご覧ください。
開発を続けるためにGitHub Starをお願いします!
このようにDacraneはモジュールを中心とした機能により、アプリケーションを動かすための面倒や複雑性を取り除き、シンプルで強力な手法を提案します。多くのクラウドネイティブなアプリ/インフラ開発者がもっと価値のある仕事に集中できるように開発を続けてまいります!
会社でのOSS開発を続けるには多くの方に賛同いただき、注目いただくことが必要不可欠です。応援いただける方はぜひGitHub Starを押していただけると嬉しいです!
最後までお読みいただきありがとうございました。今後の開発にぜひご期待ください。