Docker et Swift : conteneurisation d'applications pour iOS/macOS (niveau avancé)
La conteneurisation d'applications Swift dépasse le simple lancement de « Hello, World! » dans Docker. Au niveau avancé, les développeurs sont confrontés à des défis d'optimisation de la taille des images, de multitâche, de travail avec des frameworks réseau (SwiftNIO) et des serveurs web (Vapor). Dans cet article, nous verrons comment créer une image Docker efficace pour un projet Swift, en utilisant une construction multi-étapes, et configurer un conteneur pour un environnement de production.
1. Construction multi-étapes (Multi-stage builds) pour Swift
Le principal problème des images Docker pour Swift est leur taille. Une image complète avec les outils de compilation peut peser plus de 2 Go. La solution est la construction multi-étapes. La première étape (build) compile le binaire, la seconde (runtime) contient uniquement le fichier exécutable et les dépendances minimales.
Exemple de Dockerfile pour une application Swift serveur (par exemple, Vapor) :
# Étape 1 : constructionFROM swift:5.9-focal AS build
WORKDIR /app
COPY Package.swift Package.resolved ./RUN swift package resolve
COPY Sources ./SourcesRUN swift build -c release --static-swift-stdlib
# Étape 2 : image minimaleFROM ubuntu:22.04 AS runtime
RUN apt-get update && apt-get install -y libssl-dev ca-certificates && rm -rf /var/lib/apt/lists/*
WORKDIR /appCOPY --from=build /app/.build/release/Run .
EXPOSE 8080CMD ["./Run"]Points clés :
--static-swift-stdlib— liaison statique de la bibliothèque standard Swift, ce qui réduit les dépendances aux bibliothèques dynamiques.- Copie uniquement du binaire release — l'image finale est réduite à environ 100-150 Mo.
- Utilisation d'Ubuntu 22.04 au lieu de l'image Swift complète — économie d'espace.
2. Optimisation des couches et mise en cache des dépendances
Docker met en cache les couches, donc l'ordre des instructions est critique. Pour les projets Swift, les dépendances (Package.swift, Package.resolved) changent moins souvent que le code source. Séparez la copie des manifestes et des sources :
COPY Package.swift Package.resolved ./RUN swift package resolve
COPY Sources ./SourcesRUN swift build -c releaseCela permet de mettre en cache la résolution des dépendances et de ne pas les reconstruire à chaque modification du code. Pour accélérer la construction, utilisez --build-arg pour choisir la configuration :
docker build --build-arg CONFIGURATION=release -t my-swift-app .Dans le Dockerfile, ajoutez :
ARG CONFIGURATION=releaseRUN swift build -c ${CONFIGURATION}3. Conteneurisation de SwiftNIO et Vapor : travail avec le réseau
Les applications Swift serveur utilisent souvent SwiftNIO pour le travail asynchrone avec le réseau. Dans le conteneur, il est important de configurer correctement l'environnement réseau.
3.1. Configuration de Vapor dans Docker
Vapor écoute par défaut sur localhost:8080. Dans le conteneur, il faut spécifier 0.0.0.0 pour accepter les connexions externes. Ajoutez dans configure.swift :
app.http.server.configuration.hostname = "0.0.0.0"app.http.server.configuration.port = 8080Ou utilisez des variables d'environnement :
docker run -e HOST=0.0.0.0 -e PORT=8080 -p 8080:8080 my-swift-app3.2. SwiftNIO et healthcheck
Pour la surveillance en production, ajoutez un healthcheck dans le Dockerfile :
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1Dans le code SwiftNIO, implémentez l'endpoint /health :
func healthHandler(request: Request) -> EventLoopFuture<String> { return request.eventLoop.makeSucceededFuture("OK")}4. Techniques avancées : Docker Compose et construction multiplateforme
4.1. Docker Compose pour le backend Swift
Si