コンテナーとコンテナー オーケストレーターの活用

ヒント

このコンテンツは eBook の「Azure 向けクラウド ネイティブ .NET アプリケーションの設計」からの抜粋です。.NET Docs で閲覧できるほか、PDF として無料ダウンロードすると、オンラインで閲覧できます。

Cloud Native .NET apps for Azure eBook cover thumbnail.

コンテナーとオーケストレーターは、モノリシック デプロイ アプローチに共通する問題を解決するように設計されています。

モノリシック デプロイに関する課題

従来、ほとんどのアプリケーションは 1 つのユニットとしてデプロイされてきました。 このようなアプリケーションは、モノリスと呼ばれます。 図 3-1 に示すように、複数のモジュールやアセンブリで構成されている場合でも、アプリケーションを 1 つのユニットとしてデプロイする一般的なアプローチをモノリシック アーキテクチャと呼びます。

Monolithic architecture.

図 3-1. モノリシック アーキテクチャ。

モノリシック アーキテクチャには、シンプルであるという利点がある一方で、多くの課題があります。

デプロイ

さらに、アプリケーションの再起動が必要であり、デプロイ時にダウンタイムなしのテクノロジを適用しないと、一時的に可用性に影響する可能性があります。

スケーリング

モノリシック アプリケーションは、1 台のマシン インスタンス上で完全にホストされており、多くの場合、高機能なハードウェアが必要です。 モノリスの一部にスケーリングが必要になった場合、アプリケーション全体の別のコピーを別のマシンに展開する必要があります。 モノリスでは、アプリケーション コンポーネントを個別にスケーリングすることはできません。 スケーリングを必要としないコンポーネントをスケーリングすると、リソースの使用効率が低下し、コストがかかります。

環境

モノリシック アプリケーションは、通常、OS、ランタイム、ライブラリがプリインストールされたホスティング環境にデプロイされます。 この環境は、アプリケーションが開発またはテストされた環境とは異なる場合があります。 アプリケーション環境間の不整合は、モノリシック デプロイの一般的な問題の原因となります。

結合

モノリシック アプリケーションは、その機能コンポーネント間の結合度が高くなりがちです。 厳しい境界線がないと、システムの変更により、意図しないコストのかかる副作用が発生することがよくあります。 新しい機能や修正を実装するのは、厄介で時間がかかり、コストもかかります。 更新には広範なテストが必要です。 また、結合があると、コンポーネントのリファクターや代替実装での入れ替えも困難になります。 懸案事項を厳密に分離して構築したとしても、終わりのない "特殊なケース" でモノリシック コード ベースが劣化するため、アーキテクチャの侵食が起こります。

プラットフォームのロックイン

モノリシック アプリケーションは、1 つのテクノロジ スタックで構築されます。 統一性がある一方で、このこだわりがイノベーションの妨げになることもあります。 新しい機能とコンポーネントは、たとえ、より最新のテクノロジを使用した方が良い場合でも、アプリケーションの現行スタックを使用して構築されます。 さらに長期的なリスクとして、テクノロジ スタックが時代遅れになり、陳腐化することが挙げられます。 アプリケーション全体を新しい最新のプラットフォームに再構築するのは、最善を尽くしてもコストとリスクを伴います。

コンテナーとオーケストレーターの利点

第 1 章ではコンテナーを紹介しました。 Cloud Native Computing Foundation (CNCF) により、マイクロサービスのコンテナー化がクラウドネイティブ トレイル マップ (クラウドネイティブ体験を始める企業向けのガイダンス) の最初のステップと優先順位が付けられていることを取り上げました。 このセクションでは、コンテナーの利点について説明します。

Docker は、最も人気のあるコンテナー管理プラットフォームです。 Linux または Windows の両方のコンテナーで動作します。 コンテナーにより、どのシステムでも同じように動作する、分離していながら再現可能なアプリケーション環境を用意できます。 この側面があるので、クラウドネイティブ サービスの開発やホスティングに最適です。 コンテナーは互いに分離されています。 同じホスト ハードウェア上の 2 つのコンテナーは、ソフトウェアのバージョンが異なっていても、競合を引き起こすことはありません。

コンテナーは、プロジェクトの成果物となるシンプルなテキストベースのファイルで定義され、ソース管理にチェックインされます。 完全なサーバーと仮想マシンの更新には手作業が必要ですが、コンテナーは簡単にバージョン管理ができます。 コンテナーで実行するために構築されたアプリは、ビルド パイプラインの一部として自動化ツールを使用して開発、テスト、デプロイすることができます。

コンテナーは不変です。 一度コンテナーを定義すると、まったく同じ方法で再作成し、実行することができます。 この不変性は、コンポーネントベースの設計に適しています。 アプリケーションの一部が他の部分とは異なる方法で進化する場合、最も頻繁に変更される部分をデプロイすればよいのであれば、アプリ全体を再デプロイする必要はありません。 アプリの異なる機能や横断的な懸案事項は、別々のユニットに分割することができます。 図 3-2 は、モノリシック アプリが、特定の機能や特徴を委任することにより、コンテナーとマイクロサービスをどのように使用できるかを示しています。 アプリ自体の残りの機能もコンテナー化されています。

Breaking up a monolithic app to use microservices in the back end.

図 3-2. モノリシック アプリを分解してマイクロサービスを利用する。

クラウドネイティブ サービスは、個別のコンテナーに構築してデプロイします。 必要に応じてそれぞれを更新できます。 個々のサービスは、それぞれのサービスに適したリソースを持つノードでホストすることができます。 各サービスが実行される環境は不変であり、開発、テスト、運用の環境全体で共有し、簡単にバージョン管理できます。 アプリケーションの異なる領域間の結合は、モノリス内でのコンパイル時の依存関係ではなく、サービス間の呼び出しやメッセージとして明示的に行われます。 また、アプリの他の部分に変更を加えることなく、特定の機能に最適なテクノロジを選択することもできます。

コンテナー化されたサービスには、自動管理が必要です。 独立してデプロイされた膨大な数のコンテナーを手動で管理するのは不可能です。 たとえば、次のようなタスクについて考えてみましょう。

  • 多数のマシンで構成されるクラスター内で、コンテナー インスタンスをプロビジョニングするにはどうすればよいですか。
  • デプロイ後、コンテナーから相互を発見し、通信するにはどうすればよいですか。
  • オンデマンドでコンテナーをスケールインまたはスケールアウトするにはどうすればよいですか。
  • 各コンテナーの正常性を監視するにはどうすればよいですか。
  • ハードウェアとソフトウェアの障害からコンテナーを保護するにはどうすればよいですか。
  • ライブのアプリケーションのコンテナーをダウンタイムなしでアップグレードするにはどうすればよいですか。

コンテナー オーケストレーターを使用すると、このような懸案事項に対処し、自動化することができます。

クラウドネイティブ エコシステムでは、Kubernetes が事実上のコンテナー オーケストレーターになりました。 これは、Cloud Native Computing Foundation (CNCF) によって管理されるオープンソースのプラットフォームです。 Kubernetes を使用すると、マシン クラスター全体でコンテナー化されたワークロードのデプロイ、スケーリング、運用上の懸案事項を自動化できます。 ただし、Kubernetes のインストールと管理は非常に複雑です。

クラウド ベンダーのマネージド サービスとして Kubernetes を使用する方が、はるかに優れたアプローチです。 Azure クラウドには、Azure Kubernetes Service (AKS) というフル マネージド Kubernetes プラットフォームがあります。 AKS により、Kubernetes を管理するための複雑さや運用上のオーバーヘッドは抽象化されます。 ユーザーは Kubernetes をクラウド サービスとして使用し、その管理とサポートは Microsoft が担当します。 また、AKS は、他の Azure サービスや開発ツールと緊密に統合されています。

AKS はクラスターベースのテクノロジです。 フェデレーション仮想マシン (ノード) のプールが Azure クラウドにデプロイされます。 このようなノードを組み合わせることで、可用性の高い環境、つまりクラスターが形成されます。 クラウドネイティブ アプリケーションからは、クラスターはシームレスな 1 つのエンティティのように見えます。 内部的には、負荷を均等に分散する定義済みの戦略に従って、AKS により、コンテナー化されたサービスがこれらのノード全体にデプロイされます。

スケーリングの利点

コンテナー上に構築されたサービスからは、Kubernetes のようなオーケストレーション ツールによって提供されるスケーリングの利点を活用できます。 設計上、コンテナーによって認識されるのは、それ自体のみです。 複数のコンテナーを連携させる必要がある場合は、より高いレベルでそれらを整理する必要があります。 多数のコンテナーと、それらの共有される依存関係 (ネットワーク構成など) を整理するには、オーケストレーション ツールを利用すると時間を節約できます。 Kubernetes により、コンテナー グループに対して抽象化レイヤーが作成され、それらが "ポッド" に整理されます。 ポッドは、"ノード" と呼ばれるワーカー マシン上で実行されます。 この体系化された構造は "クラスター" と呼ばれます。 図 3-3 は、Kubernetes クラスターのさまざまなコンポーネントを示しています。

Kubernetes cluster components.図 3-3。 Kubernetes クラスターのコンポーネント。

コンテナー化されたワークロードのスケーリングは、コンテナー オーケストレーターの主要な機能です。 AKS は、コンテナー インスタンスとコンピューティング ノードという 2 つのディメンションにまたがる自動スケーリングをサポートしています。 これらを組み合わせることで、AKS で需要の急増に迅速かつ効率的に対応し、リソースを追加できるようになります。 AKS のスケーリングについては、この章で後ほど説明します。

宣言型と命令型

Kubernetes は、宣言型と命令型の両方の構成をサポートしています。 命令型のアプローチには、各手順の実行方法を Kubernetes に指示するさまざまなコマンドの実行が含まれています。 このイメージを実行する。 このポッドを削除する。 このポートを公開する。 宣言型のアプローチの場合、マニフェストと呼ばれる構成ファイルを作成し、何を実行するかではなく、何をしたいかを記述します。 Kubernetes により、マニフェストが読み込まれ、望ましい最終状態が実際の最終状態に変換されます。

命令型コマンドは、学習や対話型の実験に最適です。 それでも、Kubernetes のマニフェスト ファイルを宣言型で作成し、コードとしてのインフラストラクチャ アプローチを採用して、信頼性と反復可能なデプロイを実現したくなるものです。 マニフェスト ファイルはプロジェクトの成果物となり、Kubernetes のデプロイを自動化するための CI/CD パイプラインで使用されます。

既に命令型コマンドを使用してクラスターを構成している場合は、kubectl get svc SERVICENAME -o yaml > service.yaml を使用して宣言型マニフェストをエクスポートすることができます。 このコマンドを実行すると、次のようなマニフェストが生成されます。

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2019-09-13T13:58:47Z"
  labels:
    component: apiserver
    provider: kubernetes
  name: kubernetes
  namespace: default
  resourceVersion: "153"
  selfLink: /api/v1/namespaces/default/services/kubernetes
  uid: 9b1fac62-d62e-11e9-8968-00155d38010d
spec:
  clusterIP: 10.96.0.1
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 6443
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

宣言型構成を使用する場合、構成ファイルが置かれているフォルダーに対して kubectl diff -f FOLDERNAME を使用することで、コミットする前に変更内容をプレビューすることができます。 変更を適用することを確認したら、kubectl apply -f FOLDERNAME を実行します。 -R を追加すると、フォルダー階層を再帰的に処理できます。

また、宣言型構成を他の Kubernetes の機能と一緒に使用することもできます。その 1 つがデプロイです。 宣言型デプロイは、リリース、更新、スケーリングの管理に役立ちます。 宣言型デプロイにより、新しい変更のデプロイ、負荷のスケールアウト、以前のリビジョンへのロールバックなどの方法が Kubernetes のデプロイ コントローラーに指示されます。 クラスターが不安定な場合、宣言型デプロイによってクラスターは自動的に望ましい状態に戻されます。 たとえば、ノードがクラッシュした場合、デプロイ メカニズムによって代わりのノードが再デプロイされ、望ましい状態になります。

宣言型構成を使用すると、インフラストラクチャをアプリケーション コードと一緒にチェックインすることや、バージョン管理することができるコードとして表すことができます。 これにより、変更管理が改善され、ビルドとデプロイのパイプラインを使用した継続的配置のサポートが向上します。

コンテナーとオーケストレーターに最適なシナリオ

次のようなシナリオは、コンテナーとオーケストレーターを使用するのに最適です。

高いアップタイムとスケーラビリティを必要とするアプリケーション

個々のアプリケーションのアップタイムとスケーラビリティの要件が高い場合、マイクロサービス、コンテナー、およびオーケストレーター使用するクラウドネイティブ アーキテクチャに最適です。 これらをコンテナー内で開発し、バージョン管理された環境全体でテストし、ダウンタイムなしで運用環境にデプロイすることができます。 Kubernetes クラスターを使用することで、必要に応じてアプリをスケーリングし、ノードの障害から自動的に回復することができます。

多数のアプリケーション

多数のアプリケーションをデプロイし、管理する組織は、コンテナーとオーケストレーターの恩恵を受けます。 コンテナー化された環境や Kubernetes クラスターを設定するための先行作業は、主に固定費です。 個々のアプリケーションのデプロイ、保守、および更新にかかるコストは、アプリケーション数に応じて異なります。 アプリケーション数が少なくても、カスタム アプリケーションを手動で保守する複雑さは、コンテナーとオーケストレーターを使用したソリューションを実装するコストを上回ります。

コンテナーとオーケストレーターの使用を避けるべき場合

Twelve-Factor App (12 要素アプリ) の原則に従ってアプリを構築できない場合は、コンテナーとオーケストレーターの使用を避けることを検討する必要があります。 このような場合には、VM ベースのホスティング プラットフォーム、または何らかのハイブリッド システムを検討してください。 それがあれば、いつでも特定の機能の一部を個別のコンテナーまたはサーバーレス機能に切り離すことができます。

開発リソース

このセクションでは、次回のアプリケーションでコンテナーとオーケストレーターを使い始める場合に役立つ開発リソースの一覧を簡単に紹介します。 クラウドネイティブ マイクロサービス アーキテクチャのアプリケーションを設計する方法のガイダンスについては、本書の手引書である「.NET のマイクロサービス: コンテナー化された .NET アプリケーションのアーキテクチャ」を参照してください。

ローカル Kubernetes の開発

Kubernetes のデプロイは運用環境で本領を発揮しますが、開発マシンのローカルで実行することもできます。 個々のマイクロサービスを独立して開発することもできますが、運用環境にデプロイされたときと同じように、システム全体をローカルで実行しなければならない場合があります。 そのようなときに役立つツールがいくつかあります。Minikube と Docker Desktop です。 また、Visual Studio にも Docker 開発用のツールが用意されています。

Minikube

Minikube とは Minikube プロジェクトでは、"Minikube は macOS、Linux、Windows でローカルの Kubernetes クラスターを実装している" と述べています。主な目的は、"ローカル Kubernetes アプリケーションの開発に最適なツールであり、適合する Kubernetes 機能をすべてサポートする" ことです。Minikube のインストールは Docker とは分離されていますが、Minikube は Docker Desktop でサポートされるのとは異なるハイパーバイザーをサポートします。 現在、Minikube がサポートしている Kubernetes 機能は次のとおりです。

  • DNS
  • NodePorts
  • ConfigMaps とシークレット
  • ダッシュボード
  • コンテナー ランタイム: Docker、rkt、CRI、containerd
  • Container Network Interface (CNI) の有効化
  • イングレス

Minikube をインストールしたら、minikube start コマンドを実行してイメージをダウンロードし、ローカルの Kubernetes クラスターを起動することで、すぐに使い始めることができます。 クラスターが起動したら、標準の Kubernetes の kubectl コマンドを使用してクラスターを操作します。

Docker Desktop

Windows 上では、Docker Desktop から直接 Kubernetes を操作することもできます。 これは Windows コンテナーを使用している場合の唯一の選択肢であり、Windows 以外のコンテナーの場合にも素晴らしい選択肢です。 図 3-4 は、Docker Desktop の実行時にローカルの Kubernetes サポートを有効にする方法を示しています。

Configuring Kubernetes in Docker Desktop

図 3-4. Docker Desktop での Kubernetes の構成

Docker Desktop は、コンテナー化されたアプリをローカルで構成および実行するための最も一般的なツールです。 Docker Desktop を使用すると、運用環境にデプロイするのとまったく同じ Docker コンテナー イメージのセットに対してローカルで開発することができます。 Docker Desktop は、コンテナー化されたアプリをローカルで "構築、テスト、リリース" するために設計されています。 Linux と Windows の両方のコンテナーがサポートされています。 イメージを Azure Container Registry や Docker Hub などのイメージ レジストリにプッシュすると、AKS によりそれらがプルされ、運用環境にデプロイされます。

Visual Studio の Docker ツール

Visual Studio は、Web ベースのアプリケーションの Docker 開発をサポートしています。 新しい ASP.NET Core アプリケーションを作成する場合には、図 3-5 に示すように、Docker サポートを使用して構成する選択肢があります。

Visual Studio Enable Docker Support

図 3-5. Visual Studio で Docker サポートを有効にする

この選択肢を選ぶと、プロジェクトのルートに Dockerfile が作成されます。これを使用して、アプリをビルドして Docker コンテナーでホストすることができます。 図 3-6 に Dockerfile の例を示します。

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["eShopWeb/eShopWeb.csproj", "eShopWeb/"]
RUN dotnet restore "eShopWeb/eShopWeb.csproj"
COPY . .
WORKDIR "/src/eShopWeb"
RUN dotnet build "eShopWeb.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "eShopWeb.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "eShopWeb.dll"]

図 3-6. Visual Studio で生成された Dockerfile

サポートが追加されると、Visual Studio で Docker コンテナー内のアプリケーションを実行できるようになります。 図 3-7 は、Docker サポートを追加して作成した新しい ASP.NET Core プロジェクトから使用できるさまざまな実行オプションを示しています。

Visual Studio Docker Run Options

図 3-7. Visual Studio の Docker 実行オプション

また、いつでも既存の ASP.NET Core アプリケーションに Docker サポートを追加することができます。 図 3-8 に示すように、Visual Studio ソリューション エクスプローラーからプロジェクトを右クリックし、 [追加]>[Docker サポート] を選択します。

Visual Studio Add Docker Support

図 3-8. Visual Studio への Docker サポートの追加

Visual Studio Code の Docker ツール

Visual Studio Code には、Docker 開発をサポートする拡張機能が多く用意されています。

Microsoft は、Docker for Visual Studio Code 拡張機能を提供しています。 この拡張機能を使用すると、アプリケーションにコンテナー サポートを追加するプロセスが簡単になります。 必要なファイルがスキャフォールディングされ、Docker イメージがビルドされ、コンテナー内でアプリをデバッグできるようになります。 この拡張機能は、開始、停止、検査、削除など、コンテナーやイメージに対するアクションを簡単に実行できるビジュアル エクスプローラーを備えています。 また、Docker Compose にも対応しているので、実行中の複数のコンテナーを 1 つのユニットとして管理することができます。