Введение: зачем Swift-разработчику Docker?
Многие разработчики на Swift (особенно в мире iOS и macOS) привыкли к Xcode, симуляторам и ручному управлению зависимостями. Однако с ростом популярности серверного Swift (например, фреймворка Vapor) и необходимостью автоматизации тестирования и деплоя, контейнеризация становится обязательным навыком.
Docker позволяет упаковать ваше Swift-приложение вместе со всеми зависимостями в изолированный контейнер. Это гарантирует, что код будет работать одинаково на локальной машине, на сервере CI/CD и в production. В этой статье мы разберём, как создать Docker-образ для Swift-проекта, оптимизировать его размер и запустить в контейнере.
1. Основы Docker для Swift: Dockerfile и мультистадийная сборка
Стандартный подход к контейнеризации Swift-приложений — использование мультистадийной сборки. Это позволяет разделить этап компиляции (где нужны тяжёлые инструменты Swift) и этап выполнения (где достаточно только скомпилированного бинарника).
Рассмотрим типичный проект на Swift, например, сервер на Vapor. Создадим файл Dockerfile в корне проекта:
# Первый этап: сборка
FROM swift:5.9-focal AS build
WORKDIR /app
# Копируем файлы Package.swift и Package.resolved для кэширования зависимостей
COPY Package.swift Package.resolved ./
RUN swift package resolve
# Копируем исходный код
COPY . .
# Сборка в режиме release
RUN swift build -c release --static-swift-stdlib
# Второй этап: минимальный образ для выполнения
FROM ubuntu:focal
WORKDIR /app
# Копируем собранный бинарник из первого этапа
COPY --from=build /app/.build/release/Run .
# Открываем порт (по умолчанию Vapor использует 8080)
EXPOSE 8080
# Запускаем приложение
CMD ["./Run"]
Важные моменты:
--static-swift-stdlib— статическая линковка стандартной библиотеки Swift уменьшает зависимости на этапе выполнения.- Копирование
Package.swiftдо исходников — это трюк для кэширования слоя зависимостей Docker. - Базовый образ
ubuntu:focal— лёгкий, но содержит все необходимые системные библиотеки.
2. Сборка и запуск контейнера
Теперь, когда Dockerfile готов, соберём образ и запустим контейнер:
# Сборка образа
docker build -t my-swift-app .
# Запуск контейнера в фоне с пробросом порта
docker run -d -p 8080:8080 --name swift-container my-swift-app
# Проверка логов
docker logs swift-container
# Тестирование (если приложение — HTTP сервер)
curl http://localhost:8080/
Если вы используете Swift Package Manager без Vapor, бинарник может называться иначе. В таком случае измените путь в COPY --from=build и CMD. Узнать точное имя бинарника можно командой:
swift build -c release --show-bin-path
2.1. Работа с .dockerignore
Чтобы не копировать в контекст сборки лишние файлы (например, .git, build/), создайте .dockerignore:
.git
.gitignore
.build/
*.xcodeproj
*.xcworkspace
.DS_Store
README.md
3. Docker Compose для Swift-приложений
Если ваш проект использует базу данных (PostgreSQL, Redis) или несколько микросервисов, удобно использовать docker-compose.yml. Пример для Vapor + PostgreSQL:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- DATABASE_HOST=db
- DATABASE_PORT=5432
- DATABASE_NAME=vapor_db
- DATABASE_USER=vapor_user
- DATABASE_PASSWORD=secret
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_DB: vapor_db
POSTGRES_USER: vapor_user
POSTGRES_PASSWORD: secret
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Запуск одной командой:
docker-compose up -d
Этот подход особенно полезен для локальной разработки и CI/CD, так как вся инфраструктура поднимается автоматически.
4. Оптимизация размера образа для Swift
Образы Swift могут быть большими (гигабайты на этапе сборки). Вот несколько рекомендаций по уменьшению финального размера:
- Используйте
--static-swift-stdlib— как показано выше, это уменьшает количество динамических библиотек. - Выбирайте минимальный базовый образ: вместо
ubuntu:focalможно попробоватьswift:5.9-slim(существуют community-образы) илиalpineс дополнительными настройками, но это требует больше ручной работы. - Удаляйте кэш SPM на этапе сборки: добавьте
RUN rm -rf /app/.build/repositoriesпосле копирования исходников. - Используйте
.dockerignore— исключайте ненужные файлы, как описано выше.
Пример компактного Dockerfile для production (только бинарник):
FROM swift:5.9-focal AS build
WORKDIR /app
COPY . .
RUN swift build -c release --static-swift-stdlib && \
rm -rf /app/.build/repositories
FROM ubuntu:focal
WORKDIR /app
COPY --from=build /app/.build/release/Run .
EXPOSE 8080
CMD ["./Run"]
После сборки проверьте размер:
docker images | grep my-swift-app
Хороший результат — 50–100 МБ для production образа.
Заключение
Контейнеризация Swift-приложений с помощью Docker — это не только про серверный Swift. Вы можете упаковывать CLI-инструменты, бэкенды для iOS-приложений и даже тестовые окружения для macOS-проектов. Главное преимущество — воспроизводимость окружения и лёгкий деплой.
Начните с простого Dockerfile, добавьте .dockerignore
Блоги
Рекомендаций по книгам
Читайте также