Personalizacja na urządzeniu – sfederowana, deterministyczna kompilacja obliczeń

Deterministyczne kompilacje są wymagane do atestowania zbioru zadań w zaufanym środowisku wykonawczym (TEE) personalizacji na urządzeniu (ODP), które jest publicznie dostępne w Google Cloud jako Poufna przestrzeń (CS).

Obrazy zadań muszą generować deterministyczny skrót obrazu, który może być używany przez CS do atestowania zadań (które korzysta z architektury RFC 9334 Remote ATtestation procedureS (RATS) opracowanej przez NIST).

W tym dokumencie omówimy wdrażanie i obsługę deterministycznych kompilacji w repozytorium odp-federatedcompute. Usługi ODP Aggregator i Model Updater będą działać w przestrzeni poufnej. Repozytorium obsługuje deterministyczne kompilacje wszystkich naszych usług, które są wymagane w przypadku zastosowań produkcyjnych.

Deterministyczne kompilacje

Deterministyczne kompilacje składają się z 2 głównych komponentów:

  1. kompilacja wymaganych plików binarnych; Obejmuje to pliki JAR, biblioteki współdzielone i metadane.
  2. Obraz podstawowy i zależności czasu działania. Obraz bazowy środowiska wykonawczego używany do wykonywania skompilowanych plików binarnych.

Obecnie repozytorium ODP Federated Compute obsługuje te typy zadań:

  • Obciążenia Java + Spring
    • TaskAssignment, TaskManagement, Collector
  • Java + Spring z obciążeniami JNI TensorFlow
    • ModelUpdater, Aggregator
  • Obciążenia Pythona
    • TaskBuilder

Zależności

Poniżej znajdziesz listę zależności, od których zależy determinizm i dostępność ODP:

  • Bazel
  • GitHub
  • Maven
  • PyPi
  • Zrzuty Debiana
  • Rejestr DockerHub
  • Google Container Registry (GCR)

Deterministyczne zbiory zadań

Wszystkie zbiory zadań są kompilowane za pomocą Bazel z użyciem łańcuchów narzędzi specyficznych dla danego języka i obrazów kontenerów utworzonych za pomocą rules_oci. Plik WORKSPACE określa wszystkie zależności z odpowiednimi wersjami i hashami.

Zrzuty Debiana

Wszystkie obrazy zadań powinny być tworzone w ramach podanego pliku Dockerfile na podstawie zrzutu Debiana. Zrzuty Debiana zapewniają stabilny zrzut repozytorium z określonymi:

  • Nagłówki i biblioteki systemowe
  • Architektura systemu
    • linux_x86_64
    • Debian
  • Kompilator C++

Zadania Java Spring

Bazelremotejdk_17 służy do udostępniania hermetycznej Javy do kompilacji. Inne zależności Javy są zarządzane i zdefiniowane w pliku WORKSPACE.

Zbiory zadań Java Spring są kompilowane do pliku jar o nazwie <service>_application.jar. Słoik zawiera:

  • pliki klas Java,
  • META-INF/
    • Dane pliku manifestu Bazel
  • build-data.properties
    • Dane kompilacji Bazel
  • BOOT-INF/
    • Zależności w postaci spakowanych plików JAR wygenerowane przez rules_spring.

Warstwy obrazu

Obraz zbioru zadań Java Spring składa się z 2 warstw:

Konfiguracja obrazu

  • Punkt wejścia
    • java -jar <service>_application.jar

Zadania JNI TensorFlow

Zadania JNI Tensorflow są oparte na zadaniach Java Spring. Hermetyczny łańcuch narzędzi Clang+LLVM Bazel jest udostępniany za pomocą gotowego Clang+LLVM 16 z sysrootem dostarczanym przez obraz zrzutu Debiana do kompilowania kodu maszynowego.

Zbiory zadań JNI są kompilowane do biblioteki współdzielonej o nazwie libtensorflow.so wraz z <service>_application.jar.

Warstwy obrazu

Obraz zadania JNI TensorFlow składa się z kilku warstw:

  • Warstwa obrazu podstawowego
  • Warstwy zależności pakietu Debiana. Warstwy są generowane przy użyciu archiwów deb pobranych z debian-snapshot i przekształconych w warstwy obrazu.
    • 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
  • Warstwa zbioru zadań
    • binary_tar.tar
      • <service>_application.jar
      • libtensorflow-jni.so
      • libaggregation-jni.so

Konfiguracja obrazu

  • Etykiety (tylko w przypadku obrazów utworzonych do działania w środowisku TEE)
    • "tee.launch_policy.allow_env_override": "FCP_OPTS"
      • Umożliwia FCP_OPTSustawienie zmiennej środowiskowej w przestrzeni poufnej. Obciążenie będzie zużywać FCP_OPTS podczas uruchamiania, aby skonfigurować wymagane parametry.
      • Zmienna środowiskowa FCP_OPTS jest ustawiana podczas uruchamiania obrazu (zamiast podczas jego tworzenia), aby zachować determinizm kompilacji.
    • "tee.launch_policy.log_redirect": "always"
    • "tee.launch_policy.monitoring_memory_allow": "always"
  • Punkt wejścia
    • java -Djava.library.path=. -jar <service>_application.jar

Zadania w Pythonie

rules_python Bazela służy do udostępniania hermetycznego łańcucha narzędzi Pythona 3.10. Do deterministycznego pobierania zależności pip używany jest zablokowany plik wymagań. Obraz migawki Debiana zapewnia pobieranie deterministycznych dystrybucji na podstawie kompatybilności platformy i udostępnia łańcuch narzędzi C++ do kompilowania dystrybucji źródłowych.

Zadania w Pythonie zostaną spakowane w zestaw pobranych pakietów pip, dystrybucję Pythona 3.10, kod źródłowy Pythona ODP i skrypt uruchamiania Pythona.

  • <service>.runfiles/
    • Dystrybucja Pythona jest przechowywana w folderze python_x86_64-unknown-linux-gnu/
    • Kod źródłowy jest przechowywany w katalogu com_google_ondevicepersonalization_federatedcompute/
    • Pakiety pip są przechowywane w folderze pypi_<dependency_name>/
  • <service>.runfiles_manifest
    • Plik manifestu dla katalogu <service>.runfiles/
  • <service>
    • Skrypt w Pythonie do uruchamiania zadania w Pythonie za pomocą plików wykonywalnych

Warstwy obrazu

Obraz zadania w Pythonie składa się z 4 warstw:

  • Warstwa obrazu podstawowego
  • Warstwa tłumaczenia rozmowy
    • interpreter_layer.jar
      • <service>/<service>.runfiles/python_x86_64-unknown-linux-gnu/**
  • Warstwa pakietów
    • packages_layer.jar
      • <service>/<service>.runfiles/**/site-packages/**
  • Warstwa zbioru zadań
    • app_tar_manifest.tar
      • Zawiera kod źródłowy, skrypt startowy i plik manifestu.
        • <service>/<service>.runfiles_manifest
        • <service>/<service>
        • <service>/<service>.runfiles/com_google_ondevicepersonalization_federatedcompute/**

Konfiguracja obrazu

  • Punkt wejścia
    • /<service>/<service>

Tworzenie obrazów

Po wybraniu zbiorów zadań możesz utworzyć i opublikować obrazy.

Wymagania wstępne

Procedura

Obrazy powinny być tworzone w kontenerze Dockera utworzonym przez podany plik Dockerfile. Dostępne są 2 skrypty, które pomagają w tworzeniu ostatecznych obrazów deterministycznych.

  • docker_run.sh
    • docker_run.sh utworzy obraz Dockera z pliku Dockerfile, zamontuje katalog roboczy, zamontuje demona Dockera hosta i uruchomi Dockera z podanym poleceniem bash. Wszystkie zmienne przekazane przed poleceniem bash będą traktowane jako flagi polecenia docker run.
  • build_images.sh
    • build_images.sh uruchomi bazel build dla wszystkich obrazów i wygeneruje skróty obrazów dla każdego utworzonego obrazu.

Kompilowanie wszystkich obrazów

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

Oczekiwane hasze obrazów dla poszczególnych wersji znajdziesz w repozytorium odp-federatedcompute w GitHubie.

Publikowanie obrazów

Publikowanie jest konfigurowane za pomocą reguł Bazel oci_push. W przypadku każdej usługi repozytorium docelowe powinno być skonfigurowane dla wszystkich:

  • agregator
  • kolektor
  • model_updater
  • task_assignment
  • task_management
  • task_scheduler
  • task_builder

Publikowanie pojedynczego obrazu

Aby opublikować pojedynczy obraz:

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

Utworzone obrazy

Wszystkie utworzone obrazy muszą być przechowywane i hostowane przez twórcę, np. w rejestrze artefaktów GCP.