Home > front end >  How to setup a docker-compose springboot webserver/mysql project using gradle and Kotlin inside inte
How to setup a docker-compose springboot webserver/mysql project using gradle and Kotlin inside inte

Time:09-27

I have been struggling setting up a new project for weeks. Desired project properties:

Goals:

  • Springboot 2.7.3 Kotlin and Gradle
  • Java 18 or Kotlin SDK
  • MySQL Latest
  • Gradle Latest
  • IDE Intellij Latest
  • Docker Compose on WSL, web server and db server (with working communication link)
  • Hot reload and other development tool features working.
  • NPM where required for package management.

Problems

  • One of the problems I am finding is that I have way to many ways to start the application; npm start, gradle bootrun, docker-compose up app and others. I don't know when to use each and each doesn't seem to fully function for a good dev setup.
  • mysql connection issues are constant, seems different configs are required depending how the app is started.
  • application.yml, I'm not confident when this is being used in each run configuration.

The Application Very simple hello world REST API, simple hello world DB tables, JPA, spring web, lombok.

application.yml

development: true
server:
  port: '8080'
  servlet:
    context-path: /api
spring:
  datasource:
    url: 'jdbc:mysql://localhost:3306/farnsworthy'
    username: farnsworthy
    password: password
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.MySQL8Dialect
  sql:
    init:
      mode: always

Dockerfile

FROM openjdk:18-alpine
WORKDIR /app
LABEL maintainer="[email protected]"
VOLUME /main-app
ADD build/libs/farnsworthy-pics-backend-0.0.1-SNAPSHOT.jar /app/app.jar
ADD /src/main/resources/application.properties /app/application.properties
EXPOSE 8080 5005
ENTRYPOINT ["java", "-Dspring.config.location=/app/application-properties", "-jar","/app/app.jar"]

Docker-compose.yml

version: '3.8'
services:
  api_service:
    build: .
    container_name: api_service
    restart: always
    ports:
      - "8080:8080"
      - "5005:5005"
    depends_on:
      - mysql_db
    command: sh -c './wait-for mysql_db:3306 -- npm start'
  mysql_db:
    image: "mysql:8.0"
    container_name: mysql_db
    restart: always
    ports:
      - "3306:3306"
    expose:
      - "3306"
    environment:
      MYSQL_DATABASE: farnsworthy
      MYSQL_USER: farnsworthy
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: password

build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "2.7.3"
    id("io.spring.dependency-management") version "1.0.13.RELEASE"
    id("idea")
    kotlin("jvm") version "1.6.21"
    kotlin("plugin.spring") version "1.6.21"
    kotlin("plugin.jpa") version "1.6.21"
}

group = "com.farnsworthy.pics"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}


dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-data-rest")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    //implementation("org.springframework.data:spring-data-rest-hal-explorer")
    compileOnly("org.projectlombok:lombok")
    implementation("org.springframework.boot:spring-boot-devtools")
    runtimeOnly("mysql:mysql-connector-java")
    annotationProcessor("org.projectlombok:lombok")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "18"
    }

}

tasks.withType<Test> {
    useJUnitPlatform()
}

CodePudding user response:

I'm having a bit of a hard time understanding your project structure, but I'll make assumptions:

In production you have two processes:

  1. A spring boot application which also serves the frontend (npm part)
  2. A MySQL database.

If thats so then how I would do in dev is have three separare things:

  1. Only MySQL running in docker.
  2. Backend will be started with Gradle or from IntelliJ from Kotlins main function with Run/Debug. It might serve built frondend too, but that's not the one you'll be using in dev environment.
  3. Frontend will be started separately with npm start and you can configure it from package.json to proxy to your backend port in dev.

Now if you want to build for production you might want to extend your Gradle script to invoke npm build also (Check this out: https://github.com/srs/gradle-node-plugin/). And if all is built, it is a single JAR file which can be smashed into one single docker container, because in reality in production your app will be in a single process, except the database.

Trying to get it all in-docker-single-build-works-with-IDE is too much IMHO because you often times don't even need to spin up the whole stack to develop something.

Also spinning things up separately in dev gives you lot more flexibility. You can run any random combinations of backend/frontend (one in debug mode, other with "watch" for example). If you'd do it through docker-compose, it would be a lot harder.

  • Related