Docker e Swift: conteinerização de aplicações para iOS/macOS (nível avançado)
A conteinerização de aplicações Swift vai além da simples execução de "Hello, World!" no Docker. Em nível avançado, os desenvolvedores enfrentam desafios como otimização do tamanho das imagens, multithreading, trabalho com frameworks de rede (SwiftNIO) e servidores web (Vapor). Neste artigo, vamos analisar como criar uma imagem Docker eficiente para um projeto Swift, usando multi-stage builds, e configurar o container para um ambiente de produção.
1. Multi-stage builds para Swift
O principal problema das imagens Docker para Swift é o seu tamanho. Uma imagem completa com ferramentas de compilação pode pesar mais de 2 GB. A solução é o multi-stage build. O primeiro estágio (build) compila o binário, o segundo (runtime) contém apenas o arquivo executável e as dependências mínimas.
Exemplo de Dockerfile para uma aplicação Swift server-side (por exemplo, Vapor):
# Estágio 1: compilaçãoFROM 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
# Estágio 2: imagem mínimaFROM 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"]Pontos-chave:
--static-swift-stdlib— linkagem estática da biblioteca padrão do Swift, o que reduz as dependências de bibliotecas dinâmicas.- Copiar apenas o binário de release — a imagem final é reduzida para ~100-150 MB.
- Usar Ubuntu 22.04 em vez da imagem completa do Swift — economia de espaço.
2. Otimização de camadas e cache de dependências
O Docker armazena em cache as camadas, portanto a ordem das instruções é crítica. Para projetos Swift, as dependências (Package.swift, Package.resolved) mudam com menos frequência do que o código-fonte. Separe a cópia dos manifestos e dos fontes:
COPY Package.swift Package.resolved ./RUN swift package resolve
COPY Sources ./SourcesRUN swift build -c releaseIsso permite armazenar em cache a resolução de dependências e não recompilá-las a cada alteração no código. Para acelerar a compilação, use --build-arg para selecionar a configuração:
docker build --build-arg CONFIGURATION=release -t my-swift-app .No Dockerfile, adicione:
ARG CONFIGURATION=releaseRUN swift build -c ${CONFIGURATION}3. Conteinerização de SwiftNIO e Vapor: trabalho com rede
Aplicações Swift server-side frequentemente usam SwiftNIO para trabalho assíncrono com rede. No container, é importante configurar corretamente o ambiente de rede.
3.1. Configuração do Vapor no Docker
Por padrão, o Vapor escuta em localhost:8080. No container, é necessário especificar 0.0.0.0 para aceitar conexões externas. Adicione em configure.swift:
app.http.server.configuration.hostname = "0.0.0.0"app.http.server.configuration.port = 8080Ou use variáveis de ambiente:
docker run -e HOST=0.0.0.0 -e PORT=8080 -p 8080:8080 my-swift-app3.2. SwiftNIO e healthcheck
Para monitoramento em produção, adicione um healthcheck no Dockerfile:
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1No código SwiftNIO, implemente o endpoint /health:
func healthHandler(request: Request) -> EventLoopFuture<String> { return request.eventLoop.makeSucceededFuture("OK")}4. Técnicas avançadas: Docker Compose e compilação multiplataforma
4.1. Docker Compose para backend Swift
Se