Deploying Swift on Kubernetes: From Local Build to Production Cluster
\nSwift is not just a language for iOS and macOS. Thanks to frameworks like Vapor and Kitura, Swift is increasingly used for writing server applications. But how do you deliver such an application to users? The answer is Kubernetes. In this guide, we will walk through how to package a Swift application in Docker, set up CI/CD, and deploy it in a K8s cluster. You will learn the nuances of building Swift for Linux, how to optimize the image, and how to write correct manifests for Kubernetes.
\n\n1. Preparing the Swift Application for Containerization
\nThe first thing a developer encounters is Swift on Linux. If you are writing on macOS, you need to cross-compile the application for Linux (amd64/arm64). Let's look at an example based on Vapor 4.
\nLet's create a simple HTTP application:
\n// Sources/App/routes.swift\nimport Vapor\n\nfunc routes(_ app: Application) throws {\n app.get { req async in\n "Hello from Swift on Kubernetes!"\n }\n app.get("health") { req async in\n "OK"\n }\n}\n\nTo build for Linux, we use the official Swift image. Let's create a Dockerfile with a multi-stage build:
# First stage: build\nFROM swift:5.9-focal as builder\nWORKDIR /app\nCOPY Package.swift Package.resolved ./\nRUN swift package resolve\nCOPY . .\nRUN swift build -c release --static-swift-stdlib\n\n# Second stage: minimal image\nFROM ubuntu:22.04\nRUN apt-get update && apt-get install -y ca-certificates libsqlite3-0 && rm -rf /var/lib/apt/lists/*\nWORKDIR /app\nCOPY --from=builder /app/.build/release/Run .\nEXPOSE 8080\nCMD ["./Run"]\n\nThe key point is the --static-swift-stdlib flag. It enables static linking of the Swift standard library, which reduces the image size and simplifies deployment. Without it, the image can weigh 1+ GB.
2. Building the Image and Pushing to a Registry
\nBuild the image and push it to Docker Hub (or any other registry):
\n# Build\ndocker build -t myrepo/swift-k8s-demo:1.0.0 .\n\n# Test locally\ndocker run -p 8080:8080 myrepo/swift-k8s-demo:1.0.0\ncurl http://localhost:8080\n# Response: Hello from Swift on Kubernetes!\n\n# Push to registry\ndocker push myrepo/swift-k8s-demo:1.0.0\n\nSize optimization: an image based on ubuntu:22.04 weighs ~150 MB. If you use alpine, you can reduce it to 50 MB, but you will have to solve the glibc issue (Swift requires it). It is recommended to use official Ubuntu or Debian images.
3. Kubernetes Manifests for the Swift Application
\nNow let's deploy our application in the cluster. Create a Deployment and a Service.
\ndeployment.yaml:
\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: swift-app\n labels:\n app: swift-app\nspec:\n replicas: 3\n selector:\n matchLabels:\n app: swift-app\n template:\n metadata:\n labels:\n app: swift-app\n spec:\n containers:\n - name: swift-app\n image: myrepo/swift-k8s-demo:1.0.0\n ports:\n - containerPort: 8080\n livenessProbe:\n httpGet:\n path: /health\n port: 8080\n initialDelaySeconds: 5\n periodSeconds: 10\n readinessProbe:\n httpGet:\n path: /health\n port: 8080\n initialDelaySeconds: 3\n periodSeconds: 5\n resources:\n requests:\n memory: "64Mi"\n cpu: "100m"\n limits:\n memory: "128Mi"\n cpu: "250m"\n\nservice.yaml:
\napiVersion: v1\nkind: Service\nmetadata:\n name: swift-app-service\nspec:\n selector:\n app: swift-app\n ports:\n - protocol: TCP\n port: 80\n targetPort: 8080\n type: ClusterIP\n\nPay attention to the probes.