Деплой Swift на Kubernetes: от локальной сборки до production-кластера
Swift — это не только язык для iOS и macOS. Благодаря фреймворкам вроде Vapor и Kitura, Swift всё чаще используется для написания серверных приложений. Но как доставить такое приложение пользователям? Ответ — Kubernetes. В этом руководстве мы разберём, как упаковать Swift-приложение в Docker, настроить CI/CD и развернуть его в кластере K8s. Вы узнаете, какие нюансы есть при сборке Swift под Linux, как оптимизировать образ и как написать правильные манифесты для Kubernetes.
1. Подготовка Swift-приложения для контейнеризации
Первое, с чем сталкивается разработчик — Swift на Linux. Если вы пишете на macOS, вам нужно кросс-компилировать приложение для Linux (amd64/arm64). Рассмотрим пример на базе Vapor 4.
Создадим простое HTTP-приложение:
// Sources/App/routes.swift
import Vapor
func routes(_ app: Application) throws {
app.get { req async in
"Hello from Swift on Kubernetes!"
}
app.get("health") { req async in
"OK"
}
}
Для сборки под Linux используем официальный образ Swift. Создадим Dockerfile с двухэтапной сборкой:
# Первый этап: сборка
FROM swift:5.9-focal as builder
WORKDIR /app
COPY Package.swift Package.resolved ./
RUN swift package resolve
COPY . .
RUN swift build -c release --static-swift-stdlib
# Второй этап: минимальный образ
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y ca-certificates libsqlite3-0 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=builder /app/.build/release/Run .
EXPOSE 8080
CMD ["./Run"]
Ключевой момент — флаг --static-swift-stdlib. Он включает статическую линковку стандартной библиотеки Swift, что уменьшает размер образа и упрощает деплой. Без него образ может весить 1+ ГБ.
2. Сборка образа и загрузка в registry
Собираем образ и пушим в Docker Hub (или любой другой registry):
# Сборка
docker build -t myrepo/swift-k8s-demo:1.0.0 .
# Проверка локально
docker run -p 8080:8080 myrepo/swift-k8s-demo:1.0.0
curl http://localhost:8080
# Ответ: Hello from Swift on Kubernetes!
# Пуш в registry
docker push myrepo/swift-k8s-demo:1.0.0
Оптимизация размера: образ на основе ubuntu:22.04 весит ~150 МБ. Если использовать alpine — можно уменьшить до 50 МБ, но придётся решать проблему с glibc (Swift требует её). Рекомендуется использовать официальные образы Ubuntu или Debian.
3. Манифесты Kubernetes для Swift-приложения
Теперь развернём наше приложение в кластере. Создадим Deployment и Service.
deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: swift-app
labels:
app: swift-app
spec:
replicas: 3
selector:
matchLabels:
app: swift-app
template:
metadata:
labels:
app: swift-app
spec:
containers:
- name: swift-app
image: myrepo/swift-k8s-demo:1.0.0
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "250m"
service.yaml:
apiVersion: v1
kind: Service
metadata:
name: swift-app-service
spec:
selector:
app: swift-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
Обратите внимание на probes (пробы). Swift-приложение стартует быстро, но мы добавили initialDelaySeconds: 5 для уверенности. Ресурсы указаны минимальные — Swift-приложение на Vapor потребляет около 30-50 МБ RAM в простое.
Применяем манифесты:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# Проверка
kubectl get pods
kubectl get svc swift-app-service
4. Продвинутые сценарии: Ingress, ConfigMap и масштабирование
Для внешнего доступа добавим Ingress (например, с nginx-ingress):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: swift-app-ingress
spec:
rules:
- host: swift.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: swift-app-service
port:
number: 80
Конфигурацию (например, строку подключения к БД) лучше вынести в ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: swift-config
data:
DATABASE_URL: "postgres://user:pass@postgres-service:5432/swiftdb"
В коде Swift используем переменные окружения:
// В configure.swift
if let dbURL = Environment.get("DATABASE_URL") {
app.databases.use(.postgres(url: dbURL), as: .psql)
}
Масштабирование: для Swift-приложений с Vapor хорошо работает горизонтальное масштабирование. Используйте HPA (Horizontal Pod Autoscaler):
kubectl autoscale deployment swift-app --cpu-percent=50 --min=2 --max=10
Заключение
Мы прошли полный путь от Swift-приложения до работающего сервиса в Kubernetes. Ключевые выводы:
- Swift на сервере — это реально. Vapor и другие фреймворки позволяют создавать высокопроизводительные API.
- Статическая сборка — обязательна для уменьшения размера образа и совместимости.
- Пробы и ресурсы — критичны для стабильной работы в K8s.
- CI/CD — автоматизируйте сборку