精読「マイクロサービスアーキテクチャ 第2版」(第二部 実装 - 第8章 デプロイ)
マイクロサービスアーキテクチャ 第2版
マイクロサービスの設計、実装、運用に必要なベストプラクティスや最新技術を解説した、実践的なガイドブックです。これを読めば、マイクロサービスに関してそれっぽい会話もできますよ。
関連記事
論理から物理へ
マイクロサービスの論理的なアーキテクチャから物理的なデプロイの視点に焦点を移し、サービス間の通信方法に加え、実際のインフラでのマイクロサービスの配置に伴う複雑さについて考える必要がある。
複数インスタンス
マイクロサービスのデプロイでは、複数のインスタンスを用意することで、システムの堅牢性が向上する。インスタンス間の通信には、例えばHTTPベースのAPIを使うことが一般的で、ロードバランサを使ってリクエストのルーティングを行う。
また、インスタンスは同じハードウェアに集中しないようにし、主要なクラウドプロバイダを利用する場合、デプロイは複数のアベイラビリティゾーンに分散させる必要がある。
データベース
マイクロサービスにおけるデータベース設計では、「データベースを共有しない」という原則が重要。しかし、複数のインスタンスがある場合、同じ論理的なサービスの異なるインスタンス間でデータを共有する必要がある。これは、同じサービス内でデータを管理しているため、データベースの共有には問題ない。
データベースのスケーリングは、複数のマシンでホストすることが一般的で、読み取り専用トラフィックはリードレプリカに送られ、書き込みは通常シャーディングによって分散される。複数のデータベースを同じインフラでホストすることで、コスト削減や管理負担軽減が可能
一方、パブリッククラウドプロバイダ(AWSなど)では、各マイクロサービスに専用のデータベースを用意することが多く、これによりコスト効率が向上し、サービス所有者がデータベースをより制御しやすくなる。
環境
ソフトウェアのデプロイでは、開発から本番まで複数の環境を通過する。各環境は異なる目的を果たし、本番環境に近いほど実際の運用に近い状態でテストされる。
-
開発環境
開発者のローカルPCでコードをテスト。迅速なフィードバックが得られるが、本番環境とは異なる設定。 -
CI環境
高速テストと低速テストを実施。サービスのインスタンス数を調整し、負荷分散などの機能を検証。 -
本番前環境
手動検証を含む場合がある。可能な限り本番環境に近づけることで、動作確認の信頼性を高める。 -
本番環境
サービスは複数のインスタンスとして、複数のデータセンターに分散デプロイされる。
それぞれの環境は、コストや目的に応じて異なるトポロジーを持つため、設定やインスタンス数を調整する必要がある。環境固有の設定は成果物から分離し、ビルドを一度で済ませる仕組みが重要。
マイクロサービスのデプロイの原則
分離された実行
マイクロサービス移行初期に単一マシンでサービスを共存させると、監視やリソース競合、依存関係管理が難しくなり、自律性やデプロイの独立性が損なわれる。
現在は、コンテナ技術がコスト効率と柔軟性に優れ、分離された実行環境の主流となっている。AWS LambdaやHerokuなどの抽象化されたプラットフォームも、分離された実行環境を提供する
自動化の重視
マイクロサービス移行に伴い、運用の複雑化を防ぐため、自動化が不可欠。手作業では対応が難しくなるため、IaCなどのツールを活用し、自動化を運用文化の中核に据える必要がある。
事例として、REAとGiltは、自動化ツールの導入によりマイクロサービス移行を加速。REAは18ヶ月で70以上、Giltは移行開始後1年で10、2014年には450以上のサービスを稼働させました。このように、自動化は生産性向上とスケーラビリティの鍵。
IaC(コードとしてのインフラ)
IaC(コードとしてのインフラ) は、機械可読コードでインフラを構成する手法で、インフラのバージョン管理やテスト、自動化を可能する。
インフラ構成をコードで定義し、再現性を確保。変更履歴を追跡可能にすることで、運用効率や監査対応力を向上させる。
停止時間のないデプロイ
停止時間のないデプロイは、サービスを中断することなく新バージョンをリリースする手法で、開発・デプロイの効率を大幅に向上させる。これにより、リリース頻度を高めながら、システムの安定性を維持し、チームの作業時間や生活の質を改善できる。
主なアプローチには以下がある
- 非同期通信を活用する場合、停止時間のないデプロイは比較的容易。メッセージがサービス再起動後に配信されます。
- ローリングアップグレードでは、新バージョンのインスタンスを徐々に増やし、旧バージョンを減らすことで停止を回避します。Kubernetesなどのツールが有効です。
- ブルーグリーンデプロイのようなシンプルな手法でも同様の効果が得られます。
望ましい状態の管理
アプリケーションに必要なインフラ要件を指定し、手動介入なしにその状態を維持する機能。システムが望ましい状態から外れると、基盤プラットフォームが自動的に修正する。
-
主な特徴
- 必要なリソース(インスタンス数、メモリ、CPUなど)をプラットフォームが管理。
- 状態の変化(例:インスタンスの停止)に応じて、望ましい状態を維持するための対応を自動で実行。
- 開発者や運用者は、状態維持の方法を心配せず、望ましい状態の定義に集中できる。
-
メリット
- 自動復元:インスタンス停止やハードウェア障害が発生しても、プラットフォームが自動対応。
- 運用負担の軽減:手動操作を減らし、運用担当者は高レベルな指示だけで管理可能。
- 柔軟な運用:混合ワークロードや異なるプラットフォームへの対応が可能。
-
代表的なプラットフォーム
- Kubernetes: コンテナベースのワークロード管理。
- AWSオートスケーリンググループ: リソースを自動調整。
- Nomad: 非コンテナワークロードにも対応。
-
GitOpsとの関係
- GitOpsは「望ましい状態管理」と「Infrastructure as Code (IaC)」を統合。
- 状態の定義をGitで管理し、変更がプラットフォームに自動適用される。
デプロイの選択肢
マイクロサービスのワークロードに適したアプローチやツールを選ぶ際には、以下の原則を重視すべき
- マイクロサービスを分離して実行し、理想的には停止時間を避けてデプロイできること。
- 自動化の文化を受け入れ、インフラとアプリケーションの構成をコードで定義すること。
- 望ましい状態を管理可能なツールを選択すること。
これらの原則を踏まえ、デプロイの選択肢を簡潔にまとめ、それぞれの選択肢がこれらの考え方をどの程度実現できるかを評価する
物理マシン
マイクロサービスを物理マシンに直接デプロイするのは、リソースの無駄や管理の困難、分離環境の確保が難しいため稀。仮想化やコンテナ化の方が効率的で一般的。
仮想マシン(VM)
仮想マシン(VM)は、1台の物理サーバーを複数の小さな仮想サーバーに分けて使う技術。これにより、コンピュータのリソース(CPUやメモリ)を効率的に使え、管理が楽になる。仮想マシンはそれぞれ独立したOSを持ち、マイクロサービス間の分離を確保しますが、基盤となる物理サーバーが壊れると、複数のサービスが影響を受ける可能性がある。
仮想化には、追加のコストやリソースの無駄があるものの、分離が重要な場合や、コンテナ化が難しい場合には便利。特に大規模なシステムでは、仮想マシンを使って効果的に運用されている。
コンテナ
コンテナ技術は、サーバソフトウェアのデプロイにおいて重要な役割を果たし、特にマイクロサービスアーキテクチャで広く採用されている。コンテナは、仮想マシンに比べてリソース効率が高く、迅速に起動できます。Linuxカーネルを共有し、仮想マシンのようなハイパーバイザなしで動作するため、コスト効率に優れている。DockerやKubernetesは、コンテナの管理やオーケストレーションを簡素化し、大規模なシステムの運用に適している。
【話題のITトレンド】コンテナ技術と仮想マシンの違いとは? ー Vol.15 ーより
アプリケーションコンテナ
アプリケーションコンテナモデルは、複数のサービスやアプリケーションを単一のコンテナ内で実行し、ホストに配置する形態。このアプローチは管理の効率化やリソースオーバーヘッドの削減に寄与しますが、いくつかの欠点もある。
主な問題点は、技術選択が制限されること、スケーリング時の課題、監視機能の不足、起動時間の遅延、ライフサイクル管理の複雑さ、リソース使用の分析の難しさ、コストの問題など。特に、アプリケーションコンテナの分離性の欠如は、マイクロサービスアーキテクチャには不向きであるとされています。
最終的には、各マイクロサービスを独立したプロセスとして実行するアプローチが推奨される。
PaaS
PaaS(Platform as a Service)は、高い抽象化レベルでアプリケーションを管理するサービスで、Java WARファイルやRuby gemなどの技術固有の成果物を自動的にプロビジョニングし、実行する。PaaSはスケーリングの管理を自動化することができる一方、柔軟性に欠け、特に標準的でないアプリケーションでは適切に動作しないことが多い。
また、PaaSのプラットフォームが高度に自動化されると、トラブルシューティングや内部の調査が難しくなることがある。サーバーレス製品(FaaS)などの新しい選択肢が登場し、PaaSの役割が変化している。PaaSの適合性は、利用するアプリケーションの特性によって異なり、HerokuとNetlifyなど、異なるPaaSでもマイクロサービスのデプロイに利用できる場合がある。
FaaS
FaaSでは、関数をトリガーする「何か」が起こるまで関数は停止しており、トリガーが発生した時点で関数が実行される。関数が終了すると停止し、実行されていない関数にはコストがかからない。この「従量課金制」のメリットにより、低負荷時や予測困難な負荷に適している。
しかし、FaaSにもいくつかの制約や課題がある。例えば、関数の実行時間に制限があり、AWS Lambdaの場合は15分、Google Cloud Functionsの場合は9分が上限。また、関数は「ステートレス」であり、前回の実行結果を引き継ぐことができないため、状態管理が必要な場合は外部ストレージを使用する必要がある。
さらに、FaaSを利用する際には「コールドスタート」時間(初回起動時の遅延)が問題になることもある。特に、JVMや. NETなどのランタイムを使用する場合、コールドスタート時間が長くなることがある。しかし、近年では最適化が進み、特にGoやPython、Node.jsなどの軽量ランタイムを使うことで、コールドスタートの影響を最小限に抑えることができる。
また、関数の動的スケーリングに関しても、限られた並行処理数の制限や、インフラの他の部分に負担がかかる可能性があるため、慎重に設計する必要がある。
これらの制約を理解し、適切に活用することで、FaaSは高いスケーラビリティと低コストでサービスを運用できる強力なツールとなる。
FaaSとは?サーバレスの意味やPaaS・CaaS・IaaSとの違いを解説より
どのデプロイオプションが自分に適しているか
このテキストでは、マイクロサービスのデプロイ方法を決定する際の考慮点とアプローチについては以下の通り
-
現在の方法がうまくいっているなら、続けるべき
流行に流されず、既存の方法が効果的であれば、それを維持することが重要です。 -
制御を手放す
もし、PaaS(HerokuやFaaSプラットフォーム)などに任せられるなら、設定や管理の手間を減らすことが推奨されます。 -
コンテナ化とKubernetesの選択
コンテナ化は分離に優れ、ローカル開発にも有利ですが、Kubernetesが必須ではなく、FaaSが適している場合は、無理にKubernetesを使用する必要はありません。 -
開発者の生産性重視
開発者が使いやすいツールやプラットフォーム(Heroku、Vercelなど)を選び、製品開発に多くの時間を費やすことが最も重要です。
全体的に、マイクロサービスのデプロイ方法を決定する際には、コストや使いやすさ、制御の度合いを考慮しつつ、開発者が快適に作業できる環境を選ぶべき。
Kubernetesとコンテナオーケストレーション
コンテナ管理の需要が高まり、DockerやRancher、Mesosなどが試みたが、最終的にKubernetesが主流となった。次に、Kubernetesの必要性について説明していく。
コンテナオーケストレーションの例
コンテナオーケストレーションプラットフォーム(例:Kubernetes)は、複数のマシンでコンテナを管理し、負荷分散や冗長性を確保するために必要。これにより、リソースのスケジューリングや状態管理が自動化され、運用が効率化される。Kubernetesは、他のオーケストレーションツール(Mesos、ECS、Docker Swarmなど)と同様の機能を提供し、最も広く使用されている。
kubernetsの概念の簡略図
Kubernetesは、クラスタを「ノード」と「コントロールプレーン」で構成し、コンテナの代わりに「Pod」をスケジューリングする。Podは1つ以上のコンテナで構成され、通常はマイクロサービスのインスタンスとして使われる。Kubernetesでは、Podを安定したネットワークエンドポイントにマッピングする「サービス」や、Podの望ましい数を管理する「レプリカセット」などの概念が重要。
また、デプロイを使ってPodやレプリカセットの変更を管理し、ローリングアップグレードやスケーリングを実行します。
Kubernetesとは何かを図でわかりやすく解説!Pod、Namespaceもより
マルチテナントとフェデレーション
Kubernetesのリソース効率を最大化するためには、すべてのコンピューティングリソースを単一のクラスタにプールして、未使用のリソースを自由に再割り当てすることが理想的だが、Kubernetes自体はマルチテナント化に制約がある。
これを解決する方法として、OpenShiftのようなKubernetes上で構築されたプラットフォームを採用するか、複数の独立したクラスタを統合する「フェデレーション」モデルを使用することが考えられる。フェデレーションでは、複数のクラスタを管理できる一方で、リソースプールの効率化は難しくなる。クラスタ間でリソースを移動させることは可能ですが、簡単ではなく、アップグレード時のマイクロサービス移行などで役立つ場合がある。大規模なスケーリング効率化を目指す場合、Kubernetesフェデレーションを活用する方法は慎重に調査すべき領域。
プラットフォームと移植性
Kubernetesはコンテナ実行の抽象化を提供しますが、単独ではプラットフォームとして完結せず、追加ツールでカスタマイズが必要。移行には新たなプラットフォームの再構築が求められ、選択肢の多さに圧倒されることがある。
Helm、Operator、CRD
Kubernetesでのサードパーティアプリケーションやサブシステムの管理は混乱している。特に、Kafkaなどのアプリケーションのデプロイやライフサイクル管理には、HelmとOperatorという2つのツールがあり、どちらを使うべきかが不明確。Helmはパッケージ管理に優れ、Operatorはアプリケーションの継続的な管理に特化している。最近の進化として、カスタムリソース定義(CRD)があり、KubernetesのAPIを拡張して新しい振る舞いを追加できますが、その使いどころにはまだコンセンサスが得られていない状況。
Knative
Knativeは、FaaS(Function as a Service)スタイルのワークフローを提供するためにKubernetesを使用するオープンソースプロジェクトで、開発者がKubernetesの複雑さを隠蔽し、ソフトウェアのライフサイクルを管理しやすくすることを目指している。Knativeの実行には、サービスメッシュ(特にIstio)が不可欠であり、Istio以外のサービスメッシュはまだ不安定です。Knativeを使用する場合、Istioを組み込んでおく必要があるが、Knativeが広く使用されるには時間がかかると予測される。
将来
Kubernetesは今後も広く使用されるが、開発者が直接扱う方法は長くは続かないと予想されている。Kubernetesはコンテナワークロードの管理には優れており、今後はKnativeのように、より高レベルの抽象化が進み、開発者はその存在を意識せずに使うことになるだろう。しかし、分散システムの課題を理解する必要は依然として重要。
Kubernetsを使うべきか
Kubernetesを導入する前に、慎重に検討することが重要。Kubernetesの運用には専門的な知識が必要で、独自でクラスタを実装・管理するのは大規模で複雑な作業。多くの大規模組織は、Kubernetesの運用を専門企業にアウトソーシングしており、フルマネージドクラスタ(Google、Azure、AWSなど)を利用するのが推奨される。
また、マイクロサービスのデプロイや開発者向けに使いやすいプラットフォームを探している場合、FaaSやPaaS(Azure Web Apps、Google App Engineなど)の方が適しているかもしれない。Kubernetesを導入する前に、管理者や開発者が実際に触れてみて、評価することが大切。小規模な開発チームや数個のマイクロサービスの場合、Kubernetesは過剰な選択になることがある。
プログレッシブデリバリ
プログレッシブデリバリは、ソフトウェアのリリース時のリスクを低減する新しいアプローチ。
頻繁なリリースと低い変更失敗率は密接に関連しており、高パフォーマンスの企業は頻繁にデプロイを行い、変更失敗率が低いことが証明されている。このアプローチでは、機能トグルやカナリアリリース、並列実行などの技術を活用し、機能が制御された方法でユーザーに提供される。従来のビッグバンデプロイに代わり、誰がどの機能を使用するかを高度に管理でき、ソフトウェアの新バージョンを一部のユーザーにロールアウトするなど、リリースの概念とデプロイの概念を分離することが可能。
デプロイとリリースの分離
Jez Humbleは、デプロイとリリースを分離することが危険性の低いソフトウェアリリースの基本原則であると主張している。
- デプロイはソフトウェアのバージョンを特定の環境(通常は本番環境)にインストールすることを指し、
- リリースはユーザーがそのソフトウェアや機能を利用できるようにすることを指す。
この分離により、ユーザーに障害を見せることなく、ソフトウェアが本番環境で動作することが可能になる。ブルーグリーンデプロイは、この概念のシンプルな例で、旧バージョンと新バージョンを並行して稼働させ、新バージョンが問題なく動作することを確認後、顧客に切り替える。問題が発生した場合、影響を受ける顧客はない。この原則を受け入れることで、より洗練されたテクニックを使用できるようになります。
プログレッシブデリバリへの移行
James Governorは「プログレッシブデリバリ」という用語を考案し、これを継続的デリバリの延長であり、ソフトウェアのリリースによる影響をきめ細かく制御できるテクニックと説明している。
プログレッシブデリバリは、新機能を段階的に顧客に届けることを可能にし、もはや一度限りのロールアウトではなく、継続的な活動として行うアプローチ。この方法では、機能の制御を最も責任を負うプロダクトオーナー(PO)に委譲できるため、POが技術的な理解を持つか、サポートを受けられることが重要。
プログレッシブデリバリの手法の一例として、ブルーグリーンデプロイが挙げられますが、他にもさまざまな手法が存在する。
機能トグル
機能トグル(機能フラグ)は、デプロイされた機能を隠蔽し、機能の有効化や無効化を切り替えるために使用される。特にトランクベースのデプロイでよく利用され、未完成の機能をチェックインしてデプロイできるが、エンドユーザーには見えない状態に保たれる。機能トグルは、特定の時間に機能を有効化したり、問題発生時に無効化したりするなど、さまざまな用途がある。また、ユーザーの属性に基づいて異なるフラグ状態を持たせることも可能。これにより、ベータテストグループに対してのみ機能を有効化することができる。
機能トグルを管理するためには、LaunchDarklyやSplitといったフルマネージドソリューションがあり、最初は構成ファイルでシンプルに始め、後でより詳細な管理を考慮すると良い。
カナリアリリース
新機能を限られたユーザーにまず提供し、問題がなければ徐々に全体に展開する方法。これにより、誤りの影響を最小限に抑えられる。特にマイクロサービスアーキテクチャでは、トグルやルーティングを使い、機能の有効化/無効化を制御できる。
最近では、Spinnakerなどのツールを使って、エラー率などのメトリックに基づいて自動的にロールアウトを調整することが一般的。
並列実行
並列実行は、新旧バージョンの機能を同時に実行し、リクエストを両方の実装に送信して比較する方法。これにより、新機能が旧バージョンと同じように動作することを確認できる。マイクロサービスアーキテクチャでは、サービス呼び出しを異なるバージョンに送って結果を比較する。並列実行では、信頼できる情報源を選ぶことが重要で、特に顧客データなどが重複しないように慎重に扱う必要がある。
まとめ
マイクロサービスのデプロイに関する重要な原則の主なポイントは以下の通り
-
分離された実行
各マイクロサービスは独立して動作し、他のサービスに影響を与えないようにします。 -
自動化の重視
高度な自動化技術を採用し、インフラをコードとして管理する(IaC)ことで、環境の再作成を容易にし、情報共有を促進します。 -
停止時間のないデプロイ
マイクロサービスはユーザーに停止時間を与えずに新しいバージョンをデプロイできるようにします。 -
望ましい状態の維持
マイクロサービスは定義された状態を維持し、必要に応じて新しいインスタンスを起動します。 -
適切なプラットフォーム選択
PaaSやFaaSなどのプラットフォームを使用し、管理負担を減らします。 -
制御の手放し
自分が満足できる範囲で、システム管理の制御を他のプラットフォームに任せることが推奨されます。
また、マイクロサービスのコンテナ化やKubernetesの使用についても触れ、シンプルな解決策を選ぶことが大切。この分野は急速に進化しているため、これらの原則を理解し、適応する準備が重要。
Discussion