Builds deterministas são necessários para atestados de carga de trabalho no recurso "No dispositivo" Ambiente de execução confiável (TEE) da Personalização (ODP), disponível publicamente no Google Cloud como Confidential Space (CS).
As imagens de carga de trabalho precisam gerar um hash determinístico de imagem que pode ser usado CS para atestado de carga de trabalho (que usa a ATtestação remota RFC 9334 do NIST Arquitetura de procedimentos (RATS, na sigla em inglês).
Este documento examinará a implementação e o suporte para análises determinísticas se desenvolve no odp-federatedcompute repositório de dados. Os serviços ODP Aggregator e Model Updater serão executados Confidential Space. O repositório oferece suporte a builds determinísticos para todos os nossos serviços, que são necessários para casos de uso de produção.
Builds determinísticos
Os builds determinísticos consistem em dois componentes principais:
- A compilação dos binários necessários. Isso inclui jars, bibliotecas compartilhadas e metadados.
- A imagem base e as dependências do ambiente de execução. A base do ambiente de execução usada para executar os binários compilados.
A partir de agora, o repositório de computação federada do ODP oferece suporte aos seguintes tipos de cargas de trabalho:
- Cargas de trabalho Java + Spring
- Atribuição de tarefas, Gerenciamento de tarefas, Coletor
- Java + Spring com cargas de trabalho JNI do TensorFlow
- ModelUpdater, agregador
- Cargas de trabalho do Python
- TaskBuilder
Dependências
A lista a seguir são dependências que a ODP usa para manter o determinismo e disponibilidade:
- Bazel
- GitHub
- Maven
- PyPi
- Snapshots do Debian
- Registro do DockerHub
- Google Container Registry (GCR)
Cargas de trabalho determinísticas
Todas as cargas de trabalho são compiladas usando o Bazel com conjuntos de ferramentas específicos da linguagem e imagens de contêiner criadas usando rules_oci. O espaço de trabalho arquivo define todas as dependências com versões e hashes correspondentes.
Snapshots do Debian
Todas as imagens de carga de trabalho precisam ser criadas dockerfile criado com base em um snapshot do Debian. Debian os snapshots fornecem um snapshot de repositório estável com:
- Cabeçalhos e bibliotecas do sistema
- Arquitetura do sistema
- linux_x86_64
- Debian
- Compilador C++
Cargas de trabalho do Java Spring
do Bazel
remotejdk_17
é
usada para fornecer um Java hermético para compilação. Outras dependências do Java são
gerenciadas e definidas no espaço de trabalho
arquivo.
As cargas de trabalho Java Spring são compilados em um arquivo jar chamado
<service>_application.jar
: O jar contém:
- Arquivos de classe do Java
META-INF/
- Dados do manifesto do Bazel
build-data.properties
- Dados de build do Bazel
BOOT-INF/
- Dependências jar empacotadas, geradas por rules_spring.
Camadas de imagem
A imagem da carga de trabalho do Java Spring consiste em duas camadas:
- Camada de imagem de base
- Imagem base do Java:
gcr.io/distroless/java17-debian11
- Imagem base do Java:
- Camada de carga de trabalho
binary_tar.tar
<service>_application.jar
Configuração de imagem
- Ponto de entrada
java -jar <service>_application.jar
Cargas de trabalho JNI do Tensorflow
As cargas de trabalho do JNI do Tensorflow são criadas com base nas cargas de trabalho do Java Spring. Um O conjunto de ferramentas hermético Clang+LLVM Bazel é fornecido usando o Clang+LLVM pré-compilado. 16 com um sysroot fornecido pela imagem do snapshot do Debian para compilar o código de máquina.
As cargas de trabalho JNI são compiladas em uma biblioteca compartilhada chamada libtensorflow.so
.
com o <service>_application.jar
.
Camadas de imagem
A imagem da carga de trabalho do JNI TensorFlow consiste em várias camadas:
- Camada de imagem de base
- Imagem base do Java:
gcr.io/distroless/java17-debian11
- Imagem base do Java:
- as camadas de dependência do pacote Debian. As camadas são geradas usando deb
arquivos baixados do debian-snapshot e reempacotados como camadas de imagem
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
- Camada de carga de trabalho
binary_tar.tar
<service>_application.jar
libtensorflow-jni.so
libaggregation-jni.so
Configuração de imagem
- Rótulos (apenas para imagens criadas para execução no TEE)
"tee.launch_policy.allow_env_override": "FCP_OPTS"
- Permite que a variável de ambiente
FCP_OPTS
seja definida em confidencial espaço. A carga de trabalho consumiráFCP_OPTS
na inicialização para configurar parâmetros obrigatórios. - A variável de ambiente
FCP_OPTS
é definida quando a imagem é executada (em vez de construídos) para manter o determinismo do build.
- Permite que a variável de ambiente
"tee.launch_policy.log_redirect": "always"
"tee.launch_policy.monitoring_memory_allow": "always"
- Ponto de entrada
java -Djava.library.path=. -jar <service>_application.jar
Cargas de trabalho do Python
O rules_python do Bazel é usado para fornecem um conjunto de ferramentas hermético do Python 3.10. Requisitos de pip bloqueado arquivo é usado para a busca determinística de dependências de pip. O snapshot do Debian imagem garante que distribuições deterministas sejam buscadas com base na plataforma compatibilidade e fornece um conjunto de ferramentas em C++ para compilar distribuições de origem.
As cargas de trabalho do Python são agrupadas em um conjunto de pacotes pip baixados, um Distribuição Python 3.10, código-fonte ODP do Python e uma inicialização do Python script.
<service>.runfiles/
- A distribuição Python está armazenada em
python_x86_64-unknown-linux-gnu/
. - O código-fonte é armazenado em
com_google_ondevicepersonalization_federatedcompute/
- Os pacotes pip são armazenados em
pypi_<dependency_name>/
.
- A distribuição Python está armazenada em
<service>.runfiles_manifest
- Arquivo de manifesto para o diretório
<service>.runfiles/
- Arquivo de manifesto para o diretório
<service>
- Script Python para executar a carga de trabalho do Python usando os arquivos de execução
Camadas de imagem
A imagem da carga de trabalho do Python consiste em quatro camadas:
- Camada de imagem de base
- Imagem base do Python python:slim
- Camada de intérprete
interpreter_layer.jar
<service>/<service>.runfiles/python_x86_64-unknown-linux-gnu/**
- Camada de pacotes
packages_layer.jar
<service>/<service>.runfiles/**/site-packages/**
- Camada de carga de trabalho
app_tar_manifest.tar
- Contém código-fonte, script de inicialização e manifesto.
<service>/<service>.runfiles_manifest
<service>/<service>
<service>/<service>.runfiles/com_google_ondevicepersonalization_federatedcompute/**
- Contém código-fonte, script de inicialização e manifesto.
Configuração de imagem
- Ponto de entrada
/<service>/<service>
Criar imagens
Depois de escolher as cargas de trabalho, tudo está pronto para você criar e publicar os de imagens de contêiner.
Pré-requisitos
Procedimento
As imagens devem ser criadas dentro do contêiner do Docker criado pelo dockerfile. Dois scripts são fornecidos para ajudar na criação das imagens determinísticas finais.
- docker_run.sh
docker_run.sh
criará a imagem do Docker pelo dockerfile, mount no diretório de trabalho, montar o daemon do docker do host e executar o docker com o comando bash fornecido. Todas as variáveis transmitidas antes do comando bash ser tratadas como sinalizações de execução do Docker.
- build_images.sh
build_images.sh
vai executarbazel build
para todas as imagens e gerar a saída gera hashes de imagem para cada imagem criada.
Criar todas as imagens
./scripts/docker/docker_run.sh "./scripts/build_images.sh"
Os hashes de imagem esperados para cada versão podem ser encontrados em odp-federatedcompute no GitHub de versões.
Publicar imagens
A publicação é configurada usando oci_push Regras do Bazel. Para cada serviço, o repositório de destino precisa ser configurado para todos:
- agregador
- coletor
- model_updater
- task_assignment
- task_management
- task_scheduler
- task_builder
Publicar uma única imagem
Para publicar uma única imagem:
./scripts/docker/docker_run.sh "bazel run //shuffler/services/<servicename_no_underscore>:<servicename_with_underscore>_image_publish"
Imagens criadas
Todas as imagens criadas precisarão ser armazenadas e hospedadas pelo criador, como em um Artifact Registry do GCP.