Menggunakan volume agen Filestore dengan pengikatan lambat penyimpanan dinamis GKE Agent Sandbox

Pengikatan lambat penyimpanan dinamis memungkinkan Anda menyuntikkan volume agen Filestore langsung ke pod Sandbox Agen Google Kubernetes Engine (GKE) yang sedang berjalan dan telah dipanaskan sebelumnya saat klaim. Dengan melewati siklus proses pemasangan volume Kubernetes standar, pengikatan lambat dinamis mencapai latensi pemasangan penyimpanan di bawah 100 md tanpa memerlukan mulai ulang pod.

Arsitektur ini memungkinkan platform agen berlatensi rendah dan kepadatan tinggi untuk:

  • Menghilangkan cold start pod dan penundaan inisialisasi container.
  • Melampirkan dan melepaskan ruang kerja persisten secara dinamis sesuai permintaan.
  • Menjeda atau membuat sesi agen yang tidak aktif menjadi hibernasi dan melanjutkannya di pod sandbox yang sudah dipanaskan sebelumnya dan tersedia sambil mempertahankan status sistem file.

Sebelum memulai

  1. Selesaikan penyiapan awal di Menyiapkan lingkungan GKE untuk volume agen Filestore.
  2. Verifikasi bahwa cluster GKE Anda menjalankan versi 1.36.0-gke.3302001 atau yang lebih baru. Versi ini mendukung anotasi force-shared yang diperlukan untuk propagasi pemasangan emptyDir gVisor.
  3. Verifikasi bahwa volume-pool-sc StorageClass Anda menentukan volumeBindingMode: Immediate dan reclaimPolicy: Delete.

Ringkasan arsitektur

Arsitektur late-binding terdiri dari empat komponen:

  • Orkestrator platform atau pengontrol kustom: Layanan bidang kontrol atau pengontrol Kubernetes yang mengelola siklus proses sesi. Operator ini memantau peristiwa SandboxClaim, menyelesaikan metadata volume tenant, memanggil API daemon node penyimpanan untuk mengikat atau melepaskan penyimpanan, dan mengelola finalizer penghapusan.
  • Daemon node penyimpanan: DaemonSet dengan hak istimewa yang berjalan di setiap node gVisor yang mengekspos API pemasangan.
  • SandboxTemplate dengan force-shared: Template pod sandbox gVisor yang memungkinkan propagasi pemasangan host secara dinamis ke dalam container sandbox gVisor.
  • SandboxWarmPool: Kumpulan pod sandbox yang sudah di-warm up dan berjalan, siap menerima permintaan pemasangan secara instan setelah diklaim.

Men-deploy daemon node penyimpanan

Buat manifes bernama storage-node-daemon.yaml yang berisi DaemonSet istimewa:

Terapkan manifes:

kubectl apply -f storage-node-daemon.yaml

Deploy SandboxTemplate dan SandboxWarmPool

Buat manifes bernama sandbox-latebind.yaml yang berisi template dan warm pool:

Terapkan manifes:

kubectl apply -f sandbox-latebind.yaml

Mengklaim sandbox dan mengikat penyimpanan secara dinamis

  1. Buat manifes klaim bernama late-bind-claim.yaml yang menyertakan finalizer penghapusan (agent.sandbox/storage-cleanup):

    apiVersion: extensions.agents.x-k8s.io/v1alpha1
    kind: SandboxClaim
    metadata:
      name: late-bind-session-1
      namespace: default
      finalizers:
        - agent.sandbox/storage-cleanup
    spec:
      sandboxTemplateRef:
        name: late-bind-template
    

    Terapkan klaim:

    kubectl apply -f late-bind-claim.yaml
    
  2. Sediakan volume secara dinamis menggunakan manifes PVC bernama agent-volume-pvc.yaml:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: session-1-pvc
      namespace: default
    spec:
      accessModes: [ReadWriteMany]
      storageClassName: volume-pool-sc
      resources:
        requests:
          storage: 1Gi
    

    Terapkan PVC:

    kubectl apply -f agent-volume-pvc.yaml
    
  3. Ambil detail ekspor PV pendukung, node, dan UID pod yang ditetapkan:

    POD_NAME=$(kubectl get pods \
      -l extensions.agents.x-k8s.io/claimed-by=late-bind-session-1 \
      -o jsonpath='{.items[0].metadata.name}')
    POD_UID=$(kubectl get pod "${POD_NAME}" -o jsonpath='{.metadata.uid}')
    NODE_NAME=$(kubectl get pod "${POD_NAME}" -o jsonpath='{.spec.nodeName}')
    PV_NAME=$(kubectl get pvc session-1-pvc -o jsonpath='{.spec.volumeName}')
    NFS_IP=$(kubectl get pv "${PV_NAME}" \
      -o jsonpath='{.spec.csi.volumeAttributes.ip}')
    NFS_PATH="/$(kubectl get pv "${PV_NAME}" \
      -o jsonpath='{.spec.csi.volumeAttributes.volume}')"
    
  4. Kirim sinyal pemasangan ke daemon node di host pod:

    DAEMON_POD=$(kubectl get pods -l app=storage-node-daemon \
      --field-selector spec.nodeName="${NODE_NAME}" \
      -o jsonpath='{.items[0].metadata.name}')
    kubectl exec "${DAEMON_POD}" -c daemon -- python3 -c "
    import urllib.request, json
    payload = json.dumps({
        'action': 'bind_nfs',
        'pod_uid': '${POD_UID}',
        'volume_name': 'workspace-volume',
        'sub_dir': 'user_data',
        'nfs_server': '${NFS_IP}',
        'nfs_path': '${NFS_PATH}'
    }).encode()
    req = urllib.request.Request(
        'http://localhost:9090',
        data=payload,
        headers={'Content-Type': 'application/json'})
    print(urllib.request.urlopen(req).read().decode())
    "
    
  5. Terapkan finalizer penghapusan ke pod yang diklaim untuk mencegah pembersihan prematur saat pemasangan host aktif:

    kubectl patch pod "${POD_NAME}" --type=merge \
      -p '{"metadata":{"finalizers":["agent.sandbox/storage-cleanup"]}}'
    
  6. Verifikasi pemasangan volume di dalam pod yang sedang berjalan:

    kubectl logs "${POD_NAME}" -c agent
    

    Output mengonfirmasi bahwa volume berhasil dipasang:

    Waiting for late-bind signal...
    Filestore volume mounted successfully!
    drwxr-xr-x    2 1000     1000          4096 ... user_data
    

Menjeda dan melanjutkan sesi

Saat sesi agen berakhir atau memasuki hibernasi, orkestrator Anda harus melepas penyimpanan host sebelum mengizinkan Kubernetes menghentikan atau mendaur ulang pod.

  1. Mulai penghapusan SandboxClaim di latar belakang. Karena finalizer, Kubernetes menandai klaim untuk dihapus, tetapi menghentikan penghentian pod:

    kubectl delete sandboxclaim late-bind-session-1 --wait=false
    
  2. Lepaskan pemasangan berbagi NFS di node host:

    kubectl exec "${DAEMON_POD}" -c daemon -- python3 -c "
    import urllib.request, json
    payload = json.dumps({
        'action': 'unbind',
        'pod_uid': '${POD_UID}',
        'volume_name': 'workspace-volume',
        'sub_dir': 'user_data'
    }).encode()
    req = urllib.request.Request(
        'http://localhost:9090',
        data=payload,
        headers={'Content-Type': 'application/json'})
    print(urllib.request.urlopen(req).read().decode())
    "
    
  3. Hapus finalizer dari SandboxClaim dan pod untuk menyelesaikan penghentian:

    kubectl patch sandboxclaim late-bind-session-1 --type=merge \
      -p '{"metadata":{"finalizers":[]}}'
    kubectl patch pod "${POD_NAME}" --type=merge \
      -p '{"metadata":{"finalizers":[]}}'
    

Untuk melanjutkan sesi nanti, klaim pod yang telah dipanaskan sebelumnya dan kirim permintaan pengikatan menggunakan PVC yang ada (session-1-pvc). Pod sandbox baru akan langsung mendapatkan akses ke status ruang kerja yang dipertahankan.

Pertimbangan produksi dan desain pengontrol kustom

Perintah manual dalam dokumen ini menunjukkan mekanisme tingkat rendah dari pengikatan terlambat dinamis. Untuk menjalankan arsitektur ini secara andal dalam produksi, Anda harus mengembangkan pengontrol Kubernetes kustom atau orkestrator platform yang disesuaikan dengan siklus proses sesi aplikasi Anda.

Saat mendesain pengontrol produksi dan daemon node, terapkan pola arsitektur berikut:

Mengotomatiskan siklus proses rekonsiliasi dan finalizer

Karena daemon node penyimpanan melakukan pemasangan tingkat host di luar pengelolaan siklus proses Antarmuka Penyimpanan Container (CSI) Kubernetes standar, Kubelet tidak mengetahui pemasangan aktif di dalam emptyDir pod. Jika pod dihapus saat pemasangan aktif, Kubelet gagal menghapus direktori emptyDir dan memunculkan error Device or resource busy, sehingga pod tetap berada dalam status Terminating.

Pengontrol kustom Anda harus mengotomatiskan mesin status yang ketat menggunakan finalizer (seperti agent.sandbox/storage-cleanup):

  1. Pembuatan dan pengaitan klaim:
    • Lampirkan finalizer statis ke setiap SandboxClaim saat pembuatan.
    • Pantau Kubernetes API untuk mengetahui update status SandboxClaim. Saat klaim terikat ke pod kumpulan data hangat, ekstrak atribut volume Filestore pendukung, pod_uid, dan nodeName yang ditetapkan.
    • Kirim permintaan bind yang diautentikasi ke daemon node penyimpanan yang berjalan di node target.
    • Segera patch objek Pod yang sedang berjalan untuk menambahkan finalizer dinamis. Karena spesifikasi SandboxTemplate tidak mendukung finalizer pod statis, patching pod secara dinamis diperlukan untuk melindungi pod selama peristiwa pengurasan node atau penjadwalan ulang saat pod dikeluarkan, tetapi SandboxClaim tetap aktif.
  2. Penanganan penghentian dan pengusiran yang benar:
    • Pantau deletionTimestamp di resource SandboxClaim dan Pod.
    • Saat penghapusan atau pengusiran terdeteksi, panggil endpoint unbind daemon node untuk melepas direktori host dengan benar (umount -l).
    • Pastikan pelepasan berhasil dan semua penulisan yang tertunda telah dibersihkan sebelum menambal Pod dan SandboxClaim untuk menghapus finalizer-nya. Hal ini dapat membantu Anda melakukan penonaktifan yang bersih di seluruh penghapusan klaim yang benar, upgrade node GKE, penghentian sementara Spot VM, dan penghentian karena kehabisan memori (OOM).

Mengamankan dan memperkuat daemon node penyimpanan

  • Ganti kubectl exec dengan API yang diautentikasi: Dalam produksi, jangan gunakan kubectl exec atau ikat daemon ke localhost. Konfigurasi daemon node penyimpanan untuk mengekspos endpoint gRPC atau HTTPS khusus melalui jaringan cluster yang diamankan dengan autentikasi TLS bersama (mTLS) atau token Kubernetes ServiceAccount.
  • Mengisolasi namespace daemon dan akses jaringan: Deploy storage-node-daemon DaemonSet dengan hak istimewa di namespace administratif yang dibatasi (misalnya, sandbox-storage-system), bukan di namespace default atau tenant. Terapkan aturan NetworkPolicyKubernetes yang mengizinkan ingress ke API daemon secara eksklusif dari pod pengontrol kustom Anda dan memblokir semua traffic dari pod agen yang di-sandbox.
  • Gunakan image container yang telah disimulasikan: Hindari penginstalan paket seperti nfs-common saat runtime di initContainer. Gunakan image container bawaan yang tidak dapat diubah dengan semua utilitas pemasangan yang diperlukan telah diinstal sebelumnya untuk menghilangkan penundaan startup node dan dependensi repositori eksternal.

Menerapkan kuota penyimpanan dan isolasi multi-tenant

  • Memantau penggunaan penyimpanan per agen: Saat Anda memasang-mengikat subdirectory secara dinamis dari volume Filestore ReadWriteMany (RWX) bersama ke emptyDir, setelan emptyDir.sizeLimit Kubernetes standar tidak dapat menerapkan kuota penyimpanan per agen di jalur NFS yang di-mount. Untuk mencegah satu agen yang tidak terkendali menghabiskan volume bersama dan menyebabkan penolakan layanan (DoS), terapkan pemantauan kuota direktori di orkestrator Anda atau sediakan volume khusus menggunakan kumpulan volume.
  • Menyesuaikan payload pemasangan untuk berbagai mode akses ruang kerja: Pengontrol Anda dapat mendukung beberapa topologi penyimpanan agen dengan memvariasikan parameter yang dikirim ke daemon node:
    • Ruang kerja pribadi yang terisolasi: Mengikat subdirektori tenant unik atau PVC khusus ke satu pod sandbox dengan izin baca-tulis.
    • Ruang kerja kolaboratif: Secara bersamaan mengikat subdirektori RWX bersama yang sama di beberapa pod agen yang berkoordinasi untuk berbagi file secara real time.
    • Ruang kerja percabangan eksplorasi: Pasang direktori template dasar sebagai hanya baca (ro) sehingga agen dapat membaca aset bersama tanpa mengubah salinan master, sekaligus merutekan penulisan baru ke jalur sementara yang dapat ditulis atau direktori salin saat dipulihkan yang terpisah.

Mengoordinasikan snapshot point-in-time dan pembersihan

  • Mencapai keheningan penulisan sebelum snapshot: Untuk mengambil snapshot ruang kerja yang konsisten pada satu titik waktu tanpa merusak data, orkestrator Anda harus menjeda penulisan aktif dengan memulai alur kerja pelepasan (atau mengosongkan buffer sistem file) sebelum mengarsipkan direktori ruang kerja atau memicu snapshot Filestore.
  • Mengotomatiskan penghapusan penyediaan tenant: Saat sesi pengguna atau ruang kerja berakhir secara permanen, pastikan pengontrol Anda terlebih dahulu membatalkan pengikatan semua pemasangan aktif di semua node sebelum menjalankan tugas latar belakang asinkron untuk menghapus direktori persisten tenant dari volume pendukung.

Untuk mengetahui implementasi referensi lengkap yang menunjukkan pengelolaan finalizer dinamis, isolasi multi-tenant, dan alur kerja pemulihan snapshot, lihat contoh penyimpanan dengan binding lambat GKE Sandbox di GitHub.

Langkah berikutnya