NAI 2.4 の推論エンドポイントむけに作成したデモ アプリを、Nutanix Kubernetes Platform(NKP)のカタログに、カスタム アプリケーションとして登録してみます。
今回の内容です。
- 今回のアプリについて
- 1. nkp CLI のインストール
- 2. NKP カタログ バンドルの準備
- 3. OCI リポジトリの準備
- 4. NKP カタログ アプリケーションの登録
- 5. NKP でのアプリケーション インストール
今回のアプリについて
以前に作成した、AI チャットのデモ アプリを使用します。
このデモ アプリは、コンテナ イメージ化してあり、OCI アーティファクト形式の Helm Chart を用意してあります。
1. nkp CLI のインストール
NKP では、アプリケーション管理でも nkp CLI を使用します。そこで、作業用の Linux マシンに nkp CLI をインストールしておきます。NKP の Kubernetes クラスタ作成時に使用した nkp コマンド実行マシンがある場合は、そこでも作業できます。
作業用ユーザーは、PATH 環境変数に $HOME/bin ディレクトリを追加してあります。Nutanix Support & Insight Portal から、nkp CLI の tar.gz ファイルをダウンロードして、Linux マシンに配置しておきます。
$ ls -l nkp_v2.16.0_linux_amd64.tar.gz -rw-rw-r-- 1 gowatana gowatana 138587302 Oct 17 10:41 nkp_v2.16.0_linux_amd64.tar.gz
ファイルを展開して、nkp コマンドをインストールします。
$ tar zxvf nkp_v2.16.0_linux_amd64.tar.gz nkp $ install nkp $HOME/bin/
不要になったファイルは削除しておきます。
$ rm nkp $ rm nkp_v2.16.0_linux_amd64.tar.gz
今回の nkp CLI のバージョンは、v2.16.0 です。
$ nkp version catalog: v0.7.0 diagnose: v0.12.0 imagebuilder: v2.16.0 kommander: v2.16.0 konvoy: v2.16.0 mindthegap: v1.22.1 nkp: v2.16.0
2. NKP カタログ バンドルの準備
NKP のカタログ リポジトリを作成して、それを tar アーカイブしたカタログ バンドルを作成します。
2-1. NKP カタログ リポジトリの作成
NKP カタログ リポジトリのディレクトリを作成します。このディレクトリ名はこの後作成する OCI リポジトリのパスにも使用されます。
$ mkdir nkp-repo
nkp generate catalog-repository で、カタログ リポジトリの雛形となるファイル一式を作成します。「--apps」で指定している「nai-demo=0.0.1」は、リポジトリに含める Helm Chart のアプリ バージョンではなく、NKP カタログ リポジトリで管理するアプリ バージョンです。そのため、カタログ リポジトリ自体の設定を変更する場合は、Helm Chart とは別バージョンとは分離して管理できます。
$ nkp generate catalog-repository --apps nai-demo=0.0.1 --repo-dir ./nkp-repo/ Successfully initialized application layout for nai-demo-0.0.1 Catalog layout generated at /home/gowatana/nkp-repo
下記のようにリポジトリが生成されます。隠しファイルがあるので、tree コマンドに「-a」オプションを追加しています。
$ tree ./nkp-repo/ --charset=ascii -a
./nkp-repo/
|-- .bloodhound.yml
`-- applications
`-- nai-demo
`-- 0.0.1
|-- helmrelease
| |-- cm.yaml
| |-- helmrelease.yaml
| `-- kustomization.yaml
|-- helmrelease.yaml
|-- kustomization.yaml
`-- metadata.yaml
5 directories, 7 files
リポジトリ(nkp-repo ディレクトリ)直下の .bloodhound.yml ファイルは、ひとまずデフォルトのままにしてあります。
./nkp-repo/.bloodhound.yml
metadata.yaml ファイルは、バンドル作成時のエラー解消のため「supportLink」のみ編集してあります。
./nkp-repo/applications/nai-demo/0.0.1/metadata.yaml
- L14:supportLink を、とりあえず私の X/Twitter アカウントに変更
helmrelease.yaml ファイルは、OCI アーティファクトの URL のみ変更します。
./nkp-repo/applications/nai-demo/0.0.1/helmrelease/helmrelease.yaml
- L9:OCI アーティファクト イメージのタグ(0.0.1)
- L10:OCI リポジトリを指定
url: oci://<registry>/<org-name>/<repo-name>
↓
url: oci://ghcr.io/gowatana/nai-demo-repo/nai-demo
2-2. NKP カタログ バンドルの作成
nkp create catalog-bundle で、カタログ バンドルを作成します。今回は、nai-demo-0.0.1.tar ファイルが作成されます。
$ nkp create catalog-bundle --repo-dir ./nkp-repo/
Bundling 1 application(s) (airgapped : false)
✓ Validating metadata.yaml for nai-demo/0.0.1
✓ Building OCI artifact nkp-repo/nai-demo:0.0.1
Processing application nai-demo/0.0.1
✓ K8s v1.33.0: parsing resources
✓ K8s v1.33.0: validating
✓ Pulling requested images [====================================>1/1] (time elapsed 00s)
✓ Saving application bundle to /home/gowatana/nai-demo-0.0.1.tar
Run the following to push the artifact to your registry:
nkp push bundle --bundle /home/gowatana/nai-demo-0.0.1.tar --to-registry
Run the following command to create catalog artifact(s) after pushing them:
nkp create catalog-application --url oci:///nkp-repo/nai-demo --tag 0.0.1 --workspace kommander-workspace
$
3. OCI リポジトリの準備
NKP カタログ バンドルを OCI レジストリに Push して、OC リポジトリとして公開します。
今回の OCI レジストリは、コンテナ イメージと同様に GitHub Container Registry(ghcr.io)を使用します。
3-1. OCI レジストリへのログイン
docker login の認証情報がそのまま利用できます。パスワードには、あらかじめ GitHub の Tokens (classic) ページ(GitHub アカウントで要ログイン)で生成しておいたトークン(ghp_~ といった文字列)を入力します。
$ docker login ghcr.io Username: gowatana Password: WARNING! Your credentials are stored unencrypted in '/home/gowatana/.docker/config.json'. Configure a credential helper to remove this warning. See https://docs.docker.com/go/credential-store/ Login Succeeded
3-2. OCI レジストリへのカタログ バンドルの Push
下記のコマンドで OCI レジストリに Push します。今回している「ghcr.io/gowatana」は、私の GitHub リポジトリです。
nkp push bundle \ --bundle ./nai-demo-0.0.1.tar \ --to-registry ghcr.io/gowatana
実際に実行すると、下記のようになります。
$ nkp push bundle \ --bundle ./nai-demo-0.0.1.tar \ --to-registry ghcr.io/gowatana ✓ Creating temporary directory ✓ Extracting bundle configs from "./nai-demo-0.0.1.tar" ✓ Parsing image bundle config ✓ Starting temporary Docker registry ✓ Pushing bundled images [====================================>1/1] (time elapsed 02s)
これで、Github Container Registry のリポジトリに、NKP カタログ バンドルのパッケージがアップロードされ、OCI アーティファクトとして扱えるようになりました。
3-3. OCI リポジトリの公開
OCI リポジトリから、認証なしでアーティファクトをダウンロードできるようにしておきます。パッケージの Visibility を Public に変更しておきます。
コンテナ イメージのページにある、「Package settings」を開きます。

画面下方にある、「Change visibility」をクリックします。

「Public」を選択し、リポジトリの名前(今回は nkp-repo/nai-demo)を入力して、「I understand the consequences, change package visibility」をクリックします。

これで、コンテナ イメージの Visibility が「Public」になり、GitHub の認証なしで Pull できるようになりました。

4. NKP カタログ アプリケーションの登録
NKP のカタログ アプリケーションを、NKP の管理クラスタに登録します。
4-1. NKP 管理クラスタのコンテキスト作成
NKP の管理クラスタに接続するためのコンテキスト作成を、NKP Dashboard から実施します。すでに管理クラスタの kubeconfig ファイルがある場合は、この手順を省略して「--kubeconfig」オプションで管理クラスタに接続できます。
NKP Dashboard にログインして、画面上部で「Global」を選択して、画面右上のユーザー名 →「Ganarate Token」をクリックします。ちなみに、「admin」はビルトインではなく、手動作成したユーザーです。

「Main」を選択します。

ログイン画面が表示されたら、NKP の管理ユーザー(NKP Dashboard と同じユーザー)でログインします。

コードが表示されるので、上から順に、kubectl を実行するターミナルにコピー & ペーストして実行します。

これで、管理クラスタに接続できるコンテキスト(今回は admin-172.22.5.201)が作成されます。
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
admin-172.22.5.201 admin-172.22.5.201 admin-172.22.5.201
* nkpw02-admin@nkpw02 nkpw02 nkpw02-admin
管理クラスタのコンテキストを切り替えます。
$ kubectl config use-context admin-172.22.5.201 Switched to context "admin-172.22.5.201".
管理クラスタ(nkpm01)に接続できることを確認しておきます。
$ kubectl get nodes NAME STATUS ROLES AGE VERSION nkpm01-8x785-c2phw Ready control-plane 15d v1.33.2 nkpm01-8x785-k29gq Ready control-plane 15d v1.33.2 nkpm01-8x785-nrlvp Ready control-plane 15d v1.33.2 nkpm01-md-0-rnvvs-qdkdq-lrmlr Ready <none> 15d v1.33.2 nkpm01-md-0-rnvvs-qdkdq-m4jmn Ready <none> 15d v1.33.2 nkpm01-md-0-rnvvs-qdkdq-ncnzj Ready <none> 15d v1.33.2
カタログ アプリケーションを追加する NKP Workspace の Namespace を確認しておきます。この NKP では、「ws-01」Workspaceを作成してありますが、これは Kubernetes の「ws-01-4vp9g-d4xvq」Namespace に紐づけられています。アプリケーションをインストールするワークロード クラスタは、ws-01 Workspace に配置してあります。
$ kubectl get workspaces.workspaces.kommander.mesosphere.io NAME DISPLAY NAME WORKSPACE NAMESPACE AGE default-workspace Default Workspace kommander-default-workspace 15d kommander-workspace Management Cluster Workspace kommander 15d ws-01-4vp9g ws-01 ws-01-4vp9g-d4xvq 15d
なお、このコンテキストは一定時間経過すると期限切れになります。管理クラスタ(ワークロード クラスタも)に接続できなくなった場合は、あらためてこの手順でコンテキストを再作成します。
4-2. カタログ アプリケーションの追加
ws-01 Workspace(ws-01-4vp9g-d4xvq Namespace)に、カタログを追加します。
nkp create catalog-application \ --url oci://ghcr.io/gowatana/nkp-repo/nai-demo \ --tag 0.0.1 \ --workspace ws-01-4vp9g \ --skip-oci-registry-patches
コマンドを実行すると、下記のようになります。
$ nkp create catalog-application \ --url oci://ghcr.io/gowatana/nkp-repo/nai-demo \ --tag 0.0.1 \ --workspace ws-01-4vp9g \ --skip-oci-registry-patches Catalog application nkp-repo-nai-demo created. Use 'nkp edit ocirepository -n ws-01-4vp9g-d4xvq nkp-repo-nai-demo' to change its configuration if needed. Note that the OCIRepository is not patched by NKP with credentials due to custom configuration. Make sure to configure the url and credentials according to your cluster networking capabilities.
4-3. カタログ アプリケーション追加後の様子(管理クラスタ)
管理クラスタに、OCIRepository リソースが作成されました。
$ kubectl get ocirepository -n ws-01-4vp9g-d4xvq nkp-repo-nai-demo NAME URL READY STATUS AGE nkp-repo-nai-demo oci://ghcr.io/gowatana/nkp-repo/nai-demo True stored artifact for digest '0.0.1@sha256:851b60d0de193dae2ec7d5a3be791f80e5e86c46ec9aaf13462d1a8b955fb96d' 27s
OCIRepository リソースの情報です。
$ kubectl get ocirepository -n ws-01-4vp9g-d4xvq nkp-repo-nai-demo -o yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
annotations:
nkp.nutanix.com/skip-oci-registry-patches: "true"
creationTimestamp: "2025-10-23T12:51:04Z"
finalizers:
- finalizers.fluxcd.io
generation: 1
labels:
catalog.nkp.nutanix.com/catalog-source-artifact: "true"
name: nkp-repo-nai-demo
namespace: ws-01-4vp9g-d4xvq
resourceVersion: "43883061"
uid: 75527318-acd8-4979-9c36-9ab173885b45
spec:
interval: 6h0m0s
provider: generic
ref:
tag: 0.0.1
timeout: 1m0s
url: oci://ghcr.io/gowatana/nkp-repo/nai-demo
status:
artifact:
digest: sha256:9bd003a9d734a9a2ed482fd23f7f14923da58f19e288612c390174010e0c7000
lastUpdateTime: "2025-10-23T12:51:06Z"
metadata:
com.nutanix.nkp.catalog.application-name: nai-demo
com.nutanix.nkp.catalog.application-version: 0.0.1
com.nutanix.nkp.catalog.artifact-type: catalog-application
org.opencontainers.image.created: "2025-10-23T04:35:33Z"
org.opencontainers.image.ref.name: nai-demo:0.0.1
org.opencontainers.image.source: nai-demo:0.0.1
path: ocirepository/ws-01-4vp9g-d4xvq/nkp-repo-nai-demo/sha256:851b60d0de193dae2ec7d5a3be791f80e5e86c46ec9aaf13462d1a8b955fb96d.tar.gz
revision: 0.0.1@sha256:851b60d0de193dae2ec7d5a3be791f80e5e86c46ec9aaf13462d1a8b955fb96d
size: 883
url: http://source-controller.kommander-flux.svc.cluster.local./ocirepository/ws-01-4vp9g-d4xvq/nkp-repo-nai-demo/sha256:851b60d0de193dae2ec7d5a3be791f80e5e86c46ec9aaf13462d1a8b955fb96d.tar.gz
conditions:
- lastTransitionTime: "2025-10-23T12:51:06Z"
message: stored artifact for digest '0.0.1@sha256:851b60d0de193dae2ec7d5a3be791f80e5e86c46ec9aaf13462d1a8b955fb96d'
observedGeneration: 1
reason: Succeeded
status: "True"
type: Ready
- lastTransitionTime: "2025-10-23T12:51:06Z"
message: stored artifact for digest '0.0.1@sha256:851b60d0de193dae2ec7d5a3be791f80e5e86c46ec9aaf13462d1a8b955fb96d'
observedGeneration: 1
reason: Succeeded
status: "True"
type: ArtifactInStorage
observedGeneration: 1
url: http://source-controller.kommander-flux.svc.cluster.local./ocirepository/ws-01-4vp9g-d4xvq/nkp-repo-nai-demo/latest.tar.gz
App リソースも作成されました。
$ kubectl get apps -n ws-01-4vp9g-d4xvq nai-demo-0.0.1 NAME APP ID APP VERSION SOURCE AGE nai-demo-0.0.1 nai-demo 0.0.1 nkp-repo-nai-demo 93s
App リソースの情報です。
$ kubectl get apps.apps.kommander.d2iq.io -n ws-01-4vp9g-d4xvq nai-demo-0.0.1 -o yaml
apiVersion: apps.kommander.d2iq.io/v1alpha3
kind: App
metadata:
annotations:
apps.kommander.d2iq.io/allow-multiple-instances: "true"
apps.kommander.d2iq.io/category: general
apps.kommander.d2iq.io/display-name: nai-demo
apps.kommander.d2iq.io/licensing-tiers: pro,ultimate
apps.kommander.d2iq.io/scope: project
apps.kommander.d2iq.io/support-link: https://x.com/gowatana
apps.kommander.d2iq.io/type: custom
creationTimestamp: "2025-10-23T12:51:06Z"
generation: 1
name: nai-demo-0.0.1
namespace: ws-01-4vp9g-d4xvq
resourceVersion: "43883064"
uid: 49147775-353d-41fa-a2f1-da7955eb295e
spec:
appId: nai-demo
sourceRef:
kind: OCIRepository
name: nkp-repo-nai-demo
namespace: ws-01-4vp9g-d4xvq
version: 0.0.1
NKP Dashboard で、「ws-01」ワークスペースの「Application」画面を表示すると、カタログにデモ アプリ「nai-demo」が追加されています。

5. NKP でのアプリケーション インストール
NKP Dashboard から、デモ アプリ「nai-demo」をインストールします。
「ws-01」Workspace →「Application」を開き、「nai-demo」パネル右下のボタン →「Enable」をクリックします。

パラメータを入力して、「Enable」をクリックします。
- ID:nai-demo-1
- Selected Cluster:nkpw02(ワークロード クラスタ)
- Workplace Configuration:Helm Chart の values.yaml と同じパラメータ(下記)を入力
config: NAI_ENDPOINT_NAME: "gemma-ep-01" NAI_ENDPOINT_URL: "https://10.1.7.122/api/v1/chat/completions" secret: NAI_API_KEY: "d8cb366b-d68d-4f9e-8a65-7075e137977e"

これで、アプリがインストールされました。

ワークロード クラスタでは、ws-01 Workspace に対応した Namespace に、Service が作成されているので、EXTERNAL-IP を確認します。
$ kubectl get svc --context nkpw02-admin@nkpw02 -n ws-01-4vp9g-d4xvq -l app=nai-demo NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ws-01-4vp9g-d4xvq-nai-demo-1 LoadBalancer 10.101.202.0 172.22.5.212 80:31096/TCP 5m
Service の EXTERNAL-IP(例では 172.22.5.212)に Web ブラウザからアクセスすると、デモ アプリの AI チャットが表示されます。

5-2. インストールされたカスタム アプリの様子(管理クラスタ)
NKP の管理クラスタでは、AppDeployment リソースが作成されました。
$ kubectl get appdeployments.apps.kommander.d2iq.io -n ws-01-4vp9g-d4xvq nai-demo-1 NAME APP AGE nai-demo-1 nai-demo-0.0.1 23s
AppDeployment の情報です。
$ kubectl get appdeployments.apps.kommander.d2iq.io -n ws-01-4vp9g-d4xvq nai-demo-1 -o yaml
apiVersion: apps.kommander.d2iq.io/v1alpha3
kind: AppDeployment
metadata:
creationTimestamp: "2025-10-23T12:54:52Z"
finalizers:
- kommander.mesosphere.io/appdeployment
generation: 1
name: nai-demo-1
namespace: ws-01-4vp9g-d4xvq
resourceVersion: "43890749"
uid: af3fd0e5-d49c-4761-9342-8080d838c26f
spec:
appRef:
kind: App
name: nai-demo-0.0.1
clusterSelector:
matchExpressions:
- key: kommander.d2iq.io/cluster-name
operator: In
values:
- nkpw02
configOverrides:
name: nai-demo-1-config-overrides
status:
clusters:
- conditions:
- status: "True"
type: AppDeploymentEnabled
name: nkpw02
observedGeneration: 1
5-3. インストールされたカスタム アプリの様子(ワークロード クラスタ)
アプリをインストールしたワークロード クラスタに、コンテキストを切り替えます。
$ kubectl config use-context nkpw02-admin@nkpw02 Switched to context "nkpw02-admin@nkpw02".
コンテキストがワークロード クラスタに切り替わりました。
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
admin-172.22.5.201 admin-172.22.5.201 admin-172.22.5.201
* nkpw02-admin@nkpw02 nkpw02 nkpw02-admin
ワークロード クラスタに接続できることを確認しておきます。
$ kubectl get nodes NAME STATUS ROLES AGE VERSION nkpw02-5jkcf-wx4bc Ready control-plane 15d v1.33.2 nkpw02-md-0-9xs7f-nhlcz-dbdwd Ready <none> 15d v1.33.2
ws-01 Workspace に対応した Namespace で、アプリに関連するリソースが作成されています。
$ kubectl get all -n ws-01-4vp9g-d4xvq -l app=nai-demo NAME READY STATUS RESTARTS AGE pod/ws-01-4vp9g-d4xvq-nai-demo-1-5965c56985-fx662 1/1 Running 0 109s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ws-01-4vp9g-d4xvq-nai-demo-1 LoadBalancer 10.101.202.0 172.22.5.212 80:31096/TCP 109s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/ws-01-4vp9g-d4xvq-nai-demo-1 1/1 1 1 109s NAME DESIRED CURRENT READY AGE replicaset.apps/ws-01-4vp9g-d4xvq-nai-demo-1-5965c56985 1 1 1 109s
Pod「ws-01-4vp9g-d4xvq-nai-demo-1-~」も起動されています。
$ kubectl get pods -n ws-01-4vp9g-d4xvq NAME READY STATUS RESTARTS AGE alertmanager-kube-prometheus-stack-alertmanager-0 2/2 Running 0 14d etcd-metrics-proxy-hlxtq 1/1 Running 0 14d gatekeeper-audit-7c7c7d5f49-5dfg6 1/1 Running 0 15d gatekeeper-controller-manager-774b66c7c4-hvgt8 1/1 Running 0 15d gatekeeper-controller-manager-774b66c7c4-v8szr 1/1 Running 0 15d kommander-traefik-c5bd74457-52jrt 1/1 Running 0 14d kommander-traefik-c5bd74457-s2jf6 1/1 Running 0 14d kube-oidc-proxy-77974fb489-7zq8t 1/1 Running 0 14d kube-prometheus-stack-grafana-86d746f479-x4kcg 2/2 Running 0 14d kube-prometheus-stack-kube-state-metrics-58b99f6dc7-n6xwr 1/1 Running 0 14d kube-prometheus-stack-operator-57f998d8d7-d9qhf 1/1 Running 0 14d kube-prometheus-stack-prometheus-node-exporter-rb7bw 2/2 Running 0 14d kube-prometheus-stack-prometheus-node-exporter-rr8h4 2/2 Running 0 14d kubecost-cost-analyzer-67f74b5864-wq2kc 1/1 Running 0 14d kubecost-pre-install-hc8zx 0/1 Completed 0 14d kubecost-prometheus-alertmanager-6bc8fc8977-zhcpl 2/2 Running 0 14d kubecost-prometheus-server-7c57b45f5f-8wncj 2/2 Running 0 14d kubernetes-dashboard-api-c59dc7996-ntxfb 1/1 Running 0 14d kubernetes-dashboard-auth-dd9b69cfb-lj9nt 1/1 Running 0 14d kubernetes-dashboard-kong-5d8d8bc7b8-29dqf 1/1 Running 0 14d kubernetes-dashboard-metrics-scraper-7fbb77f87f-xd5t6 1/1 Running 0 14d kubernetes-dashboard-web-697769cddd-r4lq7 1/1 Running 0 14d prometheus-adapter-d8f96c654-cz9sj 1/1 Running 0 14d prometheus-kube-prometheus-stack-prometheus-0 3/3 Running 0 14d traefik-forward-auth-567694d49d-lr9ch 1/1 Running 0 14d ws-01-4vp9g-d4xvq-nai-demo-1-5965c56985-fx662 1/1 Running 0 80s ws-01-4vp9g-d4xvq-reloader-reloader-5ddb54d499-8hkbg 1/1 Running 0 14d
今回登録したアプリを削除するには、下記のような手順を実施します。
以上。
