Ktor 2.0.3 Help

Docker Compose

In this topic, we'll show how to run a server Ktor application under Docker Compose. We'll be using a project created in Adding persistence to a website, which uses Exposed to connect to an H2 file database. In this topic, we'll replace H2 with a PostgreSQL database running as a separate db service, while the Ktor application will be running as a web service.

Get the application ready

Add PostgreSQL dependency

First, you need to add dependencies for the PostgreSQL library. Open the gradle.properties file and specify library versions:

postgresql_version = 42.3.0

Then, open build.gradle.kts and add the following dependencies:

val postgresql_version: String by project dependencies { implementation("org.postgresql:postgresql:$postgresql_version") }

Connect to a database

The tutorial-website-interactive-persistence sample uses hardcoded driverClassName and jdbcURL in the com/example/dao/DatabaseFactory.kt file to establish a database connection. Let's extract connection settings for the PostgreSQL database to a custom configuration group. Open the src/main/resources/application.conf file and add the storage group outside the ktor group as follows:

storage { driverClassName = "org.postgresql.Driver" jdbcURL = "jdbc:postgresql://db:5432/ktorjournal?user=postgres" }

Note that jdbcURL includes the following components:

  • db:5432 is a host and port on which the PostgreSQL database is running.

  • ktorjournal is the name of the database created when running services.

These settings will be configured later in the docker-compose.yml file.

Open com/example/dao/DatabaseFactory.kt and update the init function to load storage settings from the configuration file:

fun init(config: ApplicationConfig) { val driverClassName = config.property("storage.driverClassName").getString() val jdbcURL = config.property("storage.jdbcURL").getString() val database = Database.connect(jdbcURL, driverClassName) transaction(database) { SchemaUtils.create(Articles) } }

The init function now accepts ApplicationConfig and uses config.property to load custom settings.

Finally, open com/example/Application.kt and pass environment.config to DatabaseFactory.init to load connection settings on application startup:

fun Application.module() { DatabaseFactory.init(environment.config) configureRouting() configureTemplating() }

Configure the Shadow plugin

In order to run on Docker, the application needs to have all the required files deployed to the container. Depending on the build system you're using, there are different plugins to accomplish this:

For example, to apply the Shadow plugin, open the build.gradle.kts file and add the shadow plugin to the plugins block:

plugins { application kotlin("jvm") id("com.github.johnrengelman.shadow") version "7.1.2" }

Configure Docker

Prepare Docker image

To dockerize the application, create the Dockerfile in the root of the project and insert the following content:

FROM openjdk:11 EXPOSE 8080:8080 RUN mkdir /app COPY ./build/libs/*.jar /app/ktor-docker-sample.jar ENTRYPOINT ["java","-jar","/app/ktor-docker-sample.jar"]

Note that this Dockerfile requires creating a fat JAR before running docker compose up. To learn how to use multi-stage builds to generate an application distribution using Docker, see Prepare Docker image.

Configure Docker Compose

Create the docker-compose.yml in the root of the project and add the following content:

services: web: build: . ports: - "8080:8080" depends_on: db: condition: service_healthy db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data environment: POSTGRES_DB: ktorjournal POSTGRES_HOST_AUTH_METHOD: trust ports: - "54333:5432" healthcheck: test: [ "CMD-SHELL", "pg_isready -U postgres" ] interval: 1s
  • The web service is used to run the Ktor application packaged inside the image.

  • The db service uses the postgres image to create the ktorjournal database for storing articles of our journal.

Build and run services

  1. Before running docker compose up, create a fat JAR containing a Ktor application:

    ./gradlew :tutorial-website-interactive-docker-compose:shadowJar
  2. Then, execute docker compose up...

    docker compose --project-directory snippets/tutorial-website-interactive-docker-compose up

    ... and wait until Docker Compose pulls/builds the images and starts containers. You can open http://localhost:8080/ in a browser to create, edit, and delete articles.

Last modified: 28 June 2022