Deploying Swift on Kubernetes: A Basic Guide for Developers

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 Swift and Kubernetes?

Swift is not just a language for iOS and macOS. Thanks to the Swift on Server project and frameworks like Vapor and SwiftNIO, Swift developers can build high-performance server-side applications. However, for such an application to run stably and scale, a modern infrastructure is required.

Kubernetes (K8s) is the de facto standard for container orchestration. In this guide, we will show how to package a Swift application into a Docker image, write Kubernetes manifests, and deploy it in a cluster. You will learn how to use SwiftNIO to create a lightweight HTTP server and configure it for cloud deployment.



1. Preparing the Swift Application for Containerization

1.1. Creating a SwiftNIO Project

For demonstration, we will write a minimal HTTP server using SwiftNIO. This avoids unnecessary dependencies and shows how low-level networking works. Open a terminal and create a new project:

mkdir SwiftK8sDemocd SwiftK8sDemoswift package init --type executable

Add the SwiftNIO dependency to Package.swift:

// swift-tools-version:5.7import PackageDescription

let package = Package( name: "SwiftK8sDemo", dependencies: [ .package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0") ], targets: [ .executableTarget( name: "SwiftK8sDemo", dependencies: [ .product(name: "NIO", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio") ] ) ])


1.2. Server Code with Health Check

Let's create a simple server that responds to GET requests and has a health check endpoint (/health). This is necessary for Kubernetes liveness probes. Replace the contents of Sources/SwiftK8sDemo/main.swift:

import NIOimport NIOHTTP1

final class HTTPHandler: ChannelInboundHandler { typealias InboundIn = HTTPServerRequestPart typealias OutboundOut = HTTPServerResponsePart

func channelRead(context: ChannelHandlerContext, data: NIOAny) { let req = unwrapInboundIn(data) switch req { case .head(let header): let response: String let status: HTTPResponseStatus if header.uri == "/health" { response = "{\\"status\\":\\"ok\\"}" status = .ok } else { response = "Hello from Swift on K8s!" status = .ok } var buffer = context.channel.allocator.buffer(capacity: response.utf8.count) buffer.writeString(response) let head = HTTPResponseHead(version: .init(major: 1, minor: 1), status: status) context.write(wrapOutboundOut(.head(head)), promise: nil) context.write(wrapOutboundOut(.body(.byteBuffer(buffer))), promise: nil) context.writeAndFlush(wrapOutboundOut(.end(nil)), promise: nil) default: break } }}

let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)defer { try! group.syncShutdownGracefully() }

let bootstrap = ServerBootstrap(group: group) .serverChannelOption(ChannelOptions.backlog, value: 256) .serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1) .childChannelInitializer { channel in channel.pipeline.configureHTTPServerPipeline().flatMap { channel.pipeline.addHandler(HTTPHandler()) } }

let host = ProcessInfo.processInfo.environment["HOST"] ?? "0.0.0.0"let port = Int(ProcessInfo.processInfo.environment["PORT"] ?? "8080") ?? 8080

print("Server starting on \\(host):\\(port)")try bootstrap.bind(host: host, port: port).wai

Blogs

Book Recommendations