Docker and Swift: Advanced Application Containerization

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Containerizing Swift is a Challenge and an Advantage

\n

Containerizing Swift applications for iOS and macOS was long considered the domain of enthusiasts. Unlike Go or Node.js, Swift requires compilation on the target platform, and official Docker images remained exotic for a long time. However, with the release of Swift 5.x and the emergence of official images like swift:5.10 (and newer), the situation has changed dramatically. Today, Docker allows not only running server backends on Vapor but also automating the build of CLI utilities, testing code in an isolated environment, and even preparing binary artifacts for deployment on macOS.

\n

In this article, we will cover advanced techniques: multi-stage builds, aggressive dependency caching, image size optimization, and integration with Swift Package Manager. The examples are geared towards real projects — from a simple HTTP server to a complex microservice.

\n\n

1. Multi-Stage Build: Separating Compilation and Runtime

\n

A classic mistake beginners make is using a single image for both building and running. This results in an image weighing >2 GB due to the SDK, tools, and source code. The correct approach is two stages: builder and runner.

\n

Example Dockerfile for a Vapor Application

\n
# Stage 1: Build\nFROM swift:5.10 AS builder\nWORKDIR /app\nCOPY Package.swift Package.resolved ./\nRUN swift package resolve --cache-path .build/artifacts\nCOPY Sources Sources\nCOPY Tests Tests\nRUN swift build -c release --static-swift-stdlib\n\n# Stage 2: Minimal Runtime\nFROM ubuntu:22.04\nRUN apt-get update && apt-get install -y libicu70 libxml2 ca-certificates && rm -rf /var/lib/apt/lists/*\nWORKDIR /app\nCOPY --from=builder /app/.build/release/Run .\nEXPOSE 8080\nCMD ["./Run"]
\n

Key points:

\n
    \n
  • Dependency caching — copy Package.swift and Package.resolved before copying the source code. Docker caches the layer, and when only code changes, only the binaries are rebuilt.
  • \n
  • The --static-swift-stdlib flag — statically links the Swift standard library. This reduces runtime requirements but increases the binary size by ~30%.
  • \n
  • Minimal image — use Ubuntu with only the necessary system libraries (libicu, libxml2). The final image is less than 150 MB compared to 2 GB with a single-stage build.
  • \n
\n\n

2. Aggressive Caching with BuildKit and SSH Agents

\n

When working in CI/CD (GitHub Actions, GitLab CI), each run downloads dependencies from scratch. Use Docker BuildKit to mount the Swift PM cache.

\n

Dockerfile with BuildKit Caching

\n
# syntax=docker/dockerfile:1\nFROM swift:5.10 AS builder\nWORKDIR /app\nRUN --mount=type=cache,target=/app/.build/artifacts \\\n    --mount=type=bind,source=Package.swift,target=Package.swift \\\n    --mount=type=bind,source=Package.resolved,target=Package.resolved \\\n    swift package resolve\nCOPY Sources Sources\nRUN --mount=type=cache,target=/app/.build/artifacts \\\n    swift build -c release --static-swift-stdlib
\n

Advantages:

\n
    \n
  • Persistent cache — dependency artifacts are preserved between builds on the same host.
  • \n
  • SSH agents — if your Package.swift references private repositories, use --mount=type=ssh for authentication without storing keys in the image.
  • \n
\n

For macOS hosts (e.g., MacStadium), be sure to add --platform linux/amd64, as Swift on ARM (M1/M2) requires emulation.

\n\n

3. Advanced Work with Swift Package Manager

\n

Swift PM is not just a dependency manager, but also a powerful tool for testing and linting inside a container.

\n

Running Tests in a Container with Code Coverage Support

\n
FROM swift:5.10 AS te                

Blogs

Book Recommendations