Amazon Web Services ブログ

Open Application Model による、Kubernetes でのアプリケーションファーストデリバリー

この記事は、Napptive の CTO である Daniel Higuero 氏と共同執筆したものです。

イントロダクション

クラウドネイティブなアプリケーションの時代に、Kubernetes はコンテナオーケストレーションの分野における傑出したテクノロジーとして登場しました。しかしながら、Kubernetes を使う際には、クラスターの設定、クラスター全体のアドオン、補助するツールの実行や管理だけでなく、アプリケーションのデプロイに関わる設定 (Deployment、Service、Ingress, Horizontal Pod Autoscaling、LimitRange など) を理解することをユーザーに要求します。これはアプリケーションを実行するプラットフォームの構築に高い柔軟性をもたらす一方で、本番環境においてこういった設定を完全に把握し、プラットフォームを保守・実行することは簡単なタスクではありません。顧客の話によると、Kubernetes 上でアプリケーションのプラットフォームを構築・実行することに関連する懸念は、通常 1 つのチームに降りかかります。チームの名前は、誰に尋ねるかにもよっても異なるかもしれませんが、本記事ではチーム内のメンバーをプラットフォームエンジニアと呼びます。オペレーションモデルと責任 (言い換えると、自身でも運用するものを構築したり、他のユーザーが再利用できるテンプレートを作成する) は異なる場合がありますが、その目的は通常は同じで、社内の顧客やアプリケーション開発者が簡単に利用できるプラットフォームを構築することです。

アプリケーション開発者はエンドユーザーに価値を提供するビジネスロジックと機能の実装に責任がある一方で、必ずしも Kubernetes の一部始終 (Ingress オブジェクトの詳細を適切に設定する方法など) を理解しているわけではありません。できれば、これらのチームはアプリケーションを実行する最小限の設定のみを指定したいと考えています。具体的には、どのポートをリッスンするのか、どのコンテナイメージを使用するのか、アラームの設定にどのメトリクスとしきい値を使用するのか、といったものです。

これらのペルソナは、両方ともビルダーです。内部向け、あるいは外部向けの顧客に公開されるプロダクトを開発しています。本番環境においては、構築するものは安定していて時間の経過とともに顧客の期待を満たすために進化可能である必要があります。

ソリューション概要

双方向の組織的な依存関係の削減

アプリケーション開発者を支援する 1 つの方法は、抽象化を通じて組織標準を導入することです。難しいのは、これらの抽象化を正しくおこなうことです。Kubernetes はそれ自体がアプリケーション、リソース、ストレージ、コンピュートの抽象化をおこなう一方で、この抽象化は、プラットフォーム開発者とアプリケーション開発者の双方にとって効率的であるには低レベルであることが多いと考えられています。例を挙げることで、こういった論拠を発展させてみましょう。プラットフォームチームが Kubernetes API をそのまま顧客 (すなわち、アプリケーションチーム) に公開し、変更がロールアウトされる必要があるシナリオを想像してください。おそらく、Kubernetes の廃止予定の API 移行ガイドで説明されている Kubernetes v1.22 の Ingress オブジェクトの API グループの変更のような、新しい Kubernetes のバージョンと関係しているかもしれません。Ingress オブジェクトを例に挙げると、networking.k8s.io/v1beta1 API バージョンは Kubernetes 1.22 で廃止され、ユーザーは Ingress の定義を networking.k8s.io/v1 に変更する必要がありました。この変更により、プラットフォームチームと全ての顧客に依存関係が生じました。新しい API バージョンに沿うように設定を変更する必要があったからです。またこれは、プラットフォームチームが Kubernetes クラスターをアップグレードする前に、全ての顧客一人ひとりが新しいバージョンの API を使用する必要があることを意味しています。

このチーム間の双方向依存関係の例は、通常はプラットフォームチームとアプリケーションチームは一対多の関係であり、Kubernetes をアップグレードできないシナリオに繋がる可能性があります。Kubernetes のアップグレードが顧客のアプリケーションを壊すかもしれず、Kubernetes のバージョンのアップグレードが遅れるシナリオに陥り、サポートされているライフサイクル (Amazon EKS Kubernetes リリースバージョンカレンダーを参照) から外れ、重要なアップデートの取り込みが停止するリスクがありいます。

Platform as a Product

前述のシナリオのような課題を解決する 1 つの方法は、独自の抽象化のレイヤーを作成することです。これは、サービスの API を構築する場合と同じように考えることができます。その API は安定していて、小さく、使用している基盤となるデータベースエンジンについての詳細が漏れないようにしたがるでしょう。それは API を利用するユーザーの関心事ではないからです。所有するインタフェースを通じて明確に定義された設定の選択肢の小さなセットをアプリケーションチームに公開することで、基盤となる実装 (この場合は Kubernetes) の詳細を顧客に漏らすことなく、改善点や機能をより早く実装できます。先程の例を踏まえると、このようなプラットフォームの改善は、Service と Ingress を使ってサービスを公開する従来のアプローチから、Kubernetes Gateway API でのサービスの公開に移行することかもしれません。

Open Application Model (OAM)

前述の抽象化は様々な方法で実現できますが、この記事では、アプリケーションのコンポーネントをデプロイする構成の抽象化を標準化する方法として、Open Application Model (OAM) について説明します。これは抽象化のさらなる抽象化に少し似ているように聞こえるかもしれません。そうではありますが、これらの抽象化は、抽象化を利用するペルソナの目的を果たしていることを念頭に置いてください。Kubernetes は、プラットフォームを構築するプラットフォームエンジニアが、基盤となるインフラストラクチャリソースを使用するための抽象化のレイヤーとして機能し、OAM はプラットフォームエンジニアリングチームによって構築されたプラットフォームを使用するアプリケーション開発者向けの抽象化のレイヤーとして機能します。

OAM は、クラウドネイティブなアプリケーションを構築するためのオープンソースの仕様です。サービス、構成、依存関係を含む、アプリケーションのコンポーネントを宣言的に定義できます。OAM は、開発者が大幅な変更を加えることなく異なるプラットフォームのバージョンに簡単にデプロイ可能な、ポータブルなアプリケーションを作成することを可能にします。また、デプロイ・スケーリング・更新を含む、アプリケーションのライフサイクルを管理するためのフレームワークも提供します。OAM はその柔軟性と相互運用性により、クラウドでのモダンアプリケーション開発のための強力なツールとなっています。OAM の仕様は、必要に応じて新しいコンポーネントや機能を追加し拡張できるように設計されています。また OAM 仕様をサポートするどのプラットフォームでも使用できるという意味でも、非依存的です。このモデルでは、機能的な目的を達成するためにまとめてデプロイされるサービスの集合として、Application を定義します。

KubeVela

KubeVela は前述の Open Application Model を実装するオープンソースのプロジェクトです。Kubernetes 上でアプリケーションを構築・デプロイ・管理するためのデリバリープロセスとして定義されています。開発者がアプリケーションのコンポーネントとそれらの関係を宣言的な方法で定義することを可能にする高レベルのプログラミングモデルを提供します。KubeVela のモデル主導型アプローチは、Kubernetes に関連する複雑さを大きく取り除き、開発者がインフラストラクチャの管理ではなくコードを書くことに集中できるようにします。また KubeVela は、アプリケーションの複数のコンポーネントを統合し、ローリングアップデート・ロールバック・カナリアリリースを実行できる、強力なデプロイエンジンを提供します。KubeVela の柔軟性と使いやすさは、Kubernetes の深い専門知識を必要とせずに Kubernetes 上でクラウドネイティブなアプリケーションを構築したい開発者にとって、良い選択になります。

KubeVela の Application は、以下の要素で構成されています。

  • Components: アプリケーションの機能要素について記述します。通常はバックエンドのマイクロサービスと関連付けられます。異なる Component の type が、リクエストを受信するバックエンドサービスなどの長時間実行されるプロセスと、定期的なバックアップタスクなどの短時間で終了するプロセスの両方をサポートします。
  • Traits: Trait を Component に関連付けることで、Component の基礎となる機能を拡張または変更できます。例えば、Trait はコンポーネントのログを別のサブシステムにエクスポートしたり、コンポーネントをインターネットに公開する追加の要素を作成したり、コンポーネントを実行するための設定オプションを追加したりできます。Component には、必要に応じて多くの Trait を関連付けることができます。
  • Policies: Trait と同様に、すべての Component に影響するアプリケーションレベルの設定オプションを適用する方法を提供します。
  • Workflows: 開発者がアプリケーションのデプロイ方法を定義できるようにします。これにより、コンポーネントのデプロイから他のサービスとの通信まで、複数の type のアクションを可能にする個々のワークフローステップを利用できます。

以下の図は、KubeVela のドキュメントサイトから抜粋したものです。

ソース: https://kubevela.io/docs/getting-started/core-concept

このアプローチにより、プラットフォームチームは Pod・Ingress・インフラストラクチャコントローラーのリソース (AWS Controllers for KubernetesCrossplane) など、全てのコンポーネントの低レベルの設定を保持する抽象化のレイヤーを作成でき、アプリケーションチームはそれを利用できます。アプリケーションチームは、作成・アップグレード・削除を含むコンポーネントのライフサイクル全体を担当します。以下の図は、もっとも単純な抽象化を示しています。

プラットフォームチームは、Deployment 設定、Pod Topology Spread Constraints、Ingress、Service の設定 (プロトコルまたはその他のパラメータに基づく) 及びその他の Kubernetes オブジェクトの構成など、Kubernetes のドメイン固有の設定を担当します。アプリケーションチームは、アプリケーション全体を表すとても軽量な構成を作成することに責任を持ちます。KubeVela の Component と Trait の抽象化を用いるため、アプリケーションチームは Kubernetes オブジェクトとその構成を設計した経験が豊富である必要はありません。

以下のハンズオンの例からもわかるとおり、最小限の設定で 1 つのアプリケーションを作成すると、Ingress または Service、HPA (オートスケーリング用) および Deployment というオブジェクトが生成されます。Kubernetes におけるデプロイの内容について知らなくても実現可能です。

ウォークスルー

何を構築するのか?

OAM と Kubernetes の価値を実証するために、フロントエンドのコンポーネントとバックエンドのコンポーネントを組み合わせたサンプルアプリケーションを使用します。これらのサービスが合わさることで 1 つのアプリケーションを表します。アプリケーション開発者は Kubernetes について知る必要はありません。代わりに、KubeVela によって実装された、標準化された OAM モデルを使用できます。その結果、Kubernetes オブジェクトの設定 (Deployment、Ingress、ConfigMap など) はシンプルになります。アプリケーション開発者はこの OAM ベースのコンポーネントを使用して、アプリケーションを Kubernetes クラスターにデプロイします。

前提条件

始める前に、以下の前提条件を満たす必要があります。

このセクションでは、Amazon EKS で KubeVela を使用して OAM を実装するために必要なステップを示します。

KubeVela を用いて環境をブートストラップする

最初のステップとして、OAM を使用して Kubernetes にクラウドネイティブなアプリケーションを構築およびデプロイするためのオープンソースフレームワークである KubeVela をデプロイしてみましょう。以下のコマンドで示すように、Amazon EKS クラスターに KubeVela をインストールします。

helm repo add kubevela https://charts.kubevela.net/core
helm repo update
helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wait
Apache Configuration

これらのコマンドは vela-system という名前の新しい Namespace を作成し、Amazon EKS クラスターに最新バージョンの KubeVela をインストールします。インストールした後、KubeVela を用いて OAM アプリケーションを定義およびデプロイできます。KubeVela ダッシュボードを有効化したい場合は、以下のコマンドを使用できます。

# vela addon enable velaux
Apache Configuration

ダッシュボードにアクセスするには、以下のコマンドを使用します。

# kubectl port-forward svc/velaux-server 8000:8000 -n vela-system
Apache Configuration

ブラウザを操作し、以下のようにダッシュボードにアクセスします。管理者ロールのユーザーとパスワードを登録しセットアップします。

KubeVela によるアプリケーションのデプロイ

前述のとおり、アプリケーションは 2 つのマイクロサービスで構成されています。マイクロサービスをデプロイするために、アプリケーションチームはもはや Kubernetes の Deployment の設定を覚える必要はありません。ここで OAM が登場します。

複数の Kubernetes オブジェクトをデプロイする代わりに、アプリケーションを設定するための適切な知識を持っていさえすれば、開発者はアプリケーションの高レベルな抽象化を以下のように定義できます。

# cat <<EOF > app.yaml
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: web-app
spec:
  components:
  - name: frontend
    type: webservice
    properties:
      image: "public.ecr.aws/aws-containers/ecsdemo-frontend:latest"
      ports:
      - port: 3000
        expose: true
    traits:
    - type: cpuscaler
      properties:
        cpuUtil: 80
        max: 6
        min: 1
    - type: env
      properties:
        env:
          NODEJS_URL: "http://ecsdemo-nodejs.default.svc.cluster.local/"
  - name: backend
    type: webservice
    properties:
      image: "public.ecr.aws/aws-containers/ecsdemo-nodejs:latest"
      ports:
      - port: 8080
        expose: true
    traits:
    - type: scaler
      properties:
        replicas: 2
EOF
kubectl apply -f app.yaml       
Apache Configuration

Application マニフェストの構成について説明します。フロントエンドとバックエンドという 2 つの Component があります。これらの Component は type が webservice です。これは、KubeVela のインストールに付属するビルトインのコンポーネントタイプの 1 つです。組織の標準に沿った独自のコンポーネントの実装を作成することもできます。各 Component 内で、定義された Trait を確認できます。各 Trait には独自の実装があり、デモンストレーションを目的として、2 つの異なる Trait として、オートスケーリングと ENV Trait を使用しました。覚えておいて頂きたいのは、Component と Trait を組み合わせるこの方法は、Trait で定義される API に忠実に従う限り、メトリクスのバックエンドを別のものに切り替えるなど、Trait の基礎となる実装を後で変更または拡張できるようにするためであるということです。これには、Component と Trait を組み合わせる方法を変えることは含まれません。

KubeVela は作成する全てのオブジェクトにデフォルトの Label を付与するので、web-app Application の関連するオブジェクトを全て取得できます。ターミナルで以下のコマンドを実行して、アプリケーション用にどのようなオブジェクトが作成されたのかを調べてみましょう。

# kubectl get all --selector=app.oam.dev/name=web-app -L app.oam.dev/component
NAME                            READY   STATUS    RESTARTS   AGE     COMPONENT
pod/backend-6959d96ddc-4vnlc    1/1     Running   0          3d14h   backend
pod/backend-6959d96ddc-bmm4p    1/1     Running   0          3d14h   backend
pod/frontend-76877d4554-dzldt   1/1     Running   0          3d14h   frontend

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE     COMPONENT
service/backend    ClusterIP   10.100.148.2    <none>        8080/TCP   3d14h   backend
service/frontend   ClusterIP   10.100.171.75   <none>        3000/TCP   3d14h   frontend

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE     COMPONENT
deployment.apps/backend    2/2     2            2           3d14h   backend
deployment.apps/frontend   1/1     1            1           3d14h   frontend

NAME                                  DESIRED   CURRENT   READY   AGE     COMPONENT
replicaset.apps/backend-6959d96ddc    2         2         2       3d14h   backend
replicaset.apps/frontend-76877d4554   1         1         1       3d14h   frontend

NAME                                           REFERENCE             TARGETS         MINPODS   MAXPODS   REPLICAS   AGE     COMPONENT
horizontalpodautoscaler.autoscaling/frontend   Deployment/frontend   <unknown>/80%   1         6         1          3d14h   frontend
Apache Configuration

ご覧のとおり、Service が 2 つ、Deployment が 2 つ、Horizontal Pod Autoscaler が 1 つあります。

簡潔に言うと、各オブジェクトは app.oam.dev/component ラベルの値に基づいて特定の Component に関連付けられます。KubeVela と Open OAM は、プラットフォームチームがより高レベルな概念を作成し、それらを組み合わせてより高度な構造にすることを可能にします。その後、これらの構造をアプリケーションチームが使用できるようになります。

フロントエンドサービスへのポートフォワーディングを設定することで、アプリケーションが実行されていることをテストできます。

# kubectl port-forward svc/frontend 3000:3000
Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000
Apache Configuration

その後、ブラウザで http://localhost:3000 にアクセスして、アプリケーションが実行中であることを確認できます。

クリーンアップ

以下のコマンドを使用して、Application、Component、Trait をクリーンアップできます。

kubectl delete -f app.yaml  
Apache Configuration

オプションで、このドキュメントに従って作成された Amazon EKS クラスターを削除できます。

結論

本記事では、KubeVela を使って OAM を実装する方法を紹介しました。OAM は、Kubernetes 上でクラウドネイティブなアプリケーションを構築しデプロイするための標準化されたアプローチを提供します。OAM と KubeVela で抽象化をおこなうことで、開発者が Kubernetes でクラウドネイティブなアプリケーションを構築しデプロイするプロセスをシンプルにでき、開発者は顧客に価値を提供することに集中できます。

このブログ記事で紹介したコンセプトに興味がある場合は、ソーシャルメディア (Linkedin または Twitter) を使ってお気軽にご連絡ください。

翻訳はソリューションアーキテクトの後藤が担当しました。原文はこちらです。