Runway
Runway is built and operated in the EU!

Kotlin (ktor)

First steps

Let’s build an application with Kotlin and the ktor framework. The application will respond to the / and /hello-world routes and listen on port 5000 by default.

Setup

initialize a new project with gradle:

# create a directory
$ mkdir ./new-project && cd new-project
$ gradle init \
--type kotlin-application \
--dsl kotlin \
--project-name runway \
--package main \
--incubating

Example app

Once the project is created, you have to edit app/src/main/kotlin/main/App.kt and replace it with the following:

app/src/main/kotlin/main/App.kt
package main

import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

fun main() {
    // Get the port from the environment variable or use 5000 as default
    val port = System.getenv("PORT")?.toIntOrNull() ?: 5000

    // Start the Ktor server
    embeddedServer(Netty, port) {
        routing {
            get("/") {
                call.respondText("Hello")
            }
            get("/hello-world") {
                call.respondText("Hello World")
            }
        }
    }.start(wait = true)
}

The next step is to update the app/build.gradle.kts so we can build and run our app:

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.8.10"
    id("io.ktor.plugin") version "2.3.12"
    application
}

repositories {
    mavenCentral()
    gradlePluginPortal()
}

dependencies {
    implementation("io.ktor:ktor-server-core-jvm")
    implementation("io.ktor:ktor-server-netty-jvm")
}

application {
    mainClass.set("main.AppKt")
}

Now run: ./gradlew build and it should complete. Feel free to test your app with ./gradlew run too and go to http://localhost:3000/hello-world.

Building

Add the following multi-stage Dockerfile to your repository:

Dockerfile
FROM gradle:8.0-jdk17 AS build

WORKDIR /workspace

# Copy the Gradle wrapper and build files
COPY app/build.gradle.kts settings.gradle.kts ./
# Copy the source code
COPY app/src ./src

RUN gradle installDist

FROM openjdk:17-jdk-slim
WORKDIR /app

# Set the user to nobody (in numeric)
USER 65534:65534

# Copy the app from the build stage
COPY --from=build /workspace/build/install/runway /app

EXPOSE 3000

CMD ["/app/bin/runway"]

The Dockerfile follows a common pattern when getting a project build and deployed: the first stage (build) is used to install all dependencies and compile the application with gradle installDist.

The second (final) stage uses a smaller image and copies the application from build and instructs Runway with a USER and a port (EXPOSE).

Create the app on Runway (this also initializes a git repository, if none exists yet), then commit your changes:

runway app create
git add -A
git commit -m "initial commit"

Deploy to Runway

runway app deploy

Run runway app open to see it live, or check the Runway UI. Check runway app logs if something’s off.

Congrats, your Kotlin app is running on Runway! ☕️