Search code examples
javadockerkotlinflywayktor

Flyway unrecognised migration name format when run in docker


When run from the IDE the migrations are fine

Output:

INFO: Successfully applied 1 migration to schema `db`, now at version v1

But when I run the application from a container then Output:

example  | Exception in thread "main" 
example  | org.flywaydb.core.api.FlywayException: Invalid SQL filenames found:
example  | Unrecognised migration name format: V1__Example.sql

I have tried different Java versions. Going into the container itself and looking at the migration file, it looked ok. Maybe I can get some ideas from here?

Example code to reproduce the problem:

Applikation.kt

package com.example
import com.mysql.cj.jdbc.MysqlDataSource
import com.typesafe.config.ConfigFactory
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import org.flywaydb.core.Flyway

fun main() {
    embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
        .start(wait = true)
}

fun Application.module() {
    val conf = ConfigFactory.load()
    val mysqlDataSource = MysqlDataSource()
    mysqlDataSource.setURL(conf.getString("database.url"))

    Flyway.configure().dataSource(
        mysqlDataSource
    )
        .validateMigrationNaming(true)
        .load()
        .migrate()
}

Dockerfile

FROM gradle:7-jdk11 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle buildFatJar --no-daemon

FROM eclipse-temurin:11-jdk
EXPOSE 8080:8080
RUN mkdir /app
COPY --from=build /home/gradle/src/build/libs/*.jar /app/x.jar
ENTRYPOINT ["java","-jar","/app/x.jar"]

docker-compose.yml

version: '3.5'
services:
  db:
    image: mysql:8.0
    container_name: db
    restart: always
    command: --default-authentication-plugin=caching_sha2_password
    environment:
      MYSQL_DATABASE: ${MYSQL_DB}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    ports:
      - ${MYSQL_PORT}:${MYSQL_PORT}
    expose:
      - ${MYSQL_PORT}
    healthcheck:
      test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
      interval: 5s
      timeout: 5s
      retries: 55
  api:
    image:  example:test
    container_name: example
    ports:
      - '8080:8080'
    expose:
      - '8080'
    env_file: .env
    depends_on:
      db:
        condition: service_healthy

dependencies

dependencies {
    implementation("io.ktor:ktor-server-core-jvm")
    implementation("io.ktor:ktor-server-netty-jvm")
    implementation("org.flywaydb:flyway-core:9.20.0")
    implementation("org.flywaydb:flyway-mysql:9.20.0")
    implementation("mysql:mysql-connector-java:8.0.33")
}

You can see the full code in https://github.com/Skarpton/flyway-docker-problem

Update:

It looks like in docker the program cannot find any ResourceTypeProvider. This means that there are no prefixes configured.

Code:

fun Application.module() {
    val conf = ConfigFactory.load()
    val mysqlDataSource = MysqlDataSource()
    mysqlDataSource.setURL(conf.getString("database.url"))

    val load = Flyway.configure().dataSource(
        mysqlDataSource
    )
        .validateMigrationNaming(true)
        .load()
    print(load.configuration.pluginRegister.getPlugins(ResourceTypeProvider::class.java)). //this is the interesting line
    load.migrate()

}

Outputs in ide:

[org.flywaydb.core.internal.resource.CoreResourceTypeProvider@2381b1e8]

In docker:

[]


Solution

  • The problem was with building the fat jar. The problem was that the necessary plugins were not added to the META-INF/services/org.flywaydb.core.extensibility.Plugin file. I fixed it by using the shadowjar plugin with the configuration mergeServiceFiles(). I pushed the fixed version to the original repo https://github.com/Skarpton/flyway-docker-problem