Docker & Conteneurs
Exécutez ZeroClaw dans Docker, Podman, Kubernetes ou n’importe quel runtime OCI.
Images officielles
Publié sur GitHub Container Registry (ghcr.io) à chaque version stable :
ghcr.io/zeroclaw-labs/zeroclaw:latest: dernière version stableghcr.io/zeroclaw-labs/zeroclaw:v0.7.5: épingléeghcr.io/zeroclaw-labs/zeroclaw:debian: image basée sur Debian (plus volumineuse, prise en charge plus large de glibc)
Multi-arch : linux/amd64, linux/arm64.
Remarque sur l’accès au shell : L’image
latestpar défaut est intentionnellement distroless et n’inclut passh,ashnibash. Utilisez le tagdebiansi vous avez besoin d’un shell à l’intérieur du conteneur (par exemple, pour exécuterdocker execà des fins de débogage).
Image Alpine (compilation locale)
Dockerfile.alpine construit une image Alpine activable explicitement avec des binaires musl liés statiquement pour linux/amd64 et linux/arm64. Elle n’est pas publiée sur ghcr.io.
Pour la plateforme locale :
sh
docker build -f Dockerfile.alpine -t zeroclaw:alpine .
Pour une image de registre multiplateforme, créez un builder une seule fois et poussez le manifeste. Si vous avez déjà sélectionné un builder buildx, omettez la première commande :
sh
docker buildx create --use --name zeroclaw-multiarch
docker buildx build -f Dockerfile.alpine \
--platform linux/amd64,linux/arm64 \
-t registry.example.com/zeroclaw:alpine \
--push .
L’exemple Compose fourni construit l’image pour la plateforme actuelle :
sh
docker compose -f docker-compose.yml -f docker-compose.alpine.yml up --build
L’image Alpine utilise le même montage /zeroclaw-data, les variables d’environnement schema-mirror, le chemin du tableau de bord et le port de la passerelle que les images existantes.
Exécution minimale
sh
docker run -d \
--name zeroclaw \
-v zeroclaw-data:/zeroclaw-data \
-p 42617:42617 \
ghcr.io/zeroclaw-labs/zeroclaw:latest
L’image officielle écoute déjà sur [::] avec allow_public_bind = true et require_pairing = false intégrés à sa configuration par défaut, de sorte que cet exemple direct docker run est accessible immédiatement. Les exemples Compose ci-dessous figent néanmoins les deux paramètres de liaison de la passerelle afin que des configurations persistantes ou personnalisées ne puissent pas rétablir silencieusement une écoute limitée à la boucle locale.
L’image s’attend à un état persistant dans /zeroclaw-data. Au premier lancement, elle initialise une configuration par défaut : vous devez tout de même exécuter quickstart avant qu’elle ne soit utilisable :
sh
docker exec -it zeroclaw zeroclaw quickstart
Exécution de zerocode (la TUI)
L’image fournit l’interface de terminal zerocode aux côtés du binaire zeroclaw. Le point d’entrée par défaut est zeroclaw ; lancez zerocode en le remplaçant par --entrypoint zerocode et en utilisant un TTY interactif (-it). Les deux variantes d’image publiées l’incluent :
distroless (:latest)
docker run -it --entrypoint zerocode ghcr.io/zeroclaw-labs/zeroclaw:latest
debian
docker run -it --entrypoint zerocode ghcr.io/zeroclaw-labs/zeroclaw:debian
zerocode se connecte à un démon ZeroClaw en cours d’exécution, il faut donc le faire pointer vers l’un d’eux :
- Daemon du même conteneur : exécutez-le contre le conteneur qui exécute déjà le daemon (
docker exec -it zeroclaw zerocode), qui atteint le daemon via le socket IPC local. - Un démon distant : connectez-vous via WebSocket Secure avec
zerocode --connect wss://<host>:<port>; voir Configuration à distance (WSS). C’est la méthode portable pour piloter un démon conteneurisé ou distant depuis votre propre terminal.
Persistez /zeroclaw-data (comme dans Minimum run) afin que la configuration et l’identité lues par zerocode soient les mêmes que celles utilisées par le démon.
Composer
Un docker-compose.yml minimal :
services:
zeroclaw:
image: ghcr.io/zeroclaw-labs/zeroclaw:latest
redémarrer: sauf-arrêt
ports:
- "127.0.0.1:42617:42617" # passerelle, boucle locale de l’hôte uniquement
volumes:
- ./data:/zeroclaw-data
environnement:
# host sélectionne l’interface du conteneur ; allow_public_bind prend en compte
# l’écouteur hors boucle locale et désactive l’avertissement de démarrage.
- ZEROCLAW_gateway__host=0.0.0.0
- ZEROCLAW_gateway__allow_public_bind=true
Après le démarrage du conteneur, exécutez quickstart :
sh
docker compose exec zeroclaw zeroclaw quickstart
Compose doit définir explicitement ZEROCLAW_gateway__host et ZEROCLAW_gateway__allow_public_bind. La publication d’un port ne rend pas accessible une passerelle liée à 127.0.0.1 à l’intérieur du conteneur, et allow_public_bind = true indique qu’une liaison publique est autorisée sans en sélectionner une. Conserver les deux surcharges ensemble permet également à un volume existant ou à une configuration personnalisée avec des valeurs par défaut localhost de se comporter de manière cohérente.
Cela modifie l’exposition, de sorte que les exemples publient leurs ports sur la boucle locale de l’hôte. Deux limites distinctes sont en jeu, et une seule d’entre elles est appliquée :
gateway.host = 0.0.0.0sélectionne l’interface du conteneur. Le trafic du pont Docker n’arrive pas via la boucle locale du conteneur ; cette valeur doit donc rester0.0.0.0pour qu’un port publié puisse atteindre la passerelle.ZEROCLAW_gateway__allow_public_bindest une confirmation, pas un mécanisme de blocage. Lorsqu’il vautfalse, la passerelle consigne un avertissement au démarrage et se lie quand même ; le définir surtruene fait que supprimer cet avertissement. Ne comptez pas sur ce paramètre pour garantir qu’un écouteur reste privé.- Le mappage
ports:de Compose constitue la limite que Docker applique réellement."127.0.0.1:42617:42617"publie uniquement sur l’hôte du conteneur ;"42617:42617"publie sur toutes les interfaces de l’hôte que Docker est configuré pour utiliser.
La limite d’authentification est ZEROCLAW_gateway__require_pairing, qui prend par défaut la valeur true dans le schéma, mais vaut false dans la configuration intégrée à l’image. Lorsque l’appairage est désactivé, la passerelle répond aux requêtes non authentifiées sur /webhook, /api/config, /api/memory, /api/browse et les points de terminaison de session. Pour desservir d’autres hôtes, supprimez le préfixe 127.0.0.1: et activez l’appairage, ou placez la passerelle derrière un proxy inverse authentifiant ou un tunnel.
Compose sans root avec l’image Debian
Pour les déploiements rootless avec Docker ou Podman Compose qui nécessitent des outils shell à l’intérieur du conteneur, utilisez l’image Debian actuelle et liez un répertoire de données de l’hôte :
services:
zeroclaw:
image: ghcr.io/zeroclaw-labs/zeroclaw:debian
container_name: zeroclaw
redémarrer: sauf-arrêt
ports:
- 127.0.0.1:42617:42617
volumes:
- ./data:/zeroclaw-data
environnement:
- ZEROCLAW_gateway__host=0.0.0.0
- ZEROCLAW_gateway__allow_public_bind=true
vérification de l'état:
test: [CMD, zeroclaw, "statut", --format=exit-code]
interval: 60s
timeout: 10s
nouvelles tentatives: 3
start_period: 10s
L’image Debian actuelle contient le tableau de bord empaqueté en dehors de /zeroclaw-data, de sorte que le montage bind ne le masque pas et qu’aucune surcharge gateway.web_dist_dir n’est nécessaire. Les remplacements de la passerelle utilisent les graphies du miroir de schéma indiquées par ZEROCLAW_gateway__host et ZEROCLAW_gateway__allow_public_bind. Ils sont prioritaires sur une configuration persistante utilisant localhost par défaut, et le mappage ports: limité à la boucle locale reste la limite qui restreint l’accès depuis l’hôte.
macOS : OrbStack vs Colima
macOS ne possède pas de noyau Linux natif, donc chaque option (Docker Desktop, Podman, OrbStack, Colima) exécute le conteneur dans une VM Linux légère. Pour une machine de développement Mac, les deux VM natives Mac qui méritent d’être comparées sont OrbStack et Colima, toutes deux exécutent le conteneur avec les mêmes commandes docker run/Compose ci-dessus.
| OrbStack | Colima | |
|---|---|---|
| Moteur | VM Linux personnalisée et optimisée (optimisée pour Apple Silicon) | Lima VM + containerd/Docker |
| Licence | commercial, freemium (utilisation personnelle gratuite) | MIT (Lima sous-jacent est sous licence Apache 2.0) |
| Interface | Application graphique + CLI | Privilégie la CLI (colima start/stop), scriptable |
| Idéal lorsque | sans complication, expérience utilisateur soignée | tout en OSS, configuration dans le code |
OrbStack
# Fournit la CLI docker :
brew install --cask orbstack
Colima
# La CLI docker communique avec la VM de colima :
brew install colima docker docker-compose # docker-compose = le plugin Compose v2 ; à installer si vous avez besoin de `docker compose`
colima start --cpu 4 --memory 8 # ajouter --network-address pour exposer l'IP de la VM à macOS
Les performances sont comparables pour les charges de travail de développement typiques ; les véritables différenciateurs sont la licence (commerciale vs OSS) et les préférences UX, pas la vitesse brute ; effectuez un benchmark des deux sur votre propre machine si la RAM au repos ou le débit de build est important pour vous. Dans tous les cas, vous pilotez le moteur à l’intérieur de la VM avec docker ; les quadlets systemd (ci-dessous) sont une fonctionnalité des hôtes Linux et ne s’appliquent pas sur macOS.
Podman & quadlets systemd
Sur un serveur Linux, la façon la plus propre d’exécuter le conteneur sur le long terme est un quadlet Podman : un fichier d’unité déclaratif que systemd transforme en un véritable service. Vous bénéficiez du cycle de vie systemctl, des journaux journald, du redémarrage automatique et de l’ordonnancement au démarrage, sans daemon et sans bidouille --restart, et le fichier d’unité est une configuration que vous committez dans git. C’est le modèle recommandé pour les serveurs ; docker run/Compose conviennent très bien pour un ordinateur portable.
Un quadlet est un fichier *.container (fichiers apparentés : .pod, .volume, .network, .kube, .build, .image). Le générateur systemd de Podman le lit à chaque daemon-reload et écrit un fichier .service transitoire ; vous ne rédigez jamais le .service vous-même.
Les unités rootful résident dans /etc/containers/systemd/ ; les unités rootless dans ~/.config/containers/systemd/.
/etc/containers/systemd/zeroclaw.container :
[Unit]
Description=ZeroClaw agent runtime
After=network-online.target
Wants=network-online.target
[Container]
# Pin a release in production; :latest is distroless (no shell — use :debian to exec a shell).
Image=ghcr.io/zeroclaw-labs/zeroclaw:latest
ContainerName=zeroclaw
PublishPort=127.0.0.1:42617:42617
Volume=zeroclaw-data:/zeroclaw-data
# Published on host loopback only; drop the 127.0.0.1: prefix to serve other
# hosts, and enable pairing or a tunnel before you do. If you mount a
# localhost-default config, override both gateway.host and
# gateway.allow_public_bind together.
# Optional rolling-upgrade path — re-pull a newer image on (re)start and opt into `podman auto-update`:
Pull=newer
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=multi-user.target default.target
Déployer (idempotent, réexécutable sans risque ; une nouvelle application fait converger le conteneur en cours d’exécution, sans jamais le dupliquer) :
sh
sudo cp zeroclaw.container /etc/containers/systemd/
sudo systemctl daemon-reload # le générateur transforme .container en zeroclaw.service
sudo systemctl restart zeroclaw
Ensuite, effectuez l’intégration une seule fois, puis gérez-le comme n’importe quel service :
sh
sudo podman exec -it zeroclaw zeroclaw quickstart
systemctl status zeroclaw
journalctl -u zeroclaw -f
Il n’y a pas d’étape systemctl enable pour les unités générées : c’est la ligne [Install] WantedBy= qui assure son démarrage au boot.
- Épinglage de version vs
:latest. Épinglez un tag ou un digest (Image=ghcr.io/zeroclaw-labs/zeroclaw:v0.7.5ou...@sha256:...) pour des déploiements reproductibles et auditables ; la mise à niveau se résume alors à un changement de tag révisable dans le fichier.containercommité.Pull=newer+AutoUpdate=registryoffrent à la place des mises à niveau continues, pilotées parpodman-auto-update.timer(sudo systemctl enable --now podman-auto-update.timer). Choisissez entre reproductibilité et actualité ; la boucle de déploiement reste la même dans les deux cas. - Variante rootless. Déposez le fichier dans
~/.config/containers/systemd/, utilisezsystemctl --user daemon-reload && systemctl --user restart zeroclaw, et exécutezloginctl enable-linger $USERpour qu’il survive à la déconnexion (même remarque sur le lingering que dans Service & daemon). - WSL2. Les versions modernes de WSL2 exécutent systemd (
[boot] systemd=truedans/etc/wsl.conf, puiswsl --shutdown), donc ce modèle quadlet exact fonctionne dans une distribution WSL : aucun dialecte spécifique à Windows.
Configuration à l’intérieur des conteneurs
L’image s’attend à trouver la configuration sous /zeroclaw-data/.zeroclaw/. Montez votre configuration locale dans :
sh
docker run -d --name zeroclaw \
-v $(pwd)/my-config.toml:/zeroclaw-data/.zeroclaw/config.toml:ro \
-v zeroclaw-state:/zeroclaw-data/workspace \
-p 42617:42617 \
ghcr.io/zeroclaw-labs/zeroclaw:latest
Pour les charges de travail conteneurisées, définissez uri sur chaque providers.models.<type>.<alias> avec une adresse accessible depuis le conteneur (p. ex. http://host.docker.internal:11434 pour un serveur Ollama sur l’hôte Docker Desktop). Le mécanisme générique de surcharge par variables d’environnement peut définir le même champ à l’exécution sans modifier la configuration :
sh
ZEROCLAW_providers__models__ollama__home__uri=http://ollama:11434 zeroclaw agent -a assistant
Voir Fournisseurs → Surcharges adaptées aux conteneurs pour la grammaire.
Les canaux fonctionnant par sondage (Telegram, e-mail) : fonctionnent directement
Les canaux initiés en sortie ne nécessitent aucune configuration particulière du conteneur. Polling Telegram, IMAP, MQTT, relais Nostr : tout fonctionne en mode pull ; le conteneur n’a besoin que d’un accès sortant (egress).
Canaux qui reçoivent des webhooks : nécessitent un ingress
Discord, Slack, GitHub et la plupart des canaux webhook nécessitent un accès HTTP entrant. Deux options :
- Exposer la passerelle :
-p 42617:42617+ un proxy inverse avec TLS en frontal, faire pointer l’URL du webhook vers l’adresse publique - Utiliser un tunnel : ngrok, Cloudflare Tunnel ou Tailscale Funnel ; définissez l’URL du tunnel comme cible du webhook
Configurez un tunnel en définissant le tunnel_provider de niveau supérieur [tunnel] (variable d’environnement de remplacement : ZEROCLAW_tunnel__tunnel_provider) sur l’un des fournisseurs pris en charge et en remplissant le bloc tunnel.* correspondant ; la liste complète des fournisseurs et les champs propres à chaque fournisseur se trouvent dans la Référence de configuration. L’URL publique obtenue est celle vers laquelle vous devez diriger vos émetteurs de webhooks.
Kubernetes
Des manifestes Kubernetes d’exemple sont fournis dans le répertoire deploy-k8s/. Extrait de manifeste typique :
apiVersion: apps/v1
kind: Déploiement
métadonnées:
nom: zeroclaw
spécification:
répliques: 1
stratégie:
type: Recreate # ZeroClaw est une instance unique par espace de travail
template:
spécification:
conteneurs:
- nom: zeroclaw
image: ghcr.io/zeroclaw-labs/zeroclaw:v0.7.5
ports:
- `containerPort`: 42617
volumeMounts:
- nom: données
chemin de montage: /zeroclaw-data
# `containerPort` ne publie pas sur l’hôte ; un Service ou un Ingress
# contrôle ici l’exposition. Si vous montez une configuration par défaut sur localhost,
# surchargez simultanément gateway.host et gateway.allow_public_bind.
volumes:
- nom: données
persistentVolumeClaim:
nom de la revendication: zeroclaw-data
Mise à l’échelle : ZeroClaw fonctionne avec un seul rédacteur par espace de travail. Ne procédez pas à une mise à l’échelle horizontale ; exécutez une instance par agent.
Réauthentification après déconnexion
Si vous vous déconnectez de l’interface web pendant l’exécution dans un conteneur, le paircode existant devient invalide. Générez-en un nouveau pour vous reconnecter :
sh
docker exec -it zeroclaw zeroclaw gateway get-paircode --new
Pour les déploiements Compose, utilisez plutôt docker compose exec :
sh
docker compose exec zeroclaw zeroclaw gateway get-paircode --new
Pièges
- Particularités de nom d’hôte sur macOS (Docker Desktop, colima, Rancher Desktop).
host.docker.internalfonctionne d’emblée sur Docker Desktop pour macOS. Sur colima, il n’est accessible que si vous avez effectué l’installation aveccolima start --network-address(sinon le conteneur ne peut pas du tout voir l’hôte ; connectez-vous via l’IP de passerelle de la VM, généralement192.168.5.2, ou créez un tunnel via un réseau partagé). Rancher Desktop se comporte comme Docker Desktop dans les versions récentes, mais a connu des échecs de résolution dehost.docker.internaldans des versions plus anciennes. Si les appels au fournisseur échouent avecconnection refusedvershost.docker.internal, vérifiez avecdocker run --rm alpine getent hosts host.docker.internal: une sortie vide signifie que le nom d’hôte n’est pas résolvable et que vous devez utiliser une IP explicite. - Services côté hôte. Si un fournisseur est Ollama sur l’hôte,
uri = "http://host.docker.internal:11434"(sous[providers.models.ollama.<alias>]) fonctionne sur Docker Desktop. Sur Linux Docker, vous pourriez avoir besoin de--add-host=host.docker.internal:host-gateway. - Persistance de la mémoire. La mémoire de l’agent (la base SQLite
brain.db) se trouve dans le répertoire de configuration à l’emplacement/zeroclaw-data/.zeroclaw/agents/<alias>/workspace/memory/, avec les bases de données d’instance partagées sous/zeroclaw-data/data/. Monter/zeroclaw-datapermet de tout persister ; sans ce volume, chaque redémarrage entraîne la perte de l’historique des conversations. - Montage bind sur
/zeroclaw-data. Un montage bind de l’hôte sur/zeroclaw-dataremplace l’intégralité du répertoire de l’image, y compris la configuration par défaut et (auparavant) le bundle du tableau de bord. Le tableau de bord est désormais installé dans/usr/share/zeroclawlabs/web/dist, en dehors du montage, de sorte qu’un montage bind ne le masque plus. Au premier lancement, montez un répertoire hôte vide et le conteneur initialise une configuration neuve ; la passerelle détecte automatiquement le tableau de bord depuis son chemin dans l’image. - Aucun transfert matériel par défaut. GPIO / USB nécessitent des indicateurs
--deviceexplicites (--device /dev/ttyUSB0), et l’utilisateur du conteneur doit avoir le GID correspondant pour les groupesdialout/gpio.
Suivant
- Gestion des services
- Opérations → Déploiement réseau : tunnels, proxys inverses