Skip to main content
BlogAI/ML

OCI Model Artifacts: Cold Start Model Kubernetes Lebih Cepat

Pembacaan teliti studi cold start KServe 2026: image volume, modelcar dan object storage dibandingkan pada 2, 14 dan 140 GB, plus biaya pull dingin pertama dan pemeriksaan integritas.

Matthews Wong

Software Engineer

Oktober 202612 menit baca
OCI Model Artifacts: Cold Start Model Kubernetes Lebih Cepat

Ringkasan Utama

Me-mount model weights sebagai OCI image volume membuat penambahan warm replica tidak bergantung pada ukuran model: 11,7 detik untuk artifact kelas 70B dibanding 40,7 menit jika download ulang dari object storage, menurut studi KServe 2026. Konsekuensinya, pull dingin pertama bisa dua kali lebih lama dari download biasa, jadi cache node sebelum scale.

Angka yang membuat saya membaca seluruh paper ini bukan 208x, melainkan 40,7 menit. Autoscaler yang butuh empat puluh menit untuk menambah satu replica model kelas 70B tidak sedang scaling, ia hanya mengumumkan keputusan scale setelah traffic berlalu. Sebagian besar waktunya bukan GPU atau engine, melainkan bobot model yang dikirim lagi ke node.

Post ini adalah pembacaan teliti arXiv:2607.16596 (Georgii Kliukovkin, IEEE Access 2026), pull request KServe yang dijelaskannya, dokumentasi image volume Kubernetes, dan proyek model-signing OpenSSF. Saya tidak menjalankan benchmark-nya sendiri. Semua angka di bawah berasal dari paper atau harness-nya, dan saya sebutkan di mana batas paper itu membatasi kesimpulan Anda.

Selisih terukur: warm start datar, cold start tidak

Paper ini mengukur waktu sampai prediksi pertama untuk artifact berukuran fp16 2, 14 dan 140 GB, setara model 1B, 7B dan 70B, pada satu AWS m6i.2xlarge yang menjalankan cluster kind dengan Kubernetes v1.36.1 dan containerd 2.3.1. Registry dan endpoint S3 MinIO berada di cluster yang sama, jadi tidak ada noise WAN. Angkanya median dari 10 run, 5 untuk tier 140 GB. Warm berarti image sudah ada di containerd store node; untuk S3 tidak ada node cache, jadi warm hanya berarti download ulang.

PathMode2 GB (detik)14 GB (detik)140 GB (detik)
oci+native://cold38,6443,44.585,5
oci+native://warm11,511,411,7
modelcar (oci://)cold59,6363,34.603,0
modelcar (oci://)warm15,415,215,8
s3://cold39,6137,82.318,8
s3://warm (download ulang)30,0128,42.441,6

Bacalah tabel per kolom. Pada 2 GB hampir tidak ada bedanya: oci+native:// cold (38,6 detik) bahkan satu detik lebih cepat dari S3 cold (39,6 detik), karena biaya tetap per pod mendominasi. Pada 140 GB baris OCI warm tetap 11,7 detik sedangkan S3 butuh 2.441,6 detik, sekitar 40,7 menit, yaitu 208x di paper. Modelcar 155x lebih cepat saat warm dan membawa sekitar 4 detik overhead lifecycle sidecar dibanding image volume. Pengiriman warm datar terhadap ukuran model karena kubelet hanya perlu me-mount sesuatu yang sudah ada di disk.

Tiga cara menaruh bobot model di pod

KServe kini punya lebih dari satu jalur OCI, dan bedanya ada pada siapa yang menarik bytes. Pada modelcar, image model berjalan sebagai sidecar yang berbagi filesystem pod dan container runtime yang menariknya. Pada oci+native:// webhook menulis ulang storageUri menjadi image volume Kubernetes (KEP-4639), sehingga kubelet yang menariknya dan me-mount read-only tanpa init container dan tanpa sidecar. Pada oci+fetch:// storage initializer menarik layer sendiri dan hanya mengekstrak direktori models. Jalur object storage mengunduh ke emptyDir bersama setiap kali.

PathSiapa yang pullNode cachePrasyarat
oci:// (modelcar)Container runtime, sebagai sidecarYaLifecycle sidecar (sekitar 4 detik overhead warm di paper)
oci+native://Kubelet, sebagai image volumeYaKubernetes 1.31 atau lebih baru, subPath dari 1.33, containerd 2.1 atau lebih baru (2.2 untuk subPath) atau CRI-O 1.31
oci+fetch://Storage initializer KServe (oras-py)Tidak, fetch ulang setiap pod startTanpa fitur runtime, jadi jalan di cluster lama dan registry air-gapped
s3://, gs://, hf://Storage initializer KServeTidak, salinan sementara penuh di emptyDirDisk node kosong sebesar model, per replica yang berjalan bersamaan

Sisi Kubernetes-nya kecil. Image volume stabil sejak v1.36, pertama tersedia di v1.31, dan dokumentasi menyebut ia di-mount read-only pada satu direktori serta di-resolve saat pod start sesuai pullPolicy. Blok berikut adalah bentuk itu untuk sebuah model, dengan subPath yang dibutuhkan layout kompatibel modelcar. Referensi image-nya hanya placeholder.

# Shape from the Kubernetes image-volumes docs, applied to a model.
# The reference is a placeholder. Pin by digest, not a mutable tag.
apiVersion: v1
kind: Pod
metadata:
  name: model-server
spec:
  containers:
  - name: server
    image: registry.example.com/serving/runtime:1.0
    volumeMounts:
    - name: model
      mountPath: /mnt/models
      subPath: models          # subPath on image volumes needs Kubernetes 1.33+
  volumes:
  - name: model
    image:
      reference: registry.example.com/models/llm-70b-fp16@sha256:<digest>
      # IfNotPresent: a cached node mounts instantly. Never fails the pod
      # outright when any layer is missing locally, so do not use it on
      # nodes that have not been warmed.
      pullPolicy: IfNotPresent

Mengapa pull pertama bisa dua kali lebih mahal dari download

Start OCI dingin adalah sel paling lambat di tabel. Pada 140 GB kedua jalur OCI memakan sekitar 4.585 sampai 4.603 detik dibanding 2.318,8 detik untuk S3, kira-kira 2x. Pada 14 GB rasionya 2,6 sampai 3,2x. Paper menyalahkan containerd: pull layer menulis blob ke content store lalu meng-unpack-nya ke snapshot, dua kali lewat disk yang sama, sedangkan storage initializer men-stream objek ke volume pod dalam satu pass. Durasi pull yang dilaporkan kubelet menjelaskan hampir seluruh selisihnya.

Dua catatan jujur datang dari paper sendiri. Angka S3 14 GB diuntungkan page cache MinIO, yang hilang pada 140 GB karena itu empat kali RAM mesin. Dan waktu absolut dibatasi volume gp3 125 MiB/s yang dipakai semua jalur. Penulis menyebut zstd, lazy pulling (eStargz, SOCI) dan paralelisme multi-layer sebagai kemungkinan perbaikan penalti cold, tetapi tidak menguji satu pun, dan saya juga tidak akan berpura-pura semuanya berhasil.

Jadi transaksinya adalah biaya sekali untuk penghematan berulang. Start OCI dingin juga meninggalkan sekitar sebesar artifact di containerd store, dalam 5 persen pada 14 dan 140 GB, dan data yang tersisa itu adalah warm cache. S3 tidak menyimpan state di node tetapi membuat salinan sementara penuh di setiap start.

Pre-pull image model di node yang boleh dipakai autoscaler, misalnya dengan DaemonSet yang me-mount image volume yang sama, agar replica pertama di sebuah node tidak pernah yang dingin. Ini kesimpulan saya dari baris cold dan warm, bukan sesuatu yang diuji paper.

Mengemas dan memasangnya di KServe

Image model adalah image biasa yang direktori models-nya berisi bobot. Artifact di paper berupa image satu layer dengan layout itu, dan base Busybox adalah pola yang direkomendasikan panduan salah satu vendor KServe, termasuk memecah file safetensors besar ke beberapa layer karena sebagian registry membatasi ukuran layer. Paper hanya menguji artifact satu layer, jadi perilaku pull multi-layer pada 140 GB belum terukur.

# Containerfile: weights under /models, nothing else.
FROM busybox
RUN mkdir -p /models && chmod 775 /models

# Some registries cap layer size. Split big safetensors across layers,
# two files per layer, and put config files last. (The paper only tested
# single-layer artifacts, so measure multi-layer pulls yourself.)
COPY models/ /models/

Mengaktifkannya berarti satu flag cluster ditambah satu scheme. enableOciModelSupport adalah opt-in dengan default false dan, bila diset sendirian, memberi perilaku modelcar. ociModelMode memilih default seluruh cluster antara modelcar dan native untuk URI oci:// polos, dan scheme eksplisit oci+native:// atau oci+fetch:// menimpanya untuk satu service. enableModelcar yang lama tetap ada sebagai alias. Webhook juga mengisi condition advisory OciImageVolumeCompatible di cluster yang belum bisa image volume; condition itu tidak memengaruhi Ready.

# inferenceservice-config (ConfigMap), storage initializer settings.
# Opt-in master switch, then the cluster-wide default for plain oci:// URIs.
enableOciModelSupport: true      # default false; alone it behaves as modelcar
ociModelMode: "native"           # "modelcar" or "native"

# Per-service override beats the cluster default.
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: llm-70b
spec:
  predictor:
    model:
      modelFormat:
        name: huggingface
      # oci://        -> follows ociModelMode (modelcar unless changed)
      # oci+native:// -> Kubernetes image volume, kubelet pulls
      # oci+fetch://  -> storage initializer pulls with oras-py
      storageUri: oci+native://registry.example.com/models/llm-70b-fp16:1.0

Perhatikan status oci+fetch://. Paper yang ditulis pada Juli menyebutnya masih direview. Pull request-nya di-merge ke master KServe pada 12 Agustus 2026. Ia men-stream layer langsung ke ekstraksi, yang menurut PR menurunkan puncak disk sementara dari sekitar 2x image menjadi sekitar 1x, tetapi pada PR itu layer zstd ditolak, dan ia belum disambungkan ke LLMInferenceService, yang diam-diam jatuh kembali ke modelcar.

Integritas: hash saat streaming, bukan sesudahnya

Referensi OCI bisa di-pin dengan digest dan diperiksa oleh admission verifier, sehingga paper menganggap modelcar dan oci+native:// di luar cakupan kerja integritasnya. Celahnya ada di s3://, gs://, hf:// dan oci+fetch://. Untuk jalur itu penulis mengusulkan digest pinning dan penegakan model-signing OpenSSF saat serving, serta mengukur biaya pemeriksaan SHA-256 pada object store lokal.

Metode14 GB (detik)140 GB (detik)Overhead pada 140 GB
Download biasa190,32.220,4baseline
SHA-256 streaming190,42.219,8di bawah 0,1 persen
SHA-256 setelah download203,63.406,8plus 53,4 persen

Pembacaan praktisnya: hashing di dalam loop download itu gratis, sedangkan hashing sesudahnya membaca ulang setiap byte dari disk yang sudah menjadi bottleneck. Paper tidak menarik kesimpulan dari tier 2 GB yang didominasi page cache, dan belum mengukur biaya verifikasi tanda tangan keyless, yaitu round trip Fulcio dan Rekor.

Blok verification di bawah adalah sketsa di RFC #5789 yang masih terbuka, jadi tidak ada field ini di rilis mana pun. Saya menampilkannya karena menunjukkan bentuk yang dituju: digest untuk file tunggal, bundle tanda tangan dengan identity dan issuer untuk model-signing, serta mode enforce atau warn per namespace. Perintah signing-nya adalah yang ada di halaman proyek model-transparency.

# RFC kserve/kserve#5789 sketch. OPEN and not merged: these fields do not
# exist in any release yet.
model:
  storageUri: s3://bucket/model
  verification:
    digest: "sha256:..."            # single-file or archive artifacts only
    signature:
      bundle: "s3://bucket/model.sig"
      identity: "https://github.com/org/repo/.github/workflows/release.yml@refs/heads/main"
      oidcIssuer: "https://token.actions.githubusercontent.com"

# Signing and verifying with the OpenSSF model-signing CLI today:
model_signing sign bert-base-uncased --signature model.sig
model_signing verify bert-base-uncased --signature model.sig \
  --identity "$identity" --identity-provider "$oidc_provider"

Di mana ia rusak: kegagalan yang didokumentasikan paper

Kegagalan bernama di paper itu biasa saja. Pada 140 GB storage initializer di-OOM-kill sampai batas memorinya dinaikkan empat kali lipat. Siapa pun yang memindahkan bobot besar lewat jalur init container sebaiknya menyetel batas itu lebih dulu.

Image volume punya mode kegagalan sendiri di dokumentasi Kubernetes: kegagalan me-resolve atau pull image saat pod start memblokir container, bisa menambah latensi signifikan, dan di-retry dengan backoff volume normal. Dengan Always pod menjadi Failed jika pull gagal, dan dengan Never pod menjadi Failed jika ada layer yang belum ada. Volume model dengan pullPolicy Never di node tanpa cache adalah pod yang tidak bisa start.

Mode enforce menukar ketersediaan dengan integritas secara sengaja. Paper menerima bahwa penyerang di level storage, atau sekadar bundle yang hilang atau trust root yang tak terjangkau, bisa menyebabkan denial of service saat start. Paper juga menyebut jendela time-of-check ke time-of-use: container satu pod atau operator pods/exec bisa mengubah volume bersama setelah verifikasi, jadi status verifikasi harus dikunci pada digest konten, bukan URI.

Satu trade-off lagi layak disebut. Pull OCI dingin 140 GB memakan sekitar 76 menit pada setup paper dibanding sekitar 39 menit untuk S3. Jika pola scaling Anda kebanyakan node baru, bukan replica baru di node yang sudah menyimpan image, Anda membayar penalti 2x setiap kali dan manfaat warm jarang muncul.

Apa yang bisa dan tidak bisa dikatakan benchmark ini

Setup-nya satu node, lokal LAN, artifact sintetis (model scikit-learn sungguhan ditambah ballast acak), dengan registry dan object store di mesin yang sama. Distribusi multi-node, rate limit registry dan pull paralel per layer belum terukur. Time to first prediction hanya mengukur pengiriman artifact; inisialisasi inference engine GPU tidak termasuk, jadi replica LLM sungguhan masih membayar CUDA graph capture dan warmup di atas 11,7 detik.

Harness-nya publik dengan lisensi Apache 2.0, bisa dilanjutkan, dan ter-script sampai cluster. Itu lebih penting daripada angka utamanya: angka-angka ini adalah hipotesis untuk cluster Anda, dan cara murah mengujinya adalah menjalankan ulang versi smoke dengan ukuran dan registry Anda sendiri sebelum memigrasikan apa pun.

Yang dilakukan hari Senin

Urutan yang tidak memakan biaya sebelum Anda berkomitmen pada apa pun.

  1. Cek node: versi kubelet minimal 1.31 dan runtime yang mendukung image volume (containerd 2.1 atau lebih baru, CRI-O 1.31 atau lebih baru; subPath butuh Kubernetes 1.33 dan containerd 2.2).
  2. Ukur biaya Anda hari ini: catat waktu penambahan replica dari object storage untuk model terbesar Anda dan disk node kosong yang dibutuhkan per replica bersamaan.
  3. Kemas satu model sebagai image satu layer dengan bobot di direktori models, push, lalu referensikan dengan digest, bukan tag yang bisa berubah.
  4. Aktifkan enableOciModelSupport di cluster uji, deploy model yang sama dengan oci+native://, lalu catat waktu cold start dan replica kedua di node yang sama.
  5. Untuk sumber s3 dan hf yang tetap Anda pakai, hash saat download, bukan sesudahnya, dan rencanakan digest pinning setelah RFC #5789 dirilis.
# 1. Kubelet and runtime versions per node.
kubectl get nodes -o custom-columns=NAME:.metadata.name,KUBELET:.status.nodeInfo.kubeletVersion,RUNTIME:.status.nodeInfo.containerRuntimeVersion

# 4. After deploying with oci+native://, confirm the cluster passed the
#    advisory check (OciImageVolumeCompatible) and read the pull events.
kubectl get inferenceservice llm-70b -o jsonpath='{.status.conditions}'
kubectl describe pod -l serving.kserve.io/inferenceservice=llm-70b | grep -iE 'pulling|pulled|image'

# Reproduce the paper on your own sizes: scripts are 01-cluster-up.sh to
# 04-integrity-bench.sh in the harness; override SIZES_GB and REPS to smoke test.
SIZES_GB="2" REPS=3 ./03-run-matrix.sh

Jika replica kedua tidak mendekati datar, bottleneck-nya ada di tempat yang tidak diukur paper, misalnya inisialisasi engine atau registry yang tidak sanggup mengimbangi, dan migrasi tidak akan balik modal.

Perlakukan bobot model sebagai image: pull sekali per node, alamatkan dengan digest, dan mount, bukan salin. Kemenangan terukurnya ada di jalur warm, 11,7 detik melawan 40,7 menit, dan dibayar dengan pull pertama yang dingin dan bisa dua kali lebih lama dari download biasa. Tentukan dulu autoscaler Anda sebenarnya hidup di jalur yang mana sebelum memilih jalurnya.

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Seberapa lebih cepat OCI image volume dibanding download model dari S3?

Pada studi arXiv:2607.16596, menambah warm replica artifact kelas 70B (140 GB) memakan 11,7 detik dengan oci+native:// dibanding 2.441,6 detik, sekitar 40,7 menit, untuk download ulang S3. Itu kira-kira 208x. Setup-nya satu node dengan registry lokal, jadi anggap sebagai batas atas yang perlu diuji, bukan jaminan.

Mengapa pull OCI pertama lebih lambat dari download biasa?

Paper menyebut penyebabnya containerd. Pull layer menulis blob ke content store lalu meng-unpack-nya ke snapshot, yaitu dua kali lewat disk yang sama, sedangkan storage initializer KServe men-stream objek dalam satu pass. Pada 140 GB start OCI dingin memakan sekitar 2x download S3.

Apa beda modelcar, oci+native dan oci+fetch di KServe?

Modelcar menjalankan image model sebagai sidecar yang di-pull container runtime. oci+native:// menulis ulang storageUri menjadi image volume Kubernetes yang di-pull kubelet, tanpa sidecar atau init container. oci+fetch:// membuat storage initializer menarik dan mengekstrak layer sendiri, jadi jalan tanpa dukungan image volume tetapi tidak punya node cache.

Versi Kubernetes dan containerd berapa yang dibutuhkan image volume?

Image volume pertama muncul di Kubernetes v1.31 dan stabil di v1.36. Mount subPath didukung sejak v1.33. Paper menyebut containerd 2.1 atau lebih baru (2.2 untuk subPath) atau CRI-O 1.31 atau lebih baru sebagai syarat runtime.

Bagaimana memverifikasi bobot model dari S3 atau Hugging Face di KServe?

Belum ada secara native. RFC #5789 mengusulkan blok verification dengan digest sha256 dan bundle model-signing OpenSSF, tetapi masih terbuka. Sampai saat itu, hash bytes saat di-stream, yang diukur paper di bawah 0,1 persen overhead, bukan di pass kedua yang memakan sampai 53 persen.