RunPod
!!ここから参加すると pokutuna.icon にもあなたにもクレジットが付与されます!!
ssh 接続
学習コードが hydra 等を使い python スクリプトとして独立して書け、実験回しまくるフェーズならこちら 手元のノートブックに対し実行だけ GPU インスタンス、という形にできる
VSCode でカーネル選ぶ
> Notebook: Select Notebook Kernel
.ipynb を開いた状態での右上の Select Kernel ボタン
これがでる
https://gyazo.com/8a490bac0eaaef9f58dbc3c20c44ebff
Existing Jupyter Server を選択
URL 入力欄が出る
RunPod の Pod を立て、この Jupyter Lab リンクをコピーして貼り付ける
https://ID-PORT.proxy.runpod.net/?token=TOKEN みたいな形式の URL
https://gyazo.com/4d8858691328eb23a544c398f5af7ce5
適当な名前をつけて接続
2回目以降、名前つけたやつに繋げられねーんだけど、となりがち
この右上の更新ボタン 🔁 みたいなのを押すといける
https://gyazo.com/e165a3c466a46c22d7cc6cdb4cb77be9
環境変数
Secrets に色々入れておいてあれこれ参照させる
これ押すの意外と忘れる問題
https://gyazo.com/c32d0358597ab497e667ff52dbd2cb9d
code:envs
GOOGLE_CLOUD_PROJECT="{{ RUNPOD_SECRET_GOOGLE_CLOUD_PROJECT }}"
CLOUDSDK_CONFIG=/workspace/.config/gcloud
GOOGLE_APPLICATION_CREDENTIALS=/workspace/.config/gcloud/application_default_credentials.json
HF_HOME=/workspace/.cache/huggingface
HF_TOKEN="{{ RUNPOD_SECRET_HF_TOKEN }}"
WANDB_PROJECT="{何か適当に決める}"
WANDB_API_KEY="{{ RUNPOD_SECRET_WANDB_API_KEY }}"
WANDB_DIR="/workspace/wandb/logs"
KAGGLE_API_KEY="{{ RUNPOD_SECRET_KAGGLE_API_KEY }}"
TOKENIZERS_PARALLELISM=false
UV_BREAK_SYSTEM_PACKAGES=1
GITHUB_TOKEN="{{ RUNPOD_SECRET_GITHUB_TOKEN }}"
UV_CACHE_DIR=/workspace/.cache/uv
PROJECT_ROOT=/workspace/{何か決める}
PATH=/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/workspace/tools/google-cloud-sdk/bin:/workspace/tools/gh/bin
ここで適当に PATH 設定すると起動時にコマンドがもろもろ足りないので PATH を追加する場合は以下も足す
/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
gcloud 使う時は CLOUDSDK_CONFIG 設定した1 度 gcloud auth login して認証情報残す
UV_CACHE_DIR はデフォルトで $HOME/.cache/uv
NetworkVolume を使う場合 filesystem が違うのでハードリンクにできずコピーになる
JUPYTER_PASSWORD={{ RUNPOD_SECRET_JUPYTER_PASSWORD }} がある時しか Jupyter が起動しない?
Python 依存の管理
素直に uv 使う
↑の環境変数のように UV_CACHE_DIR を設定しておく
template の pytorch イメージに色々入っているものと重複するのは気になる
その場合 pyproject.toml に書かない
system を使うなら uv で管理しておいて uv pip install --system -e . する?
キャッシュだけ Network Volume において、$ uv sync --system で暮らしてみる & その場合素直に python.py すればいいはず
$ uv pip install --system --break-system-packages -e .
UV_BREAK_SYSTEM_PACKAGES=1 しておけば --break~ は要らない
作業終わったら Pod 終了する
runpodctl コマンドとデフォルトの環境変数 $RUNPOD_POD_ID で Pod 内から自身を停止できる
$ runpodctl stop pod $RUNPOD_POD_ID
notebook の最後やコマンドの後、学習 & 保存したあとにこれ実行したらいい
途中でコケても実行させたいので notebook 実行の時は ssh 側でも安全装置するかな?
$ sleep 2h && runpodctl stop pod $RUNPOD_POD_ID
COMMAND を実行して終わったら 10 回ベル鳴らして 1分待機、C-c しなかったら Pod 止める
$COMMAND; for i in {1..5}; do echo -e '\a'; sleep 0.1; done; sleep 60; runpodctl stop pod $RUNPOD_POD_ID
code:コピペ用.sh
; for i in {1..5}; do echo -e '\a'; sleep 0.1; done; sleep 60; runpodctl stop pod $RUNPOD_POD_ID
ツールのインストール & workspace 下への配置
code:install_once.sh
# dirs
mkdir -p /workspace/.cache/huggingface
mkdir -p /workspace/.cache/uv
mkdir -p /workspace/tools/
# gcloud
# これだとでかすぎる
# bash install.sh --disable-prompts --install-dir=/workspace/tools
curl -o /tmp/google-cloud-cli.tar.gz \
tar -xf /tmp/google-cloud-cli.tar.gz -C /workspace/tools/
rm /tmp/google-cloud-cli.tar.gz
地味に時間がかかる、出力ファイルのログでなくていいし gcloud storage & bq が使えるだけでいいんだけど
/workspace/tools/google-cloud-sdk/bin 以下に配置される
code:install_once.sh
# gh
/worksapce/tools/gh/bin/gh を使う
$ gh repo clone pokutuna/hogehoge kaggle で clone できる / $ gh repo sync で push & pull
fine-grained な PAT はあるが SSH キーやログイン情報はないので gh コマンドでやりくりする、まあ十分
2026/2/5
uv はもう pytorch コンテナにインストール済みだったので不要
起動スクリプト
start.sh
nginx 起動
pre_start.sh
SSH, Jupyter 起動, 環境変数設定
post_start.sh
最後に sleep infinity する
PyTorch コンテナなどは CMD [ "/start.sh" ]
コンテナ作成時の上書きはこれを上書く
start.sh が終わった頃に何かしたいが
/workspace/startup.sh を実行するものとして /post_start.sh の末尾に追記して /start.sh を実行する
天才
code:CMD.sh
NetworkVolume
Network Volume のほうが Pod の Storage より安い $0.07/GB/month
Stopped Pod は $0.20/GB/month
容量はあとから増やせるので大きくしすぎなくて良い
S3 互換 API がある
Pod 起動前、つまり GPU 代気にせず巨大なファイル配置できるので便利
awscli も使える
$ aws s3 ls --profile=runpod s3://VOLUME_ID/
たとえば eu-ro-1 なら
code:~/.aws/config
region = eu-ro-1
code:~/.aws/credentials
aws_access_key_id = user_...
aws_secret_access_key = rps_...
S3 互換 API で起動前にモデルを Network Volume に置いておく
H100 とか借りて charge が発生している時間で巨大モデルダウンロードするの無駄すぎるので
Colab で HuggingFace モデルをダウンロードして Runpod に配置するテク(ひどい)
code:cell.py
from google.colab import userdata
%env HF_TOKEN={userdata.get('HF_TOKEN')}
%env AWS_ACCESS_KEY_ID={userdata.get('RUNPOD_STORAGE_ACCESS_KEY_ID')}
%env AWS_SECRET_ACCESS_KEY={userdata.get('RUNPOD_STORAGE_SECRET_ACCESS_KEY')}
code:cell.py
model = "Qwen/Qwen3-8B"
!uvx hf download $model --local-dir=/content/models/$model
code:cell.py
!uvx --from=awscli aws s3 sync /content/models/$model s3://VOLUME/models/$model --region=REGION --endpoint-url=ENDPOINT
偶に一部が失敗するので upload failed 無いか見る
一部失敗したときは --checksum-algorithm=CRC32C など(常に付けても良い)
fatal error: Error during pagination: The same next token was received twice: ...
ListObject にコケるんだろうから s3 cp --recursive したらうまくいくが差分だけ上げたりはできない
リトライ付きの公式のスクリプト
消しづらいしゴチャつくので huggingface の cache を上げるより model 個別に上げるほうがいい
これ Colab がいい感じに ASIA で動いてたら非効率な感じするねえ...
HF → Colab(ASIA) → Runpod (US or EU) みたいな転送になる
Google Cloud → HuggingFace へのアップロードは笑えるくらい速いんだけど
GPU なしモードは脱出用
実は GPU 1 枚時の 1/2 なだけでさしてお得じゃない
スペックは 0.5vCPU 0.5Gi に落とされる、セットアップやモデルダウンロードするのややキツいしあまり意味はない
16vCPU 251GBmem + H100 80GB ← $2.62/h
0.5vCPU 0.5GB ← $1.31/h
と考えるといかにアホなことをしようとしていたかわかる
最初から NetworkVolume で暮らそう