RunPod
招待リンク
ここから参加すると pokutuna.icon にもあなたにもクレジットが付与されます
Overview | RunPod Documentation
ssh 接続
Connect to a Pod with SSH - Runpod Documentation
環境変数
Environment variables - Runpod Documentation 事前定義のもの
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
GITHUB_TOKEN="{{ RUNPOD_SECRET_GITHUB_TOKEN }}"
UV_CACHE_DIR=/workspace/.cache/uv
ここで適当に PATH 設定すると起動時にコマンドがもろもろ足りないので PATH を追加する場合は以下も足す
/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
code:envs
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:/workspace/tools/uv/bin
gcloud 使う時は CLOUDSDK_CONFIG 設定した1 度 gcloud auth login して認証情報残す
UV_CACHE_DIR はデフォルトで $HOME/.cache/uv
Caching | uv
NetworkVolume を使う場合 filesystem が違うのでハードリンクにできずコピーになるので volume 側においておくのが良い
Python 依存の管理
素直に uv 使う
↑の環境変数のように UV_CACHE_DIR を設定しておく
template の pytorch イメージに色々入っているものと重複するのは気になる
uv venv --system-site-packages などを使って torch 等は管理しない方法もありそう
その場合 pyproject.toml に書かない
system を使うなら uv で管理しておいて uv pip install --system -e . する?
作業終わったら Pod 終了する
runpodctl コマンドとデフォルトの環境変数 $RUNPOD_POD_ID で Pod 内から自身を停止できる
Manage Pods | RunPod Documentation
$ 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
#!/usr/bin/bash
# dirs
mkdir -p /workspace/.cache/huggingface
mkdir -p /workspace/.cache/uv
mkdir -p /workspace/tools/
# gcloud
curl https://sdk.cloud.google.com > install.sh
bash install.sh --disable-prompts --install-dir=/workspace/tools
Google Cloud CLI インストーラの使用  |  Google Cloud SDK Documentation
地味に時間がかかる、出力ファイルのログでなくていいし gcloud storage & bq が使えるだけでいいんだけど
/workspace/tools/google-cloud-sdk/bin 以下に配置される
code:install_once.sh
# gh
GITHUB_CLI_VERSION=2.78.0 && mkdir -p /workspace/gh && curl -L https://github.com/cli/cli/releases/download/v${GITHUB_CLI_VERSION}/gh_${GITHUB_CLI_VERSION}_linux_amd64.tar.gz | tar -xz -C /workspace/tools/gh/ --strip-components=1 --no-same-owner
cli/docs/install_linux.md at trunk · cli/cli
VERSION はその時新しいものを https://github.com/cli/cli/releases/ から探す
ARCH は決め打ちだけど arch によって切り替えるやつ すると丁寧だけど amd64 しか使わんだろう
/worksapce/tools/gh/bin/gh を使う
$ gh repo clone pokutuna/hogehoge kaggle で clone できる / $ gh repo sync で push & pull
fine-grained な PAT はあるが SSH キーやログイン情報はないので gh コマンドでやりくりする、まあ十分
code:install_once.sh
# uv
curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/workspace/tools/uv/bin sh
NetworkVolume
Network Volume のほうが Pod の Storage より安い $0.07/GB/month
Stopped Pod は $0.20/GB/month
容量はあとから増やせるので大きくしすぎなくて良い
S3 互換 API がある
S3-compatible API - Runpod Documentation
Pod 起動前、つまり GPU 代気にせず巨大なファイル配置できるので便利
awscli も使える
$ aws s3 ls --profile=runpod s3://VOLUME_ID/
たとえば eu-ro-1 なら
code:~/.aws/config
profile runpod
region = eu-ro-1
endpoint_url = https://s3api-eu-ro-1.runpod.io
code:~/.aws/credentials
runpod
aws_access_key_id = user_...
aws_secret_access_key = rps_...
S3 互換 API で起動前にモデルを Network Volume に置いておく
H100 とか借りて charge が発生している時間で巨大モデルダウンロードするの無駄すぎるので
Colab で HuggingFace モデルをダウンロードして Runpod に配置するテク(ひどい)
code:cell.py
!pip install huggingface_hubhf_transfer
!pip install awscli
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"
!HF_HUB_ENABLE_HF_TRANSFER=1 hf download $model --local-dir=/content/models/$model
code:cell.py
!aws s3 sync /content/models/$model s3://VOLUME/models/$model --region=REGION --endpoint-url=ENDPOINT
偶に一部が失敗するので upload failed 無いか見る
一部失敗したときは --checksum-algorithm=CRC32C など(常に付けても良い)
Volume が太ってくると sync できなくなる
fatal error: Error during pagination: The same next token was received twice: ...
ListObject にコケるんだろうから s3 cp --recursive したらうまくいくが差分だけ上げたりはできない
runpod/runpod-s3-examples@main - upload_large_file.py
リトライ付きの公式のスクリプト
消しづらいしゴチャつくので 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 が良い派なので使わないかなあ