Continuous Delivery to Kubernetes with jib, skaffold and ktor

Every new software feature is probably meant for production. The sooner your Continuous Delivery pipeline brings it to production, the sooner you can get customer feedback.

Reducing this lead time to production is the goal of many Continuous Delivery systems. This post shows how every saved code change is delivered to a production like environment within seconds. The target environment is kubernetes – the application is based on ktor and kotlin.

Ktor is a kotlin framework for building asynchronous servers. Kubernetes is a container-orchestration system. Jib makes containerizing a ktor application via gradle easy. Jib became general available earlier this week and integrates well with skaffold.

The above mentioned technologies are part of this project’s tech stack:

The application code is based on a simple ktor hello world app:

    install(Routing) {
        get("/") {
            call.respondText("hello", ContentType.Text.Html)
        }
    }
https://github.com/lotharschulz/ktorjib/blob/master/src/main/kotlin/info.ls.ktorjib/Main.kt#L13-L21

Jib enables you to build docker images for java applications without a docker file. You can define docker images as part of gradle kotlin DSL definitions:

container {
        ports = listOf("8080")
        mainClass = main_class

        jvmFlags = listOf(
                "-server",
                "-Djava.awt.headless=true",
                "-XX:+UnlockExperimentalVMOptions",
                "-XX:+UseCGroupMemoryLimitForHeap",
                "-XX:InitialRAMFraction=2",
                "-XX:MinRAMFraction=2",
                "-XX:MaxRAMFraction=2",
                "-XX:+UseG1GC",
                "-XX:MaxGCPauseMillis=100",
                "-XX:+UseStringDeduplication"
        )
    }
https://github.com/lotharschulz/ktorjib/blob/master/build.gradle.kts#L43-L62

Also you can define JVM args as part of gradle kotlin DSL definitions:

    applicationDefaultJvmArgs = listOf(
            "-server",
            "-Djava.awt.headless=true",
            "-Xms128m",
            "-Xmx256m",
            "-XX:+UseG1GC",
            "-XX:MaxGCPauseMillis=100"
https://github.com/lotharschulz/ktorjib/blob/master/build.gradle.kts#L19-L25

Last preparation step before you can ship the project to kubernetes is to make sure docker, minikube and skaffold are installed.

Now, you can make skaffold watch your code directory and deploy changes to minikube. Just issue

skaffold dev

in your terminal.

Whenever your code changes, skaffold applies the changes to your cluster. The screen cast below uses a simple integration test bash script (web.sh) to verify the changed functionality.

#!/bin/bash
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -euo pipefail
IFS=$'\n\t'

while :
do
        echo "curl http://127.0.0.1:8080/: "
        curl http://127.0.0.1:8080/ || true
        echo " "
        sleep 4s
done
https://www.youtube.com/watch?v=T-Ed_tbi1f8 best view in full screen

Conclusion

You can deploy to Kubernetes and thus test your code changes within seconds with the above setup. This reduces lead time to production significantly and provides faster feedback.

Lothar Schulz

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.