A
u
Zine El Abidine Moualhi, Etienne Deneuve
Jun 16, 2026 · 13 min read

Apporter des workflows Docker Compose-style à Apple Container

Side view worker wearing gloves

Le projet container d’Apple est l’une des évolutions les plus intéressantes de l’écosystème de développement local de ces dernières années.

Pendant longtemps, exécuter des containers sur macOS a impliqué d’accepter une pile d’abstraction qui n’était pas réellement native de la plateforme : machines virtuelles, daemons, couches de partage de fichiers, couches réseau, puis outils de développement construits par-dessus.

Cela a fonctionné. Mais cela venait aussi avec des compromis.

Apple change la discussion avec container. Le projet est écrit en Swift, conçu pour Apple Silicon, et pensé pour exécuter des containers Linux comme des machines virtuelles légères sur macOS. Il reste compatible avec les images OCI, ce qui lui permet de s’intégrer à l’écosystème container existant au lieu de créer un monde fermé.

Mais il manquait une brique évidente pour le développement au quotidien : un container seul est utile, mais les vraies applications ne sont presque jamais composées d’un seul container.

La plupart des environnements modernes combinent plusieurs services : une API, une base de données, une queue, un worker, un reverse proxy, une stack de métriques ou un service de migration. Pour beaucoup d’équipes, docker compose up n’est pas juste une commande. C’est le point d’entrée du projet.

C’est pour cette raison que nous avons commencé container compose.

Le problème : les équipes ont besoin de composition

Le CLI container d’Apple donne déjà aux développeurs macOS une manière native de construire et d’exécuter des containers. C’est important.

Mais les workflows de développement ont besoin d’orchestration au niveau du projet.

Une application ne dit pas seulement :

Terminal window
run this image

Elle dit plutôt :

démarre Postgres
attends qu'il soit healthy
puis démarre l'API
monte ces fichiers
expose ces ports
lance ce service seulement en mode debug
scale ce worker
stream les logs du projet
arrête et nettoie tout proprement

C’est cette couche que Docker Compose a rendue familière.

Notre objectif avec container compose est d’apporter ce type de workflow à l’écosystème container d’Apple, tout en restant alignés avec la manière dont le runtime Apple fonctionne réellement.

Pas un clone du daemon Docker.

Pas une couche Kubernetes complète.

Un plugin natif pour le CLI container d’Apple, capable de comprendre des workflows proches de Docker Compose.

Ce que nous avons construit

container compose est un plugin natif pour le CLI container d’Apple.

Il permet de démarrer, arrêter, inspecter et gérer des applications multi-containers depuis des fichiers Compose standards :

Terminal window
container system start
container compose up -f compose.yaml -p demo
container compose ps -p demo
container compose logs -p demo
container compose down -p demo

L’intention est simple : conserver le workflow que les développeurs connaissent déjà, mais le faire fonctionner avec le runtime container d’Apple.

Le plugin supporte les commandes de cycle de vie attendues :

Terminal window
container compose up
container compose down
container compose ps
container compose logs
container compose exec
container compose run
container compose config
container compose watch
container compose stats

Il inclut aussi des workflows opérationnels comme la sauvegarde et le chargement d’une archive de stack pour des migrations hors ligne.

C’est important parce que le développement local ne consiste pas seulement à démarrer des containers. Il consiste à obtenir un environnement répétable : inspecter ce qui tourne, valider la configuration résolue, streamer les logs, exécuter des commandes dans les services, copier des fichiers, observer les ressources et supprimer proprement les ressources d’un projet.

Pourquoi un plugin, et pas un simple wrapper ?

Le chemin le plus simple aurait été d’écrire un wrapper autour de commandes shell.

Nous ne voulions pas seulement cela.

Un wrapper peut masquer la complexité pour une démo simple, mais il se casse vite quand les vrais workflows arrivent : ordre des dépendances, health checks, profiles, scaling, nommage des projets, substitution d’environnement, contexts machines, volumes, secrets et gestion des erreurs.

container compose est écrit en Swift et construit sur l’écosystème container d’Apple. Le package dépend de container, containerization, des packages Swift associés, ainsi que de swift-argument-parser et Yams pour le CLI et le parsing YAML.

Cela donne une base plus solide qu’un enchaînement de commandes opaques.

Le plugin peut parser et résoudre les fichiers Compose, construire un plan d’exécution, valider les contraintes tôt, puis piloter le runtime container de manière intentionnelle.

Le démarrage n’est pas juste “start everything”

L’une des parties les plus importantes d’une orchestration façon Compose est l’ordre de démarrage.

Démarrer dix containers dans un ordre aléatoire est facile. Les démarrer correctement est plus difficile.

container compose démarre les services par vagues de dépendances. Les services d’une même vague peuvent démarrer en parallèle. La vague suivante démarre seulement lorsque les exigences de dépendance précédentes sont satisfaites.

Par exemple :

services:
db:
image: postgres:16
healthcheck:
test: ["CMD", "pg_isready"]
interval: 5s
timeout: 3s
retries: 5
api:
image: myapp:latest
depends_on:
db:
condition: service_healthy

Dans ce cas, l’API ne doit pas démarrer simplement parce que le process de base de données existe. Elle doit démarrer quand la base est réellement healthy.

Le plugin supporte des conditions de dépendance comme service_started, service_healthy et service_completed_successfully. Cette dernière est particulièrement utile pour les services one-shot, comme les migrations.

C’est la différence entre un environnement local qui fonctionne souvent et un environnement local suffisamment déterministe pour une équipe.

Une sémantique de projet

Les workflows Compose ont besoin d’un modèle de projet.

Un projet définit la frontière qui permet à l’outil de savoir quels containers appartiennent ensemble. Sans cela, des commandes comme down, ps, logs ou stats deviennent fragiles.

container compose résout le nom du projet à partir du flag -p, de COMPOSE_PROJECT_NAME, du champ name: dans le fichier Compose ou du nom du dossier parent.

Cela signifie que :

Terminal window
container compose up -p demo
container compose logs -p demo
container compose down -p demo

opère sur la même stack logique.

Les containers suivent une convention de nommage prévisible :

{project}_{service}_{index}

Par exemple :

demo_web_1
demo_web_2
demo_db_1

Cette prévisibilité compte pour le debug, les scripts et la transmission du projet à un autre développeur.

Résolution des fichiers Compose

Le plugin supporte les noms standards que les développeurs attendent :

compose.yaml
compose.yml
docker-compose.yaml
docker-compose.yml

Il supporte aussi plusieurs fichiers :

Terminal window
container compose up -f base.yml -f production.yml

Les fichiers passés plus tard surchargent les précédents.

C’est essentiel pour les vrais projets, où une équipe peut avoir une stack de base, une surcharge de développement, une surcharge CI ou une surcharge locale.

Le plugin supporte aussi la substitution de variables depuis les fichiers .env et l’environnement shell :

image: ${IMAGE_NAME:-nginx:latest}

Cela garde les fichiers Compose portables sans tout coder en dur.

Profiles, scaling et limites de ressources

Les stacks modernes contiennent souvent des services qui ne doivent pas démarrer tout le temps.

Un debugger, un exporter de métriques, une interface d’administration ou un helper local peuvent être utiles, mais seulement quand on les demande explicitement.

Les profiles répondent à ce besoin :

services:
app:
image: myapp:latest
debugger:
image: mytools:latest
profiles: [debug]

Puis :

Terminal window
container compose up

démarre l’application par défaut, tandis que :

Terminal window
container compose up --profile debug

démarre aussi le debugger.

Le scaling est également supporté :

Terminal window
container compose up --scale web=5

Le plugin valide les cas où le scaling ne peut pas fonctionner, par exemple lorsque plusieurs replicas tentent de binder le même port statique sur l’hôte.

Les limites de ressources sont supportées via deploy.resources.limits, avec une validation alignée sur le modèle container d’Apple.

Travailler avec Apple container machines

L’écosystème container d’Apple inclut les container machines, et container compose permet d’exécuter un projet dans une machine existante avec --machine.

Par exemple :

Terminal window
container machine create --name dev
container compose up --machine dev -f compose.yaml -p demo
container compose ps --machine dev -p demo
container compose logs --machine dev -p demo
container compose down --machine dev -p demo

Le plugin distingue alors deux contextes d’exécution : l’application sandbox et une container machine.

Cette distinction est importante, car toutes les fonctionnalités ne se comportent pas exactement de la même manière dans les deux contextes. Le plugin explicite ces contraintes au lieu de prétendre que les environnements sont identiques.

Observabilité de l’orchestration locale

Les outils locaux doivent être debuggables.

Quand un démarrage échoue, les développeurs doivent comprendre ce qui s’est passé : quel service a démarré, quelle dépendance a échoué, quelle vague a rollback, quelle opération réseau ou volume a été lancée, et où le temps a été consommé.

container compose émet des événements d’orchestration dans macOS Unified Logging sous :

com.simplifi-ed.container-compose

On peut les inspecter depuis Console.app ou depuis le terminal :

Terminal window
log stream --predicate 'subsystem == "com.simplifi-ed.container-compose" AND category == "orchestration"'

Le plugin émet aussi des signposts Instruments pour les chemins critiques du démarrage : parse, plan, création réseau, création volume et vagues d’exécution.

C’est un principe de conception : l’infrastructure locale doit aussi être observable.

Host DNS pour le développement local

Le développement local a souvent besoin de hostnames stables.

Les ports sont utiles, mais les hostnames simplifient les tests navigateur, les callbacks, les cookies et le routage multi-services local.

container compose inclut une fonctionnalité Host DNS opt-in :

services:
web:
image: nginx:1.27.3
ports:
- "8080:80"
x-compose:
hosts:
- web.demo.local

Puis :

Terminal window
container compose up --host-dns

mappe le hostname déclaré vers 127.0.0.1 sur l’hôte macOS.

Le plugin reste non privilégié. macOS demande une autorisation uniquement lors de l’écriture dans /etc/hosts, et container compose down supprime le bloc du projet quand c’est possible.

Migration offline d’une stack

Une autre fonctionnalité importante était la possibilité de packager une stack résolue.

container compose save peut regrouper manifest.json, compose.yaml et images.tar dans une archive portable :

Terminal window
container compose save -f compose.yaml -o stack.tar

Puis une autre machine peut la charger :

Terminal window
container compose load -i stack.tar
container compose up -f compose.yaml

Cette fonctionnalité ne cherche pas à résoudre tous les problèmes de migration. Elle ne package pas les volumes, l’état des systèmes de fichiers des containers, le push/pull registry ou les secrets. Elle se concentre sur une frontière pratique : configuration Compose résolue et images OCI locales.

C’est suffisant pour beaucoup de workflows offline, de démos, de workshops ou d’environnements contrôlés.

Ce que ce projet n’est pas

Ce projet n’affirme pas qu’Apple Container doit remplacer tous les workflows containers existants aujourd’hui.

Il n’affirme pas non plus que la sémantique Docker Compose peut être copiée parfaitement dans un runtime différent.

Le modèle d’Apple a ses propres contraintes. Certaines sont architecturales. Certaines sont liées à la maturité de l’écosystème. Certaines viennent simplement du fait que nous construisons sur une base nouvelle.

La bonne approche n’est donc pas la compatibilité aveugle.

La bonne approche est une compatibilité pragmatique :

  • garder le modèle Compose quand il a du sens
  • préserver les commandes familières quand c’est possible
  • valider tôt les cas non supportés
  • rendre explicite le comportement propre au runtime
  • utiliser les capacités natives de macOS au lieu de lutter contre elles

C’est la ligne que nous essayons de tenir.

Les contributions sont ouvertes

Ce projet est open source, et les contributions sont bienvenues.

L’objectif n’est pas de construire un outil interne fermé pour une seule équipe. L’objectif est d’explorer ce que devrait être une orchestration Compose-style au-dessus d’Apple Container, avec des retours réels de développeurs qui essaient de l’utiliser sur de vrais projets.

Les contributions peuvent prendre plusieurs formes : tester le plugin sur des fichiers Compose existants, signaler des fonctionnalités non supportées, améliorer la compatibilité avec des stacks courantes, affiner le comportement spécifique à macOS, améliorer la documentation et les exemples, proposer de meilleurs defaults, contribuer du code Swift ou aider à définir ce que doit devenir un workflow natif proche de Compose sur Apple Container.

Apple Container est encore un écosystème jeune. Le meilleur moment pour façonner l’expérience développeur, c’est maintenant, avant que les patterns ne deviennent des standards accidentels.

Le repository est ouvert :

https://github.com/Simplifi-ED/compose

Issues, idées, tests et pull requests sont les bienvenus.

Open source entre l’Europe et l’Afrique

container compose est un projet parmi d’autres dans un effort open source plus large que nous construisons chez Simplifi’ED et Omnivya.

Nous pensons que l’open source ne consiste pas seulement à publier des repositories. Il s’agit de créer des ponts techniques : entre équipes, entre écosystèmes, et entre régions qui résolvent souvent des problèmes d’ingénierie similaires dans des contextes différents.

C’est important pour nous parce que nous travaillons entre l’Europe et l’Afrique.

Les contraintes sont réelles des deux côtés : expérience développeur, coût d’infrastructure, souveraineté, montée en compétence, maturité cloud, sécurité, réglementations locales et besoin de construire des logiciels capables de survivre hors des conditions parfaites de laboratoire.

L’open source nous donne une manière concrète de partager ces apprentissages. Il nous permet de publier des outils, documenter nos décisions, inviter les retours et discuter d’architecture avec des ingénieurs, entreprises, écoles et communautés au-delà d’une frontière commerciale.

Nous avons déjà créé d’autres projets open source, et nous serons heureux d’en parler : ce qui a fonctionné, ce qui a échoué, ce qui doit être amélioré, et où la collaboration a du sens.

Pourquoi c’est important

Le poste de travail développeur est en train de changer à nouveau.

Pendant des années, la réponse par défaut sur macOS consistait à exécuter un moteur container Linux via une couche de virtualisation, puis à construire le workflow développeur au-dessus.

Apple expose maintenant une fondation plus native.

Cela ne remplace pas automatiquement l’écosystème autour des containers. L’écosystème, ce n’est pas seulement l’exécution d’images. C’est l’orchestration, la configuration, les logs, les health checks, les profiles, les volumes, les secrets, le réseau, le DNS local, les workflows offline et la mémoire musculaire des développeurs.

container compose existe parce que la prochaine génération d’outillage container sur macOS a besoin de cette couche.

Nous voulons que les développeurs puissent continuer à écrire :

Terminal window
container compose up

et obtenir une vraie stack applicative, pas seulement un container isolé.

État actuel

Le projet est actif et évolue.

Aujourd’hui, il couvre déjà une partie importante de l’orchestration locale Compose-style : commandes de cycle de vie, vagues de dépendances, démarrage basé sur les health checks, nommage de projet, résolution de configuration, profiles, scaling, limites de ressources, logs, exec, stats, watch, save/load, host DNS et support des Apple container machines.

Il reste des limites. Certaines sont documentées. Certaines évolueront avec la maturité de l’écosystème container d’Apple. Certaines demanderont des décisions de conception explicites, car la containerisation native macOS n’a pas exactement la même architecture que Docker Desktop.

C’est précisément pour cela que nous avons commencé maintenant.

Plus cette couche existe tôt, plus les équipes peuvent expérimenter le runtime container d’Apple avec des workflows proches de ceux qu’elles connaissent déjà.

Essayez-le

Installez le plugin via le tap Homebrew Simplifi-ED :

Terminal window
brew tap Simplifi-ED/compose
brew trust --formula simplifi-ed/compose/container-compose
brew install simplifi-ed/compose/container-compose

Démarrez le runtime container d’Apple :

Terminal window
container system start

Puis lancez une stack Compose :

Terminal window
container compose up -f compose.yaml -p demo

Inspectez-la :

Terminal window
container compose ps -p demo
container compose logs -p demo
container compose stats -p demo

Supprimez-la :

Terminal window
container compose down -p demo

C’est le début d’un workflow de développement container plus natif sur macOS.

Pas en abandonnant l’ergonomie Compose.

En l’apportant à Apple Container, de manière ouverte, avec la communauté.

Apple Container Docker Compose Open Source Containers MacOS

Articles relatifs