RunPod Hubにテンプレートを公開するまで|手順と8リリース分の失敗ログ

生成AI

⚠️ 注意: AI画像生成時は著作権・肖像権にご注意ください。商用利用前には各サービスの利用規約をご確認ください。当ブログは生成された画像に関する責任を負いかねます。

📝 本記事にはアフィリエイトリンクが含まれています。

要約

自作のComfyUIテンプレートをRunPod Hubに公開するまでの手順と、そこで踏んだ失敗をまとめました。

RunPod Hubは、GitHubリポジトリに .runpod/hub.json.runpod/tests.json を置いてリリースを切ると、RunPod側がDockerイメージをビルドしてテストまで走らせてくれる仕組みです。手順自体はシンプルなんですが、僕はv0.3.2にたどり着くまでに8回リリースを切りました。

失敗の中身は大きく3つでした。handlerを用意しなかったことビルドが緑なのにパッケージが入っていなかったことtests.jsoninput を空にしていたことです。どれもRunPodのドキュメントには書かれていない挙動が絡んでいます。

はじめに

RunPodには公式のComfyUIテンプレートがあります。ComfyUI + Manager + JupyterLab入りのものが、標準GPU版とBlackwell版の2本立てで用意されていて、素のComfyUIを動かすだけならそれで十分です。

じゃあ個人がテンプレートを出す意味はどこにあるのか。僕の答えはモデル調達の部分でした。ComfyUI本体は公式が面倒を見てくれますが、「ACE-Step 1.5 XLのdiffusion modelとtext encoderとVAEを、正しい場所に、正しい組み合わせで置く」ところは誰もやってくれません。ここが実際に一番詰まるところなんですよね。

その部分をまとめたテンプレートは以前から公開していて、記事のDeployリンクから起動できるようにしていました。

ACE-Step 1.5 XLをRunPodで動かす公開ComfyUIテンプレートを作りました
ACE-Step 1.5 XLをRunPod上のComfyUIで動かす公開テンプレートをv3.0.0に更新。base/SFT/turbo、qwen text encoder、CUDA 12.8と13.0の使い分け、RTX 4090での生成時間、つまずいた点まで実録でまとめます。

ただ、これはRunPodのconsoleに作った個人テンプレートで、Hubには載っていません。Hubの掲載数を見ると、runpod-workers/worker-comfyui が13,815デプロイ、次点でも338デプロイという規模です。自分の10個のテンプレートは、そこに1件も並んでいませんでした。

機能を足すより、置き場所を変えるほうが効くんじゃないか。そう思ってHubへの掲載を試したのが今回です。

モチベル
Hubに出すのって、そんなに大変なの?
クーラット
手順だけ見ると15分で終わる内容だよ。ただ、テストが落ちたときに何を見ればいいかがどこにも書いてなくて、そこで8リリース溶かした。

この記事で使っているリポジトリはこちらです。

GitHub - RyoheiTanaka/runpod-template-acestep15xl
Contribute to RyoheiTanaka/runpod-template-acestep15xl development by creating an account on GitHub.

RunPod Hubにテンプレートを公開するまでの手順

まず全体の流れです。RunPod Hubへの掲載は、GitHubリポジトリを起点に進みます。

1
テンプレート専用のリポジトリを用意する

.runpod/ ディレクトリはリポジトリのルート固定です。サブディレクトリに置いても認識されません。つまり1つのGitHubリポジトリにつき、Hubのlistingは1本です。

複数テンプレートをmonorepoで管理していた場合は、ここで分割が必要になります。僕はこれで既存のmonorepoからテンプレートを1本切り出しました。

2
Dockerfileを置く

HubはリポジトリのDockerfileから自前でイメージをビルドします。GHCRやDocker Hubに置いた既存のイメージを指定する仕組みではありません。

DockerfileREADME.md、そして handler.py は、リポジトリのルートと .runpod/ のどちらに置いても認識されます。.runpod/ のほうが優先されるので、Hub用だけ別のDockerfileを使いたい場合はそちらに置く形になります。僕はルートのものをそのまま使いました。

ビルドされたイメージは registry.runpod.net/<オーナー名>-<リポジトリ名>-main-dockerfile:<コミットSHA> という名前になります。リポジトリ名から機械的に組み立てられているのが分かります。

3
.runpod/hub.json を書く

listingの定義ファイルです。タイトル・説明・アイコン・カテゴリと、デプロイ時のハードウェア要件や環境変数のスキーマを書きます。中身は次のセクションで詳しく扱います。

4
.runpod/tests.json を書く

掲載審査で走るテストの定義です。ここが今回の失敗の中心になりました。 テストはhandlerにジョブを投げて応答を待つ形で実行されます。

5
.gitattributes を置く

Windowsから作業している場合は必須です。これが無いと start.sh がCRLFのままコミットされ、Linuxコンテナで bash\r エラーになります。

*.sh text eol=lf
*.md text eol=lf
*.json text eol=lf
*.py text eol=lf
Dockerfile text eol=lf

6
GitHub releaseを切る

Hubが見ているのはcommitではなくreleaseです。 ドキュメントにも “the Hub indexes releases, not commits” と明記されています。mainにpushしてもビルドは走りません。タグを打ってreleaseを作った時点で、Hubがイメージのビルドとテストを開始します。

検知は自動で、ドキュメントでは「通常1時間以内」とされています。consoleに「Check for new release」の手動ボタンもあるので、待ちたくないときはそこから叩けます。

7
consoleからHubに申請する

ビルドとテストが通ると、RunPodチームの手動レビューに回ります。ここは自動化されていないので、待ち時間が発生します。

ドキュメントの分量について
RunPodのHub関連ドキュメントは、/hub/overview/hub/publishing-guide/hub/revenue-sharing の3ファイルで、合計500行弱です。ここに書かれていない挙動は、実際に出して確かめるしかありませんでした。

hub.jsonとtests.jsonに何を書くか

hub.jsonのtypeはserverlessしかない

最初に知っておくべき制約です。type に指定できるのは "serverless" だけで、Podテンプレートとして出す枠は存在しません

ただし、Serverlessとして登録しても、HubのページからはEndpointとPodの両方が選べます。ComfyUIのようにWeb UIを持つものをPodで使ってほしい場合でも、登録自体はserverlessで問題ありませんでした。

{
  "title": "ComfyUI ACE-Step 1.5 XL — FreeCraftLog",
  "type": "serverless",
  "category": "audio",
  "config": {
    "runsOn": "GPU",
    "containerDiskInGb": 60,
    "gpuCount": 1,
    "gpuIds": "AMPERE_24,ADA_24,ADA_32_PRO,AMPERE_48,ADA_48_PRO,BLACKWELL_96,AMPERE_80,ADA_80_PRO,HOPPER_141"
  }
}

gpuIdsは推測で書かない

gpuIds はデプロイ可能なGPUプールの指定です。ここを手書きしていたら、ADA_32_PRO(RTX 5090 / 32GB)が抜けていました。

これがけっこう痛くて、20GB要件を満たすカードの中でavailabilityがHIGHかつ最安(執筆時点の2026年9月で community $0.69/hr)という、一番デプロイしやすい選択肢だったんです。それを黙って除外していました。BLACKWELL_96 も同様に落としていました。

GPUのラインナップは変わるので、書くときはライブカタログを引いて確かめたほうがいいです。記憶で書くと、こういう抜け方をします。

なお、プール単位で許可したうえで特定のGPUだけを外す書き方もできます("-NVIDIA GeForce RTX 4090" のように先頭にマイナスを付ける形です)。プールの粒度が合わないときはこちらが使えます。

allowedCudaVersionsは下限ではなく完全一致

これも同じ種類のミスでした。allowedCudaVersions12.8 / 12.9 / 13.0 だけを書いていたんですが、この項目は下限ではなく完全一致のリストです。

執筆時点(2026年9月)では13.1と13.2も存在していて、しかもこの2つしかcapacityを持たないカードがあります(RTX 5000 Adaは13.1のみ、RTX PRO 6000 MaxQも13.1のみ)。CUDA 12.8のイメージが問題なく動くホストを、リストに書いていないというだけで除外していました。

構造的な保守負債でもあります。13.3が出れば、また同じことが起きます。Pod用のAPIには minCudaVersion という開放的な下限指定があるんですが、hub.json 側には文書化されていません。

迷ったら広めに書く
今は12.4から13.2まで9個を列挙しています。イメージ側が動作条件を持っている場合はそちらで弾かれるので、allowedCudaVersions を絞る意味はあまりありませんでした。

envのinputでデプロイ画面のフォームを作れる

config.envinput を持たせると、Hubのデプロイ画面に選択肢として出ます。モデルの種類を選ばせるような用途に使えます。

{
  "key": "ACESTEP_XL_VARIANT",
  "input": {
    "name": "Diffusion model",
    "type": "string",
    "options": [
      { "label": "Turbo (fastest to download)", "value": "xl_turbo" },
      { "label": "Base", "value": "xl_base" }
    ],
    "default": "xl_turbo"
  }
}

presets を併用すると、組み合わせに名前を付けて提示できます。「Turbo(最小構成・推奨)」「全モデル(初回起動が最も長い)」のような単位ですね。

tests.jsonのinputは空にできない

そして tests.json です。最終的にこうなりました。

{
  "tests": [
    {
      "name": "comfyui_serves_system_stats",
      "input": { "health_check": true },
      "timeout": 900000
    }
  ],
  "config": {
    "gpuTypeId": "NVIDIA RTX A5000",
    "gpuCount": 1
  }
}

input に何を書くかがテストの内容そのものになります。ドキュメント上の定義は “Raw job input payload” で必須項目、合格条件は「200を返すこと」とだけ書かれています。中身が空だとどうなるかは書かれていません。 ここを空にしていたのが3つ目の失敗で、後のセクションで扱います。

handlerなしで5リリース失敗した

ここからが本題です。

endpointTypeのLBに賭けた

ComfyUIはそれ自体がHTTPサーバなので、handlerを書かずにそのまま公開できないかと考えました。根拠にしたのはドキュメントのこの1行です。

endpointType | When set to "LB", users can deploy your listing as a Serverless endpoint or a Pod directly from the Hub page. | 必須: いいえ

LB(load balancing)にすればHTTPサーバを直接公開できる、と読みました。実装もそれに合わせました。ロードバランサは指定ポートをpollingして 200=healthy / 204=initializing / それ以外=unhealthy と解釈するので、モデルのダウンロード中に204を返すヘルスチェックサーバを別途書いています。

結果は、v0.1.0 から v0.2.2 までの5リリースすべて失敗でした。

実例を1つも確認していなかった

失敗の理由より、判断の仕方のほうが問題でした。

endpointType の記述は、ドキュメント全体でこの表の1行と、2026年1月のリリースノートの2箇所しかありません。ベータ機能で、実際に動いている例を1つも見つけていない状態で、僕はそこに5リリースを積んだわけです。

一方、Hubに実際に載っているComfyUI系のlistingを見に行くと、2つともhandler方式でした。

listing デプロイ数 handler endpointType
runpod-workers/worker-comfyui 13,815 あり なし
vavo/LTX2.5-serverless あり なし

そして両者の tests.jsoninput は、handlerが処理する実際のジョブでした。worker-comfyui はComfyUIのワークフローJSON一式、LTX2.5は {"health_check": true} です。

Hubのテストは、handlerにジョブを投げて応答を待ちます。handlerが無ければ、ポートやヘルスチェックを何度直しても通りません。 僕が直していたのは、テストが到達すらしていない場所でした。

受理はテスト通過ではない
v0.1.0 はhandlerなしで受理されました。それを「handlerは不要」と読んだんですが、受理は入口のファイルチェックを通っただけで、テストに通る保証ではありませんでした。

教訓としてはひとつです。成功しているものがどう作られているかを、最初に見る。 ドキュメント2行の機能に賭ける前にやることでした。

handlerの中身

最終的に入れたhandlerはこういう形です。ジョブの inputworkflow があればComfyUIのキューに流し、無ければ /system_stats を返します。

def handler(job):
    job_input = job.get("input") or {}

    ready, error = wait_for_comfy()
    if not ready:
        return {"error": error}

    workflow = job_input.get("workflow")
    if not workflow:
        return {
            "status": "ready",
            "comfyui": _get_json("/system_stats"),
        }

    return run_workflow(workflow)

ComfyUIはhandlerの隣で動き続けるので、同じイメージがPodとしてもServerlessとしても使えます。Podで起動したときはWeb UIをそのまま触れて、Serverlessで起動したときはこのキューAPIが生えている、という形です。

ビルドが緑でも、パッケージが入っているとは限らない

3リリース分を溶かした失敗です。今回いちばん恥ずかしいところでもあります。

入れたつもりで入っていなかった

handlerを追加した v0.3.0 で、Dockerfileに runpod パッケージを足しました——つもりでした。

文字列置換が無言で不一致になっていて、実際には追加されていませんでした。Dockerfileが変わっていないのでビルドの結果も何も変わらず、当然ながら緑になります。僕はその緑を見て「runpodパッケージ込みでビルド成功」と、コミットメッセージとrelease notesの両方に書きました。確認していなかったんです。

Hub側のログはこうなりました。

workersEffective=0  workersHealthy=0  workersUnhealthy=0  workersRunning=0  workersMax=1
timeInQueue  522228 → 882512

ワーカーが1台も立ちません。

Serverlessではhandlerがワーカーそのもので、ジョブキューに接続して自分の存在を報告するのがSDKの役目です。import runpod で落ちていたので、RunPodからはワーカーが存在しないように見えていました。

失敗が握りつぶされていた

さらに悪いことに、start.sh がhandlerの失敗を無視して続行していました。

[start] starting the serverless handler
ModuleNotFoundError: No module named 'runpod'
[start] handler exited, continuing to serve ComfyUI

ログには出ているんですが、コンテナは生きたままComfyUIを配り続けます。この沈黙のせいで、原因が3リリース分見えませんでした。 その間、container diskを増やしたりCUDAの下限を変えたりGPUの種別を変えたりしていましたが、全部空振りです。ワーカーは毎回ちゃんと確保されていました。

対策はバグとバグの種類の両方に入れた

まず、インストールと同じレイヤでimportを検証するようにしました。効いていなければビルドが落ちます。

RUN python -m pip install --no-cache-dir --target /opt/runpod/pylibs runpod \
    && PYTHONPATH=/opt/runpod/pylibs python -c 'import runpod; print("runpod:", runpod.__version__)'

次に、Serverlessで動いているときだけhandlerの死をコンテナごと落とすようにしました。

elif [ -n "${RUNPOD_ENDPOINT_ID:-}" ]; then
  echo "[start] error: handler failed on a Serverless worker"
  exit 1

Podでは従来どおり続行します。Podにはそもそもジョブキューが無いので、handlerが抜けるのは正常な動作だからです。

runpodを分離して入れている理由
--target /opt/runpod/pylibs でComfyUIの環境から分離しています。同じ環境に入れると、cu130ベース(Ubuntu 24.04のシステムPython)で error: uninstall-no-record-file になるためです。runpodが fastapi[all] を引き込み、pipがapt由来のパッケージを置き換えようとするんですが、それらはRECORDファイルを持っていません。--target は何もアンインストールしないので、この経路を踏みません。
モチベル
ビルドが通ってたら、入ってると思っちゃうよね。
クーラット
変更が効いてないときほどビルドは静かに成功する。だから「入ったこと」自体をビルドの中で確かめる形にした。

空のinputはhandlerに届かない

handlerが入って、ワーカーも立つようになりました。それでもテストは通りません。リクエストが IN_PROGRESS のまま止まります。

ログにはこう出ていました。

Failed to get job. | Error Message: Job has missing field(s): id or input.

runpod SDKのソースを読むと、キーの存在チェックしかしていません。

if "id" not in jobs or "input" not in jobs:
    raise Exception("Job has missing field(s): id or input.")

tests.json には "input": {} と書いていました。SDKがこれを弾いているということは、RunPod側が空の input をフィールドごと落として配っていることになります。空のオブジェクトを渡しているつもりが、キーごと消えていたわけです。

{"health_check": true} に変えたら通りました。

面白かったのは、この形を一度は退けていたことです。LTX2.5の tests.json{"health_check": true} と書いてあるのを見て、「テストを通すためだけの抜け道だな、真似すべきじゃない」と読んでいました。実際には必然の形でした。空にできない以上、意味のある最小のジョブを何か用意するしかありません。

なので今のhandlerでは、workflow を持たないジョブに対してComfyUIの /system_stats を返すようにしています。テスト専用の分岐ではなく、エンドポイントとしても意味のある応答です。

workersUnhealthyの0と1で切り分けが正反対になる

失敗の内容とは別に、診断のやり方でも回り道をしました。

Hubのログにこういう行が出ます。

scaleup to catch up - immediate scaling for empty endpoint
  workersRunning=0 workersHealthy=0 workersUnhealthy=0 workersMax=1 timeInQueue=882512

僕は empty endpoint という文字列だけを見て、同じ行の後半を読んでいませんでした。ここを読むかどうかで、調べる方向が正反対になります。

workersUnhealthy 意味 次に見る場所
0 起動して落ちたのではない。1台も割り当たっていない 設定・GPU要件・イメージの取得
1以上 起動はした コンテナの中身・ログ

workersUnhealthy=0 は「コンテナは動いたが不健康」ではなく「そもそも動いていない」です。僕はこれを後者だと思い込んで、コンテナの中身をずっと直していました。

Hubのイメージは外から取得できない

診断が遅れたもうひとつの理由がこれです。Hubがビルドしたイメージは registry.runpod.net に置かれますが、Hubのデプロイ経由でしか認証が通りません。

同じイメージ名でPodを立てようとすると、こうなります。

Failed to get Hub registry auth. Is this a template you have access to?
error creating container: No such image: registry.runpod.net/...

しかもこれを16秒ごとに繰り返します(課金は発生し続けます)。

つまりHubに出したイメージは、そのままではログを読む手段がありません。 GHCRへpushするワークフローを別途用意して、そこから普通のPodを立てて、ようやくコンテナの中のログが読めるようになりました。Hubに出すなら、独自の配布経路も持っておいたほうがいいです。

ローカルで測った数字を、実行環境の数字として使わない

これは初期に踏んだ罠なんですが、教訓が独立して使えるので残します。

Hubのテストが2回失敗したとき、僕は自宅のマシンで測った419秒を根拠に「モデルのダウンロードが遅くてcold startの上限に抵触している」と診断しました。対策として RUNPOD_INIT_TIMEOUT の延長を考え、次にモデルをイメージに焼き込むことを検討しています。

実機で測ったら、前提が崩れました。

イメージ pull   5分45秒   (78%)
モデル DL       1分27秒   (20%)
ComfyUI 起動      11秒
合計            7分23秒
RunPod Podの初回起動7分23秒の内訳。イメージpull 5分45秒(78%)、モデルダウンロード1分27秒(20%)、ComfyUI起動11秒(2%)
初回起動の内訳。律速はモデルのダウンロードではなくイメージのpull

RunPodでのモデルダウンロードは87秒でした。419秒は自宅回線の速度であって、RunPodの速度ではありません。約5倍違います。律速はダウンロードではなく、イメージのpullでした。

そして焼き込みは、完全に逆方向の対策です。5分45秒かかっているpullを太らせて、87秒しかかかっていないダウンロードを削る取引になります。実行していたら悪化していました。

ネットワークが律速になる処理では、環境が変わると桁が変わります。自分の環境で測った数字は、自分の環境の話でしかない、ということですね。

そのほかに踏んだこと

原因ではなかったものです。ただ、LBのヘルスチェックを書く人は同じところを踏むと思うので、1つだけ書いておきます。

ヘルスチェックの初版は、リクエストを受けるたびにその場でComfyUIをprobeしていました。実測がこれです。

comfy_is_up() when down: False  took 2056 ms
comfy_is_up() when down: False  took 2010 ms
comfy_is_up() when down: False  took 2011 ms

誰もlistenしていないポートへの接続は、ECONNREFUSEDで即座に失敗せず、timeoutをフルに待つことがあります。 しかもそれが起きるのはモデルのダウンロード中、つまり204を返したい区間そのものです。ロードバランサ側のtimeoutが2秒より短ければ、204は一度も観測されずunhealthyと判定されます。目的が丸ごと崩れていました。

probeを専用スレッドに移して2秒間隔で状態をキャッシュし、リクエスト処理はフラグを読むだけにしたら、こうなりました。

ComfyUI down:   204 in  48.0 ms /  11.7 ms / 1.9 ms
ComfyUI up:     200 in   2.2 ms /   1.8 ms / 1.8 ms
ComfyUI gone:   204 in   2.3 ms /   1.9 ms / 1.7 ms

ヘルスチェックのエンドポイントは「判定処理を実行する場所」ではなく「判定済みの結果を返す場所」にする。そういう形で覚えました。

副産物: イメージが10.10GBから4.81GBになった

原因を追いかける過程で、ベースイメージを差し替えました。

runpod/pytorch:2.8.0-py3.11-cuda12.8.1-cudnn-devel-ubuntu22.04
  ↓
pytorch/pytorch:2.8.0-cuda12.8-cudnn9-runtime

devel はnvccやヘッダや静的ライブラリを含みますが、ComfyUIは実行時にどれも使いません。イメージ全体のうち、自分のリポジトリ由来は1.7GBしかありませんでした。

GHCRでの圧縮後サイズがこうなりました。

v3.1.0-cuda12.8   10.10 GB
v3.2.0-cuda12.8    4.81 GB

52%減です。ただし起動時間は同じ比率では縮みません。 ある1回の計測では、pullが5分45秒から4分01秒(30%減)でした。runtimeイメージはレイヤの枚数が少なく(11枚に対してdevelは34枚)、ダウンロードは並列化できても巨大な1枚のレイヤの展開は直列になるためです。

起動時間は固定値として見ないでください
同じ4.81GBのイメージでも、データセンターによってpullの時間は変わります。同じ日に測って4分01秒と4分27秒でした。確実に言えるのはイメージサイズが減ったことで、時間の短縮幅は環境依存です。

container diskについても分かったことがあります。turbo構成での実測がこれです。

Disk space check passed: 39.27GB free (78.5% available)   ← disk=50 設定時

使用量10.73GBに対し、turbo構成のモデル合計が10.71GB。つまりイメージはcontainer diskを消費していません(書き込み層だけです)。hf download --local-dir がHFキャッシュに二重保存していないことも、ここから分かります。

現在の状況

v0.3.2 でビルドとテストが通り、その後RunPodチームの手動レビューを経て、2026年9月15日にHubへ掲載されました。全8リリースでした。

掲載ページはこちらです。Podとしてもサーバーレスエンドポイントとしても、このページからDeployできます。

console.runpod.io/hub/RyoheiTanaka/runpod-template-acestep15xl

RunPod HubのComfyUI ACE-Step 1.5 XL掲載ページ。README・Deployボタン・リポジトリ情報
Hubの掲載ページ。Deployボタンの先でPodかServerlessかを選べる

レビュー自体は8月30日にテストが通ってから2週間ほどかかりました。掲載されたことに僕は通知で気づけず、たまたまconsoleを開いて知りました。申請したあとは、たまに見に行ったほうがよさそうです。

公開後にタイトルとアイコン、既定プリセット、container disk(all プリセット向けに60GB)を変えた v0.3.3 を出しましたが、こちらは審査なしで自動反映されました。GitHub Releaseを切ると30分以内に検知され、ビルドとテストが通った直後にlistingが切り替わります。申請中にあった「Check for new release」ボタンは、公開後の管理画面からは消えます。上の hub.json の例は v0.3.3 の状態のものです。

Serverlessでの動作は確認できています。

--- Starting Serverless Worker | Version 1.12.0 ---
All fitness checks passed. (2002.52ms)
delayTime 29.23s / executionTime 2.08s / Completed

8回のうち、実際に原因だったのは3つだけでした。残りは、原因ではないところを直していた時間です。振り返るとそのほとんどが「確認していれば分からなかったはずがないこと」で、Hubの仕様が難しかったというより、確かめる順番の問題だったと思っています。

よくある質問

QRunPod Hubに掲載するのにhandler.pyは必須ですか?
A

必須です。Hubのテストはhandlerにジョブを投げて応答を待つ形で実行されるので、handlerが無いとテストに通りません。endpointType: "LB" を指定してHTTPサーバを直接公開する方法も試しましたが、5リリース分すべて失敗しました。ドキュメントには「リポジトリのルートか .runpodhandler.pyDockerfileREADME.md があること」とだけ書かれていて、LB指定時に不要になるとは書かれていません。

QHubは何をきっかけに再ビルドしますか?
A

GitHub releaseです。ドキュメントにも “the Hub indexes releases, not commits” と書かれているとおり、mainブランチへのcommitでは再ビルドされません。検知は自動で通常1時間以内、consoleに手動の「Check for new release」ボタンもあります。

Q1つのリポジトリに複数のテンプレートを載せられますか?
A

できません。hub.jsontests.json を置く .runpod/ ディレクトリはリポジトリのルート直下と決まっているので、1リポジトリにつきlistingは1本です。monorepoで複数テンプレートを管理している場合は分割が必要になります。

Qtests.jsonのinputは空でもいいですか?
A

空にできません。"input": {} にすると、RunPod側がinputフィールドごと落としてワーカーに配るため、SDKが Job has missing field(s): id or input. で弾きます。{"health_check": true} のように、何か中身のあるジョブを渡す必要があります。

QHubがビルドしたイメージを自分でpullできますか?
A

できません。registry.runpod.net に置かれますが、Hubのデプロイ経由でしか認証が通らないため、同じイメージ名でPodを立てても Failed to get Hub registry auth で失敗し続けます。コンテナ内のログを読みたい場合は、GHCRなど別の配布経路を自分で用意する必要があります。

まとめ

RunPod Hubにテンプレートを公開する手順自体は、ファイルを2つ置いてreleaseを切るだけです。詰まったのは、そこに書かれていない部分でした。

  • .runpod/ はルート固定。1リポジトリ=1 listing
  • 再ビルドの契機はcommitではなくGitHub release
  • HubはリポジトリのDockerfileから自前でビルドする。既存イメージの指定ではない
  • Hubのテストはhandlerにジョブを投げる。 handlerが無ければ通らない
  • tests.jsoninput空にできない
  • allowedCudaVersions は下限ではなく完全一致
  • ログの workersUnhealthy が0か1以上かで、切り分けの方向が正反対になる
  • HubのイメージはHubの外からpullできないので、別の配布経路を持っておく

そして一番効いた教訓は、技術的なものではありませんでした。すでに動いているものがどう作られているかを、最初に見る。 Hubに載っているlistingを2つ開いていれば、5リリース分は起きなかったはずです。

同じ構成をとりあえず動かしてみたい場合は、consoleの公開テンプレートからDeployできます。Hubから起動する場合は、掲載ページのDeployボタンからServerless endpointかPodを選びます。

関連記事

ACE-Step 1.5 XLをRunPodで動かす公開ComfyUIテンプレートを作りました
ACE-Step 1.5 XLをRunPod上のComfyUIで動かす公開テンプレートをv3.0.0に更新。base/SFT/turbo、qwen text encoder、CUDA 12.8と13.0の使い分け、RTX 4090での生成時間、つまずいた点まで実録でまとめます。
Wan2.2をRunPodで動かす公開ComfyUIテンプレートを作りました|T2V/I2Vを検証
Wan2.2をRunPod上のComfyUIで動かす公開テンプレートをv3.2.0に更新。T2V/I2V/TI2Vの切り替え、LightX2V LoRA、CUDA 12.8と13.0の使い分け、RTX 4090での生成時間まで実録でまとめます。
RunPodでComfyUIを使う方法|モデル追加・ワークフロー実行・画像保存まで解説
RunPodでComfyUIを起動した後、何をすればいいか迷う人向け。最初の設定からモデル・LoRA・VAEの配置場所、ワークフローJSONの読み込み、画像生成と保存、Pod停止、よくあるエラー対処まで実際の画面で全手順を解説します。起動直後に何から手をつければいいか迷わないための実用ガイドです。
RunPodの料金はいくら?GPU単価・ストレージ・クレジットと止め忘れ対策
RunPodは月額固定ではなく従量課金です。料金はGPUの時間単価・Podを起動していた時間・Volumeのストレージ・クレジット残高の4つで決まります。GPU単価の見方、StopとTerminateの違い、止め忘れを防ぐチェックリスト、無料枠やクーポンの有無まで実際に使いながら整理しました。
RunPodの使い方|登録からComfyUI起動まで実際にやった手順【2026年版】
RunPodは、GPUを時間単位で借りられるクラウドGPUサービスです。従量課金で月額固定はなく、のチャージから使えます。アカウント登録・クレジット購入・Pod起動・ComfyUI接続までを、実際にやった画面スクショつきで解説します。GPU選びや停止忘れ対策も初心者向けにまとめました。
AIで作った画像集・プロンプトPDF付き BOOTHで販売中

⚠️ AI画像生成をご利用の際の重要な注意事項

著作権・知的財産権について

  • 既存のキャラクター、作品、ブランドロゴなどの模倣・複製は著作権侵害にあたる可能性があります
  • 商用利用時は特に注意が必要です

肖像権について

  • 実在人物(著名人・一般人問わず)の顔や特徴を模倣した画像生成はお控えください
  • 無断での肖像権使用は法的トラブルの原因となります

利用規約の確認

  • 各AI画像生成サービスの利用規約を必ずご確認ください
  • 商用利用の可否、生成画像の権利関係は各サービスで異なります

免責事項

  • 当ブログの情報を参考にしたAI画像生成により生じた問題について、当ブログは一切の責任を負いません
  • 法的問題が生じた場合は、利用者の自己責任となります
  • 最新の法律・規約情報は公式情報をご確認ください

適切なAI画像生成を心がけ、創作活動を楽しみましょう。
詳細についてはAIと著作権についてをご覧ください。

コメント