גרסת build דטרמיניסטית של מחשוב מאוחד להתאמה אישית במכשיר

נדרשות גרסאות build דטרמיניסטיות לאימות עומסי עבודה במכשיר סביבת ביצוע מהימנה (TEE) להתאמה אישית (ODP), זמינה לציבור ב- Google Cloud כ-Confidential Space (CS).

התמונות של עומס העבודה צריכות ליצור גיבוב (hash) של תמונה דטרמיניסטי שיכול לשמש CS לאימות עומסי עבודה (שמשתמש ב-RFC 9334 Remote ATtestation) ארכיטקטורת RATS (RATS)).

במסמך הזה נבחן את ההטמעה של דטרמיניסטי ותמיכה מבוססת odp-federatedcompute של מאגר הנתונים. שירותי אגרגטור ODP ו-Model Updater יפעלו בתוך מרחב סודי. המאגר תומך בגרסאות build דטרמיניסטיות לכל בשירותים האלה, שנדרשים בתרחישים לדוגמה בסביבת הייצור.

גרסאות build דטרמיניסטיות

ה-build הדטרמיניסטי מורכב משני חלקים עיקריים:

  1. אוסף של הקבצים הבינאריים הנדרשים. כולל צנצנות, ספריות משותפות ומטא-נתונים.
  2. יחסי התלות של קובץ האימג' הבסיסי ושל סביבת זמן הריצה. הבסיס של סביבת זמן הריצה תמונה שמשמשת להפעלת הקבצים הבינאריים שעברו הידור.

נכון לעכשיו, מאגר המחשוב המאוחד של ODP תומך בסוגים הבאים של עומסי עבודה:

  • עומסי עבודה (workloads) של Java + Spring
    • הקצאת משימות, ניהול משימות, אוסף משימות
  • Java ו-Spring עם עומסי עבודה (workloads) של JNI tensorflow
    • ModelUpdater, Aggregator
  • עומסי עבודה (workloads) של Python
    • TaskBuilder

יחסי תלות

ברשימה הבאה מפורטים יחסי תלות שעליהם מסתמך ה-ODP כדי לשמור על הדטרמיניזם וזמינות:

  • Bazel
  • GitHub
  • Maven
  • PyPi
  • קובצי snapshot של Debian
  • Registry של DockerHub
  • Container Registry (GCR)

עומסי עבודה דטרמיניסטיים

כל עומסי העבודה עוברים הידור באמצעות Bazel עם כלים ספציפיים לשפה וקובצי אימג' של קונטיינרים שפותחו באמצעות rules_oci. פלטפורמת Workspace קובץ מגדיר את כל יחסי התלות עם גרסאות וגיבובים תואמים.

קובצי snapshot של Debian

כל התמונות של עומסי העבודה צריכות להיות בנויות במסגרת dockerfile על בסיס תמונת המצב של Debian. Debian קובצי snapshot מספקים תמונת מצב יציבה של המאגר עם דטרמיניסטי:

עומסי עבודה (workloads) של Java Spring

בזלת remotejdk_17 הוא ששימשו להרכבת Java הרמטית. יחסי תלות אחרים של Java הם מנוהלות ומוגדרות במערכת WORKSPACE .

עומסי העבודה של Java Spring עוברים הידור לקובץ מאגר בשם <service>_application.jar הצנצנת מכילה:

  • קבצים של כיתת Java
  • META-INF/
    • נתוני מניפסט של Bazel
  • build-data.properties
    • נתוני build של Bazel
  • BOOT-INF/
    • יחסי תלות של צנצנות ארוזות, שנוצרו על ידי rules_spring

שכבות תמונה

התמונה של עומס העבודה של Java Spring מורכבת משתי שכבות:

  • שכבת תמונת בסיס
  • שכבת עומס העבודה
    • binary_tar.tar
      • <service>_application.jar

הגדרת התמונה

  • נקודת כניסה
    • java -jar <service>_application.jar

עומסי עבודה (workloads) של JNI Tensorflow

עומסי העבודה של JNI Tensorflow מבוססים על עומסי העבודה של Java Spring. א' צרור הכלים הרמטי של Clang+LLVM Bazel מסופק באמצעות Clang+LLVM מובנה 16 עם sysroot שסופק על ידי תמונת המצב של Debian כדי להדר קוד מכונה.

עומסי העבודה של JNI עוברים הידור לספרייה משותפת בשם libtensorflow.so יחד עם <service>_application.jar.

שכבות תמונה

התמונה של עומס העבודה של tensorflow JNI מורכבת מכמה שכבות:

  • שכבת תמונת בסיס
  • שכבות התלות של חבילות Debian. השכבות נוצרות באמצעות deb ארכיונים שהורדו מ-debian-snapshot ואורזים מחדש כשכבות תמונה
    • libc++1-16_amd64.tar
    • libc++abi1-16_amd64.tar
    • libc6_amd64.tar
    • libunwind-16_amd64.tar
    • libgcc-s1_amd64.tar
    • gcc-13-base_amd64.tar
  • שכבת עומס העבודה
    • binary_tar.tar
      • <service>_application.jar
      • libtensorflow-jni.so
      • libaggregation-jni.so

הגדרת התמונה

  • תוויות (רק לתמונות שמיועדות לפעול בסביבת TEE)
    • "tee.launch_policy.allow_env_override": "FCP_OPTS"
    • "tee.launch_policy.log_redirect": "always"
    • "tee.launch_policy.monitoring_memory_allow": "always"
  • נקודת כניסה
    • java -Djava.library.path=. -jar <service>_application.jar

עומסי עבודה (workloads) של Python

הפרמטר rules_python של בזל משמש כדי לספק צרור כלים הרמטי של Python 3.10. הדרישות לגבי PIP נעול קובץ משמשת לאחזור דטרמיניסטי של יחסי תלות של PIP. קובץ ה-snapshot של Debian תמונה מבטיחה שההתפלגויות הדטרמיניסטיות יאוחזרו בהתבסס על הפלטפורמה תאימות ומספק צרור כלים של C++ לקבלת הפצות מקור.

עומסי העבודה של Python נארזים בקבוצה של חבילות PIP שהורדתם, הפצת Python 3.10, קוד המקור של ODP Python וסטארט-אפ של Python סקריפט.

  • <service>.runfiles/
    • הפצת Python מאוחסנת במסגרת python_x86_64-unknown-linux-gnu/
    • קוד המקור מאוחסן במסגרת com_google_ondevicepersonalization_federatedcompute/
    • חבילות 'תמונה בתוך תמונה' מאוחסנות ב-pypi_<dependency_name>/
  • <service>.runfiles_manifest
    • קובץ מניפסט לספרייה <service>.runfiles/
  • <service>
    • סקריפט Python להרצת עומס העבודה של Python באמצעות קובצי ההרצה

שכבות תמונה

התמונה של עומס העבודה ב-Python מורכבת מארבע שכבות:

  • שכבת תמונת בסיס
    • קובץ אימג' בסיסי של Python python:slim
  • שכבת התרגום
    • interpreter_layer.jar
      • <service>/<service>.runfiles/python_x86_64-unknown-linux-gnu/**
  • שכבת החבילות
    • packages_layer.jar
      • <service>/<service>.runfiles/**/site-packages/**
  • שכבת עומס העבודה
    • app_tar_manifest.tar
      • מכיל קוד מקור, סקריפט הפעלה ומניפסט.
        • <service>/<service>.runfiles_manifest
        • <service>/<service>
        • <service>/<service>.runfiles/com_google_ondevicepersonalization_federatedcompute/**

הגדרת התמונה

  • נקודת כניסה
    • /<service>/<service>

יצירת תמונות

אחרי שבוחרים את עומסי העבודה, אתם מוכנים ליצור ולפרסם תמונות.

דרישות מוקדמות

  • Bazel 6.4.0
    • יש להתקין את Java ו-C++
  • Docker

התהליך

יש לבנות את התמונות בתוך מאגר ה-Docker שנוצר על ידי המכשיר שסופק dockerfile. סופקו שני סקריפטים כדי לסייע בבניית התמונות הדטרמיניסטיות הסופיות.

  • docker_run.sh
    • docker_run.sh יבנה את קובץ האימג' של ה-Docker מקובץ ה-Docker, יטען אותו את ספריית העבודה, טוענים את ה-Daemon של המארח ונמצאת ב-Docker שסופקה על ידי פקודת bash. כל משתנה שיועבר לפני פקודת bash ייחשבו כדגלים להרצה ב-Docker.
  • build_images.sh
    • build_images.sh יריץ את הפקודה bazel build לכל התמונות ויפיק פלט גיבובים (hash) של תמונות שנוצרו על ידי כל תמונה שנוצרה.

יצירת כל התמונות

./scripts/docker/docker_run.sh "./scripts/build_images.sh"

ניתן למצוא את גיבובי התמונות הצפויים לכל גרסה בקטע odp-Federatedcompute GitHub גרסאות חדשות.

פרסום תמונות

הפרסום מוגדר באמצעות oci_push כללים לבילויים. לכל שירות צריך להגדיר את מאגר היעד הכול:

  • אתר אגרגטור
  • אספן
  • model_updater
  • task_assignment
  • task_management
  • task_scheduler
  • task_builder

פרסום של תמונה אחת

כדי לפרסם תמונה אחת:

./scripts/docker/docker_run.sh "bazel run //shuffler/services/<servicename_no_underscore>:<servicename_with_underscore>_image_publish"

תמונות מובנות

היוצר צריך לאחסן את כל התמונות שנוצרו ולארח אותן, למשל מרשם פריטי המידע שנוצרו בתהליך הפיתוח (Artifact) של GCP.