Search code examples
dockerkotlingradledocker-composektor

Running simple Kotlin Ktor app in docker container with PostgresSql database


I want to create simple Kotlin app that uses PostgresSql and Kotlin Ktor, everything should be embedded in docker container.

So far I managed to run separately PostgresSql and PgAdmin which connected to each other successfully and I created docker-compose.yml file for that that works fine form me. The problem starts when I want to add to it my Kotlin app.

Here is my docker-compose.yml file


version: "3.9"
networks:
  m8network:
    ipam:
      config:
        - subnet: 172.20.0.0/24
services:
  postgres:
    image: postgres
    environment:
      - "POSTGRES_USER=SomeFancyUser"
      - "POSTGRES_PASSWORD=pwd"
      - "POSTGRES_DB=MSC8"
    ports:
      - "5432:5432"
    volumes:
      #           - postgres-data:/var/lib/postgresql/data
      - D:\docker\myApp\data:/var/lib/postgresql/data
    networks:
      m8network:
        ipv4_address: 172.20.0.6
  pgadmin:
    image: dpage/pgadmin4
    depends_on:
      - postgres
    environment:
      - "[email protected]"
      - "PGADMIN_DEFAULT_PASSWORD=pwd"
    #           - "PGADMIN_ENABLE_TLS=False"
    ports:
      - "5001:80"
    networks:
      m8network:
  app:
    build: .
    ports:
      - "5000:8080"
    links:
      - postgres
    depends_on:
      - postgres
    restart: on-failure
    networks:
      m8network:
#volumes:
#    postgres-data:
#        driver: local

And heres is my app source code.


package com.something.m8

import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.sqlite.driver.asJdbcDriver
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import io.ktor.application.*
import io.ktor.html.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import kotlinx.html.*
import java.io.PrintWriter
import java.util.*


fun HTML.index() {
    head {
        title("Hello from Ktor!")
    }
    body {
        div {
            +"Hello from Ktor"
        }
    }
}

fun main() {
    println("starting app")
    val props = Properties()
    props.setProperty("dataSourceClassName", "org.postgresql.ds.PGSimpleDataSource")
    props.setProperty("dataSource.user", "SomeFancyUser")
    props.setProperty("dataSource.password", "pwd")
    props.setProperty("dataSource.databaseName", "M8")
    props.setProperty("dataSource.portNumber", "5432")
    props.setProperty("dataSource.serverName", "172.20.0.6")
    props["dataSource.logWriter"] = PrintWriter(System.out)
    println("a")
    val config = HikariConfig(props)
    println("b")

    val ds = HikariDataSource(config)
    println("c")
    val driver: SqlDriver = ds.asJdbcDriver()
    println("d")
    MSC8.Schema.create(driver)
    println("e")
    embeddedServer(Netty, port = 8080,
       // host = "127.0.0.1"
    ) {
        routing {
            get("/") {
                call.respondHtml(HttpStatusCode.OK, HTML::index)
            }
            get("/m8/{code}") {
                val code = call.parameters["code"]
                println("code $code")
                call.respondRedirect("https://google.com")
            }
        }
    }.start(wait = true)
}

And the Dockerfile for app


#FROM openjdk:8
FROM gradle:6.7-jdk8

WORKDIR /var/www/html
RUN mkdir -p ./app/
WORKDIR /var/www/html/app
COPY build.gradle.kts .
COPY gradle.properties .
COPY settings.gradle.kts .
COPY Redirect/src ./Redirect/src
COPY Redirect/build.gradle.kts ./Redirect/build.gradle.kts
COPY gradlew .
COPY gradle ./gradle
EXPOSE 8080

USER root
WORKDIR /var/www/html
RUN pwd
RUN ls
RUN chown -R gradle ./app
USER gradle
WORKDIR /var/www/html/app
RUN ./gradlew run

With this setup I have two problems

First problem:

When I run docker-compose.exe up --build I receive exception HikariPool$PoolInitializationException: Failed to initialize pool: The connection attempt failed. on line val ds = HikariDataSource(config) I set up static ip for postgres (172.20.0.6) and when I'm using this ip in PGAdmin it works so why my app cannot connect to the postgres?

Second problem:

I tried to test if app is starting properly and everything works fine in most basics. So I commented all source code related to the connection to the DB since that point when I run docker-compose.exe up --build my app displays only letter e from line println("e") and at this point everything seems to be frozen, postgres and PGAdming doesn't startup, and after that container seems to be unresponsive and app doesn't respond on port 5000 or 8080. Is there any way that I can run app so it won't block exectution of other parts?


Solution

  • First problem: I started using host name instead IP adress so now I'm using postgres instead 172.20.0.6. And the rest of it is connected to second problem

    Second problem:

    The issue was that I was starting the app during build phase of container.

    Instead RUN ./gradlew run I used

    RUN gradle build
    ENTRYPOINT ["gradle","run"]
    

    Also I noticed that I don't have to use gradle wrapper while I'm using FROM gradle:6.7-jdk8

    Now everyting is working fine.