Aller au contenu principal

Déploiement du code bac à sable

La capacité d'exécution de code Python d'Aivory est fournie par un service bac à sable indépendant. Cette page décrit l'architecture sidecar, la signification de chaque configuration clé dans composer, les limites de sécurité et la façon de déployer bac à sable indépendamment sur une autre machine. Python bac à sable

Architecture : contrôle sidecar + conteneur de session unique

Le bac à sable se compose de deux miroirs :

MiroirRôle
ghcr.io/hjxwz123/aivory-sandbox-sidecarService de contrôle (sidecar) : recevoir des demandes HTTP en arrière-plan, conduire Docker daemon à créer / récupérer des conteneurs de session
ghcr.io/hjxwz123/aivory-sandboxMiroir d’exécution : un conteneur verrouillé pour chaque session, qui exécute réellement le code utilisateur
┌──────────┐ POST /sessions /exec /files ┌───────────────┐ docker exec ┌────────────────┐
│ app 后端 │ ────────────────────────────► │ sidecar 控制面 │ ────────────► │ 会话容器 │
└──────────┘ SANDBOX_BASE_URL └───────────────┘ │ aivory-sandbox │
└────────────────┘

Sidecar n'exécute pas le code de l'utilisateur lui-même. /var/run/docker.sock Docker Daemon, un conteneur pour chaque session. /workspace Entre plusieurs exécutions de la même session, les paquets installés par pip et les fichiers générés sont toujours en ligne avec l'interprète de code ChatGPT.

Mise en œuvre de Docker-in-Docker

Le programme est basé sur l’hôte. /var/run/docker.sock Dans un conteneur sidecar, le conteneur de session est en fait créé par l'hôte daemon. Si votre environnement n'autorise pas l'hébergement d'un socket d'hôte, vous pouvez également fournir à sidecar un dind (docker:dind) daemon indépendant pour le coût d'une couche supplémentaire avec des coûts de stockage. De toute façon, le sidecar doit avoir accès à un daemon Docker, ce qui est une exigence rigide.

Le miroir d'exécution contient un stack de données (numpy, panda, sccipy, scikit-learn, matplotlib, seaborn, plotly, etc.), une bibliothèque de traitement de documents (python-pptx, python-docx, openpyxl, reportlab, weasyprint, etc.) et des polices Noto Sans CJK.

Bac à sable intégré : configuration zéro par défaut

Production de composite Il est liésandbox des services, docker compose up -d Une commande est tirée avec bac à sable, sans aucune configuration supplémentaire:

  • ** Ne publiez aucun port hébergeur **: uniquement app par le privéinternal L’accès au réseau (SANDBOX_BASE_URL=http://sandbox:8000 Les réseaux sociaux ne touchent jamais.
  • ** La clé API interne **: appsandbox Les deux services lisent le même SANDBOX_API_KEY (avoué par défaut aivory-bundled-sandbox Parce que bac à sable n'est pas exposé à l'extérieur, cette valeur par défaut est disponible; mais chaque fois que vous avez l'intention d'exposer le port bac à sable à tout autre réseau, il doit être remplacé par une valeur aléatoire forte.
  • ** Démarrer le miroir. **: SANDBOX_PULL_ON_START=1 Laisser sidecar froid démarrer avant de tirer l'image du temps d'exécution, le contrôle de la santéstart_period: 120s C’est pour cette raison qu’il est réservé.
  • ** La douce dépendance **: appdepends_on bac à sable. bac à sable n'est disponible que lorsque le code exécute des erreurs, le reste de l'application fonctionne normalement.

Composer les éléments clés individuellement

Ce qui suit est composésandbox Les variables environnementales du service sont répertoriées comme étant les valeurs par défaut pour produire compose :

VariableValeur par défautExpliquer
SANDBOX_API_KEYaivory-bundled-sandboxLa clé d’identification de Bearer doit app Sidecar n'a pas de clé refusant de démarrer, l'évaluation utilise une comparaison de temps constante
SANDBOX_IMAGEghcr.io/hjxwz123/aivory-sandbox:latestLe miroir de chaque séance.
SANDBOX_PULL_ON_START1Tirez l'image du temps d'exécution avant le démarrage pour vous assurer que la première exécution n'échoue pas
SANDBOX_NETWORKnoneRéseau de conteneurs de session. none Réseau totalement désactivé ; bridge Connexion à Internet (en fonctionnement) pip install)
SANDBOX_MEMORY2gLimite de mémoire pour les conteneurs de session individuels
SANDBOX_CPUS1Limite de la CPU pour un conteneur de session unique
SANDBOX_MAX_SESSIONS16Limite du nombre de conteneurs de session survivants en même temps
SANDBOX_EXEC_TIMEOUT_CAP_MS600000Durée maximale d’exécution d’une seule exécution (10 minutes)
SANDBOX_IDLE_TTL_CAP_SECONDS86400Limite d'exploitation dur pour les fenêtres de recyclage gratuites (24 heures)
SANDBOX_READ_ONLY_ROOTFS1Le système de fichiers racine des conteneurs de session ne lit que, le disque de protection remplit les attaques
SANDBOX_WORKSPACE_SIZE512mSeulement en mode lecture /workspace Il est possible d'écrire la taille de tmpfs
SANDBOX_LOCAL_STORAGE_DIR/var/lib/aivory/sandbox-archivesCatalogue d'archives d'espaces de travail locaux pour la pérennisation de la configuration zéro avec des volumes permanents

SANDBOX_API_KEY : authentification partagée avec l’application

sidecar est exposé à la capacité de "Drive Host Docker", équivalent à l'hôte RCE, donc ** L’autorisation est obligatoire. **:key pour sidecar temporaire refuse directement le démarrage (la seule exception est la configuration explicite) SANDBOX_ALLOW_NO_AUTH=1 Il s’agit d’un environnement de développement local). app Services et sandbox Les services doivent configurer la même valeur pour générer une clé forte :

openssl rand -hex 24

SANDBOX_NETWORK : le défaut par défaut, le coût de la connexion

Définitivement none Le conteneur de session n’a pas de réseau, ni le code utilisateur. pip install Aucune demande ne peut être envoyée.Modifier bridge Le code post peut être connecté, mais le coût est clair:

Pensez-y avant d’ouvrir le réseau bridge.

Le bac à sable du réseau signifie que le code utilisateur peut envoyer les données de la session (les fichiers téléchargés, les résultats intermédiaires générés) à n'importe quelle adresse accidentelle, ou bien scanner activement et attaquer les services disponibles dans le conteneur bac à sable de votre réseau intérieur. none

Limite des ressources : MEMORY / CPUS / MAX_SESSIONS

SANDBOX_MEMORY (avoué par défaut 2g) et SANDBOX_CPUS (avoué par défaut 1 limitation des conteneurs de session individuels; SANDBOX_MAX_SESSIONS (avoué par défaut 16 Limiter le nombre total de sessions survivantes en même temps.Considérez la capacité de l'hôte dans le pire des cas: MAX_SESSIONS x MEMORY est la quantité totale de mémoire que le conteneur de session peut occuper. SANDBOX_MAX_CONCURRENT_EXECS (par défaut 4) limiter le nombre d'exécutions globales simultanées, SANDBOX_PIDS_LIMIT (par défaut 256) Défense contre les bombes de fork.

Le contrôle sidecar lui-même est également limité à compose mem_limit: 1g / pids_limit: 512 L'archivage permet de sauvegarder jusqu'à 200 MiB d'espace de travail tar packs dans la mémoire (SANDBOX_MAX_ARCHIVE_BYTES), mem_limit Il est nécessaire de maintenir une quantité supérieure à cette valeur.

Deux « têtes dures » : EXEC_TIMEOUT_CAP_MS et IDLE_TTL_CAP_SECONDS

Ces deux variables sont ** Le plafond des opérations. ** Pour travailler avec les paramètres réglables de la console d'administration :

  • L’exécution d’un délai supplémentaire d’exécution par l’administrateur en arrière-plan (sandbox_exec_timeout_sec Elles seront retenues. SANDBOX_EXEC_TIMEOUT_CAP_MS (Dans les 600000ms par défaut, c’est-à-dire 10 minutes).
  • La fenêtre de récupération libre est configurée par l'administrateur (sandbox_idle_ttl_sec Elles seront retenues. SANDBOX_IDLE_TTL_CAP_SECONDS Dans les 86400s par défaut, c'est-à-dire 24 heures. Lorsque l'arrière-plan n'est pas lancé, Sidecar recycle les sessions gratuites pendant 30 minutes.

C’est-à-dire que l’administrateur peut faire des raccourcis sous le plafond, mais qu’il n’est pas toujours possible de maintenir le plafond fixé dans compose.

Protection du disque : READ_ONLY_ROOTFS / WORKSPACE_SIZE

SANDBOX_READ_ONLY_ROOTFS=1 (Ouvrir par défaut) Le système de fichiers racine du conteneur de session ne peut que lire, il n'y a que trois endroits où l'on peut écrire, et tous tmpfs avec une taille maximale:

La voiePetite sourceDéfinitivement
/workspaceSANDBOX_WORKSPACE_SIZE512m
/tmpSANDBOX_TMPFS_SIZE256m
Utilisateur $HOMESANDBOX_TMPFS_SIZE256m

Par conséquent, il n'est pas possible de remplir le disque de l'hôte par une seule session, quelle que soit la façon dont les fichiers sont écrits. /workspace/uploads/ Le code produit est écrit. /workspace/outputs/ Tous sont soumis WORKSPACE_SIZE Restreindre le temps nécessaire pour un espace de travail plus grand (comme le traitement de grands ensembles de données) SANDBOX_WORKSPACE_SIZE Attention, les tmpfs occupent la mémoire.

SANDBOX_LOCAL_STORAGE_DIR : Permanence de l’archivage de l’espace de travail

Lorsque le conteneur de session est recyclé (excès de temps ou destruction explicite), le /workspace Les archives tar sont stockées ; la même conversation est automatiquement récupérée lors de la prochaine exécution du code. ** Conversation ID ** Par conséquent, même si le conteneur de session a été changé, le contenu de l'espace de travail peut également être recyclé.

SANDBOX_LOCAL_STORAGE_DIR Spécifiez le répertoire d'archives locales et composez-le sur le nom sandbox-archives Sur les volumes persistants, la persistance de configuration zéro n'est pas requise pour S3/OSS/MinIO.

  • Cette variable ** Il peut être configuré à partir de variables environnementales. ** et n'accepte jamais les valeurs provenant de la requête ou de la console d'administration (sidecar s'exécute à la racine et détient docker.sock, permettant à distance de spécifier un chemin d'écriture équivaut à l'ouverture d'une fenêtre d'écriture d'hôte).
  • L’archive locale n’est pas valable si elle est vide et la récupération est perdue (reaped = gone).
  • ** Applicable uniquement aux points **: Les volumes Docker normaux ne sont pas partagés entre copies et le déploiement de copies multiples doit être remplacé par le backend S3/OSS.
  • L’archivage est le meilleur effort : plus de 200 MiB d’espaces de travail sautent l’archivage et enregistrent les journaux, et l’échec de l’archivage/la récupération n’entraîne pas l’échec de la demande d’exécution.

Console d'administration

En plus des variables d'environnement compose, certaines actions peuvent être effectuées dans la console d'administration. Définir le site En ligne, il n’est pas nécessaire de redémarrer :

Positionnement arrièreRôleObligation
Le délai d’exécution est limité (sandbox_exec_timeout_sec)Durée maximale d'exécution de chaque codeSANDBOX_EXEC_TIMEOUT_CAP_MS Régime
Temps de récupération (sandbox_idle_ttl_sec)Combien de temps après la récupération du conteneur ?SANDBOX_IDLE_TTL_CAP_SECONDS Régime
Le stockage à l’arrière (storage_provider)Où se trouvent les archives de la zone de travail ?local (Résumé de l’objet du texte) s3 / aliyun_oss
L’adresse et la clé du bac à sable sandbox_base_url / sandbox_api_key)Bac à sable pour couvrir les variables environnementalesLes variables environnementales entrent en vigueur

Choix du stockage s3 Remplir les endpoints, buckets et crédits. ** Services compatibles MinIO et S3 ** Le même choix s3 Lorsque vous remplissez l'endpoint défini, vous passez automatiquement à l'adresse path-style + SigV4 signature sans commutateur supplémentaire.

Frontières sécurisées

bac à sable est isolé au niveau du conteneur et chaque conteneur de session est rempli d'un ensemble de verrouillage :

  • ** Fonctionne sans root. **, --cap-drop ALL, --security-opt no-new-privileges
  • ** Impossible sans réseau ** (--network none)。
  • ** Lisez uniquement le système de fichiers. **+ une limite supérieure de tmpfs (voir ci-dessus), en plus de la limite de memory/cpu/pids/nofile.
  • Exécution dans la même séance ** séries ** Parallèlement, la distribution globale est limitée; stdout/stderr est réduit à 32 KB; les fichiers de fichier de produit sont limités à 20 Mo, jusqu'à 20 Mo à la fois, pour un total de 50 Mo.
  • Possibilité de : passer SANDBOX_SECCOMP_PROFILE Fixez le profil seccomp sur le conteneur de session (le parcours doit être lu dans le conteneur sidecar) pour restreindre encore la zone d'attaque du noyau.
docker.sock est l'équivalent de root

L’architecture sidecar doit être capable d’exécuter Docker Daemon. /var/run/docker.sock L’équivalent root sur l’hébergeur : toute personne ayant accès au service sidecar est équivalente à l’hébergeur.

  1. ** N’exposez jamais les ports sidecar au réseau public ** Le déploiement intégré est déjà fait (pas de ports publiés); liaison de l'interface intranet ou VPN lors du déploiement indépendant.
  2. SANDBOX_API_KEY Il doit être une valeur aléatoire forte (à l'exception de la valeur par défaut du réseau privé pour le stack intégré).
  3. L'environnement de production recommande de placer un avant le socket nu. docker-socket-proxy Le conteneur crée/start/exec/kill/inspect avec l’image pull, les autres API sont rejetées, puis le sidecar est lancé. DOCKER_HOST: tcp://socket-proxy:2375 Il n’y a pas de socket.

Il s'agit d'un isolant de niveau conteneur, suffisant pour soutenir le déploiement d'un seul appareil, mais ** pas ** gVisor/microVM.Le protocole HTTP de sidecar est un contrat stable, et les déploiements avec des exigences de sécurité plus élevées peuvent remplacer l'exécution par gVisor, Firecracker, etc. app Aucune modification du côté n’est nécessaire.

Si Sidecar est redémarré, il sera détecté automatiquement. aivory.sandbox=1 Les conteneurs de stockage étiquetés, continuent de suivre et de recycler selon le TTL, ne laissent pas de conteneurs orphelins.

Déploiement indépendant : bac à sable dans une autre machine

L'exécution de code est une charge concentrée en CPU/mémoire et le démantèlement du bac à sable sur une machine indépendante permet d'éviter le pillage des ressources avec l'application principale. le service bac à sable dispose d'un entrepôt public et d'un miroir indépendants, qui peuvent être tirés sans nécessité de construire :

** Déploiement sur le bac à sable **

git clone https://github.com/hjxwz123/aivory-sandbox.git
cd aivory-sandbox

export OWNER=hjxwz123
export SANDBOX_API_KEY=$(openssl rand -hex 24)
printf 'SANDBOX_API_KEY=%s\n' "$SANDBOX_API_KEY" # 保存这个值

docker compose pull
docker compose up -d

Un compose indépendant affiche le sidecar sur l'hôte. 48217 Port (il reste 8000 dans le conteneur). vérification:

curl -H "Authorization: Bearer $SANDBOX_API_KEY" http://localhost:48217/healthz

retourner {ok, docker, image} C’est prêt.

** 2 – L’application se fait par le passé**

Dans l’application principale .env Modifier les deux variables et supprimer (ou arrêter de démarrer) les paramètres intégrés de la base sandbox Les services :

SANDBOX_BASE_URL=http://<沙箱机内网地址>:48217
SANDBOX_API_KEY=<第 1 步生成的同一个值>

Il est également possible de remplir les variables environnementales directement dans la console d'administration. sandbox_base_url / sandbox_api_key La valeur d’arrière-plan a la priorité sur les variables environnementales.

Il faut changer de clé, le port n’est accessible qu’à l’intérieur.

La clé de la clé de la clé de la clé (aivory-bundled-sandbox Ceci n'est acceptable que sous la condition « bac à sable sans port, accessible uniquement sur le réseau privé ». Une fois que bac à sable écoute le port de la carte réseau réelle, toute personne qui reçoit la clé peut conduire le Docker de l'hôte. openssl rand -hex 24 Créer une nouvelle clé ; utiliser un pare-feu / un groupe de sécurité48217 Limitez l’accès au serveur d’application principal et essayez d’utiliser des liens intranet ou VPN entre les deux machines.

Vérification de défaillance

phénomèneVérifier la direction
Le premier code a échoué.L’écran ne s’est pas arrêté lors du démarrage à froid. docker compose logs sandbox L’inspection médicale est réservée à 120 personnes. start_period
Les examens sont toujours malsains.Sidecar n'est pas disponible sur Docker Daemon /var/run/docker.sock L’hébergeur et l’hébergeur Daemon.
Sidecar déclenche le retraitSANDBOX_API_KEY Sidecar est conçu pour démarrer sans clé.
Dans le code pip installéchecDéfinitivement SANDBOX_NETWORK=none Pas de réseau, évaluation des risques bridge
Le disque est rempli.A frappé/workspace Les limites de tmpfs sont augmentées. SANDBOX_WORKSPACE_SIZE
Zone de travail perdue après le recyclageSANDBOX_LOCAL_STORAGE_DIR Il n'est pas configuré ou le volume correspondant n'est pas suspendu; ou le fond storage_provider Vacuée
Les autres fonctions affectéesIl ne doit pas se produire : app Le bac à sable est une dépendance douce, seule la fonction d'exécution de code peut signaler des erreurs ; si l'ensemble est anormal, le problème est ailleurs.