Serverless KubernetesはPod単位の弾力性をサポートし、数秒以内の起動、秒単位の課金、1分あたり2,000 Podの起動といった利点があります。多くのユーザーがServerless Kubernetesを使用してArgoワークフローを実行しています。このトピックでは、エラスティックコンテナインスタンスを使用して、Alibaba Cloud Container Service for Kubernetes (ACK) クラスタでArgoワークフローを実行する方法について説明します。
KubernetesクラスタにArgoをデプロイする
ACK Serverlessクラスタを作成します。
(推奨) ACK Serverlessクラスタを作成します。詳細については、ACK Serverlessクラスタの作成を参照してください。
ACKクラスタを作成し、クラスタにack-virtual-nodeコントローラをデプロイして仮想ノードを生成します。詳細については、ACKマネージドクラスタの作成と仮想ノードコントローラをデプロイし、それを使用してElastic Container InstanceベースのPodを作成するを参照してください。
KubernetesクラスタにArgoをデプロイします。
(推奨) ack-workflowコンポーネントをインストールします。詳細については、ack-workflowを参照してください。
コンポーネントを使用せずにArgoをデプロイします。詳細については、Argoクイックスタートを参照してください。
Argoコマンドをインストールします。詳細については、argo-workflowsを参照してください。
インフラストラクチャ構成を最適化する
デフォルトでは、KubernetesクラスタにArgoをデプロイした後、argo-serverコアコンポーネントとworkflow-controllerコアコンポーネントに対応するPodのリソースは指定されていません。対応するPodのサービス品質(QoS)レベルは低いです。クラスタリソースが不足している場合、コンポーネントでOOM (メモリ不足) killが発生し、Podがエビクトされる可能性があります。クラスタサイズに基づいて、前述のコアコンポーネントに対応するPodのリソースを調整することをお勧めします。また、requestsまたはlimitsを2 vCPUと4 GiB以上のメモリに設定することをお勧めします。
OSSバケットをアーティファクトリポジトリとして使用する
デフォルトでは、ArgoはMinIOをアーティファクトリポジトリとして使用します。本番環境では、アーティファクトリポジトリの安定性を考慮する必要があります。 ack-workflowを使用すると、オブジェクトストレージサービス(OSS)バケットをアーティファクトリポジトリとして使用できます。 OSSバケットをアーティファクトリポジトリとして構成する方法については、Alibaba Cloud OSSの構成を参照してください。
OSSを構成した後、次の例に基づいてワークフローを作成して構成を検証できます。
workflow-oss.yamlという名前のファイルを作成し、次のテンプレートをファイルにコピーします。
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: artifact-passing- spec: entrypoint: artifact-example templates: - name: artifact-example steps: - - name: generate-artifact template: whalesay - - name: consume-artifact template: print-message arguments: artifacts: # bind message to the hello-art artifact # generated by the generate-artifact step - name: message from: "{{steps.generate-artifact.outputs.artifacts.hello-art}}" - name: whalesay container: image: docker/whalesay:latest command: [sh, -c] args: ["cowsay hello world | tee /tmp/hello_world.txt"] outputs: artifacts: # generate hello-art artifact from /tmp/hello_world.txt # artifacts can be directories along with files - name: hello-art path: /tmp/hello_world.txt - name: print-message inputs: artifacts: # unpack the message input artifact # and put it at /tmp/message - name: message path: /tmp/message container: image: alpine:latest command: [sh, -c] args: ["cat /tmp/message"]
ワークフローを作成します。
argo -n argo submit workflow-oss.yaml
ワークフローの実行結果を表示します。
argo -n argo list
期待される出力:
エグゼキュータを選択する
Argoによって作成されたワーカーPodには、少なくとも次のコンテナが含まれています。
メインコンテナ
ビジネスロジックを実行するビジネスコンテナ。
待機コンテナ
サイドカーとしてPodに挿入されるArgoシステムコンポーネント。待機コンテナには、次のコア特性があります。
Podの起動段階
メインコンテナが依存するアーティファクトと入力をロードします。
Podの実行段階
メインコンテナが終了するのを待ち、関連するサイドカーコンテナを強制終了します。
メインコンテナの出力とアーティファクトを収集し、メインコンテナのステータスを報告します。
待機コンテナは、エグゼキュータを使用してメインコンテナにアクセスし、管理します。 Argoは、エグゼキュータをContainerRuntimeExecutorに抽象化します。次のリストは、ContainerRuntimeExecutorのAPI操作について説明しています。
GetFileContents:outputs/parametersを使用してメインコンテナの出力パラメータを取得します。
CopyFile:outputs/artifactsを使用してメインコンテナの出力を取得します。
GetOutputStream:メインコンテナの標準出力(標準エラーを含む)を取得します。
Wait:メインコンテナが終了するのを待ちます。
Kill:関連するサイドカーコンテナを強制終了します。
ListContainerNames:Pod内のコンテナの名前を一覧表示します。
Argoは、動作原理は異なりますが、ネイティブKubernetesアーキテクチャで動作するように設計された複数のエグゼキュータをサポートしています。 ACK Serverlessのアーキテクチャは、ネイティブKubernetesのアーキテクチャとは異なります。 ACK ServerlessクラスタでArgoワークフローを実行するには、適切なエグゼキュータを選択する必要があります。 ACK ServerlessクラスタでArgoワークフローを実行するには、エグゼキュータとしてEmisarryを選択することをお勧めします。次の表は、ネイティブKubernetesクラスタでサポートされているエグゼキュータについて説明しています。
エグゼキュータ | 説明 |
Emisarry | エグゼキュータは、共有emptyDirファイルとemptyDirを依存関係として使用して、関連する機能を構成します。 エグゼキュータは標準機能emptyDirのみに依存し、他の依存関係はありません。 ACK ServerlessクラスタでArgoワークフローを実行するには、このエグゼキュータを使用することをお勧めします。 |
Kubernetes API | エグゼキュータは、Kubernetes APIを使用して関連する機能を構成します。エグゼキュータはKubernetes APIを依存関係として使用しますが、完全な機能を提供することはできません。 クラスタに多数のタスクが含まれている場合、エグゼキュータはKubernetesコントロールプレーンに負荷をかけます。これはクラスタサイズに影響します。エグゼキュータを使用しないことをお勧めします。 |
PNS | エグゼキュータは、PodのchrootとPID (プロセス識別)共有に基づいて関連する機能を構成します。エグゼキュータはPodのプロセス空間を汚染し、特権を必要とします。 ACK Serverlessクラスタは、より厳格なセキュリティ分離を必要とし、特権をサポートしていません。これらのクラスタはエグゼキュータをサポートしていません。 |
Docker | エグゼキュータは、Docker CLIを使用して関連する機能を構成し、基盤となるコンテナランタイムDockerを依存関係として使用します。 ACK Serverlessクラスタには実際のノードが含まれておらず、仮想ノードのDockerコンポーネントにアクセスできません。これらのクラスタはエグゼキュータを使用できません。 |
Kubelet | エグゼキュータは、Kubelet Client APIを使用して関連する機能を構成し、Kubernetesの基盤となるコンポーネントKubeletを依存関係として使用します。 ACK Serverlessクラスタには実際のノードが含まれておらず、仮想ノードのKubeletコンポーネントにアクセスできません。これらのクラスタはエグゼキュータを使用できません。 |
Elastic Container Instanceで実行するようにArgoタスクをスケジュールする
デフォルトでは、ACK ServerlessクラスタはすべてのPodをElastic Container Instanceで実行するようにスケジュールします。これらのクラスタに追加の構成を実行する必要はありません。 ACKクラスタでPodをElastic Container Instanceで実行するようにスケジュールする場合は、ACKクラスタを構成する必要があります。詳細については、x86ベースの仮想ノードにPodをスケジュールするを参照してください。
次の例では、ラベルを追加してACKクラスタを構成します。
alibabacloud.com/eci: "true"
ラベルを追加します。ラベルが追加されると、ラベルが付いたPodは自動的にElastic Container Instanceで実行するようにスケジュールされます。(オプション)
{"schedulerName": "eci-scheduler"}
を指定します。この設定を使用することをお勧めします。 Virtual Kubeletを更新または変更すると、webhookが短時間利用できなくなる可能性があります。この設定を使用すると、Podは実際のノードにスケジュールされません。
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: parallelism-limit1-
spec:
entrypoint: parallelism-limit1
parallelism: 10
podSpecPatch: '{"schedulerName": "eci-scheduler"}' # PodをElastic Container Instanceで実行するようにスケジュールします。
podMetadata:
labels:
alibabacloud.com/eci: "true" # ラベルを追加して、PodをElastic Container Instanceで実行するようにスケジュールします。
templates:
- name: parallelism-limit1
steps:
- - name: sleep
template: sleep
withSequence:
start: "1"
end: "10"
- name: sleep
container:
image: alpine:latest
command: ["sh", "-c", "sleep 30"]
Pod作成の成功率を向上させる
本番環境では、Argoワークフローに複数のコンピューティングPodが含まれている場合があります。ワークフロー内のPodが失敗すると、ワークフロー全体が失敗します。 Argoワークフローの成功率が低い場合は、Argoワークフローを複数回実行する必要があります。これは、タスクの実行効率に影響し、Argoワークフローの計算コストを増加させます。 Pod作成の成功率を向上させるには、次の対策を講じる必要があります。
Argoワークフローを定義する
Elastic Container Instance Podを作成する
単一ゾーンのリソース不足が原因で発生するPod作成の失敗を防ぐために、複数のゾーンを構成します。詳細については、複数ゾーンにPodをデプロイするを参照してください。
単一仕様のリソース不足が原因で発生するPod作成の失敗を防ぐために、複数の仕様を指定します。詳細については、複数の仕様を指定してPodを作成するを参照してください。
vCPUとメモリ仕様を指定する方法を使用してPodを作成します。システムは、インベントリに基づいて仕様を自動的に一致させます。
2 vCPUと4 GiB以上のメモリ仕様を指定します。これらの仕様のインスタンスは、安定したパフォーマンスを提供できる専用のエンタープライズレベルインスタンスです。
Podの作成に失敗した場合にPodを再作成するかどうかを指定するために、Podの障害処理ポリシーを構成します。詳細については、Podの障害処理ポリシーを構成するを参照してください。
サンプル構成:
eci-profileを変更して複数のゾーンを構成します。
kubectl edit -n kube-system cm eci-profile
data
セクションのvSwitchIds
の値として複数のvSwitch IDを指定します。data: ...... vSwitchIds: vsw-2ze23nqzig8inprou****,vsw-2ze94pjtfuj9vaymf**** # 複数のvSwitch IDを指定して複数のゾーンを構成します。 vpcId: vpc-2zeghwzptn5zii0w7**** ......
Podを作成するときに複数のポリシーを使用して成功率を向上させます。
k8s.aliyun.com/eci-use-specs
アノテーションを使用して複数の仕様を指定します。この例では、3つの仕様が指定されています。システムは、ecs.c6.large
、ecs.c5.large
、2-4Gi
のインベントリリソースを順番に一致させます。k8s.aliyun.com/eci-schedule-strategy
アノテーションを使用して、マルチゾーンスケジューリングポリシーを構成します。この例では、VSwitchRandom
スケジューリングポリシーを使用して、Podをランダムなゾーンにスケジュールします。retryStrategy
パラメータを使用して、Argoワークフローの再試行ポリシーを構成します。この例では、Always
値を指定して、失敗したすべての手順を再試行します。k8s.aliyun.com/eci-fail-strategy
アノテーションを使用して、Podの障害処理ポリシーを構成します。この例では、fail-fast
値は迅速な失敗を指定します。 Podの作成に失敗すると、システムはエラーを報告します。 ProviderFailedがPodのステータスとして表示されます。上位層のオーケストレーションは、Podの作成を再試行するか、Podを実際のノードにスケジュールするかを決定します。
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: parallelism-limit1- spec: entrypoint: parallelism-limit1 parallelism: 10 podSpecPatch: '{"schedulerName": "eci-scheduler"}' podMetadata: labels: alibabacloud.com/eci: "true" annotations: k8s.aliyun.com/eci-use-specs: "ecs.c6.large,ecs.c5.large,2-4Gi" k8s.aliyun.com/eci-schedule-strategy: "VSwitchRandom" k8s.aliyun.com/eci-fail-strategy: "fail-fast" templates: - name: parallelism-limit1 steps: - - name: sleep template: sleep withSequence: start: "1" end: "10" - name: sleep retryStrategy: limit: "3" retryPolicy: "Always" container: image: alpine:latest command: [sh, -c, "sleep 30"]
Podのコストを最適化する
Elastic Container Instanceは複数の課金方法をサポートしています。計算リソースのコストを削減するために、さまざまな課金方法に基づいてワークロードを計画できます。
Podのコストを最適化する方法については、以下を参照してください。
Podの作成を高速化する
Podが起動する前に、システムは指定されたコンテナイメージをプルする必要があります。イメージのプルは、ネットワークの状態やイメージのサイズなどの要因により、Podの起動時に長時間かかる主な操作です。Podの作成を高速化するために、Elastic Container Instanceはイメージキャッシュ機能を提供します。イメージのキャッシュを作成できます。その後、イメージキャッシュを使用してPodを作成できます。こうすることで、イメージレイヤーをダウンロードする必要がなくなったり、ダウンロードするイメージレイヤーの数を減らすことができます。これにより、Podの作成が高速化されます。
イメージキャッシュは、次のタイプに分類されます。
自動的に作成されたイメージキャッシュ:デフォルトでは、Elastic Container Instance Podに対してイメージキャッシュの自動作成が有効になっています。Elastic Container Instance Podを作成するときに完全に一致するイメージがない場合、システムはPodに対応するイメージを自動的に使用してイメージキャッシュを作成します。
手動で作成されたイメージキャッシュ:カスタムリソース定義(CRD)を使用してイメージキャッシュを作成できます。
並列度の高いArgoタスクを実行する前に、手動でイメージキャッシュを作成することをお勧めします。イメージキャッシュを作成した後、イメージキャッシュを指定し、PodのイメージプルポリシーをIfNotPresentに設定します。こうすることで、Podは起動時にイメージをプルする必要がなくなります。これにより、Podの作成が高速化され、Argoタスクの実行時間が短縮され、実行コストが削減されます。詳細については、ImageCacheを使用してPodの作成を高速化するを参照してください。
「Elastic Container Instanceで実行するようにArgoタスクをスケジュールする」セクションまたは「Podの作成の成功率を向上させる」セクションで前述の操作を実行した場合、イメージキャッシュが作成されます。Elastic Container Instanceコンソールにログインして、イメージキャッシュの状態を確認できます。次のYAMLテンプレートを使用して、既存のイメージキャッシュを含むワークフローを作成し、Podの起動速度をテストできます。
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: parallelism-limit1-
spec:
entrypoint: parallelism-limit1
parallelism: 100
podSpecPatch: '{"schedulerName": "eci-scheduler"}'
podMetadata:
labels:
alibabacloud.com/eci: "true"
annotations:
k8s.aliyun.com/eci-use-specs: "ecs.c6.large,ecs.c5.large,2-4Gi"
k8s.aliyun.com/eci-schedule-strategy: "VSwitchRandom"
k8s.aliyun.com/eci-fail-strategy: "fail-fast"
templates:
- name: parallelism-limit1
steps:
- - name: sleep
template: sleep
withSequence:
start: "1"
end: "100"
- name: sleep
retryStrategy:
limit: "3"
retryPolicy: "Always"
container:
imagePullPolicy: IfNotPresent
image: alpine:latest
command: [sh, -c, "sleep 30"]
ワークフローが作成された後、ワークフローのPodイベントで、一致するイメージキャッシュのIDを確認できます。Podの起動時に、イメージのプルプロセスはスキップされます。
Podの作成を高速化する
Argo は AI 推論分野で使用されています。AI ベースのシナリオでは、コンピューティングタスクは大容量のデータへのアクセスを必要とします。一般的なコンピューティングストレージ分離アーキテクチャでは、コンピューティングノードへのデータロードの効率が、タスク全体の時間とコストに直接影響します。多数の Argo タスクがストレージ内のデータに並行してアクセスする必要がある場合、ストレージシステムの帯域幅とパフォーマンスのボトルネック問題が発生します。たとえば、Argo タスクが OSS のデータを並行してロードし、OSS バケットの帯域幅にボトルネック問題が発生した場合、Argo タスクのコンピューティングノードはデータロードフェーズでブロックされます。各コンピューティングノードはより長い時間が必要になります。これはコンピューティング効率に影響を与え、コンピューティングコストを増加させます。
この問題を解決するには、Fluid を使用できます。バッチコンピューティングタスクを実行する前に、Fluid データセットを作成してプリロードし、OSS のデータを少数のキャッシュノードにプリキャッシュできます。その後、Argo タスクを同時に開始できます。Fluid では、Argo はキャッシュノードからデータを読み取ります。キャッシュノードは OSS の帯域幅を拡張し、コンピューティングノードのデータ読み込み効率を向上させることができます。これにより、Argo タスクの実行効率が向上し、Argo タスクの実行コストが削減されます。詳細については、Fluid の概要を参照してください。
次の例では、100 個の同時タスクが設定され、10 GB のテストファイルを OSS からロードし、MD5 ハッシュを計算します。
Fluid をデプロイします。
ACK コンソールにログインします。
左側のナビゲーションペインで、マーケットプレイス > マーケットプレイスを選択します。
ack-fluidを見つけて、対応するカードをクリックします。
ack-fluidページで、デプロイをクリックします。
表示されたパネルで、Fluid をデプロイするクラスターを選択し、パラメーターを設定して、OK をクリックします。
Fluid がデプロイされると、ack-fluidコンポーネントの公開詳細ページにリダイレクトされます。Helmページに戻ります。ack-fluid コンポーネントが「デプロイ済み」状態になっていることがわかります。 kubectl コマンドを実行して、Fluid がデプロイされているかどうかを確認することもできます。
テスト用のデータを準備します。
Fluid をデプロイした後、Fluid データセットを使用してデータを高速化できます。後続の操作を実行する前に、10 GB のテストファイルを OSS バケットにアップロードする必要があります。
テストファイルを生成します。
dd if=/dev/zero of=/test.dat bs=1G count=10
テストファイルを OSS バケットにアップロードします。詳細については、シンプルアップロードを参照してください。
高速化データセットを作成します。
データセットと JindoRuntime を作成します。
kubectl -n argo apply -f dataset.yaml
次のサンプルコードは、dataset.yaml ファイルの例を示しています。YAML ファイルの AccessKey ペアと OSS バケットに実際の値を指定します。
apiVersion: v1 kind: Secret metadata: name: access-key stringData: fs.oss.accessKeyId: *************** # OSSバケットへのアクセスに使用するAccessKey ID。 fs.oss.accessKeySecret: ****************** # OSSバケットへのアクセスに使用するAccessKeyシークレット。 --- apiVersion: data.fluid.io/v1alpha1 kind: Dataset metadata: name: serverless-data spec: mounts: - mountPoint: oss://oss-bucket-name/ # OSSバケットのパス。 name: demo path: / options: fs.oss.endpoint: oss-cn-shanghai-internal.aliyuncs.com # OSSバケットのエンドポイント。 encryptOptions: - name: fs.oss.accessKeyId valueFrom: secretKeyRef: name: access-key key: fs.oss.accessKeyId - name: fs.oss.accessKeySecret valueFrom: secretKeyRef: name: access-key key: fs.oss.accessKeySecret --- apiVersion: data.fluid.io/v1alpha1 kind: JindoRuntime metadata: name: serverless-data spec: replicas: 10 # 作成するJindoRuntimeキャッシュノードの数。 podMetadata: annotations: k8s.aliyun.com/eci-use-specs: ecs.g6.2xlarge # ポッドの仕様を指定します。 k8s.aliyun.com/eci-image-cache: "true" labels: alibabacloud.com/eci: "true" worker: podMetadata: annotations: k8s.aliyun.com/eci-use-specs: ecs.g6.2xlarge # ポッドの仕様を指定します。 tieredstore: levels: -mediumtype: MEM # キャッシュの種類。ローカルディスクを使用する仕様を指定する場合は、この値をLoadRaid0にすることができます。 volumeType: emptyDir path: /local-storage # キャッシュのパス。 quota: 12Gi # キャッシュの最大容量。 high: "0.99" # ストレージ容量の上限。 low: "0.99" # ストレージ容量の下限。
説明この例では、Elastic Container Instance ポッドのメモリがキャッシュノードとして使用されます。各 Elastic Container Instance ポッドは、専用の VPC ネットワークインターフェースコントローラー (NIC) を使用します。各ポッドの帯域幅は、他のポッドの影響を受けません。
結果を表示します。
高速化データセットのステータスを確認します。PHASE の値が Bound の場合、高速化データセットが作成されています。
kubectl -n argo get dataset
予想される出力:
ポッドに関する情報を確認します。高速化データセットを使用して、10 個の JindoRuntime キャッシュノードが作成されます。
kubectl -n argo get pods
予想される出力:
データをプリロードします。
高速化データセットが作成された後、DataLoad を作成してデータのプリロードをトリガーできます。
DataLoad を作成してデータのプリロードをトリガーします。
kubectl -n argo apply -f dataload.yaml
次のサンプルコードは、dataload.yaml ファイルの例を示しています。
apiVersion: data.fluid.io/v1alpha1 kind: DataLoad metadata: name: serverless-data-warmup namespace: argo spec: dataset: name: serverless-data namespace: argo loadMetadata: true
DataLoad でデータのプリロードの進行状況を確認します。
kubectl -n argo get dataload
次の図は、出力例を示しています。テストファイルのサイズは 10 GB ですが、プリロード速度は高速です。
Argo ワークフローを実行します。
データがプリロードされた後、Argo タスクを同時に実行できます。Argo ワークフローをテストするには、イメージキャッシュ機能を Fluid と一緒に使用することをお勧めします。
Argo ワークフローの argo-test.yaml 構成ファイルを準備します。
次のサンプルコードは、argo-test.yaml ファイルの例を示しています。
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: parallelism-fluid- spec: entrypoint: parallelism-fluid parallelism: 100 podSpecPatch: '{"terminationGracePeriodSeconds": 0, "schedulerName": "eci-scheduler"}' podMetadata: labels: alibabacloud.com/fluid-sidecar-target: eci alibabacloud.com/eci: "true" annotations: k8s.aliyun.com/eci-use-specs: 8-16Gi templates: - name: parallelism-fluid steps: - - name: domd5sum template: md5sum withSequence: start: "1" end: "100" - name: md5sum container: imagePullPolicy: IfNotPresent image: alpine:latest command: ["sh", "-c", "cp /data/test.dat /test.dat && md5sum test.dat"] volumeMounts: - name: data-vol mountPath: /data volumes: - name: data-vol persistentVolumeClaim: claimName: serverless-data
Argo ワークフローを作成します。
argo -n argo submit argo-test.yaml
ワークフローの実行結果を表示します。
argo -n argo list
予想される出力:
kubectl get pod -n argo --watch
コマンドを実行して、タスクの実行状況を表示します。サンプルシナリオの 100 個の Argo タスクは、2 ~ 4 分以内に完了します。同じ Argo タスクセットに Fluid を使用しない場合、10 GB のテストファイルを OSS からロードして MD5 ハッシュを計算するには 14 ~ 15 分かかります。
テスト結果は、Fluid が計算効率を向上させ、計算コストを削減できることを示しています。