Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PFCP の概要

Preferred Computing Platform™(PFCP™)は、Preferred Networks が構築・運用する深層学習・AI ワークロード向けのクラウドサービスです。独自開発したアクセラレータ MN-Core™ シリーズを唯一利用でき、高い AI 計算力と計算効率を実現できます。

強力な計算ボードと高速なネットワーク

MN-Core 2 ボードを 8 基搭載した MN-Server 2 V1 サーバを複数専有して利用できます。 すべてのノードは深層学習に最適化された高速なネットワークで相互に接続されています。

MN-Server 2 と MN-Core 2

フルマネージドサービス

深層学習・AI ワークロード向けに拡張された Kubernetes クラスタ1をマルチテナントで利用できます。 大規模分散学習から推論サーバの高可用な運用まで幅広く機械学習ワークロードを実行できます。 ワークロードの状況を観測するためのマネージドなモニタリングサービス2も付随しています。

そのほかの特徴

  • ユーザの権限管理、ネットワーク ACL の制御が柔軟に行えます
  • 高信頼な永続ストレージを使用してデータを保存できます
  • 多くの Kubernetes カスタムアドオンが追加されており、AI ワークロードの実行や監視をすぐに始められます
  • コマンドラインツールを用いて、PFCP が提供するコンテナイメージを使用して任意のワークロード設定ファイルから実行できます
    • ユーザが管理するコンテナイメージを持ち込んでの利用も可能です
  • パブリッククラウドとの連携をサポートし、強い権限を持つ鍵を使用せずにパブリッククラウドのリソースを安全に利用できます

  1. Kubernetes は、Cloud Native Computing Foundation(CNCF)にホストされたオープンソースのコンテナオーケストレーションプラットフォームです。コンテナ化されたアプリケーションの展開、スケーリング、可用性の管理を自動化するためのツールで、この分野の標準として広く採用されています。

  2. Grafana、Prometheus、Alertmanager といったオープンソースのツールで構成されています。

用語集

PFCP で使用される用語について説明します。

組織

PFCP を利用する際に必要であり、Kubernetes クラスタの利用、ポータルの利用、認証認可などのベースとなるリソースです。 一般的にテナントと呼称されるものに相当します1

PFCP を利用するには、利用したい組織から招待される必要があります。 また、Kubernetes クラスタやポータルなどの PFCP リソースを操作するときは、組織の選択が必要です。

1 つの組織で PFCP の複数クラスタが利用可能であり、複数の Namespace を作成できます。 Namespace 単位で権限分離・ネットワーク隔離も可能です。 このため、利用するリージョンごと・利用する用途ごとに、組織を細かく分割する必要はありません。

ルートネームスペース・サブネームスペース

PFCP では、各組織ごとに Namespace が 1 つ提供され、追加の Namespace はその Namespace に従属する Namespace として作成されます。 前者をルートネームスペース、後者をサブネームスペースと呼びます。 PFCP のネームスペースの詳細については、Namespace でクラスタを論理的に分割する をご確認ください。

ルートネームスペースとサブネームスペースは標準の Kubernetes クラスタにはない、PFCP 独自の用語です。 ルートネームスペースとサブネームスペースとでは仕様や扱い方が異なるため、区別する必要がある場合はこれらの呼称を使用しています。 一方で、Kubernetes の Namespace リソース全般にあてはまる記述であり、ルートネームスペースとサブネームスペースのどちらであるかを区別する必要がない場合は、 Namespace を使用しています。

ユーザロール(組織管理者・一般ユーザ)

PFCP には、組織管理者・一般ユーザの 2 種類のロールが定義されています。 ロールの詳細や利用できる操作については、PFCP のロール をご確認ください。

一方、Kubernetes には RBAC2 を実現するために Role/ClusterRole リソースがあります。 PFCP でも標準の ClusterRole3 が提供されていますが、この ClusterRole と PFCP のユーザロールは一対一でマッピングされません4。 組織管理者が RoleBinding を作成することで、Namespace ごとにマッピングを変更できます。

一般ユーザのユーザを個別に対象とする RoleBinding を作成することも、ユーザをグループにまとめ、グループを対象に RoleBinding を作成することも可能です。

RoleBinding の詳細については、 ユーザのクラスタアクセス権限を管理する をご確認ください。 ユーザ管理の詳細については、 組織のユーザを管理する をご確認ください。

モニタリングサービス

PFCP でマネージドサービスとして提供している、Grafana、Prometheus、Alertmanager の総称です。

Identity-Aware Proxy(IAP)

PFCP で提供している、ワークロードをインターネットに公開するための仕組みです。 アクセス時の認証が自動で設定されるため、ワークロードを安全に公開できます。

認証方式の違いにより API Identity-Aware Proxy(API IAP)と WebApp Identity-Aware Proxy(WebApp IAP)の 2 つに分かれています。 詳細な使い方は ワークロードをウェブ API として公開する または ワークロードをウェブアプリとして公開する を参照してください。


  1. Google Cloud のプロジェクト、Amazon Web Service のアカウントとも近い概念です。

  2. Role Based Access Control

  3. org-adminorg-editorg-view の 3 つが提供されています。

  4. 組織管理者に限り、ルートネームスペースとすべてのサブネームスペースで org-admin にマッピングされます。

PFCP リリースノート

2025年7月

  • PFCP: ワークロードをウェブ API として公開する "API Identity-Aware Proxy" 機能が利用可能になりました(ドキュメント

2025年6月

2025年5月

  • Kubernetes: 共有ノード用に shared-standardshared-best-effort の 2 つの PriorityClass が追加されました(ドキュメント
  • PFCP: PFCP ポータルからワークスペースを作成する際に Pod の PriorityClass が選択可能になりました

2025年4月

  • MN-Core: MN-Core SDK v0.2 がリリースされました(更新内容はコンテナイメージ内の /opt/pfn/pfcomp/RELEASE_NOTES.md をご参照ください)
  • Kubernetes: 新しい計算ノードの種類として「共有ノード」が利用可能になりました(ドキュメント
  • Kubernetes: ワークスペース内の PersistentVolume を残したまま計算リソースを節約する「ワークスペース休止」機能が利用可能になりました(ドキュメント

2025年3月

  • PFCP: PFCP ポータルにおいて PFCP 提供コンテナイメージの一覧が閲覧可能になりました(ドキュメント

2025年2月

  • Kubernetes: ブラウザから使えるインタラクティブな作業環境を提供する「ワークスペース」機能が利用可能になりました(ドキュメント
  • Kubernetes: 全拠点の全てのクラスタで Kubernetes v1.31 へのアップグレードを実施しました(ドキュメント
  • Kubernetes: 組織管理者が Kubernetes Role リソースの操作が可能になりました(ドキュメント

2024年12月

  • Kubernetes: PFCP ポータルにおいて組織で利用可能な専有ノードの一覧が閲覧可能になりました
  • PFCP: 組織に属するユーザをグループにまとめる「ユーザグループ」機能が利用可能になりました(ドキュメント

2024年11月

  • Kubernetes: 全拠点の全てのクラスタにおいて GitOps ツールの Flux が利用可能になりました(ドキュメント

2024年10月

  • Kubernetes: SR1-01 クラスタの永続化ストレージにおいて同一組織内の Namespace であればファイルストレージが共有できるようになりました(ドキュメント

2024年9月

2024年6月

2024年4月

メンテナンスポリシ

計画メンテナンスおよび緊急メンテナンスのポリシについて説明します。

定期メンテナンスのポリシ

PFCP では信頼性を維持するために定期的な計画メンテナンスを実施します。

項目内容
実施日毎月第一月曜日
実施日の告知実施予定の1か月前まで
(第一月曜日から変更がある場合のみ告知)
実施内容の告知実施日の2週間前まで
(メンテナンスを実施する場合のみ告知)

Kubernetes バージョンのアップグレードのポリシ

Kubernetes クラスタの安定性、パフォーマンス、セキュリティの向上を目的にマイナーバージョンアップグレードを定期的に実施しています。

項目内容
実施頻度4ヶ月毎
採用するバージョン最新のマイナーバージョンから1つ前のマイナーバージョン
(例: 最新が v1.30 の場合、採用するバージョンは v1.29)
実施日の告知定期メンテナンスの実施内容として告知

アップグレードおよびその他メンテナンスのクラスタとワークロードへの影響

クラスタアップグレードなどの計算ノードの一時的な停止を伴うメンテナンスのユーザ影響を説明します。

クラスタと計算ノードへの影響

  • クラスタの操作が一時的に不安定になります
  • ユーザ割り当ての専有ノードのうち、アップグレード実施中の計算ノードが一時的に使用できなくなります
    • 専有ノードの契約台数が 4 台未満の場合は 1 台ずつ、4 台以上の場合は最大 25%(小数切り捨て)が一時的に使用できなくなります
    • 1 台のみ契約されている場合は一時的に利用できるノードがなくなります
  • 共有ノードは 25%(小数切り捨て)が一時的に使用できなくなります

ワークロードへの影響

  • 計算ノードのアップグレード実施に伴い該当ノードで実行中のワークロード(Kubernetes Pod)は削除されます
  • 削除されたワークロードは、再スケジューリングポリシに基づき、別の計算ノードまたは同ノードで自動的に再作成されます
    • Deployment や Job などの上位リソースを使わずにユーザにより直接作成された Pod(Bare Pod)は自動的に再作成されません
    • 直接 Pod リソースを作成することは避けることを推奨します

データ保持に関する注意点

  • ワークロードが保持するデータのうち、永続ストレージに保存されていないデータは失われることに注意してください
    • ローカルメモリ上のデータ、一時的なファイルシステム上のデータなど
  • 永続ストレージに保存されているデータは保持されます

計算ノードのメンテナンス実施に備えて推奨される対応

  • 計算結果や生成物などの重要なデータは必ず永続ストレージに保存してください
  • ワークロードがステートフルな場合は、データの永続化および復旧手順を十分に検討・準備してください

重要

メンテナンスや障害以外にもあらゆる理由でワークロード、プロセスは停止します。重要なデータは必ず永続ストレージに保存してください。

緊急メンテナンスのポリシ

サービスの提供継続が困難またはセキュリティ上の重大な脆弱性が発見されたなどの理由から予定されていないメンテナンスを実施することがあります。 クラスタおよび計算ノード、ワークロードに影響がある場合には事前に実施内容を告知します。

計算ノードの障害復旧ポリシ

計算ノードで障害が発生した場合の復旧ポリシについて説明します。

計算ノードの障害

計算ノードが正常に動作していないと判断した場合に障害が発生したとして復旧対応を実施します。下記は正常に動作していないと判断する一例です。

  • 計算ノードが搭載するデバイスの一部が機能していない
  • 計算ノードとの通信が確立できない

計算ノードの障害復旧ポリシ

計算ノードで障害が発生したと判断した場合には下記のポリシに基づき復旧対応を実施します。

  • ユーザへの事前の告知なしに該当計算ノード上のワークロード(Kubernetes Pod)を削除し、計算ノードを再起動します
    • 削除されたワークロードは、再スケジューリングポリシに基づき、別の計算ノードまたは同ノードで自動的に再作成されます
      • Deployment や Job などの上位リソースを使わずにユーザにより直接作成された Pod(Bare Pod)は自動的に再作成されません
      • 直接 Pod リソースを作成することは避けることを推奨します
  • 専有ノードの場合に再起動で復旧が見込めない場合には代替の計算ノードとの入れ替えを行います

計算ノードの障害に備えて推奨される対応

  • 計算結果や生成物などの重要なデータは必ず永続ストレージに保存してください
  • ワークロードがステートフルな場合は、データの永続化および復旧手順を十分に検討・準備してください

重要

メンテナンスや障害以外にもあらゆる理由でワークロード、プロセスは停止します。重要なデータは必ず永続ストレージに保存してください。

PFCP チュートリアル: ワークロードをデプロイする

このページでは、クラスタを使用してサーバのワークロードのデプロイを行い、モニタリングサービスの使用方法を学びます。

事前準備

左カラム「クラスタに接続する」の手順を実行して下記を完了してください。

  1. PFCP ポータルにログインできている
  2. クラスタへの接続が構成できている

Namespace の作成

本チュートリアルで使用する Namespace1 を作成します。

Info

Namespace の作成には「組織管理者」の権限が必要です。「一般ユーザ」の権限では Namespace の作成に失敗します。

一般ユーザでの操作の場合は、組織の組織管理者に対して Namespace の作成を依頼してください。

  1. ポータルのネームスペースにアクセスします。

  2. ネームスペースの作成 画面を開きます。

    • クラスタ名: 利用するクラスタを選択
    • ネームスペース名: org-<組織名>--<任意の値> 2
  3. 作成 ボタンをクリックすると、Namespace が作成されます。

  4. kubectl コマンド実行時のデフォルトの Namespace として、作成した Namespace を設定します。

    $ kubectl config set-context --current --namespace=<作成したNamespace名>
    
  5. Namespace が作成されていること、設定が正しいことを確認します。 kubectl get pod を実行してください。エラーが出なければ正しく設定されています。エラーが出力された場合は、Namespace が存在することを確認のうえ、実行コマンドが正しいかを再度確認してください。

    // 正しく設定されている場合
    $ kubectl get pod
    No resources found in <作成したNamespace名> namespace.
    
    // 設定に誤りがある場合
    $ kubectl get pod
    Error from server (Forbidden): pods is forbidden: User "oidc:org-<組織名>/<ユーザ名>" cannot list resource "pods" in API group "" in the namespace "<作成したNamespace名>"
    

ワークロードのデプロイ

PFCP の Kubernetes クラスタを用いて、サンプルの Pod を実行します3。 加えて、作成した Pod をインターネットに対して公開し、ブラウザからアクセスできることを確認します。

なお、サンプルのコンテナイメージとして podinfo を使用しています。

  1. 以下のコマンドを実行し、podinfo を実行する Deployment を作成します。

    $ kubectl create deployment podinfo --image=stefanprodan/podinfo --port=9898
    deployment.apps/podinfo created
    
  2. Pod の起動を確認します。

    $ kubectl get pod
    NAME                       READY   STATUS    RESTARTS   AGE
    podinfo-554c877494-p58gf   1/1     Running   0          25s
    
  3. 次に、起動した Pod を公開するための Service を作成します。

    $ cat << EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: podinfo
      name: podinfo
    spec:
      ports:
      - name: http
        port: 8080
        protocol: TCP
        targetPort: 9898
      selector:
        app: podinfo
    EOF
    service/podinfo created
    
    $ kubectl get service
    NAME      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    podinfo   ClusterIP   10.100.212.250   <none>        8080/TCP   77s
    
  4. 作成された Service をインターネット公開するために、Ingress を作成します。

    $ HOST=podinfo-<任意の名前>.<組織名>.sr1-01.ingress.pfcomputing.com
    $ kubectl create ingress podinfo-ingress --class=nginx --rule="${HOST}/*=podinfo:8080"
    ingress.networking.k8s.io/podinfo-ingress created
    
    $ kubectl get ingress
    NAME              CLASS   HOSTS          ...
    podinfo-ingress   nginx   <HOSTと同じ値>   ...
    
  5. ブラウザから https://<HOSTと同じ値> にアクセスします。podinfo の画面が表示されたら成功です。

モニタリングの確認

PFCP では、Grafana と Prometheus がマネージドサービスとして提供されています。 これらを使用して、作成した Pod のリソース仕様状況を確認します。

  1. Grafana のダッシュボードにアクセスします。ポータルのトップページ に表示されているリンクからアクセスできます。

  2. 左上のハンバーガーアイコンから Dashboards > kube-prometheus > Kubernetes / Compute Resources / Pod と辿ることで、Pod のリソース使用状況を確認できます。 Namespace 及び Pod 名は適切なものをプルダウンで選択します。以下のような画面が確認できます。

    GrafanaでPodのリソース使用状況を確認

  3. Pod で計装されているメトリックについても、Prometheus による収集と Grafana による可視化が可能です。 例として、上記で作成した podinfo Pod のメトリック4を収集します。

    以下のServiceMonitorカスタムリソースを作成します。

    $ cat << EOF | kubectl apply -f -
    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      name: podinfo
    spec:
      selector:
        matchLabels:
          app: podinfo
      endpoints:
      - interval: 30s
        port: http
        path: /metrics
    EOF
    servicemonitor.monitoring.coreos.com/podinfo created
    
  4. podinfo のスクレイプに成功し、メトリックの収集ができていることを確認します。 Prometheus の WebUI にアクセスし、 上部のタブから Status > Targets を選択します。 <作成したNamespace名>/podinfo/0 がターゲット一覧に表示され、ステータスが Up になっていれば、正しくスクレイプできています。

    Prometheusでターゲットの追加確認

  5. 収集したメトリックは、Grafana で可視化できます。 Grafana のダッシュボードを開き、左上のハンバーガーアイコンから Explore を選択します。 例として以下の PromQL クエリを実行すると、 /metrics endpoint がコールされた回数が時系列表示されます。

    sum by (pod) (rate(promhttp_metric_handler_requests_total{namespace="<作成したNamespace>", job="podinfo"}[$__rate_interval]))
    

    Grafanaで、Podのメトリックを可視化


  1. 作成した Namespace は、PFCP ではサブネームスペースとして扱われます。詳しくは 用語集 をご確認ください。

  2. 作成済の Namespace と異なる接尾辞をつける必要があります。複数人でチュートリアルを実施する場合は、ユーザ名の使用を推奨します。

  3. ワークロード実行の詳細については、公式ドキュメント をご確認ください。

  4. podinfoは、 /metrics でPrometheus用のメトリックを提供しています。

PFCP チュートリアル: MN-Core を PyTorch から使用する

このドキュメントでは、MLSDK(Machine Learning Software Development Kit)を使用して MN-Core を活用する方法について説明します。

後方互換性に関する注意

MLSDK は現在不安定であり,将来のアップデートでは下位互換性がなくなったり、重大な変更が導入される可能性もあります。 特定のバージョンの MLSDK を使用する場合は、コンテナイメージを適宜修正してください。

MLSDKとは

MLSDK は、PyTorch から MN-Core を使用できるようにするためのコンパイラ、ランタイムソフトウェアスタック、ドキュメントを含むソフトウェア開発環境です。 名前に「Machine Learning」とありますが、機械学習分野以外の高速な計算処理を行うソフトウェアの開発にも使用できます。

環境構築

MLSDK はコンテナイメージとして配布されます。

最新バージョンの MLSDK(registry.pfcomputing.internal/mncore-sdk/mncore-sdk-full:latest)のコンテナイメージを使用して、MN-Core 2 を 1 つ搭載した Pod を起動してください。 次のマニフェストをmanifest.yaml として保存してください。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mlsdk-tutorial
spec:
  selector:
    matchLabels:
      app: mlsdk-tutorial
  template:
    metadata:
      labels:
        app: mlsdk-tutorial
    spec:
      containers:
      - name: app
        image: registry.pfcomputing.internal/mncore-sdk/mncore-sdk-full:latest
        workingDir: /root
        ports:
        - containerPort: 8888
        command: ["sleep", "infinity"]
        resources:
          limits:
            # MN-Core 2 を複数利用する場合は "1" を "4" などに置き換えてください。
            preferred.jp/mncore2: "1"
            memory: 240Gi
          requests:
            memory: 80Gi

以下のコマンドで Deployment を作成し、Pod が起動するのを待ちます。

kubectl apply -f manifest.yaml

Pod が起動したら、以下のコマンドを実行すると、上で構成した Pod にアクセスできます。

kubectl exec -it deployment/mlsdk-tutorial -- /bin/bash

Pod が適切に構成されたら、次のコマンド gpfn3-smi list を使用して、Pod 内の接続された MN-Core 2 を表示できます。

$ gpfn3-smi list
0: mnc2p28s0

数字「0」は Pod 内の MN-Core 2 デバイスのデバイスインデックスを表し、「mnc2」で始まる文字列は Pod 内のデバイス ID です。

何も表示されない場合は、Pod の構成に間違いがないかどうか再確認して、もう一度お試しください。

MLSDK チュートリアルを開始する

MLSDK で MN-Core を使用する (英語) を参照してチュートリアルを開始します。

MLSDK チュートリアルのドキュメントは、コンテナイメージ内部にも保持されています(/opt/pfn/pfcomp/codegen/MLSDK/README.md)。

クリーンアップ

作成したリソースは、以下のコマンドで削除してください。

kubectl delete -f manifest.yaml

PFCP チュートリアル: クラウドストレージのデータをクラスタに取り込む

このページでは、クラウドストレージにあるデータを PFCP に持ち込むための手順を解説します。

ここでは一例として、ユーザが管理する AWS S3 に保存されているデータを PFCP 上の Persistent Volume にコピーします。

事前準備

左カラム「クラスタに接続する」の手順を実行して下記を完了してください。

  1. PFCP ポータルにログインできている
  2. クラスタへの接続が構成できている

また、AWS アカウントと、データを同期させる対象の S3 バケットが必要です1

パブリッククラウドと ID 連携を構成し、データをコピーする

AWS 側の設定

ここでは sr1-01 拠点を利用している場合の設定を説明します。他の拠点を利用している場合はドメイン名等を適宜読み替えてください。

  1. アクセスしたい AWS アカウント内に OIDC プロバイダを作成します2

    • プロバイダー URL
      • SR1-01 クラスタ: https://token.sr1-01.kubernetes.pfcomputing.com
    • 許可するオーディエンス: sts.amazonaws.com
  2. AWS へのアクセスに使用する IAM ロールを作成します。この IAM ロールは、ID 連携により Kubernetes ServiceAccount に紐づけて使用します。 ここでは data-transfer-sr1-01 という IAM ロールを作成します。

  3. ID 連携による紐づけを許可するために、IAM ロールを引き受けさせる Kubernetes ServiceAccount を指定して、以下のような信頼ポリシを構成します3。 ServiceAccount は、既存のものを指定するか、後ほど新たに作成します。ここでは data-transfer-sa という ServiceAccount を作成します。

    {
        "Version": "2012-10-17",
        "Statement": [{
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                // 前のステップで作成した oidc provider の ARN を指定します。
                "Federated": "arn:aws:iam::{aws_account_id}:oidc-provider/token.sr1-01.kubernetes.pfcomputing.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    // このIAMロールを引き受けさせる Kubernetes ServiceAccount 名を指定します。
                    "token.sr1-01.kubernetes.pfcomputing.com:sub": "system:serviceaccount:<namespace>:data-transfer-sa"
                }
            }
        }]
    }
    
  4. 転送したいデータを含んだ S3 のバケットに、特定の IAM ロールからアクセス可能にするポリシを設定します4

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "AWS": "arn:aws:iam::{aws_account_id}:role/data-transfer-sr1-01"
          },
          "Action": [
            "s3:ListBucket",
            "s3:GetObject",
          ],
          "Resource": [
            "arn:aws:s3:::example-bucket",
            "arn:aws:s3:::example-bucket/*"
          ]
        }
      ]
    }
    

Kubernetes クラスタ側の操作

  1. ServiceAccount を作成します。データコピーに利用する ServiceAccount の annotations に、S3 のバケットにアクセス可能な AWS IAM ロール data-transfer-sr1-01 を指定します。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: data-transfer-sa
      annotations:
        aws.id-federation.preferred.jp/role-arn: "arn:aws:iam::{aws_account_id}:role/data-transfer-sr1-01"
    
  2. ID 連携が正常に動作していることを確認します。Pod を作成する際に、 spec.serviceAccountName にこの ServiceAccount を指定します。 Pod には 1 時間が有効期限である AWS のセッショントークンが自動的に設定されます。有効期限が到来すると、AWS SDK は更新されたトークンを自動で読み込み直します。 aws sts get-caller-identity コマンドを実行し、セッショントークンが ServiceAccount に紐づいた AWS IAM Role へ AssumeRole できることを確認します。

    $ kubectl run --rm --overrides='{"spec":{"serviceAccountName": "data-transfer-sa"}}' id-federation-check --image=amazon/aws-cli -- sts get-caller-identity
      {
          "UserId": "***********************:botocore-session-1751604047",
          "Account": "{aws_account_id}",
          "Arn": "arn:aws:sts::{aws_account_id}:assumed-role/data-transfer-sr1-01/botocore-session-1751604047"
      }
    
  3. データを格納するための永続ストレージ(Persistent Volume Claim、 PVC)を作成します5

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: data-transfer-pvc
    spec:
      resources:
        requests:
          storage: 10Gi
      storageClassName: standard-rwx-<組織名>
    
  4. AWS CLI のs3 syncコマンドでデータをコピーする Job を作成します。 上記で作成した PVC をマウントし、template.spec.serviceAccountName に、 AWS との ID 連携を有効にした data-transfer-sa を指定します。 <バケット名><オブジェクト名>は適切に変更してください。

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: data-transfer-job
    spec:
      template:
        spec:
          serviceAccountName: data-transfer-sa # ID 連携を構成した ServiceAccount を指定
          containers:
          - name: transfer
            image: amazon/aws-cli
            command: ["aws"]
            args: ["s3", "sync", "s3://<バケット名>/<オブジェクト名>", "/mnt/data"]
            volumeMounts:
            - mountPath: "/mnt/data"
              name: my-volume
          volumes:
          - name: my-volume
            persistentVolumeClaim:
              claimName: data-transfer-pvc
          restartPolicy: OnFailure
    

    kubectl logs job/data-transger-job を実行し、コマンドが正常に終了していることを確認します。

    $ kubectl logs job/data-transger-job
        download: s3://<バケット名>/file1.txt to /mnt/data/file1.txt
        ...
        Completed 10 of 10 file(s), 100% done.
    

クリーンアップ

チュートリアルで作成したリソースをすべて削除します。

kubectl delete job/data-transfer-job
kubectl delete pvc/data-transfer-pvc
kubectl delete serviceaccount/data-transfer-sa

必要に応じて、 AWS 側のリソースも削除します。


  1. Amazon S3 の開始方法

  2. IAM で OpenID Connect (OIDC) ID プロバイダーを作成する - AWS Identity and Access Management

  3. OpenID Connect フェデレーション用のロールを作成する

  4. Amazon S3 のポリシーとアクセス許可

  5. ファイルストレージを使用する

Info

This document is based on registry.pfcomputing.internal/mncore-sdk/mncore-sdk-minimal:v0.2.


How to Use MN-Core with MLSDK

In this document, we explain how to use MN-Core using MLSDK (Machine Learning Software Development Kit).

What is MLSDK?

MLSDK is a software development kit that includes a compiler, runtime software stack, and documentation to enable using MN-Core from PyTorch. Although it is called "Machine Learning," it can also be used for applications other than the machine learning field, as long as they are written with PyTorch.

Prerequisites

The followings are assumed in this document.

  • You are a user of
    • PFCP (Preferred Computing Platform)
  • You have a basic knowledge of the followings:
    • Pytorch
    • Kubernetes

Notes on the Backward Compatibility

MLSDK is currently unstable, and there may be future updates that will not be backward compatible; Breaking changes are likely to be introduced.

If you want to use the same version of MLSDK, please modify the container image accordingly.

MLSDK Images

MLSDK is distributed as container images at Amazon ECR repository, registry.pfcomputing.internal/mncore-sdk. We provide two types of images as of Jan 2025: registry.pfcomputing.internal/mncore-sdk/mncore-sdk-minimal and registry.pfcomputing.internal/mncore-sdk/mncore-sdk-full. The former is a minimal image that contains only libraries, executables, and scripts that are mandatory to run MN-Core 1/2. The latter is a fatter image that is built on the top of the minimal image, with the standard development tools (e.g., gcc, binutils, make, cmake, ...) and the development environments (e.g., JupyterLab).

We provide two types of tag series for the minimal and full images. One tag type is "release", which is a stable version of MLSDK, published roughly once every three months. The other tag type is "snapshot", which delivers the latest development branch (that may not be mature) to users for trial purposes. The release tag follows the vYY.MM format (e.g., v24.12 for a Dec 2024 release), and the snapshot tag follows the snapshot_YYYYMMDD_githash (e.g., snapshot_20241201_0123456789abcdef). In addition to the aforementioned tags that immutably correspond to a unique image, we also provide latest and snapshot_latest tags to allow users to obtain the latest image for each series.

Launching an MLSDK Container

If you are new to PFCP and want to launch a kubernetes pod (a collection of running containers) with access to MN-Core 1/2 devices, the tutorial in the PFCP documentation is a good starting point.

Once a pod is properly configured, you can use the command gpfn3-smi list (see the following example) to display the connected MN-Core 2 devices within the pod. The number 0 represents the device index of the MN-Core 2 device within the pod, and the string starting with mnc2 is the device ID within the pod. If nothing is displayed, it indicates that there may be an issue with the pod configuration. Please double-check the configuration and try again.

$ gpfn3-smi list
0: mnc2p28s0

How to use MLSDK API

From here, we explain how to run existing applications on MN-Core devices using the Python API (MLSDK API) included in MLSDK with several examples. The API reference is [../build/MLSDK/docs/index.txt](raw text version) or [../build/MLSDK/docs/html/index.html](HTML version).

First, we start with an example of running a pure function on MN-Core. Then, we demonstrate how to run a inference with a pretrained model. Finally, we introduce an example of model training.

Notes on Running Examples

You can locate all examples shown in this document in the MLSDK directory, where this README.md exists. In addition, you can run any command that starts with $ as is.

Notes on Environment Variable Settings

You need to set several environment variables to use the MLSDK API. To set these variables, we recommend that you use the shell scripts /opt/pfn/pfcomp/codegen/build/codegen_preloads.sh and /opt/pfn/pfcomp/codegen/build/codegen_pythonpath.sh. You are advised to write a shell script that loads these two files and then executes any given python script like the following:

#! /bin/bash

set -eux -o pipefail

source /opt/pfn/pfcomp/codegen/build/codegen_preloads.sh
source /opt/pfn/pfcomp/codegen/build/codegen_pythonpath.sh

exec "$@"

In this tutorial, we refer the shell script as exec_with_env.sh.

The MLSDK directory can be found at /opt/pfn/pfcomp/codegen/MLSDK/ in the image. Move to the directory before following the examples below.

Example: Running a Pure Function on MN-Core

First, let's go through an example of running a pure function, meaning the function has no state, on MN-Core.

Save the following code as add.py:

import torch
from mlsdk import CacheOptions, Context, MNDevice, storage


def run_add():
    device = MNDevice("mncore2:0")
    context = Context(device)
    Context.switch_context(context)

    def add(input: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]:
        x = input["x"]
        y = input["y"]
        return {"out": x + y}

    sample = {"x": torch.randn(3, 4), "y": torch.randn(3, 4)}

    compiled_add = context.compile(
        add,
        sample,
        storage.path("/tmp/add_two_tensors"),
        name="add",
        cache_options=CacheOptions("/tmp/add_two_tensors_cache"),
    )
    result = compiled_add({"x": torch.ones(3, 4), "y": torch.ones(3, 4)})
    result_on_cpu = result["out"].cpu()
    print(f"{result_on_cpu=}")
    assert torch.allclose(result_on_cpu, torch.ones(3, 4) * 2)


if __name__ == "__main__":
    run_add()

And type the following command to run it! You should see the result of the computation done on MN-Core 2.

$ ./examples/exec_with_env.sh python3 examples/add.py
...
result_on_cpu=tensor([[2., 2., 2., 2.],
        [2., 2., 2., 2.],
        [2., 2., 2., 2.]])

The MLSDK API enables the use of MN-Core through a concept called "context." A context is an object used to control and manage the MN-Core device. You can create a context like the following:

device = mlsdk.MNDevice("mncore2:0")
context = Context(device)

In the code above, "mncore2:0" specifies that the context will use the MN-Core 2 device of index 0. If there are multiple MN-Core 2 devices in a pod, you can specify "mncore2:1", "mncore2:2", and so on to use the second, third, and subsequent MN-Core 2 devices, respectively.

To run a program on MN-Core, you need to compile a Python function into a function that runs on the MN-Core device using the compile method of the context. It takes three positional arguments and returns a compiled function.

The first argument is the function to be compiled. The function should have the type of Callable[[dict[str, torch.Tensor]], dict[str, torch.Tensor]].

The second argument is an input example that is passed to the function being compiled. As mentioned later, the compiled function returned by compile always expects inputs with the same shape. Therefore, a dummy input is required to specify the input shape.

The third argument is the directory to store intermediate and final compile artifacts, serialized as binary files. This directory is referred to as the "codegen directory". The files generated in the codegen directory are extremely useful for debugging and profiling. There is a tool called "codegen-dashboard", which is described later, to visualize the information in the codegen directory.

The keyword argument name="add" is not required, but we set this for later explanations. See the section of codegen-dashboard.

The keyword argument cache_options=CacheOptions("/tmp/add_two_tensors_cache") enables caching of the exported ONNX graph and the compilation results of MLSDK, which will be stored in "/tmp/add_two_tensors_cache".

Note that you can port and reuse compiled functions with the caching feature. For example, you can compile a function with the cache_options argument and copy/move the cache directory to a different place, and then reuse the pre-compiled function by passing the cache_options argument so that it refers to the ported cache directory.

The returned value by compile is a function with the type Callable[[dict[str, TensorLike]], dict[str, TensorLike]]. TensorLike is an alias for Union[torch.Tensor, TensorProxy]. TensorProxy is an object that represents a torch.Tensor on the device managed by the context or on the host memory. If you call the .cpu() method on a TensorProxy, it returns torch.Tensor that holds the content of the TensorProxy.

The function returned by compile always expects inputs with the same shape. In other words, the arguments passed to the function must always have the same keys, and the value of torch.Tensor that corresponds to each key must always have the same shape.

Example: Running Inference with a Trained Model

Next, let's go through an example of running inference with a trained model. Save the following code as infer.py.

import torch
from mlsdk import Context, MNDevice, set_tensor_name_in_module, storage


def run_infer():
    device = MNDevice("mncore2:0")
    context = Context(device)
    Context.switch_context(context)

    model = torch.nn.Linear(4, 4)
    model.eval()
    set_tensor_name_in_module(model, "model")
    for p in model.parameters():
        context.register_param(p)
    for b in model.buffers():
        context.register_buffer(b)

    def infer(input: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]:
        x = input["x"]
        y = model(x)
        return {"out": y}

    sample = {"x": torch.randn(4, 4)}

    compiled_infer = context.compile(
        infer,
        sample,
        storage.path("/tmp/infer"),
    )
    result = compiled_infer({"x": torch.ones(4, 4)})
    result_on_cpu = result["out"].cpu()
    print(result_on_cpu)


if __name__ == "__main__":
    run_infer()

Then, running ./examples/exec_with_env.sh python3 examples/infer.py will perform inference using the pretrained model (model = torch.nn.Linear(4, 4)). Let's do this.

$ ./examples/exec_with_env.sh python3 examples/infer.py
...
# Because the model weight is initialized randomly, you will see a different result.
tensor([[-0.4468, -0.2559,  0.0939,  0.8574],
        [-0.4468, -0.2559,  0.0939,  0.8574],
        [-0.4468, -0.2559,  0.0939,  0.8574],
        [-0.4468, -0.2559,  0.0939,  0.8574]])

In this example, we introduce new APIs in addition to the ones used in add.py.

  • set_tensor_name_in_module(model, "model")
  • context.register_param(p)
  • context.register_buffer(b)

The first one is relatively simple. set_tensor_name_in_module sets names for all tensors in a given torch.nn.Model. You can get the set name using get_tensor_name function.

context.register_param and context.register_buffer registers a given tensor with a given name. After registration, you can synchronize registered tensors between PyTorch side and MN-Core side by calling synchronize. The usage of synchronize is explained in the next section.

Example: Training a Model

Finally, let's go through an example of training a model.

import torch
from mlsdk import (
    Context,
    MNCoreMomentumSGD,
    MNDevice,
    set_buffer_name_in_optimizer,
    set_tensor_name_in_module,
    storage,
)


def run_train():
    class Model(torch.nn.Module):
        def __init__(self):
            super().__init__()
            self.linear = torch.nn.Linear(10, 1)

        def forward(self, *, x):
            return {"y": self.linear(x)}

    device = MNDevice("mncore2:0")
    context = Context(device)
    Context.switch_context(context)

    sample = {"x": torch.ones(1, 10)}
    model = Model()
    model.linear.weight.data.fill_(1.0)
    model.linear.bias.data.fill_(1.0)
    model.train()

    set_tensor_name_in_module(model, "model")
    for p in model.parameters():
        context.register_param(p)
    for b in model.buffers():
        context.register_buffer(b)

    optimizer = MNCoreMomentumSGD(model.parameters(), 0.1, 0, 0.9, 1.0)
    set_buffer_name_in_optimizer(optimizer, "optim0")
    context.register_optimizer_buffers(optimizer)

    def f(inp):
        optimizer.zero_grad()
        loss = torch.relu(model(**inp)["y"]).sum()
        loss.backward()  # type: ignore[no-untyped-call]
        optimizer.step()
        return {"loss": loss}

    compiled_f = context.compile(
        f,
        sample,
        storage.path("/tmp/train"),
    )

    print(f"Original {model.linear.bias=}")
    for _ in range(10):
        compiled_f(sample)
    context.synchronize()
    print(f"Optimized {model.linear.bias=}")


if __name__ == "__main__":
    run_train()

Let's run this example. You can see the model parameters are changed by the optimizer.

In this example, we use a new API synchronize(). It synchronizes tensors on MN-Core DRAM and PyTorch tensors. After calling the function, you can check the optimized parameters in your program.

$ ./examples/exec_with_env.sh python3 examples/train.py
...
Original model.linear.bias=Parameter containing:
tensor([0.9000], requires_grad=True)
Optimized model.linear.bias=Parameter containing:
tensor([-2.0413], requires_grad=True)

How to Port Your Workload to MN-Core 2

Running Your Workload Using pfvm:cpu

Before running your workload on MN-Core 2, we highly recommend running it on pfvm:cpu first. With this backend, you can ensure that your code can be converted to ONNX accurately. For more details, please check Backends other than mncore2:0.

We, the MN-Core compiler team, believe that users can go through this process without specific knowledge of MN-Core. If the function passed to compile only contains static shapes, the process should be successful.

Note on Static Shape Requirements

When compiling functions for execution on the MN-Core 2 backend, it's important to note that the functions passed to the compiler must only contain static shapes. Static shapes refer to the fixed dimensions of tensors at compile-time and do not involve dynamic graphs such as if statements or loops. In particular, the following restrictions apply to the functions:

  • Tensors must have fixed dimensions at compile-time.
  • The shape of each tensor must be known and constant throughout the function.
  • Control flow constructs such as if statements, loops, and recursion are not supported in functions.

If the dynamic constructs in the function rely on runtime information or user input to determine loop counts or other control flow decisions, the compiled functions will always follow the same decisions based on the input shapes at the time of trace, regardless of any changes to the user input or runtime context.

Replacing pfvm:cpu with (emu2:0 or mncore2:0)

After running your workload on pfvm:cpu, let's compile your code for MN-Core 2. If you have MN-Core 2 in your pod, you can use mncore2:0. However, the emulator backend of MN-Core 2, emu2:0, is sufficient for checking if your code can run on MN-Core 2.

During this process, you may encounter several compiler errors. When your code fails to compile, one option is to adjust the input size. For example, adjusting the batch size or the image size can be effective. Also, it is recommended to use a batch size that is a power of 2.

Practical Examples Using MLSDK API

Here are some examples using MLSDK API that are included in the MLSDK container image.

MNIST

The script for training MNIST is available at mnist.py.

$ ./examples/exec_with_env.sh python3 examples/mnist.py
...
epoch 8, loss 0.14200307160075182
epoch 9, iter    0, loss 0.3466796875
epoch 9, iter  100, loss 0.12501551845286152
epoch 9, iter  200, loss 0.11559456260643193
epoch 9, iter  300, loss 0.12726582522408106
epoch 9, iter  400, loss 0.12854511630802673
epoch 9, iter  500, loss 0.13125214200771737
epoch 9, iter  600, loss 0.1303801415565605
epoch 9, iter  700, loss 0.1311912290039824
epoch 9, iter  800, loss 0.13359734881087937
epoch 9, iter  900, loss 0.13450224351935858
epoch 9, loss 0.13449914363812235
...
eval acc 0.9567

timm Model Inference

timm is a library that contains many computer vision models.

You can run a timm model on MN-Core 2 using run_timm.py. This script classifies an image and prints the result. Please use run_timm.sh to run the Python script. This shell script installs timm in venv environment and then runs the inference.

$ ./examples/run_timm.sh --model_name resnet50.a1h_in1k --batch_size 16
...
MNCore2 top-5 classes:
- espresso (967)
- cup (968)
- chocolate sauce, chocolate syrup (960)
- consomme (925)
- eggnog (969)
Torch top-5 classes:
- espresso (967)
- cup (968)
- chocolate sauce, chocolate syrup (960)
- eggnog (969)
- consomme (925)

You can use other timm models.

$ ./examples/run_timm.sh --model_name mobilenetv3_small_050.lamb_in1k --batch_size 16
...
MNCore2 top-5 classes:
- cup (968)
- trifle (927)
- face powder (551)
- ice cream, icecream (928)
- coffee mug (504)
Torch top-5 classes:
- cup (968)
- trifle (927)
- ice cream, icecream (928)
- face powder (551)
- coffee mug (504)

Image Generation from Text Prompt

You can get a beautiful image of Fujisan with the following command. We need to skip VAE decoder compilation for now.

$ ./examples/run_stable_diffusion.sh --skip_vae_decoder_compilation --prompt "Fujisan" --device mncore2:0
...
Output image saved at /tmp/mlsdk_stable_diffusion_out/output.png

In case out of memory error happens, you can set the number of threads used for the compilation by the option num_compiler_threads, e.g. --num_compiler_threads 32.

Large Language Model (LLM) Inference

The script for running Llama 1B inference is available at llm_infer.py. You need to install the transformers library and set the environment variable MNCORE_USE_EXTERNAL_DATA_FORMAT=1 to run the script. run_llm_infer.sh does this setting in addition to what exec_with_env.sh does.

Currently, the compilation of the prefill phase requires specifying some environment variables. Therefore, we split the example into two parts, one for the compilation of the prefill phase, and the other for the decoding phase. This will be addressed in later releases.

Let's run the inference. The prefill phase runs on MN-Core, and the decoding phase runs on CPU.

You can specify the prompt by additionally passing arguments like --prompt 'What is the meaning of life?'. Note that the --num_compiler_threads option is also available here.

$ MNCORE_USE_LEGACY_ONNX_EXPORTER=1 CODEGEN_TIME_SLICE_SCATTERED_INDEXING_BCAST=1 CODEGEN_OP_DEF=Gather=GatherBcast ./examples/run_llm_infer.sh --compile_prefill --prepare_attention_mask_on_cpu --device mncore2:0
...
=========== Generated with compilation ==========
 </s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s><s> <|system|>
You are a friendly chatbot who is an expert on MN-Core.</s>
<|user|>
The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens. With some proper optimization, we can achieve this within a span of "just" 90 days using 16 A100-40G GPUs 🚀🚀. The training has started on 2023-09-01.</s>
<|assistant|>
Yes, that's correct. The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens using 16 A100-40G GPUs. The training has started on 2023-09
========== Generated with model.generate ==========
 <s> <|system|>
You are a friendly chatbot who is an expert on MN-Core.</s>
<|user|>
The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens. With some proper optimization, we can achieve this within a span of "just" 90 days using 16 A100-40G GPUs 🚀🚀. The training has started on 2023-09-01.</s>
<|assistant|>
Yes, that's correct. The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens using 16 A100-40G GPUs. The training has started on 2023-09
Generated outputs matched.

Let's do the opposite: prefill on CPU, and decode on MN-Core.

$ MNCORE_USE_LEGACY_ONNX_EXPORTER=1 ./examples/run_llm_infer.sh --compile_decode --prepare_attention_mask_on_cpu --device mncore2:0
...
=========== Generated with compilation ==========
 </s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s></s><s> <|system|>
You are a friendly chatbot who is an expert on MN-Core.</s>
<|user|>
The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens. With some proper optimization, we can achieve this within a span of "just" 90 days using 16 A100-40G GPUs 🚀🚀. The training has started on 2023-09-01.</s>
<|assistant|>
Yes, that's correct. The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens using 16 A100-40G GPUs. The training has started on 2023-09
========== Generated with model.generate ==========
 <s> <|system|>
You are a friendly chatbot who is an expert on MN-Core.</s>
<|user|>
The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens. With some proper optimization, we can achieve this within a span of "just" 90 days using 16 A100-40G GPUs 🚀🚀. The training has started on 2023-09-01.</s>
<|assistant|>
Yes, that's correct. The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens using 16 A100-40G GPUs. The training has started on 2023-09
Generated outputs matched.

After the compilation and execution, the above script performs a comparison of the generated sequence against the generation API of transformers. The results may not match exactly, depending on the model weights and prompt. However, they are unlikely to be completely different.

Tools for Debugging and Profiling

When working with MN-Core, you may often need to debug and profile complex scenarios. In this section, we will introduce some useful tools for debugging.

Backends Other than mncore2:0

pfvm:cpu Backend

The compile function converts the passed function into an internal representation called ONNX before executing it. Occasionally, there may be errors in this conversion from the function to ONNX or ONNX to MN-Core machine instructions. To detect such cases, the pfvm:cpu backend comes in handy.

The pfvm:cpu backend allows you to run ONNX models on CPU without compiling it for MN-Core. You can use it by specifying "pfvm:cpu" instead of "mncore2:0" when creating the context.

device = mlsdk.MNDevice("pfvm:cpu")
context = Context(device)
Context.switch_context(context)

Programs that does not work correctly with "pfvm:cpu" will not work with "mncore2:0" either. Therefore, this functionality should be the first thing to try when a program does not work with MN-Core.

emu2:0 Backend

Even if you don't have an MN-Core 2 device installed on your system, you can still test your program's behavior on MN-Core 2 using an emulator. The "emu2:0" backend is specifically designed for this purpose. This is essentially an emulator for MN-Core 2 that allows your program to run in a simulated environment just like a real MN-Core 2 device would. By using this backend, you can ensure that your code will work as expected before running it on the real device.

Just like as other backends, you can use it with the following code.

device = mlsdk.MNDevice("emu2:0")
context = Context(device)
Context.switch_context(context)

codegen-dashboard

serve Subcommand

codegen-dashboard is a web-based dashboard for the MN-Core compiler. It allows users to view ONNX files, logs, error messages and more. The executable is named codegen-dashboard-external, and located under the /opt/pfn/pfcomp/codegen/build/codegen-dashboard/ directory. To start codegen-dashboard-external, execute the following command and open the indicated URL in your web browser.

$ /opt/pfn/pfcomp/codegen/build/codegen-dashboard/codegen-dashboard-external serve /tmp/add_two_tensors/add
Started to serve at http://localhost:8327

Please note that this document assumes that you are working inside a Kubernetes pod, hence http://localhost:8327/ is inaccessible from your local machine. To access the page, enable port forwarding using the command below:

$ kubectl port-forward <POD_NAME> 8327:8327

The codegen-dashboard serve <codegen_dir> [flags] command requires the location of the MN-Core compiler output directory, termed as codegen_dir. In Example: Running a Pure Function on the MN-Core, the directory is generated to /tmp/add_two_tensors/add 1. codegen-dashboard can also accept optional flags such as --port <port number>, --host <hostname>, etc. For the comprehensive list of available flags, refer to codegen-dashboard serve --help.

genhtml Subcommand

codegen-dashboard provides a genhtml <codegen_dir> [flags] subcommand. This command generates HTML files inside the specified codegen_dir, which can be accessed via file URIs. The genhtml subcommand offers a subset of the features available in the serve command, but is very handy when sharing with others.

$ /opt/pfn/pfcomp/codegen/build/codegen-dashboard/codegen-dashboard-external genhtml /tmp/add_two_tensors/add
Writing /tmp/add_two_tensors/add/model.onnx.html ...
Writing /tmp/add_two_tensors/add/logviewer.html ...
Writing /tmp/add_two_tensors/add/index.html ...

Use Perfetto for Profiling

Perfetto UI

You can profile your code with Perfetto, which loads traced data from a local file and shows the detailed analysis in an interactive way. The module mncore.utils.perfetto_trace provides an easy way to generate files that can be loaded from Perfetto UI.

To profile your code, first import trace_scope function from the module:

from mlsdk import trace_scope

Then enclose the entrypoint of your code with:

with trace_scope("trace-file-name.pb"):
  your_entry_point() # e.g. main() or run() or whatever

And that's all! The trace file will be saved to "trace-file-name.pb" when you run the code. Here is an example of adding up two tensors, which is already introduced in this tutorial, but with tracing enabled. Save the following code with add_trace.py:

import torch
from mlsdk import CacheOptions, Context, MNDevice, storage, trace_scope


def run_add():
    device = MNDevice("mncore2:0")
    context = Context(device)
    Context.switch_context(context)

    def add(input: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]:
        x = input["x"]
        y = input["y"]
        return {"out": x + y}

    sample = {"x": torch.randn(3, 4), "y": torch.randn(3, 4)}

    compiled_add = context.compile(
        add,
        sample,
        storage.path("/tmp/add_two_tensors"),
        name="add",
        cache_options=CacheOptions("/tmp/add_two_tensors_cache"),
    )
    result = compiled_add({"x": torch.ones(3, 4), "y": torch.ones(3, 4)})
    result_on_cpu = result["out"].cpu()
    print(f"{result_on_cpu=}")
    assert torch.allclose(result_on_cpu, torch.ones(3, 4) * 2)


if __name__ == "__main__":
    with trace_scope("trace.pb"):
        run_add()

Type the following command to check the result:

$ ./exec_with_env.sh python3 add_trace.py
...
result_on_cpu=tensor([[2., 2., 2., 2.],
        [2., 2., 2., 2.],
        [2., 2., 2., 2.]])
[908.203] perfetto.cc:53691       Tracing session 1 ended, total sessions:0
$ ls *.pb
trace.pb

Then you can access Perfetto UI and open the file (trace.pb in this example) to check the result.


  1. If you omit the name keyword argument in compile() method, the codegen_dir will be generated to /tmp/add_two_tensors/<random string> by default.

PFCP のロール

PFCP で利用可能なロールと、各ロールで利用できる操作を説明します。

ロールの種類

PFCP には、 組織管理者一般ユーザ の 2 種類のロールがあります。

組織管理者

  • 所属組織のすべての操作が可能です。
  • Kubernetes クラスタのルートネームスペースとすべてのサブネームスペースに対して、Kubernetes 標準ロールadmin 相当の権限を持ちます。

一般ユーザ

  • 所属組織の Kubernetes クラスタを利用できます。
  • Kubernetes クラスタのルートネームスペースに対して、Kubernetes 標準ロールedit 相当の権限を持ちます。
  • Kubernetes クラスタのサブネームスペースに対しては、初期状態では権限を持ちません。RoleBinding による権限の付与が必要です。
  • ユーザ管理操作はできません。

利用可能な操作一覧

クラスタ利用

操作組織管理者一般ユーザ
kubectl のセットアップoo
[Kubernetes リソースの操作]
  ルートネームスペース:
  Kubernetes 標準ロールの admin 相当1
o
  ルートネームスペース:
  Kubernetes 標準ロールの edit 相当2
oo
  サブネームスペース:
  Kubernetes 標準ロールの admin 相当1
o
  サブネームスペース:
  RoleBinding により個別に権限付与
N/Ao3
サブネームスペースの作成・削除o
リソースクオータの確認oo

ユーザ管理

操作組織管理者一般ユーザ
ユーザの招待・削除o
ユーザの権限変更o
ユーザグループの作成・削除o
ユーザグループへのユーザの追加・削除o
ユーザグループと外部認証基盤との連携作成・削除o

  1. Kubernetes 標準の admin とは一部異なり、一部リソースの権限削除および PFCP で利用しているカスタムリソースの権限追加がされています。org-admin という ClusterRole で定義されています。権限の詳細は、各リソースごとのドキュメントページをご確認ください。 ↩2

  2. org-admin と同様、Kubernetes 標準の edit とは一部異なります。org-edit という ClusterRole で定義されています。権限の詳細は、各リソースごとのドキュメントページをご確認ください。

  3. RoleBinding で紐づける Role により、付与される権限が異なります。RoleBinding の詳細は、権限設定(RBAC) をご確認ください。

組織のユーザを管理する

PFCP では、組織管理者が組織に属するユーザの管理をおこないます。

PFCP におけるユーザの管理には以下の 2 つの方法があります。

  1. ポータル上でのユーザの直接管理
  2. 外部認証基盤との連携によるグループ単位の管理

ユーザの管理

ご利用の組織へ、直接ユーザの招待、ロール変更、削除をおこなう方法を説明します。

Info

直接招待を行うアカウントは、Google の個人アカウントもしくは Google Workspace アカウントのみ使用できます。

ユーザを招待する

  1. ポータルの ユーザ管理ページ にアクセスし、招待メールを送る ボタンをクリックします。
  2. 招待したいユーザの Eメールロール を入力し、招待メールを送る ボタンをクリックします。
  3. 送信した招待は、受諾待ち一覧 に表示されます。招待メールが受理されると、一覧から消えます。
  4. 招待が期限切れになってしまった場合は再送してください。

ユーザのロールを変更する

  1. ポータルの ユーザ管理ページ にアクセスし、ユーザ一覧 を表示します。
  2. ロールを変更したいユーザを選択し、ロールを変更します。
    • ログインしているユーザ自身のロールは変更できません。

ユーザを組織から削除する

  1. ポータルの ユーザ管理ページ にアクセスし、 ユーザ一覧 を表示します。
  2. 削除したいユーザを選択し、組織メンバーから削除します。
    • 削除したユーザを元に戻したい場合は、再度招待が必要です。
    • ログインしているユーザ自身は削除できません。

ユーザグループの管理

組織に属するユーザをグループにまとめることができます。 グループ単位での管理により、ネームスペースに対する権限管理を効率化します。 また、外部認証基盤とユーザグループとを連携させることにより、ご利用の組織のアカウントを連携させることが可能です。

権限管理については、権限設定(RBAC) をご確認ください。

ユーザグループへの所属

ユーザはユーザグループに 2 通りの方法で所属できます。どちらの方法でも、ユーザはグループに所属しているものと扱われます。

  • ユーザグループへの直接の所属
    • ポータル上で、ユーザをユーザグループに追加します。
  • ユーザグループと外部認証基盤のグループの連携
    • ユーザグループを外部認証基盤のグループと連携させることで、外部認証基盤のグループに所属するユーザを自動的にユーザグループに追加します。

ユーザグループを作成する

  1. ポータルの ユーザグループ管理ページ にアクセスし、新規作成 ボタンをクリックします。
  2. フォームを入力し、作成 ボタンをクリックします。

ユーザグループを削除する

  1. ポータルの ユーザグループ管理ページ にアクセスします。
  2. 削除したいグループを選択し、削除 ボタンをクリックします。

ユーザグループにユーザを追加する

  1. ポータルの ユーザグループ管理ページ にアクセスし、編集したいグループを選択します。
  2. メンバー追加 セクションで追加したいユーザを選択し、追加 ボタンをクリックします。
    • 追加するユーザは、まず組織に招待し受諾されている必要があります。

Info

グループへの所属が Kubernetes クラスタへの接続情報に反映されるまでには、最大 1 時間かかります。

ユーザグループからユーザを削除する

  1. ポータルの ユーザグループ管理ページ にアクセスし、編集したいグループを選択します。
  2. メンバー セクションで削除したいユーザを選択し、選択したメンバーを外す ボタンをクリックします。

ユーザグループと外部認証基盤との連携を作成する

  1. ポータルの 外部認証連携ページ にアクセスします。
  2. 外部認証基盤のグループ IDPFCP のグループ名 を入力し、グループ連携を追加 ボタンをクリックします。
    • PFCP のグループは先に作成しておく必要があります。

ユーザグループと外部認証基盤との連携を削除する

  1. ポータルの 外部認証連携ページ にアクセスします。
  2. 削除したい連携を選択し、選択したグループ連携を削除する ボタンをクリックします。

PFCP ポータルにログインする

PFCP では、Kubernetes クラスタに接続するための認証情報の取得や、各種管理機能を扱うためのポータルを提供しています。

Info

PFCP ポータルにログインするには、組織管理者によるユーザ招待が必要です。 初めてログインするときは、招待メールのリンクからログインしてください。 2 回目以降は、ポータルサイトからログインできます。

初回ログイン

  1. 組織管理者にユーザの招待を依頼します。
  2. 招待メールを受領したら、メール本文の ACCEPT INVITATION ボタンをクリックします。
  3. 招待内容の確認画面が表示されます。組織名と招待メールの送信者が正しいことを確認し、 続ける をクリックします。
  4. 招待メールを受領したメールアドレスを使用してログインします。
  5. ログイン後、組織名の入力画面が表示されるので、招待された組織名を入力します。
  6. ログイン状態の再確認が行われたあと、ポータルに自動で遷移します。

2回目以降のログイン

  1. ポータルにアクセスします。
  2. 組織名の入力画面が表示されるので、ご利用の組織名を入力します。
  3. 登録されたメールアドレスを使用してログインします。

クラスタに接続する

このページでは、Kubernetes クラスタに接続する方法を説明します。

クラスタの操作に使用するコマンドラインツールのインストール

Kubernetes のコマンドラインツールである kubectl ツールを用いて、Kubernetes クラスタに接続します。

kubectl ツールのインストールは、公式ドキュメントを参考に実施します。

Kubernetesクラスタの接続情報を設定

  1. ポータルのkubectlのセットアップ にアクセスします。
  2. クラスタ名 のドロップダウンから使用したいクラスタを選択します。
  3. 認証情報の取得 をクリックし、出力されたコマンドをコピーしてターミナルで実行します。

接続確認

kubectl auth whoami を実行し、Username にご自身のメールアドレス、Groups にご利用の組織名のグループが表示されることを確認します。

$ kubectl auth whoami
ATTRIBUTE   VALUE
Username    oidc:<ご利用の組織名>/<ご利用のメールアドレス>
Groups      [oidc:<ご利用の組織名> system:authenticated]

Kubernetes の基礎を学ぶ

PFCP はオープンソースのコンテナオーケストレーションプラットフォームである Kubernetes をベースに構成されています。このサイトのドキュメントは Kubernetes の基本的なコンセプトや用語を理解していることが前提になっています。まだ Kubernetes に慣れていない方は、ここで Kubernetes の基礎を確認してください。また、公式サイトや書籍を通じて Kubernetes についてさらに深く知ることで、PFCP をより効果的に利用できるようになります。

Kubernetes の概要

Kubernetes は、Cloud Native Computing Foundation(CNCF)にホストされたオープンソースのコンテナオーケストレーションプラットフォームです。コンテナ化されたアプリケーションの展開、スケーリング、可用性の管理を自動化するためのツールで、この分野の標準として広く採用されています。

詳細は、Kubernetes の公式ドキュメントを参照ください。

Info

PFCP は Kubernetes をベースとして深層学習・AI ワークロード向けのクラウドサービスとして構成されています。提供するクラスタはマネージドで、ユーザがクラスタ自体を運用する必要がありません。

クラスタとノード

クラスタはワークロードを実行・管理するためのマシン群の集合体です。ユーザからみると 1 つのまとまった計算リソースとして扱えます。

ノードはクラスタを構成する 1 つのマシンで、その実体は一般的な仮想マシンや物理マシンです。

Kubernetes はユーザからワークロードのデプロイが指示されると、ワークロード定義に記述された CPU やメモリ、MN-Core といったデバイスの要求数を確認し、適切なノードにワークロードをスケジュール、実行します。

Info

PFCP ではユーザのワークロードを実行するためのノードのことを「計算ノード」と呼びます。

Namespace

Kubernetes Namespace は 1 つのクラスタを論理的に分割するための機能です。 Kubernetes ではリソースの名前が Namespace 内でユニークである必要があります。 ステージングや本番などの環境を分割したり、複数のチームやプロジェクトから使用する場合に Namespace を使うことでリソースの管理が容易になります。

詳細は、Kubernetes の公式ドキュメントを参照ください。

Info

一般に Kubernetes Namespace の管理にはクラスタ全体の管理者権限が必要ですが、PFCP では Kubernetes カスタムアドオンを使用して組織管理者が Namespace を管理できます。

Pod

Kubernetes ではワークロードを Pod という 1 つ以上のコンテナで構成します。Pod は Kubernetes におけるデプロイ可能な最小単位です。 1 つの Pod に含まれるコンテナは必ず同一のノード上で実行され、同じネットワークとストレージを共有しながら動作します。

詳細は、Kubernetes の公式ドキュメントを参照ください。

コンテナとコンテナイメージ

コンテナはシステムの他の部分とは分離して一連のプロセスを実行する技術です。コンテナはホストや他のプロセスから切り離されるため、環境依存による問題を引き起こしにくく、どの環境でも同じように実行できます。

コンテナを実行するために必要なコードやライブラリ、ランタイムはコンテナイメージと呼ばれるパッケージに含める必要があります。 コンテナイメージはコンテナイメージレジストリと呼ばれるサービスに保存され、配信されます。

詳細は、Kubernetes の公式ドキュメントを参照ください。

Info

PFCP の専用コンテナイメージレジストリは、MN-Core の使用に必要なファイルやソフトウェアを含むコンテナイメージを提供しており、すぐに MN-Core の使用を開始できます。

Note

PFCP ではユーザ自身がビルドしたコンテナイメージをクラスタで使用するためのコンテナイメージレジストリを提供していません。 外部のコンテナイメージレジストリサービスをご利用ください。

Pod を管理する上位のリソース: Deployment、StatefulSet、Job、CronJob...

Kubernetes は Pod を管理するより上位のリソースタイプを提供し、様々な種類のワークロードをサポートします。

  • Deployment: クラスタのノード間で分散された複数の Pod レプリカを実行します。失敗した Pod や応答しなくなった Pod は自動的に置き換えられるため、サービスを可用性高く運用する用途に向いています。
  • StatefulSet: 各 Pod レプリカに一意の ID を保持して実行します。ステートフルなアプリケーションの実行に役立ちます。
  • Job: 1 つ以上の Pod レプリカを作成して指定された数の Pod が正常に終了するまで、Pod の作成と実行を再試行し続けます。ワンショットの学習を行う用途に向いています。
  • CronJob: Linux cron のように指定のスケジュールに基づき Kubernetes Job を作成します。

Note

上位リソースを使わずにユーザにより直接作成された Pod(Bare Pod)はノードの障害などが理由で停止された場合に自動的に他のノードで再実行されません。 基本的に直接 Pod を作成することは避け、上位のリソースを使用してください。

詳細は、Kubernetes の公式ドキュメントを参照ください。

Info

PFCP では深層学習・AI ワークロードの実行に便利な Kubernetes 組み込みではないカスタムのリソースも提供しています。カスタムのリソースについては、本ユーザガイドをご参照ください。

Service

Service は一連の Pod に固定されたネットワークエンドポイントを提供します。 Pod は実行するたびに異なる IP アドレスが自動先に割り当てられるため、直接 Pod に対しては安定してアクセスできません。

加えて、Kubernetes はクラスタ内部のアドレス解決用に組み込みの DNS を提供し、Service の名前を使用したサービスディスカバリ機能を提供します。Service の名前を使用して安定してワークロードにアクセスできます。

詳細は、Kubernetes の公式ドキュメントを参照ください。

Ingress

Ingress はクラスタ外から Kubernetes Service に対しての HTTP/HTTPS アクセスを提供します。ホスト名やパスに応じたリクエストの振り分けが可能です。

詳細は、Kubernetes の公式ドキュメントを参照ください。

Info

PFCP では、Ingress を使用してサービスにインターネットから安全に公開できます。 ワークロードをウェブ API として公開する または ワークロードをウェブアプリとして公開する を参照してください。

永続ストレージ

実行中の Pod に保存されたデータは Pod の停止とともに失われます。 Pod の存続期間を超えてデータを保持する必要がある場合には、PersistentVolumeClaim を使用して永続ストレージをプロビジョニングし、Pod にマウントして使用できます。

詳細は、Kubernetes の公式ドキュメントを参照ください。

マニフェストファイル

クラスタ上に作成・管理したいリソースの状態(構成)を記述した YAML または JSON 形式のファイルをマニフェストファイルと呼びます。一般に YAML 形式で記述されます。

Kubernetes ではクラスタに対してワークロードをデプロイするにはコマンドラインツールなどから命令的に作成・更新する方法と、マニフェストファイルを使用して宣言的に作成・更新する方法の 2 つがあります。 命令的な方法は一時的に操作する場合に素早く行える利点があります。一方で再現性が低いため、多くの場合に望ましい状態をファイルとして管理できるマニフェストファイルを使用した宣言的な方法の使用を推奨します。

詳細は、Kubernetes の公式ドキュメントを参照ください。

Namespace でクラスタを論理的に分割する

Kubernetes では、Namespace リソースを作ることで複数の作業空間を構築し、各作業空間ごとに独立したリソース管理ができます。 検証・本番環境のように権限やネットワーク接続性の要件が異なる環境を運用したい場合や、複数のチームで利用する場合に有用です。

PFCP では、Namespace リソースの作成機能を提供しています。 ただし、PFCP の Kubernetes クラスタはマルチテナント型で構成されているため、Namespace リソースの作成に関して一般の Kubernetes クラスタとは異なる以下の制約があります。

ネームスペースの制約

  • 各組織には、ルートネームスペースとして 1 つの Namespace リソースが提供されます。
  • 追加の Namespace リソースは、このルートネームスペースに従属するサブネームスペース1として作成します。
  • ルートネームスペースのリソース名は、org-<組織名> です。
  • サブネームスペースのリソース名は、org-<組織名>-- が接頭辞として付きます。
  • ルートネームスペースは、PFCP の全クラスタで事前に作成されます。削除できません。
  • サブネームスペースは、PFCP の各クラスタごとに個別に作成します。削除可能です。
  • kubectl などを利用して直接 Namespace リソースを作成することはできません。2
  • サブネームスペースに従属するサブネームスペース(孫ネームスペース)を作成することはできません。

以下では、サブネームスペースを管理する方法を説明します。

サブネームスペースの作成

以下の手順で、サブネームスペースを作成します。

  1. ポータルのネームスペースにアクセスします。
  2. ネームスペースの作成 画面を開きます。
  3. クラスタ名ネームスペース名、説明を入力します(説明は任意項目です)。
  4. 組織内の他の Namespace からの通信を許可しない場合は、 オプション2にチェックを入れてください。
  5. 作成 ボタンをクリックすると、サブネームスペースが作成されます。

作成したサブネームスペースは、通常の Namespace リソースとして使用できます。

# サブネームスペース `org-<組織名>--foo` を作成した場合
$ kubectl get all -n org-<組織名>--foo
No resources found in org-<組織名>--foo namespace.

組織管理者は、作成したサブネームスペースに対して org-admin Role の権限が自動で付与されます。 一般ユーザは、サブネームスペースに対して自動での権限付与がされないため、RoleBinding を作成して権限を付与する必要があります。 RoleBinding の詳細は、権限設定をご確認ください。

サブネームスペースの変更

  1. ポータルのネームスペースにアクセスします。
  2. 変更したいサブネームスペースの変更画面を開き、設定を修正します。クラスタ名、ネームスペース名は変更できません。
  3. 更新 ボタンをクリックすると、サブネームスペースが変更されます。

Info

ルートネームスペースの変更はできません。

サブネームスペースの削除

  1. ポータルのネームスペースにアクセスします。
  2. 削除したい Namespace を選択し、削除します。

Warning

サブネームスペースを削除すると、Namespace リソース内で作成された全リソースが削除されます。

Info

ルートネームスペースの削除はできません。

参考: コマンドラインツールでサブネームスペースを操作する

サブネームスペースの機能は、Hierarchical Namespaceの SubnamespaceAnchor カスタムリソースで実現しています。 kubectl-hnsプラグインを導入すると、サブネームスペースの操作をターミナルから行えます。

サブネームスペースの作成

# org-<組織名>--foo サブネームスペース を作成する
$ kubectl hns create org-<組織名>--foo -n org-<組織名>
Successfully created "org-<組織名>--foo" subnamespace anchor in "org-<組織名>" namespace

階層構造の閲覧

$ kubectl hns tree org-<組織名>
org-<組織名>
└── [s] org-<組織名>--foo

Namespaceの削除

$ kubectl delete subnamespaceanchor org-<組織名>--foo -n org-<組織名>

  1. サブネームスペース機能を提供するために、Hierarchical Namespaceを採用しています。

  2. Hierarchical Namespace のカスタムリソースである SubnamespaceAnchor を使用すれば、サブネームスペースとして Namespace リソースを作成できます。 ↩2

ユーザのクラスタアクセス権限を管理する

PFCP では、Kubernetes における Role/RoleBinding を用いた Role Based Access Control(RBAC)が利用できます。 RoleBinding を作成することで、Role に定義された権限をユーザやグループに付与できます。

Note

以下を読み進める前に PFCP のロール を確認し、PFCP で利用可能なロールについて把握してください。

PFCP で標準提供するロールとグループ

以下の 3 つの ClusterRole1 が利用できます。

  • org-view
    • ユーザのワークロードを閲覧するために必要な権限を有します。
  • org-edit
    • org-view の権限に加えて、ユーザのワークロードを実行するために必要な権限を有します。
  • org-admin
    • org-edit の権限に加えて、Role/RoleBinding 操作などの管理者権限を有します。

Info

各 ClusterRole は Kubernetes 標準の view/edit/admin ClusterRole を基として一部リソースの権限削除および PFCP で利用しているカスタムリソースの権限追加がされています。 具体的にどのリソースに対してどの操作が許可されているかについては下記コマンドで参照できます。

$ kubectl get clusterrole org-view org-edit org-admin -o yaml

また、以下の 2 つのグループが標準で提供されています。

  • org-<組織名>(例:org-pfn
    • 組織管理者と一般ユーザの両方がこのグループに所属します。
    • ルートネームスペースに対してのみ org-edit Role が与えられます。サブネームスペースに対しては Role が付与されません。
  • org-<組織名>/admin(例:org-pfn/admin
    • 組織管理者が所属するグループです。
    • ルートネームスペースおよびすべてのサブネームスペースに対して、org-admin ClusterRole が与えられます。

ルートネームスペースは、組織に属するすべてのユーザが org-edit 以上の権限を有しているため、初期設定のままご利用いただけます2。 新規に作成したサブネームスペースについては、一般ユーザは権限をもちません。一般ユーザに権限を付与するには、RoleBinding を作成します。

RoleBinding の作成

RoleBinding は、以下の 2 通りで作成できます。

  1. グループに対する RoleBinding の作成
  2. ユーザに対する RoleBinding の作成

サブネームスペースに対して、グループ・ユーザのそれぞれに org-edit の ClusterRole2を付与する方法を説明します。

グループに対する RoleBinding の作成

すべてのユーザに対し、サブネームスペース(org-<組織名>--foo)への権限を付与するには、以下の RoleBinding を作成します。

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: org-edit
  namespace: org-<組織名>--foo
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: org-edit
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: oidc:org-<組織名>

また、組織のユーザを管理する で作成したユーザグループへ権限を付与できます。 ユーザグループ(ops)に対し、サブネームスペース(org-<組織名>--foo)への権限を付与するには、以下の RoleBinding を作成します。

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: org-edit-ops # name は任意です
  namespace: org-<組織名>--foo
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: org-edit
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: oidc:org-<組織名>/ops  # PFCP のユーザグループ名を指定します。

Info

外部認証基盤との SAML 連携をご利用になりたい場合は、サポートまでお問い合わせください。

ユーザに対する RoleBinding の作成

特定のユーザ(alice@example.com)に対し、サブネームスペース(org-<組織名>--foo)への権限を付与するには、以下の RoleBinding を作成します。

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: org-edit-user-alice  # name は任意です
  namespace: org-<組織名>--foo
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: org-edit
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: oidc:org-<組織名>/alice@example.com

一般ユーザのルートネームスペースに対するワークロード実行権限を削除する

PFCP で標準提供するロールとグループ に記載のとおり、一般ユーザにはルートネームスペースへの org-edit 権限がデフォルトで付与されます。 一般ユーザに対するルートネームスペースへの org-edit 権限付与をやめる場合は、以下のコマンドを実行します。

$ kubectl -n org-<組織名> delete rolebindings org-edit

これにより、一般ユーザはルートネームスペースでの任意のリソース作成とワークロードの実行ができなくなります。

独自の Role を作成する

org-admin ClusterRole には任意の Role をネームスペースに作成する権限が含まれており、組織管理者は独自の権限設定を持つ Role を作成し一般ユーザに付与できます。

例えば Pods の閲覧権限のみを許可する独自の Role は次のようになります。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-view
  namespace: org-<組織名>--foo
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]

参考リンク

FAQ

Q. 組織管理者権限を使用していますが、クラスタを操作するときは org-edit ロールを使用したいです

組織管理者に付与される org-admin ロールではサブネームスペースや RoleBinding などを操作できる強い権限を持つため、学習ワークロードを実行する際は org-edit ロールを使うことで、誤操作を防止できます。 これは、org-edit ロールが付与された ServiceAccount を作り、その ServiceAccount としてふるまうことで実現できます。

org-<組織名>--foo サブネームスペースを org-edit ロールで操作する場合の手順を、以下に記します。

// `org-<組織名>--foo` ネームスペースに ServiceAccount を作ります。
$ kubectl -n org-<組織名>--foo create sa org-edit-sa
serviceaccount/org-edit-sa created

// 作成した ServiceAccount に `org-edit` ロールを付与します。
$ kubectl -n org-<組織名>--foo create rolebinding org-edit-sa --clusterrole=org-edit --serviceaccount=org-<組織名>--foo:org-edit-sa
rolebinding.rbac.authorization.k8s.io/org-edit-sa created

// `--as system:serviceaccount:<Namespace>:<ServiceAccount>` フラグを付与することで、対象 ServiceAccount になりすまして処理を行います。
// 対象 ServiceAccount になりすませていることを確認します。
$ kubectl --as system:serviceaccount:org-<組織名>--foo:org-edit-sa auth whoami
ATTRIBUTE   VALUE
Username    system:serviceaccount:org-<組織名>--foo:org-edit-sa
Groups      [system:serviceaccounts system:serviceaccounts:org-<組織名>--foo system:authenticated]

// org-admin ロールであれば ResourceQuota を作成することができますが、なりすましているときは作成ができません。
$ kubectl auth can-i create resourcequotas -n org-<組織名>--foo
yes
$ kubectl --as system:serviceaccount:org-<組織名>--foo:org-edit-sa auth can-i create resourcequotas -n org-<組織名>--foo
no

--as フラグを都度追加するのを避けたい場合は、kubeconfig の user フィールドに以下の通り設定を追加することで、デフォルトの設定にできます。

 - name: pfcp-<組織名>-<クラスタ名>
   user:
+    as: system:serviceaccount:<Namespace>:<ServiceAccount>
     auth-provider:
       config

  1. ClusterRole はどの Namespace からでも利用できるロールです。

  2. 一般ユーザに対するルートネームスペースへの org-edit ClusterRole の付与が不要な場合には、オプトアウトできます。設定方法は 一般ユーザのルートネームスペースに対するワークロード実行権限を削除する を参照してください。 ↩2

Namespace 間の通信を制御する

PFCP では、Namespace をまたぐ通信は以下のポリシーに従い制御されます。

Namespaceをまたぐ通信のポリシー

  • 異なる組織の Namespace をまたいだ通信は、全て拒否されます。
  • 同一組織の Namespace をまたいだ通信は、デフォルトでは全て許可されます。
  • 通信を拒否するポリシーを任意に追加できます。PFCP サービス側で拒否されている通信は許可できません。

拒否したい通信のポリシーを追加するには、CiliumNetworkPolicy カスタムリソース1 2を使用します。 CiliumNetworkPolicy を使用した拒否ポリシーを追加する例として、Namespace 外からの内向きの通信を拒否する方法を説明します。

CiliumNetworkPolicyによるNamespace外からの内向き通信の拒否

隔離したい Namespace 内に CiliumNetworkPolicy リソースを作成することで、他の Namespace からの通信を拒否します。本番ワークロードを実行する Namespace において、他の Namespace からのアクセスを禁止したい場合に有用です。

例として、下記のリソースをorg-<組織名> Namespace に作ると、同一 Namespace 内の通信および org-<組織名>--foo Namespace からの通信のみ許可されます。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: "deny-except-org-<組織名>--foo"
  namespace: "org-<組織名>"
spec:
  endpointSelector: {}
  ingressDeny:
  - fromEndpoints:
    - matchExpressions:
      - key: k8s:io.kubernetes.pod.namespace
        operator: NotIn
        values: ["org-<組織名>", "org-<組織名>--foo"]

spec.ingressDeny に加えて、spec.egressDeny も使用できます。特定の宛先への外向きの通信を拒否したい場合は、 spec.egressDeny をご利用ください。

なお、spec.ingressおよびspec.egressは使用できません。拒否されている宛先との通信の許可はできません。

サブネームスペース作成時の内向き通信遮断オプションについて

ポータルからサブネームスペースの作成・変更を行う際に、オプションを有効にすることで、他の Namespace からの通信を全て拒否する CiliumNetworkPolicy を作成できます。 本番ワークロードの実行環境など、他の Namespace から通信できない環境を作るときに利用できます。

この CiliumNetworkPolicy は deny-all-ingress という名前で作成されます。 作成後は、必要に応じて自由に書き換えてポリシーを変更できます。


  1. CiliumNetworkPolicy の一部機能は制限されています。

  2. CiliumNetworkPolicy の詳細な説明については、公式のドキュメント をご確認ください。

組織のリソース使用を確認する

PFCP では、Namespace 単位ではなく組織単位でクオータが設定されており、組織内の全 Namespace のリソース合計数に上限が設定されています。 上限を超えてリソースを作成しようとした場合、作成に失敗します。

ポータルのリソースクオータ から、使用中のリソースの合計および使用上限を確認できます。

Info

上限の緩和をリクエストしたい場合は、サポート窓口までご連絡ください。

コマンドラインツールでリソースクオータを確認する

組織内 Namespace を合算したリソースクオータを実現するために、PFCP では Hierarchical Resource Quota の機能を使用しています。 kubectl-hnsプラグインを導入すると、リソースクオータの確認をターミナルから行えます。

以下のコマンドにより、組織全体のリソース使用状況を確認できます。

$ kubectl get hrq -o yaml -n org-<組織名>

出力される結果の中に .status.hard および .status.used という 2 つの項目があります。

  • .status.hard: 指定した Namespace 配下のリソースの作成上限を示しています。上限を超えるリソースの作成はできません。
  • .status.used: 指定した Namespace 配下の作成済のリソースの合計数を示しています。
$ kubectl get hrq org-resource-quota -o yaml -n org-<org-name>
apiVersion: hnc.x-k8s.io/v1alpha2
kind: HierarchicalResourceQuota
metadata:
  name: org-resource-quota
  namespace: org-<org-name>
spec:
  hard:
    count/configmaps: "100"
    count/cronjobs.batch: "100"
    ...
status:
  hard:
    count/configmaps: "100"
    count/cronjobs.batch: "100"
    ...
  used:
    count/configmaps: "3"
    count/cronjobs.batch: "0"
    ...

参考リンク

Namespace のリソース使用を制限する

ResourceQuota リソースを作成することで、Namespace ごとにリソース使用を制限できます。1 2 特定の Namespace での計算リソースの使いすぎを防止し、Namespace 間のリソース配分を調整できます。3

サブネームスペース org-<組織名>--foo にクオータを設定したい場合は、以下のような ResourceQuota を作成します。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: quota
  namespace: org-<組織名>--foo
spec:
  hard:
    requests.preferred.jp/mncore2: 4
    requests.nvidia.com/gpu: 0

この例では、MN-Core 2 の使用上限を 4 つに限定し、NVIDIA 製の GPU の使用を制限しています。

参考リンク


  1. Namespace ごとの ResourceQuota は、自動では作成されません。必要に応じて作成してください。

  2. ルートネームスペースにも ResourceQuota を作成できます。

  3. 組織単位のクオータよりも大きな値を設定した場合は、組織単位のクオータが優先されます。

ストレージ利用可能枠を拡張する

全ての組織には、無料で 256GB までのストレージと、 32MB/s、 8KIOPS のベストエフォート I/O 帯域幅が提供されます。

追加のストレージ利用枠を希望する場合は、サポート窓口までご連絡ください。

FAQ

Q. 利用可能枠が余っているはずだが、永続ストレージのプロビジョニングに失敗する

PersistentVolumeClaim を削除することで動的に払い出された PersistentVolume も削除されます。 削除された領域は 12 時間が経過すると再度利用可能な状態となります。 クオータの表示にはすぐに反映されますが、12 時間が経過するまでは再利用できないためご注意ください。

Info

PersistentVolume 削除後にストレージ利用可能枠を急ぎ回復したい場合は、サポート窓口までご連絡ください。

GitOps スタイルの継続的デリバリを構成する

GitOps は、Git を用いてリソース構成情報を宣言的に記述・管理し、その変更を自動でクラスタに適用する手法です。GitOps を取り入れることで、設定の変更点や履歴が明確に追跡可能となり、デプロイプロセスが自動化されることにより手作業が削減されます。

PFCP では、 Kubernetes 上の GitOps を実現する手段として Flux をマネージドサービスとして提供しています。Flux は、Kubernetes 上での GitOps を実現するために使用されるオープンソースの自動化ツールです。リポジトリ内の変更を監視し、それを自動的にクラスタに適用する役割を担います。以下では、実際に Flux を用いて GitOps を可能にする方法について紹介します。

Flux の導入と設定

以下では、単に「リポジトリ」といった際は GitHub リポジトリを指すものとします。

  1. ポータルのネームスペースにアクセスし、 Flux の Kubernetes リソースを利用するためのネームスペースを作成します。ここでは例として、 org-foo--flux というネームスペースを作成します。

  2. 作成した org-foo--flux Namespace に、 flux という名前の ServiceAccount を作成します。Flux はこの ServiceAccount を使用してマニフェストを適用します。 ServiceAccount に flux 以外の名前を設定すると動作しないので注意が必要です。

    kubectl create serviceaccount flux --namespace=org-foo--flux
    
  3. Flux によりマニフェストを適用したい Namespace から Flux が使用する org-foo--flux Namespace の Flux ServiceAccount に対して権限を付与します。

    kubectl create rolebinding flux \
       # Flux によってマニフェストを適用したい Namespace
       --namespace=org-foo--target \
       # Flux がマニフェストの適用に使用する権限
       --clusterrole=org-edit \
       # Flux がマニフェストの適用に使用する ServiceAccount
       --serviceaccount=org-foo--flux:flux
    

    Flux によってマニフェストを適用したい Namespace が複数ある場合には、それぞれの Namespace から同様に権限を付与する必要があります。

    org-admin が必要なリソースを管理したい場合

    --clusterrole=org-edit の部分は管理したいリソースの種類に合わせて変更してください。たとえば RoleBinding を Flux で管理したい場合は、flux ServiceAccount に org-admin を付与する必要があります。その場合、一般ユーザによる組織管理者権限を持つ flux ServiceAccount を使ったクラスタ操作を避けるために、必ず org-foo--flux namespace の使用者を組織管理者のみに限定してください。

  4. 以下のmanifest.yamlファイルを記述し、GitRepository リソースおよび Kustomization リソースを作成します。この例では、https://github.com/pfcomputing/hellomain ブランチに存在するマニフェストがクラスタに適用されます。

    apiVersion: source.toolkit.fluxcd.io/v1
    kind: GitRepository
    metadata:
      name: hello
      namespace: org-foo--flux
    spec:
      interval: 5m
      url: https://github.com/pfcomputing/hello
      ref:
        branch: main
    ---
    apiVersion: kustomize.toolkit.fluxcd.io/v1
    kind: Kustomization
    metadata:
      name: hello
      namespace: org-foo--flux
    spec:
      interval: 10m
      sourceRef:
        kind: GitRepository
        name: hello
      path: "./kustomize"
      prune: true
      timeout: 1m
    
  5. マニフェストを適用します。

    kubectl apply -f manifest.yaml
    

これらの手順により、設定したリポジトリに存在するマニフェストファイルとクラスタの状態が同期されます。

Flux におけるプライベート Git リポジトリの利用

パブリックなリポジトリだけでなく、プライベートなリポジトリを参照して GitOps を行うことも可能です。以下に手順を示します。

  1. Git リポジトリにアクセスするための Secret を作成します。

    export KEY_NAME=flux-ssh-key
    ssh-keygen -t ed25519 -f $KEY_NAME
    kubectl create secret generic flux-git-secret \
    --from-literal=known_hosts="$(ssh-keyscan github.com)" \
    --from-file=identity=$KEY_NAME
    
  2. cat $KEY_NAME.pub の結果を GitHub の該当リポジトリに読み取り権限を持つデプロイキーとして登録します(GitHub ドキュメント)。

  3. manifest.yaml GitRepository を以下のように編集します。

    • URL をプライベートなリポジトリに書き換え
    • spec.secretRef フィールドにname: flux-git-secret を指定
    apiVersion: source.toolkit.fluxcd.io/v1
    kind: GitRepository
    ...
    spec:
      ...
      url: # 利用したいプライベートリポジトリに書き換え
      secretRef: # フィールドを追加
        name: flux-git-secret
    
  4. マニフェストを適用します。

    kubectl apply -f manifest.yaml
    

これらの変更により、プライベートなリポジトリに存在するマニフェストとクラスタの状態が同期されます。

Flux は、GitHub 以外のリポジトリの使用や通知機能の利用なども可能です。より詳しくは以下をご確認ください。

ワークロードのコストを管理する

Warning

ワークロードのコスト管理機能はプレビュー版です。予告なく仕様が変更される場合があるので利用には注意してください。

このページではワークロードのコストを管理する機能について説明します。

コストタグを設定する

Warning

コストタグを利用したコストの集計機能は後日追加予定です。

PFCP の Kubernetes クラスタに作成する Pod および PersistentVolumeClaim リソースには「コストタグ」と呼ばれるコスト管理のためのメタデータを設定できます。コストタグを設定することで、コストタグごとにクラスタの利用量を集計できます。

コストタグは次の名前の専用のラベルとしてリソースに設定します。ラベルには最大 16 文字の任意の文字列を設定できます。16 文字以上の文字列を設定した場合は先頭から 16 文字のみが記録されます。

  • cost.preferred.jp/tag

次の例では Pod および PersistentVolumeClaim リソースにコストタグを設定しています。

apiVersion: v1
kind: Pod
metadata:
  name: jupyter-notebook
  labels:
    # コストタグの設定
    cost.preferred.jp/tag: dev-research
spec:
  # ...
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jupyter-notebook-data
  labels:
    # コストタグの設定
    cost.preferred.jp/tag: dev-research
spec:
  # ...

デフォルトのコストタグをサブネームスペースに設定する

コストタグはリソースだけでなくサブネームスペースにも設定できます。サブネームスペースにコストタグを設定すると、そのサブネームスペース配下に作成された全ての Pod および PersistentVolumeClaim リソースの利用に対してコストタグの値が自動適用されます。サブネームスペースへのコストタグの設定は組織管理者の権限が必要です。

例えばサブネームスペース org-<組織名>--foo にコストタグを設定する場合は次のようにします。

$ kubectl edit subnamespaceanchor org-<組織名>--foo -n org-<組織名>
- spec: {}
+ spec:
+   labels:
+   - key: cost.preferred.jp/tag
+     value: dev

サブネームスペースにコストタグが設定された状態で Pod や PersistentVolumeClaim リソースにもコストタグを設定した場合は、リソースに設定したコストタグの値が採用されます。例えば次のようにコストタグが設定されていた場合は、Pod リソースのコストタグは dev-research として処理されます。

  • サブネームスペースのコストタグの値: dev
  • Pod リソースのコストタグの値: dev-research

永続ストレージの種類と比較

PFCP では、データを永続的に保存するためのストレージとしてファイルストレージとブロックストレージを提供しています。 PFCP のファイルストレージは NFS(Network File System)、ブロックストレージは NVMe/TCP を通信プロトコルとしてストレージシステムと接続されています。

ファイルストレージ

PFCP のファイルストレージは複数の Pod から NFS プロトコルを利用してデータを共有できます。 組織内のワークロードから共通して参照されるデータを格納する場所、ログや処理した結果を保存する場所としての利用に適しています。

ブロックストレージ

PFCP のブロックストレージは NVMe/TCP を利用して Pod からストレージシステムに対するより高度な操作を可能にします。

ブロックストレージ上にファイルシステムを作成して扱うときは複数 Pod からのアクセスが実行できない代わりにより高速なアクセスが可能となります。 これは高い応答性能が求められるデータベースでの利用に適しています。

ブロックストレージ上にファイルシステムを作成せず raw device として扱うときはそのまま Linux のブロックデバイスとしての利用が可能となります。 これは既存のファイルシステムでは実現できない機能を実現したいときに利用されます。 デバイスレベルでの暗号化が求められる特殊なアプリケーションでの利用、専用のフォーマットを用いる仮想ディスクとしての利用などです。

比較

ここでは PFCP で提供しているストレージタイプにおいて利用可能なアクセスモードを示します。 表中のアクセスモードは以下に示す省略形で表記しています: ReadWriteOnce(RWO)、 ReadOnlyMany(ROX)、ReadWriteMany(RWX)、ReadWriteOncePod(RWOP)

ストレージタイプRWOROXRWXRWOP備考
ファイルストレージ
ブロックストレージファイルシステムを作成して扱うとき
ブロックストレージファイルシステムを作成せず raw block device として扱うとき

ファイルストレージを使用する

PFCP では、Pod からマウントして利用できるファイルストレージを提供しています。 ReadWriteMany のファイルストレージであり、組織内の複数の Pod から同時に読み書き可能です。

PersistentVolumeClaim の作成と Pod へのマウント

ファイルストレージを利用するには、PersistentVolumeClaim リソースを作成することで必要なストレージ領域を要求し、 動的に払い出された PersistentVolume を Pod からマウントします。その具体例を説明します。

  1. 組織ごとに用意された専用の StorageClass を指定して、PersistentVolumeClaim を作成します。利用可能な StorageClass 名は standard-rwx-<組織名> です。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: hello-sample-pvc
    spec:
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 10Gi
      storageClassName: standard-rwx-<組織名>
    

    この例では、10GiB のファイルストレージを要求する PersistentVolumeClaim を作成しています。 このマニフェストを Kubernetes に適用すると、動的に PersistentVolume が作成され、 以下の通り PersistentVolumeClaim のステータスが Bound になることが確認できます。

    $ kubectl -n org-<組織名> get pvc
    NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS               VOLUMEATTRIBUTESCLASS   AGE
    hello-sample-pvc   Bound    pvc-c5bb8161-f8f3-4b2d-b001-0aee300b7478   10Gi       RWX            standard-rwx-<組織名>   <unset>   3d2h
    
  2. この PersistentVolumeClaim を指定して Pod にマウントすることで、ファイルストレージとして利用できます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: jupyter-notebook
    spec:
      containers:
      - name: jupyter-notebook
        image: quay.io/jupyter/scipy-notebook:2024-03-14
        volumeMounts:
        - mountPath: "/hello-sample"
          name: hello-sample-pv
      volumes:
      - name: hello-sample-pv
        persistentVolumeClaim:
          claimName: hello-sample-pvc
    

参考

ブロックストレージを使用する

PFCP では ReadWriteOnce、ReadWriteOncePod の PersistentVolume としてブロックストレージを利用できます。 ReadWriteOncePod のボリュームに対しては単一の Pod からのみアクセスが許可されます。

PersistentVolumeClaim にファイルシステムを作成して Pod へマウント

ブロックストレージにファイルシステムを作成して利用するには、PersistentVolumeClaim リソースを作成することで必要なストレージ領域を要求し、 動的に払い出された PersistentVolume を Pod からマウントします。 その具体例を説明します。

  1. 組織ごとに用意された専用の StorageClass を指定して、PersistentVolumeClaim を作成します。利用可能な StorageClass 名は standard-rwo-<組織名> です。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: hello-sample-pvc
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      storageClassName: standard-rwo-<組織名>
      volumeMode: Filesystem
    

    この例では、10GiB のブロックストレージにファイルシステムを作成して要求する PersistentVolumeClaim を作成しています。volumeMode はデフォルト値が Filesystem ですので実際にはここの指定は記述しなくても作成されるものは同じです。 このマニフェストを Kubernetes に適用すると、動的に PersistentVolume が作成され、 以下の通り PersistentVolumeClaim のステータスが Bound になることが確認できます。

    $ kubectl -n org-<組織名> get pvc
    NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS           VOLUMEATTRIBUTESCLASS   AGE
    hello-sample-pvc   Bound    pvc-ac98a6ff-58cd-4bef-8057-4837949107d0   10Gi       RWO            standard-rwo-<組織名>   <unset>                 7s
    
  2. この PersistentVolumeClaim を指定して Pod にマウントすることで、ファイルシステムとして利用できます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: jupyter-notebook
    spec:
      containers:
      - name: jupyter-notebook
        image: quay.io/jupyter/scipy-notebook:2024-03-14
        volumeMounts:
        - mountPath: "/hello-sample"
          name: hello-sample-pv
      volumes:
      - name: hello-sample-pv
        persistentVolumeClaim:
          claimName: hello-sample-pvc
    

PersistentVolumeClaim にファイルシステムを作成しないで Pod から使う

ブロックストレージを直接ブロックデバイスとして利用するには、PersistentVolumeClaim リソースを作成することで必要なストレージ領域を要求し、 Pod からはデバイスファイルを経由して動的に払い出された PersistentVolume を利用します。 その具体例を説明します。

  1. 組織ごとに用意された専用の StorageClass を指定して、PersistentVolumeClaim を作成します。利用可能な StorageClass 名は standard-rwo-<組織名> です。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: hello-sample-pvc
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      storageClassName: standard-rwo-<組織名>
      volumeMode: Block
    

    この例では、10GiB のブロックストレージを生のブロックデバイスとして利用するための PersistentVolumeClaim を作成しています。volumeMode に Block と指定することでブロックストレージにファイルシステムを作成する操作が行われなくなります。 このマニフェストを Kubernetes に適用すると、動的に PersistentVolume が作成され、 以下の通り PersistentVolumeClaim のステータスが Bound になることが確認できます。

    $ kubectl -n org-<組織名> get pvc
    NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS           VOLUMEATTRIBUTESCLASS   AGE
    hello-sample-pvc   Bound    pvc-fb34c017-ce51-488c-a445-65981b031e0b   10Gi       RWO            standard-rwo-<組織名>   <unset>                 119s
    
  2. この PersistentVolumeClaim を指定して Pod のデバイスファイルとすることで、Pod からはブロックデバイスとして利用できます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: block-demo
    spec:
      containers:
      - name: block-demo
        image: ubuntu
        command:
        - sleep
        - "3600"
        volumeDevices:
        - name: hello-sample-pv
          devicePath: /dev/block
      volumes:
      - name: hello-sample-pv
        persistentVolumeClaim:
          claimName: hello-sample-pvc
    

    ここでは Pod の中からブロックデバイスとして操作できることの例を示します。 この例ではデバイスファイルは nvme2n1 にマッピングされ、PersistentVolumeClaim で指定した 10GiB の大きさを持つブロックデバイスとして認識されていることがわかります。

    $ kubectl -n org-<組織名> exec -it block-demo -- bash
    root@block-demo:/# ls -lF /dev/block
    brw-rw---- 1 root disk 259, 20 Aug  9 03:49 /dev/block
    root@block-demo:/# lsblk /dev/block
    NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
    nvme2n1 259:20   0  10G  0 disk
    root@block-demo:/#
    

参考

Namespace 間でファイルストレージを共有する

PFCP で提供されている 2 種類の永続ストレージのうち、 ファイルストレージについては組織内に作成された複数のネームスペースにまたがる複数の Pod から同時に読み書き可能です。

ファイルストレージの共有

Kubernetes における従来通りのファイルストレージは PersistentVolumeClaim リソース(以下 PVC)が作成されたネームスペースからのみ読み書きできるように アクセス範囲が制限されています。 PFCP では、同じ組織内のネームスペースであれば PVC が作成されたのとは異なるネームスペースからでも読み書きできるように ファイルストレージを共有する機能1が提供されています。

以下では、同じ組織内のネームスペースをまたいでファイルストレージを共有する方法を説明します。

ステップ 1. 共有元のネームスペースで PVC を作成する

説明のために例として作成する PVC の名前を pvc1 、 ファイルストレージを提供する側のネームスペースを org-example--namespace1pvc1 の提供を受けて利用する側のネームスペースを org-example--namespace2 とします。 まず始めにファイルストレージを提供する側のネームスペースで共有したい PVC に trident.netapp.io/shareToNamespace アノテーションを付与します。 このアノテーションに設定されたネームスペースからの共有アクセスが認められるようになります。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
  namespace: org-example--namespace1
  annotations:
    trident.netapp.io/shareToNamespace: org-example--namespace2
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: standard-rwx-example
  resources:
    requests:
      storage: 100Gi

Info

  • PVCの共有先はカンマで区切ることで複数指定することができます。例:trident.netapp.io/shareToNamespace: org-example--namespace2,org-example--namespace3,org-example--namespace4
  • アスタリスク * を指定するとどのネームスペースからでもアクセスを許可することができます。例:trident.netapp.io/shareToNamespace: *
  • PVC の trident.netapp.io/shareToNamespace アノテーションはいつでも追加、変更できます2

ステップ 2. 共有先のネームスペースで TridentVolumeReference を作成する

ファイルストレージが共有される先のネームスペースにおいてカスタムリソース TridentVolumeReference を作成します。 ここに記述する内容でどのネームスペースのどの PVC を参照しようとしているのかをシステムに通知します。

TridentVolumeReference を作成するためには org-trident-edit という ClusterRole で定義されている権限を持つことが必要です。 PFCP の初期状態では組織管理者 org-admin の ClusterRole に対して RoleBinding により紐付けられています。 つまり、初期状態では TridentVolumeReference を作成できるのは組織管理者のみです。

この説明の例ではネームスペース org-example--namespace2 からネームスペース org-example--namespace1 で共有設定がされている PVC pvc1 を参照したいので以下のような記述になります。

apiVersion: trident.netapp.io/v1
kind: TridentVolumeReference
metadata:
  name: my-first-tvr
  namespace: org-example--namespace2
spec:
  pvcName: pvc1
  pvcNamespace: org-exapmle--namespace1

ステップ 3. 共有先のネームスペースで PVC を作成する

ファイルストレージが共有される先のネームスペースにおいて PVC を作成します。 このとき trident.netapp.io/shareFromPVC アノテーションを付与することでどのネームスペースのどの PVC を利用するのかを指定します。

この説明の例ではネームスペース org-example--namespace1 にある PVC pvc1 を共有したいので以下のような記述になります。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  annotations:
    trident.netapp.io/shareFromPVC: org-example--namespace1/pvc1
  name: pvc2
  namespace: org-example--namespace2
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: standard-rwx-example
  resources:
    requests:
      storage: 100Gi

Info

共有先の PVC で指定するストレージのサイズに共有元の PVC のサイズを超える値を指定することはできません。

ステップ 4. 通常の PVC と同じように利用する

通常の PVC と同様にして Pod にマウントしてファイルストレージとして利用します。

共有ファイルストレージの削除

複数のネームスペースで共有されているファイルストレージであっても削除の順番に特別な注意を払う必要はありません。 必要のなくなったネームスペースから PVC を通常の方法で削除してください。 どのネームスペースからも共有ファイルストレージが参照されていないことを検知するとシステムによってボリュームが削除されます。

参考リンク


  1. Astra Trident の TridentVolumeReference を採用しています。

  2. 実際に共有アクセスが可能かどうかを評価するのは後述する共有する側の PVC を作成するタイミングになります。

計算ノードの種類と比較

PFCP では、 2 種類の計算ノードが利用可能です。

以下は各種類の計算ノードの各機能のサポート状況です。

機能専有ノード共有ノード
費用月額従量課金
拡張リソース (MN-Core 2 等) を要求していない Pod の作成×
Pod の CPU/Memory 等のリソース要求量制限なしあり
RWX の永続ストレージ×
RWO の永続ストレージ
サブネームスペースでのリソースクオータ
モニタリング

専有ノードを使用する

専有ノードは、組織のワークロードで専有できる計算ノードの種類です。 組織内の Namespace に作成された Pod は組織間のワークロードで共有される計算ノードである共有ノードでの実行を明示的に指定しない限り専有ノードにスケジュールされるため、利用者自身によるノード選択(nodeSelector の記述)は不要です。

組織に割り当てられた専有ノードは ReservedNode というリソースを通じて参照できます。次のコマンド例では組織に割り当てられた全ての専有ノードを出力します。

kubectl get reservednodes

ReservedNode リソースは Kubernetes の Node リソースと同様に扱うことができ、Label SelectorField Selector による選択ができます。Field Selector がサポートするフィールドは次の通りです。

  • metadata.name
  • spec.unschedulable

なお、ReservedNode リソースは読み取り専用であるため、リソースの変更はできません。

共有ノードを使用する

Warning

本機能は現状では SR1 のみでの提供となっています。 また、提供される共有ノードの数には上限があり、利用状況によっては利用できない可能性があります。 共有ノードの利用状況の可視化は今後の提供を予定しています。

PFCP では、複数の組織で共有されるノードを提供しています。共有ノードは、組織に割り当てられた専有ノードとは異なり複数の組織で共有されます。

利用できるノード

以下を共有ノードとして提供しています。

  • MN-Server 2(preferred.jp/mncore2

利用方法

Pod に専用の PriorityClass を指定することで、自動的に共有ノードにスケジューリングされます。PriorityClass は Pod の優先度を指定するための機能ですが、ここではどのタイプのノードに Pod をスケジューリングするかの制御にも利用されます。 そのため、利用者自身によるノード選択(nodeSelector の記述)は不要です。 以下は Pod を共有ノードで利用する例です。

apiVersion: v1
kind: Pod
metadata:
  name: shared
spec:
  priorityClassName: shared-standard # or shared-best-effort
  ...(省略)...

共有ノードを使用するための PriorityClass は以下の通りです。

  • shared-standard: 共有ノード用の PriorityClass のなかでもっとも優先度が高くプリエンプトされない(追い出されない)
  • shared-best-effort: shared-standard PriorityClass の Pod にプリエンプトされる

Pod の優先度とプリエンプションの詳細は Kubernetes 公式ドキュメントを参照ください。

共有ノードで各組織が利用できる MN-Core 2 の数は PriorityClass それぞれで上限が設定されています。以下のコマンドで利用可能な MN-Core 2 の数を確認できます。

kubectl -n org-<組織名> get hrq shared-standard shared-best-effort -o yaml

Warning

PriorityClass experimental-shared は廃止予定です。2025/9/1 に利用できなくなります。

制約事項

  • 永続ストレージのファイルストレージ(StorageClass standard-rwx-<組織名>)が使用できません
    • RWO の永続ストレージは利用可能です。
  • 1 つの MN-Core 2 で要求できる最大リソース量には制限があります。1 Pod で 2 つの MN-Core 2 を要求する場合では上限値は 2 倍になります。各リソースの 1 つの MN-Core 2 あたりの上限値は以下の通りです。
    リソース1つの MN-Core 2 あたりの上限値
    CPU7000m
    Memory125Gi
    Ephemeral Storage80Gi

セキュリティ

共有ノードは専有ノードとは異なり、複数の組織のワークロードが同じノード上でカーネルを共有します。 組織間のセキュリティ境界についてより強固な分離が必要な場合は、専有ノードの利用を推奨します。

追加のセキュリティ対策

共有ノードでは Linux の User Namespaces を用いて、ホストから Pod 内のコンテナの UID/GID を強制的に分離します。 この技術を用いることで脆弱性等によりコンテナからホストに侵入された場合でも、ホスト内の root ユーザ、つまり UID が 0 のユーザとしてホストを操作できないため、リスクが低減されます。 Linux の User Namespaces は過去の多くのコンテナに関する CVE を防ぐことが知られています1。 詳細は Kubernetes 公式の User Namespaces のドキュメントをご参照ください。


  1. https://github.com/kubernetes/enhancements/tree/217d790720c5aef09b8bd4d6ca96284a0affe6c2/keps/sig-node/127-user-namespaces#motivation

ユーザ管理のコンテナイメージを使用する

Info

このページでは、ユーザ自身が管理するコンテナイメージレジストリに保存されているコンテナイメージを使用するための手順を説明します。 PFCP が提供するコンテナイメージの使用については、PFCP 提供のコンテナイメージについて をご参照ください。

PFCP では Amazon ECR および Google Artifact Registry のプライペートレジストリに保存されているコンテナイメージの取得をサポートしています。 Image pull secrets provisionerというシステムがデプロイされており、 これを使うことで ECR や Google Artifact Registry からイメージを取得するための Secret を自動作成・更新できます。

ECRのコンテナイメージを使用したワークロードの起動

  1. AWS 側で、使用する Kubernetes ServiceAccount に対する ID 連携を構成します。

    • この Kubernetes ServiceAccount を使う Pod が、ECR からイメージを取得できるように信頼関係を構成します。
    • 構成方法については、AWS ドキュメント Create an OpenID Connect (OIDC) identity provider in IAM - AWS Identity and Access Management をご確認ください。
    • プロバイダー URL は以下の値をお使いください。1
      • SR1-01 クラスタ: https://token.sr1-01.kubernetes.pfcomputing.com
      • IK1-01 クラスタ: https://token.ik1-01.kubernetes.pfcomputing.com
    • AWS のマニフェスト管理に Terraform をご利用であれば、Terraform 設定の例 も参照ください。
  2. 使用する ServiceAccount に、以下のアノテーションを付与します。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      namespace: NAMESPACE
      name: SERVICE-ACCOUNT-NAME
      annotations:
        # 使用したいコンテナイメージが格納されているECRレジストリを指定します。
        imagepullsecrets.preferred.jp/registry: 999999999999.dkr.ecr.LOCATION.amazonaws.com
        # ID連携を用いたECRアクセスにおいて使用されるaud値を指定します。
        imagepullsecrets.preferred.jp/audience: sts.amazonaws.com
        # ECRアクセスの際に、AssumeRoleにより使用されるIAM Roleを指定します。
        imagepullsecrets.preferred.jp/aws-role-arn: arn:aws:iam::999999999999:role/ROLE-NAME
    
  3. Pod の .spec.serviceAccountName フィールドを指定することで、Pod がこの ServiceAccount を使うように設定します。

    apiVersion: v1
    kind: Pod
    metadata:
      name: POD-NAME
    spec:
      serviceAccountName: SERVICE-ACCOUNT-NAME
      ...
    
  4. Pod を起動し、ECR からイメージ取得できることを確認します。

Google Artifact Registryのコンテナイメージを使用したワークロードの起動

  1. Google Cloud 側で、使用する Kubernetes ServiceAccount に対する ID 連携を構成します。

    • この Kubernetes ServiceAccount を使う Pod が、Google Artifact Registry からイメージを取得できるように信頼関係を構成します。
    • 構成方法については、Google Cloud ドキュメント Configure workload identity federation with Kubernetes | IAM Documentation | Google Cloud をご確認ください。
    • 発行者(issuer)URL は以下の値をお使いください。1
      • SR1-01 クラスタ: https://token.sr1-01.kubernetes.pfcomputing.com
      • IK1-01 クラスタ: https://token.ik1-01.kubernetes.pfcomputing.com
    • Google Cloud のマニフェスト管理に Terraform をご利用であれば、Terraform 設定の例 も参照ください。
  2. 使用する ServiceAccount に、以下のアノテーションを付与します。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      namespace: NAMESPACE
      name: SERVICE-ACCOUNT-NAME
      annotations:
        # 使用したいコンテナイメージが格納されているGoogle Artifact Registryのレジストリを指定します。
        imagepullsecrets.preferred.jp/registry: LOCATION-docker.pkg.dev
        # ID連携を用いたGoogle Artifact Registryアクセスにおいて使用されるaud値を指定します。
        imagepullsecrets.preferred.jp/audience: //iam.googleapis.com/projects/999999999999/locations/global/workloadIdentityPools/POOL-NAME/providers/PROVIDER-NAME
        # ID連携に使うWorkload Identityプロバイダのリソース名を指定します。
        imagepullsecrets.preferred.jp/googlecloud-workload-identity-provider: projects/999999999999/locations/global/workloadIdentityPools/POOL-NAME/providers/PROVIDER-NAME
        # ID連携に使うGoogleサービスアカウントのEメールアドレスを指定します。
        imagepullsecrets.preferred.jp/googlecloud-service-account-email: SERVICE-ACCOUNT-ID@PROJECT-NAME.iam.gserviceaccount.com
    
  3. Pod の .spec.serviceAccountName フィールドを指定することで、Pod がこの ServiceAccount を使うように設定します。

    apiVersion: v1
    kind: Pod
    metadata:
      name: POD-NAME
    spec:
      serviceAccountName: SERVICE-ACCOUNT-NAME
      ...
    
  4. Pod を起動し、Google Artifact Registry からイメージ取得できることを確認します。

より詳細については image pull secrets provisioner の README をご確認ください。


  1. PFCP の複数クラスタをご利用の場合、クラスタごとに設定が必要です。 ↩2

PFCP 提供のコンテナイメージを使用する

このページでは、PFCP サービスの一部としてお客様に提供するコンテナイメージを使用するための手順を説明します。 お客様が管理するコンテナイメージの使用については、お客様管理のコンテナイメージについて をご参照ください。

Warning

PFCP 提供のコンテナイメージは、PFCP の Kubernetes クラスタ内からのみ利用できます。 それ以外の環境ではイメージの取得に失敗します。

PFCP 提供のコンテナイメージ一覧

PFCP が提供するコンテナイメージの一覧は、ポータルの イメージ ページで確認できます。

PFCP 提供のコンテナイメージを使用したワークロードの起動

以下の手順で、PFCP 提供のコンテナイメージを使用したワークロードを起動します。

  1. Pod の spec.containers.image フィールドに、使用したいコンテナイメージを指定します。
    apiVersion: v1
    kind: Pod
    metadata:
      name: POD-NAME
    spec:
      containers:
      - name: CONTAINER-NAME
        image: registry.pfcomputing.internal/IMAGE:TAG
      ...
    
  2. Pod を起動し、コンテナイメージを取得できることを確認します。

インタラクティブな作業環境を作成する

インタラクティブな作業環境をクラスタ上に作成するにはワークスペース機能を使用します。 ワークスペースは、ブラウザからアクセスできるインタラクティブな作業環境です。 JupyterLab などのインターフェイスを通して PFCP の計算リソースを利用できます。

ワークスペースの隔離

ワークスペースの各インスタンスを隔離する単位は、個人ユーザネームスペース の 2 通りがあります。 ワークスペースを作成する際に、どちらかの隔離タイプを選んで作成できます。

個人ユーザ

個人ユーザ単位で隔離するワークスペースは、ワークスペースを作成したユーザのみが利用できます。 そのため、SSH 秘密鍵など個人の認証情報を安全に保存できます。

組織管理者を含め、他のユーザは利用できません。 ただし、組織管理者はワークスペースを休止・削除できます。

利用可能な操作を以下に一覧します。

操作ワークスペースを作成したユーザ組織管理者その他のユーザ
ブラウザからワークスペースへのアクセスo
ワークスペースの更新o
稼働中のワークスペースの休止oo
休止中のワークスペースの再開o
ワークスペースの削除oo

ネームスペース

ネームスペース単位で隔離するワークスペースは、ワークスペースが作成されたネームスペースに対し org-edit Role をもつユーザが利用できます。 そのため、ネームスペースに対する権限をもつユーザ間でワークスペースを共有できます。

ネームスペースに対し org-edit Role をもたないユーザは利用できません。

ワークスペースを作成する

Note

ワークスペースは、お使いの組織の計算リソースを利用します。 計算リソースが不足している場合、ワークスペースの作成に失敗することがあります。

Note

個人ユーザ単位で隔離するワークスペースは、ルートネームスペースにのみ作成可能です。 そのため、作成にはルートネームスペースに対する org-edit または org-workspace-edit ClusterRole の付与が必要です。 ClusterRole を付与する方法は、RoleBinding の作成 をご参照ください。

  1. ポータルの ワークスペースページ にアクセスし、新規作成 ボタンをクリックします。
  2. フォームを入力し、作成 ボタンをクリックします。

ワークスペースにアクセスする

  1. ポータルの ワークスペースページ にアクセスします。
  2. アクセスしたいワークスペースの URL 列にあるリンクをクリックします。

ワークスペースを休止・再開する

Warning

ワークスペースを休止すると、ワークスペース内のデータが削除されます。 PersistentVolume に保存されているデータは、休止中も保持されます。

利用していないワークスペースを休止することで、計算リソースを節約できます。

  1. ポータルの ワークスペースページ にアクセスします。
  2. 休止したいワークスペースを選択し、休止 ボタンをクリックします。

休止したワークスペースは、同様の手順で再開できます。

  1. ポータルの ワークスペースページ にアクセスします。
  2. 再開したいワークスペースを選択し、再開 ボタンをクリックします。

ワークスペースを削除する

Warning

ワークスペースを削除すると、ワークスペース内のデータ、およびワークスペースから作成した PersistentVolume がすべて削除されます。

  1. ポータルの ワークスペースページ にアクセスします。
  2. 削除したいワークスペースを選択し、削除 ボタンをクリックします。

Kubernetes マニフェストでワークスペースを管理する

ワークスペースはポータルでの操作のほかに、Kubernetes マニフェストを使った管理も可能です。 マニフェストを使うことで、ワークスペースの管理を自動化でき、ワークスペース設定の再現性を高めることができます。

Workspace カスタムリソース

ワークスペースの各インスタンスは、Workspace カスタムリソースで表現されます。

Workspace リソースから、ワークスペースの実体となる Pod が作成されます。 Workspace リソースを作成・更新・削除することで、ワークスペースを管理できます。

Workspace リソースは以下の形式で定義されます。

apiVersion: preferred.jp/v1alpha1
kind: Workspace
metadata:
  name: ...
  namespace: ...
spec:
  owner:
    type: Individual
  podTemplate: ...
  volumeClaimTemplates:
  - ...

Info

kubectl explain workspace コマンドでも各フィールドの説明を確認できます。

  • spec.owner.type フィールド
    • ワークスペースの隔離タイプを指定します。
    • 個人ユーザで隔離する場合は Individual、ネームスペースで隔離する場合は Namespace を指定します。
  • spec.podTemplate フィールド
    • ワークスペースの実体となる Pod に適用する PodTemplateSpec を指定します。
  • spec.volumeClaimTemplates フィールド
    • ワークスペースから作成する PersistentVolumeClaim のリストを指定します。
    • 作成する PersistentVolumeClaim を spec.podTemplate で参照することで、ワークスペースから PersistentVolume を利用できます。

ClusterWorkspacePreset カスタムリソース

ClusterWorkspacePreset カスタムリソースは、ワークスペースの各インスタンスに適用されるデフォルトの設定を表現します。

Workspace リソースからワークスペースの実体となる Pod が作成される際、Workspace リソースの spec.podTemplate フィールドに記述しなかったフィールドは、ClusterWorkspacePreset カスタムリソースから引き継がれます。 spec.podTemplate フィールドに記述したフィールドは、その値で上書きされ Pod が作成されます。

PFCP で定義されている ClusterWorkspacePreset リソースは、kubectl get clusterworkspacepreset コマンド(または kubectl get cwspreset)で確認できます。 一部の値を抜粋すると、以下のようになっています。

apiVersion: preferred.jp/v1alpha1
kind: ClusterWorkspacePreset
metadata:
  name: default
spec:
  podTemplate:
    spec:
      containers:
      - name: workspace
        image: registry.pfcomputing.internal/mncore-sdk/mncore-sdk-full
        command:
        - /app/jupyter/bin/jupyter
        - lab

この値にしたがい、Workspace リソースの spec.podTemplate フィールドを記述しなかった場合、MN-Core SDK のコンテナイメージで JupyterLab を起動する workspace コンテナをもつ Pod が作成されます。 spec.podTemplate フィールドでコンテナイメージやコマンドなどを指定することで、このデフォルト設定を上書きできます。 また、workspace コンテナのリソース要求の設定や、workspace 以外のコンテナの追加も可能です。

ワークロードをウェブアプリとして公開する

PFCP の WebApp Identity-Aware Proxy(WebApp IAP)機能を使うことで、ワークロードをウェブアプリとしてインターネットに公開できます。 公開するウェブアプリには自動でアクセス時の認証が設定され、同一組織に属するユーザのみブラウザからアクセスできます。

WebApp IAP を利用してウェブアプリをインターネットに公開する方法を説明します。

Info

CLI などからアクセスする ウェブ API としてワークロードを公開したい場合は ワークロードをウェブ API として公開する を参照してください。

Ingressリソースを使用したウェブアプリの公開

  1. 公開するワークロードと Service リソースを用意します。ここでは例として、example-svc Service の 80 番ポートへアクセスすることでワークロードへアクセスできる状態になっているとします。

  2. 以下を参考に、Ingress マニフェストを作成します。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
    spec:
      rules:
      - # Ingress に割り当てるドメインを指定します。
        # 注意: ウェブ API での公開と異なり、`ingress.pfcomputing.com` のサブドメインを指定します。
        host: example.<組織名>.<クラスタ名>.ingress.pfcomputing.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              # 公開対象の Service 名とポートを指定します。
              service:
                name: example-svc
                port:
                  number: 80
    

    サブドメインの制限

    ウェブアプリ用 Ingress ではドメインとして *.<組織名>.<クラスタ名>.ingress.pfcomputing.com のみ使用できます。

    例えば、組織名が foo でクラスタ名が sr1-01 の場合は *.foo.sr1-01.ingress.pfcomputing.com となります。

  3. ポータルのパブリックエンドポイント にアクセスし、 クラスタ名ネームスペース名 を選択します。出力されるパブリックエンドポイント一覧の中に、作成した Ingress のサブドメインが含まれることを確認します。

  4. 指定したサブドメインにブラウザからアクセスし、ログインした後1、公開したサービスにアクセスできることを確認します。

制限事項

  • Service リソースの NodePortLoadBalancer タイプを使用したサービスの公開をサポートしていません

  1. ブラウザに有効な認証キャッシュが存在する場合、ログイン処理はスキップされます。

ワークロードをウェブ API として公開する

PFCP の API Identity-Aware Proxy(API IAP)機能を使うことで、ワークロードをウェブ API としてインターネットに公開できます。 公開するウェブ API には自動でアクセス時の認証が設定され、アクセスには Kubernetes ServiceAccount のトークンが必要になります。

API IAP を利用してウェブ API をインターネットに公開する方法を説明します。

Info

ブラウザからアクセスする ウェブアプリ としてワークロードを公開したい場合は ワークロードをウェブアプリとして公開する を参照してください。

Ingressリソースを使用したウェブ API の公開

  1. 公開するワークロードと Service リソースを用意します。ここでは例として、example-svc Service の 80 番ポートへアクセスすることでワークロードへアクセスできる状態になっているとします。

  2. 以下を参考に、Ingress マニフェストを作成します。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
    spec:
      rules:
      - # Ingress に割り当てるドメインを指定します。
        # 注意: ウェブアプリでの公開と異なり、`api.iap.pfcomputing.com` のサブドメインを指定します。
        host: example.<組織名>.<クラスタ名>.api.iap.pfcomputing.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              # 公開対象の Service 名とポートを指定します。
              service:
                name: example-svc
                port:
                  number: 80
    

    サブドメインの制限

    ウェブ API 用 Ingress ではドメインとして *.<組織名>.<クラスタ名>.api.iap.pfcomputing.com のみ使用できます。

    例えば、組織名が foo でクラスタ名が sr1-01 の場合は *.foo.sr1-01.api.iap.pfcomputing.com となります。

  3. 以下を参考に、Ingress へアクセスするための Kubernetes ServiceAccount を作成します。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-sa
      # Ingress と同じ Namespace を指定します。
      namespace: org-foo
      labels:
        # アクセスを許可する Ingress リソースの名前を指定します。
        ingress.preferred.jp/allowed-ingress: example-ingress
    

    default ServiceAccount

    Kubernetes が自動作成する default という名前の ServiceAccount は Ingress へのアクセスに利用できません。

  4. kubectl を利用して Kubernetes ServiceAccount のトークンを発行します。Ingress リソースに設定したドメインへ https:// をつけた値を Audience に設定する必要があります。トークンの有効期限は必要に応じて調整してください。

    $ kubectl create token example-sa --duration 12h --audience https://example.<組織名>.<クラスタ名>.api.iap.pfcomputing.com
    eyJ...
    

    トークンの有効期限

    無期限に有効なトークンを発行することはできません。代わりに十分に長い期間を指定してください。

  5. 発行したトークンを Authorization HTTP ヘッダーに指定し、設定したドメインにアクセスします。公開したサービスにアクセスできることを確認します。

    $ curl -v -H "Authorization: Bearer eyJ..." https://example.<組織名>.<クラスタ名>.api.iap.pfcomputing.com
    

トークンの管理

発行済みの Kubernetes ServiceAccount のトークンを無効にするには、Kubernetes ServiceAccount 自体を削除してください。トークンごとに細かく無効化したい場合は Bound トークン の利用を検討してください。

Kubernetes ServiceAccount の ingress.preferred.jp/allowed-ingress ラベルを削除すると、トークンを無効化せずに一時的にアクセスを遮断できます。アクセスを再開する場合は再度ラベルを設定してください。

Ingress にアクセス可能な Kubernetes ServiceAccount の一覧は kubectl コマンドで確認できます。

$ kubectl get serviceaccount --selector ingress.preferred.jp/allowed-ingress
NAME         SECRETS   AGE
example-sa   0         4s

制限事項

  • Service リソースの NodePortLoadBalancer タイプを使用したサービスの公開をサポートしていません
  • 複数の Ingress で同一のドメインを共有している場合はアクセスできません
  • 60 秒間通信のない状態が続くとコネクションが切断されます

パブリッククラウドと ID 連携を構成する

パブリッククラウドのリソースへのアクセスに使う鍵は強力な認証情報であり、外部への持ち出しはセキュリティリスクがあります。 鍵を持ち出さずにパブリッククラウドのリソースを利用するために、PFCP ではパブリッククラウドとの ID 連携をサポートします。 ID 連携を使用すると、Kubernetes クラスタの ServiceAccount に対してパブリッククラウドの権限が付与され、アクセスが可能になります。

ここでは、Amazon Web Service(以下、AWS)と Google Cloud の 2 種類のパブリッククラウドについて、ID 連携を組む方法について紹介します。

AWSとの連携

AWS 側の設定

  1. AWS ドキュメント IAM で OpenID Connect (OIDC) ID プロバイダーを作成する - AWS Identity and Access Management を参照して、アクセスしたい AWS アカウント内に OIDC プロバイダを作成します。

    • プロバイダー URL1
      • SR1-01 クラスタ: https://token.sr1-01.kubernetes.pfcomputing.com
      • IK1-01 クラスタ: https://token.ik1-01.kubernetes.pfcomputing.com
    • 許可するオーディエンス: sts.amazonaws.com
  2. AWS へのアクセスに使用する IAM ロールを作成します。この IAM ロールは、ID 連携により Kubernetes ServiceAccount に紐づけて使用します。

  3. ID 連携による紐づけを許可するために、IAM ロールを引き受けさせる Kubernetes ServiceAccount を指定して、以下のような信頼ポリシを構成します(ドキュメント)。

    {
        "Version": "2012-10-17",
        "Statement": [{
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                // 前のステップで作成した oidc provider の ARNを指定します。
                "Federated": "arn:aws:iam::XXXXXXXXXXX:oidc-provider/token.sr1-01.kubernetes.pfcomputing.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    // このIAMロールを引き受けさせる Kubernetes ServiceAccount 名を指定します。
                    "token.sr1-01.kubernetes.pfcomputing.com:sub": "system:serviceaccount:<namespace>:<serviceaccount>"
                }
            }
        }]
    }
    
    Warning

    Conditionの設定を必ず記述してください。忘れると、他の組織を含むすべての ServiceAccount に対して権限が付与されてしまいます。

  4. AWS では、Cloud Trail による ID 連携の監査ログがデフォルトで有効になっており、90 日間保存されます。90 日を超えて監査ログを保存しておきたい場合は、AWS アカウント の証跡の作成 - AWS CloudTrail を参照し設定を変更します。

Kubernetesクラスタ側の設定

  1. ServiceAccount の annotations に、ServiceAccount に付与する AWS IAM ロールを指定します。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: foo
      annotations:
        aws.id-federation.preferred.jp/role-arn: "arn:aws:iam::{aws_account_id}:role/{role}"
    
  2. Pod を作成する際に、 .spec.serviceAccountName にこの ServiceAccount を指定します。 Pod 内で AWS SDK を使用すると、ServiceAccount に紐づいた AWS IAM Role を用いて AWS にアクセスします。 セッショントークンの有効期限は 1 時間です。AWS SDK を使い続ける限り自動で更新されます。

  3. 動作確認をします。まず、Pod が使用している IAM ロールを確認します。

    $ kubectl get po <pod> -o yaml | grep AWS_ROLE_ARN:
        AWS_ROLE_ARN:                 arn:aws:iam::861856390547:role/id-federation-test-sr1-01
    

    次に、Pod に Web ID token ファイルのマウントがあることを確認します。

    $ kubectl get po <pod> -o yaml | grep AWS_WEB_IDENTITY_TOKEN_FILE:
        AWS_WEB_IDENTITY_TOKEN_FILE:  /var/run/secrets/sts.amazonaws.com/serviceaccount/token
    

Google Cloud との連携

PFCP には gcp-workload-identity-federation-webhook がデプロイされており、これを使い Google Cloud との ID 連携を構成できます。

Google Cloud 側の設定

Kubernetes との Workload Identity 連携を構成する | IAM のドキュメント | Google Cloud を参照し、以下の設定をおこないます。

  1. アクセスしたい Google Cloud プロジェクト内に Workload Identity のプールとプロバイダを作成します。

    • 発行元 URL
      • SR1-01 クラスタ: https://token.sr1-01.kubernetes.pfcomputing.com
      • IK1-01 クラスタ: https://token.ik1-01.kubernetes.pfcomputing.com
  2. Google Cloud へのアクセスに使用する Google IAM サービスアカウントを作成し、許可するリソースに対するアクセス権を付与します。このサービスアカウントは、ID 連携により Kubernetes ServiceAccount に紐づけて使用します。

  3. ID 連携による紐づけを許可するために、Workload Identity ユーザロール(roles/iam.workloadIdentityUser)を上記の Google IAM サービスアカウントに付与します。このとき、Kubernetes ServiceAccount に限定して権限の借用を許可するために、以下をメンバーとして指定します。

    principal://iam.googleapis.com/projects/<Google CloudのプロジェクトID> \
    /locations/global/workloadIdentityPools/<作成したWorkload IdentityプールのID> \
    /subject/<クラスタの発行元URL>::system:serviceaccount:<Kubernetes ServiceAccountのNamespace>:<Kubernetes ServiceAccountのName>
    

Kubernetes クラスタ側の設定

  1. ServiceAccount の annotations に、Workload Identity プロバイダ、借用させる IAM サービスアカウント、Workload Identity プロバイダが期待するオーディエンスの値をアノテーションとして設定します。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      annotations:
        googlecloud.id-federation.preferred.jp/workload-identity-provider: |-
          projects/<Google CloudのプロジェクトID>/locations/global/workloadIdentityPools/<作成したWorkload IdentityプールのID>/providers/<作成したWorkload IdentityプールプロバイダのID>
        googlecloud.id-federation.preferred.jp/service-account-email: |-
          <Google IAM サービスアカウント名>@<Google Cloudのプロジェクト名>.iam.gserviceaccount.com
        googlecloud.id-federation.preferred.jp/audience: <下記のオーディエンス>
    

    オーディエンスの値はデフォルトで以下の形式になります。

    //iam.googleapis.com/projects/<Google CloudのプロジェクトID> \
    /locations/global/workloadIdentityPools/<作成したWorkload IdentityプールのID> \
    /providers/<作成したWorkload IdentityプールプロバイダのID>
    
  2. Pod を作成する際に、 .spec.serviceAccountName にこの ServiceAccount を指定します。 Pod 内で Google Cloud SDK を使うと、指定した ServiceAccount に紐づいた Google IAM サービスアカウントを借用して Google Cloud にアクセスします。 認証情報の有効期限はデフォルトで 24 時間です。Google Cloud SDK を使い続ける限り、自動で更新されます。

より詳細については gcp-workload-identity-federation-webhook の README をご覧ください。


  1. PFCP の複数クラスタをご利用の場合、クラスタごとに設定が必要です。

メトリクスモニタリングとアラーティング

PFCP では、Grafana1・Prometheus2 を使用したメトリクスモニタリング機能とアラート機能をマネージドサービスとして提供しています。また、Prometheus Operator を導入しており、Kubernetes カスタムリソースを用いてモニタリング対象やアラートルールを宣言的に管理できます。

モニタリング機能へのアクセス

ポータルのトップページ に掲載のリンクからモニタリングサービスの各機能にアクセスできます。

Grafana ダッシュボード

Kubernetes ワークロードの状況を可視化する Grafana ダッシュボードを標準提供しています。 標準提供のダッシュボードには、例えば以下のダッシュボードが含まれます。

  • kube-prometheus > Kubernetes / Compute Resources / Namespace (Workloads)
    • Namespace 単位のリソース使用状況
  • kube-prometheus > Kubernetes / Compute Resources / Pod
    • Pod のリソース使用状況

また、Grafana WebUI より任意のダッシュボードを作成できます。 ダッシュボードを追加する場合は専用のフォルダを作成し、その中にダッシュボードを作成することを推奨します。

メトリクスモニタリング

Pod のメトリクスをスクレイプする

Prometheus Operator の ServiceMonitor、PodMonitor カスタムリソースを使用して、Pod のメトリクスをスクレイプできます。また取得したメトリクスを可視化するには Grafana ダッシュボードが使用できます。

ServiceMonitor、PodMonitor の使い方については、Prometheus Operatorの公式ドキュメントをご参照ください。

アラートルールを追加する

Kubernetes ワークロードの健全性を確認するアラートルールを標準で提供しています。標準で提供されるアラートルールは Prometheus WebUI の Alerts タブで確認できます。

加えて、Prometheus Operator の PrometheusRule カスタムリソースを使用して任意のアラートルールを追加できます。 PrometheusRule の使い方については、以下をご確認ください。

アラート通知先を追加する

Prometheus Operator の AlertmanagerConfig カスタムリソースを使用して、アラートを任意のサービスやツールに送信できます。 AlertmanagerConfig の使い方については、以下をご確認ください。

サンプルのマニフェストファイル

apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
  name: alertmanager-config
spec:
  inhibitRules:
  - equal:
    - namespace
    - alertname
    sourceMatch:
    - name: severity
      value: critical
    targetMatch:
    - matchType: =~
      name: severity
      value: warning|info
  - equal:
    - namespace
    - alertname
    sourceMatch:
    - name: severity
      value: warning
    targetMatch:
    - name: severity
      value: info
  - equal:
    - namespace
    sourceMatch:
    - name: alertname
      value: InfoInhibitor
    targetMatch:
    - name: severity
      value: info
  route:
    groupBy:
    - alertname
    groupInterval: 5m
    groupWait: 30s
    receiver: slack
    repeatInterval: 12h
    routes:
    - matchers:
      - name: alertname
        value: InfoInhibitor
      receiver: "null"
    - matchers:
      - name: alertname
        value: Watchdog
      receiver: "null"
  receivers:
  - name: "null"
  - name: slack
    slackConfigs:
    - apiURL:
        name: alertmanager-cred
    key: slack-url
      sendResolved: true

Prometheus サーバの仕様

提供する Prometheus サーバの仕様は次のとおりです。

  • メトリクス保持期間(Retention time): 15 日
  • メトリクス保持サイズ(Retention size): 95GiB

Warning

メトリクス保持期間、保持サイズの変更はサポートしていません。

制限事項

  • Grafana・Prometheus において、組織内の権限管理機能を提供していません。一般ユーザが全てのメトリックやダッシュボードが閲覧可能です。

  1. Grafana はさまざまなデータソースからの時系列データを可視化するためのオープンソースのダッシュボードツールです。https://grafana.com/docs/grafana/latest

  2. Prometheus は、時系列データの収集とクエリに特化したオープンソースの監視・アラートシステムです。 https://prometheus.io/docs/

Pod にセキュリティポリシを適用する

Kubernetes では、セキュリティリスクを低減するために Pod Security Standards(以下、PSS)という Pod セキュリティの推奨構成が定義されています。PFCP では、PSS に準拠した Pod セキュリティプロファイルが適用されます。

PSS には、Restricted・Baseline・Privileged の 3 つのポリシーがあり、PFCP ではデフォルトで Baseline が適用されます。Baseline は、コンテナワークロードに対する制限を少なめにしつつも、既知の特権昇格に対し対策されたポリシーです。

より Pod セキュリティを強化したい場合には、Restricted ポリシーも利用できます。 Pod の label に policy.preferred.jp/pod-security: restricted をつけることで Restricted が適用され、ポリシーに違反する Pod は作成できなくなります。

Info

特権昇格が可能な Privileged ポリシーは利用できません。

PSS の各ポリシーの詳細については、 Kubernetesの公式ドキュメント をご参照ください。

MN-Core シリーズ利用時のプロファイル

MN-Core シリーズのリソースを要求する Pod を作成すると、MN-Core シリーズを用いた演算の処理速度を向上するために、自動的に SYS_NICE capability が付与されます1。 この対応は、MN-Core シリーズのリソースを要求する Pod に限定されます。 MN-Core シリーズのリソースを要求しない Pod の場合は、PSS Baseline に準拠しているため、SYS_NICE capability は付与できません。


  1. Kubernetes の標準機能ではなく、PFCP 独自の拡張です。

仕様: 拠点と計算ノード

拠点

SR1

  • インターネット向け通信のソース IP アドレス
    • 202.214.130.143/32

計算ノード

MN-Server 2 V1(ノード名: isXXzXcqXX

項目仕様
CPUIntel Xeon Platinum 8480+(56 コア) x 2
メモリ1.0TiB
アクセラレータMN-Cores 2 ボード x 8
インターコネクトNVIDIA ConnectX-6 Dx(100Gbps) x 4
ブートディスク容量878GiB

仕様: ソフトウェアバージョン

クラスタとアドオン

ソフトウェア名バージョンドキュメントサイト
Kubernetesv1.32.5https://kubernetes.io/
Ciliumv1.15.8https://docs.cilium.io/en/v1.15/
Prometheus Operatorv0.80.0https://prometheus-operator.dev/
Hierarchical Namespacesv1.1.0-pfnet.7https://github.com/pfnet/hierarchical-namespaces
Amazon EKS Pod Identity Webhookv0.6.6https://github.com/aws/amazon-eks-pod-identity-webhook
GCP Workload Identity Federation Webhookv0.5.0https://github.com/pfnet-research/gcp-workload-identity-federation-webhook
Image pull secrets provisionerv0.0.7https://github.com/pfnet/image-pull-secrets-provisioner
Astra Tridentv25.02.1https://docs.netapp.com/us-en/trident/index.html
Fluxv2.6.0https://fluxcd.io/flux

モニタリングサービス

ソフトウェア名バージョンドキュメントサイト
Grafanav12.0.0+security-01https://grafana.com/docs/grafana/latest/