Sono necessarie build deterministiche per l'attestazione del carico di lavoro nella funzionalità sul dispositivo Trusted Execution Environment (TEE) per la personalizzazione (ODP), disponibile pubblicamente su Google Cloud come Confidential Space (CS).
Le immagini del carico di lavoro devono generare un hash delle immagini deterministico che possa essere utilizzato CS per l'attestazione del carico di lavoro (che utilizza l'attestazione remota RFC 9334) del NIST architettura procedureS (RATS)).
Questo documento illustrerà l'implementazione e il supporto per modelli deterministici nel odp-federatedcompute repository Git. I servizi ODP Aggregator e Model Updater verranno eseguiti Spazio riservato. Il repository supporta build deterministiche per tutti i nostri necessari per i casi d'uso di produzione.
Build deterministiche
Le build deterministiche sono costituite da due componenti principali:
- La compilazione di file binari richiesti. Sono inclusi jar, librerie condivise e metadati.
- Le dipendenze dell'immagine di base e del runtime. La base dell'ambiente di runtime immagine utilizzata per eseguire i file binari compilati.
Al momento, il repository Federated Compute di ODP supporta i seguenti tipi di carichi di lavoro standard:
- Carichi di lavoro Java + Spring
- TaskAssignment, TaskManagement, Raccoglitore
- Java + Spring con carichi di lavoro TensorFlow JNI
- ModelUpdater, aggregatore
- Carichi di lavoro Python
- TaskBuilder
Dipendenze
Di seguito sono elencate le dipendenze su cui si basa ODP per mantenere il determinismo e disponibilità:
- Bazel
- GitHub
- Maven
- PyPi
- Snapshot Debian
- Registro DockerHub
- Google Container Registry (GCR)
Carichi di lavoro deterministici
Tutti i carichi di lavoro vengono compilati utilizzando Bazel con e immagini container specifiche per i vari linguaggi rules_oci. L'AREA DI LAVORO file definisce tutte le dipendenze con le versioni e gli hash corrispondenti.
Snapshot Debian
Tutte le immagini dei carichi di lavoro devono essere create all'interno dockerfile basato su uno snapshot Debian. Debian forniscono uno snapshot del repository stabile con dati deterministici:
- Intestazioni e librerie di sistema
- Architettura di sistema
- linux_x86_64
- Debian
- Compilatore C++
Carichi di lavoro Java Spring
Bazel's
remotejdk_17
è
utilizzato per fornire un Java ermetico per la compilazione. Altre dipendenze Java
gestiti e definiti in WORKSPACE
.
I carichi di lavoro Java Spring vengono compilati in un file jar denominato
<service>_application.jar
. Il barattolo contiene:
- File di classe Java
META-INF/
- Dati manifest Bazel
build-data.properties
- Dati di build Bazel
BOOT-INF/
- Dipendenze jar pacchettizzate, generate da rules_spring.
Livelli immagine
L'immagine del carico di lavoro Java Spring è costituita da due livelli:
- Livello immagine di base
- Immagine di base Java:
gcr.io/distroless/java17-debian11
- Immagine di base Java:
- Livello carico di lavoro
binary_tar.tar
<service>_application.jar
Configurazione immagine
- Punto di ingresso
java -jar <service>_application.jar
Carichi di lavoro TensorFlow JNI
I carichi di lavoro TensorFlow TensorFlow si basano sui carichi di lavoro Java Spring. R la toolchain ermetica Clang+LLVM Bazel viene fornita utilizzando Clang+LLVM predefinito 16 con un sysroot fornito dall'immagine snapshot Debian per compilare il codice della macchina.
I carichi di lavoro JNI vengono compilati in una libreria condivisa denominata libtensorflow.so
con <service>_application.jar
.
Livelli immagine
L'immagine del carico di lavoro JNI TensorFlow è composta da diversi livelli:
- Livello immagine di base
- Immagine di base Java:
gcr.io/distroless/java17-debian11
- Immagine di base Java:
- Livelli di dipendenza dei pacchetti Debian. Gli strati vengono generati utilizzando deb
archivi scaricati da debian-snapshot e riproposti come livelli immagine
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
- Livello carico di lavoro
binary_tar.tar
<service>_application.jar
libtensorflow-jni.so
libaggregation-jni.so
Configurazione immagine
- Etichette (solo per immagini create per essere eseguite all'interno di TEE)
"tee.launch_policy.allow_env_override": "FCP_OPTS"
- Consente di impostare la variabile di ambiente
FCP_OPTS
in riservato spazio di archiviazione. Il carico di lavoro consumeràFCP_OPTS
all'avvio per la configurazione parametri obbligatori. - La variabile di ambiente
FCP_OPTS
viene impostata quando viene eseguita l'immagine per mantenere il determinismo delle build.
- Consente di impostare la variabile di ambiente
"tee.launch_policy.log_redirect": "always"
"tee.launch_policy.monitoring_memory_allow": "always"
- Punto di ingresso
java -Djava.library.path=. -jar <service>_application.jar
Carichi di lavoro Python
rules_python di Bazel è utilizzato per una toolchain ermetica per Python 3.10. Requisiti di un pip bloccato file viene utilizzato per il recupero deterministico delle dipendenze pip. Lo snapshot Debian garantisce che le distribuzioni deterministiche vengano recuperate in base alla piattaforma compatibilità e fornisce una toolchain C++ per compilare le distribuzioni di origine.
I carichi di lavoro Python verranno pacchettizzati in un insieme di pacchetti pip scaricati, la distribuzione in Python 3.10, il codice sorgente Python ODP e un avvio Python lo script.
<service>.runfiles/
- La distribuzione Python è archiviata in
python_x86_64-unknown-linux-gnu/
- Il codice sorgente si trova in
com_google_ondevicepersonalization_federatedcompute/
- I pacchetti PIP sono memorizzati in
pypi_<dependency_name>/
- La distribuzione Python è archiviata in
<service>.runfiles_manifest
- File manifest per la directory
<service>.runfiles/
- File manifest per la directory
<service>
- Script Python per eseguire il carico di lavoro Python utilizzando i runfile
Livelli immagine
L'immagine del carico di lavoro Python è composta da quattro livelli:
- Livello immagine di base
- Immagine di base Python python:slim
- Livello Interprete
interpreter_layer.jar
<service>/<service>.runfiles/python_x86_64-unknown-linux-gnu/**
- Livello pacchetti
packages_layer.jar
<service>/<service>.runfiles/**/site-packages/**
- Livello carico di lavoro
app_tar_manifest.tar
- Contiene codice sorgente, script di avvio e manifest.
<service>/<service>.runfiles_manifest
<service>/<service>
<service>/<service>.runfiles/com_google_ondevicepersonalization_federatedcompute/**
- Contiene codice sorgente, script di avvio e manifest.
Configurazione immagine
- Punto di ingresso
/<service>/<service>
Crea immagini
Una volta scelti i carichi di lavoro, puoi creare e pubblicare in formato Docker.
Prerequisiti
Procedura
Le immagini devono essere create all'interno del container Docker creato dockerfile. Vengono forniti due script per aiutare a creare le immagini deterministiche finali.
- docker_run.sh
docker_run.sh
creerà l'immagine Docker dal file Docker, monta la directory di lavoro, monta il daemon docker host ed esegui docker con il comando bash fornito. Qualsiasi variabile passata prima del comando bash come flag dell'esecuzione di Docker.
- build_images.sh
build_images.sh
eseguiràbazel build
per tutte le immagini e restituirà il codice per ogni immagine creata.
Crea tutte le immagini
./scripts/docker/docker_run.sh "./scripts/build_images.sh"
Gli hash delle immagini previsti per ogni release sono disponibili in GitHub odp-federatedcompute di machine learning.
Pubblica immagini
La pubblicazione viene configurata utilizzando oci_push Regole bazel. Per ogni servizio, il repository di destinazione deve essere configurato tutti:
- aggregatore
- raccoglitore
- model_updater
- task_assignment
- task_management
- task_scheduler
- task_builder
Pubblica una singola immagine
Per pubblicare una singola immagine:
./scripts/docker/docker_run.sh "bazel run //shuffler/services/<servicename_no_underscore>:<servicename_with_underscore>_image_publish"
Immagini create
Tutte le immagini create dovranno essere archiviate e ospitate dal creator, ad esempio in un Artifact Registry di Google Cloud.