Docker

Docker is a container platform: it allows packaging software in a format that can then be run in isolation in any supported operating system.

Publishing a Ktor application to docker is very easy and only takes a few steps:

  • Install

  • A JAR packaging tool

In this page we will guide you through creating a docker image and publishing an application to it.

In this tutorial, we will use the Gradle shadow plugin. It packages all the output classes, resources, and all the required dependencies into a single JAR file, and appends a manifest file to tell Java which is the entry-point main class containing the main method.

First, you need to add the shadow plugin dependency in your file:

After that, you have to apply it, along with the application plugin:

  1. apply plugin: "com.github.johnrengelman.shadow"
  2. apply plugin: 'application'

Then specify the main class, so it knows what to run when running the java’s JAR inside Docker:

  1. mainClassName = 'org.sample.ApplicationKt'

The string is the fully qualified name of the class containing your main function. When main function is a top-level function in a file, the class name is the file name with the Kt suffix. In the example above, main function is in the file Application.kt in package org.sample.

Finally, you have to configure the shadow plugin:

  1. baseName = 'my-application'
  2. classifier = null
  3. version = null
  4. }

For more information about configuring this plugin see

So a full build.gradle file would look like this:

Gradle

application.conf

Application.kt

Docker - 图3

note

You can check this at the ktor-samples repository.

In the root folder of your project create a file named Dockerfile with the following contents:

  1. FROM openjdk:8-jre-alpine
  2. ENV APPLICATION_USER ktor
  3. RUN adduser -D -g '' $APPLICATION_USER
  4. RUN mkdir /app
  5. RUN chown -R $APPLICATION_USER /app
  6. COPY ./build/libs/my-application.jar /app/my-application.jar
  7. WORKDIR /app
  8. CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:InitialRAMFraction=2", "-XX:MinRAMFraction=2", "-XX:MaxRAMFraction=2", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "my-application.jar"]

Let’s see what is what:

This line tells Docker to base an image on a pre-built image with Alpine Linux. You can use other images from . Alpine Linux benefit is that the image is pretty small. We also select JRE-only image since we don’t need to compile code on the image, only run precompiled classes.

  1. RUN mkdir /app
  2. COPY ./build/libs/my-application.jar /app/my-application.jar
  3. WORKDIR /app

The last line instructs Docker to run java with G10s GC, 4G of memory and your packaged application.

Build an application package:

  1. ./gradlew build

Build and tag an image:

  1. docker build -t my-application .

Start an image:

  1. docker run -m512M --cpus 2 -it -p 8080:8080 --rm my-application

With this command, we start Docker in a foreground mode. It will wait for the server to exit, it will also respond to Ctrl+C to stop it. -it instructs Docker to allocate a terminal (tty) to pipe the stdout and to respond to the interrupt key sequence.

Since our server is running in an isolated container now, we should tell Docker to expose a port so we can actually access the server port. Parameter -p 8080:8080 tells Docker to publish port 8080 from inside a container as a port 8080 on a local machine. Thus, when you tell your browser to visit localhost:8080 it will first reach out to Docker, and it will bridge it into internal port 8080 for your application.

You can adjust memory with -m512M and number of exposed cpus with --cpus 2.

By default, a container’s file system persists even after the container exits, so we supply --rm option to prevent garbage piling up.

For more information about running a docker image please consult docker run documentation.

Once your application is running locally successfully, it might be a time to deploy it:

These commands will tag your application for a registry and push an image. Of course, you need to replace hub.example.com/docker/registry/tag with an actual URL for your registry.

We won’t go into details here since your configuration might require authentication, specific configuration options and even special tools. Please consult your organization or cloud platform, or check documentation.