Skip to main content

Dockerizing the Ktor server

·3 mins

I will admit. I don’t know everything about Docker. I watched a couple of videos and played around with it but I don’t have extensive experience.

However, I understand the basic concepts and I am aware of its benefits to projects like this.

Docker provides consistent environments, which means I don’t have to worry about env setups and differences between development and production.

It is isolated from other applications and system dependencies, so I don’t have to worry about what version of Java is installed on the server and does that version conflicts with other applications that I may want to run.

It is portable. I can run it on my machine and it will run the same way on cloud providers hopefully.

These reasons are enough for me to dockerize my project. Also ktor documentation is quite well and can guide me through the process.

Before starting to dockerize the project, the generated ktor project provides some useful gradle tasks to use docker. In the README file you will find some of those tasks.

TaskDescription
./gradlew testRun the tests
./gradlew buildBuild everything
buildFatJarBuild an executable JAR of the server with all dependencies included
buildImageBuild the docker image to use with the fat JAR
publishImageToLocalRegistryPublish the docker image locally
runRun the server
runDockerRun using the local docker image

You can fiddle around with those to test your docker environment. I’ve already installed docker and docker desktop. So, we can start.

As I’ve said the ktor documentation is quite good. https://ktor.io/docs/docker-compose.html#build-run

I created the DockerFile. It setups gradle dependencies, builds application and creates a runtime image. We need to place this file at the root directory of the project.

# Stage 1: Cache Gradle dependencies
FROM gradle:latest AS cache
RUN mkdir -p /home/gradle/cache_home
ENV GRADLE_USER_HOME /home/gradle/cache_home
COPY build.gradle.* gradle.properties /home/gradle/app/
COPY gradle /home/gradle/app/gradle
WORKDIR /home/gradle/app
RUN gradle clean build -i --stacktrace

# Stage 2: Build Application
FROM gradle:latest AS build
COPY --from=cache /home/gradle/cache_home /home/gradle/.gradle
COPY . /usr/src/app/
WORKDIR /usr/src/app
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
# Build the fat JAR, Gradle also supports shadow
# and boot JAR by default.
RUN gradle buildFatJar --no-daemon

# Stage 3: Create the Runtime Image
FROM amazoncorretto:22 AS runtime
EXPOSE 8080
RUN mkdir /app
COPY --from=build /home/gradle/src/build/libs/*.jar /app/ktor-docker-sample.jar
ENTRYPOINT ["java","-jar","/app/ktor-docker-sample.jar"]

Next step is creating a docker compose file. It is in yaml format. It is really simple because we only have one application at the moment. If you want to edit the ports, remember to edit the exposed ports in DockerFile as well.

services:
  web:
    build: .
    ports:
      - "8080:8080"

If you are following along the steps with me, I really recommend using the IntelliJ IDE and Docker plugin. You can run the docker compose services individually and monitor the states of the images and containers in docker. It will be especially useful when we will integrate a database.

I am not done with docker configurations but this was a good start for the project.