Spring Boot in Docker doesn’t show new changes to code

I have a Spring Boot Kotlin Gradle app running in Docker, but after I added a new RestController, I only see a white label error page when I go to the URL (http://localhost:8080/users). The code I write doesn’t seem to be reflected in the Docker container, how can I fix this?

Controller

@RestController
@RequestMapping("/users")
class UserController {
    @GetMapping
    fun users(): String {
        return "bzbz 🐝";
    }
}

Dockerfile

# Use the official Gradle image with JDK 17 as the base image
FROM gradle:7.4.1-jdk17 AS builder

WORKDIR /app

COPY . .

RUN ./gradlew clean build -x test

EXPOSE 8080

CMD ["java", "-jar", "./build/libs/twitch-bot-0.0.1-SNAPSHOT.jar"]

compose.yml

version: '3'

services:
  mysql:
    image: 'mysql:latest'
    environment:
      - 'MYSQL_DATABASE=twitch-bot'
      - 'MYSQL_PASSWORD=secret'
      - 'MYSQL_ROOT_PASSWORD=secret'
      - 'MYSQL_HOST=localhost'
    ports:
      - '3306:3306'
  spring-boot-kotlin:
    depends_on:
      - mysql
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '8080:8080'

  • 3

    Are you rebuilding the container and restarting the compose network? You’re showing nothing that would do that automatically.

    – 

  • 1

    Also, if you use Spring Boot gradle plugin (if you’ve generated your project using spring starter, it does), you do not need your own Dockerfile. You can directly compile an up-to-date docker image using ./gradlew bootBuildImage. And as said by @jonrsharpe, any code change must be manually rebuilt and then you must update your docker-compose deployment (docker-compose up -d).

    – 

  • While I did see an issue with your docker-compose configuration, it would help a lot if you add some logs from the containers for questions like this. I helps in making sure that we can provide a solution for your problem from the best possible angle, Thank you!

    – 

I see a problem with your docker-compose configuration. you are not waiting until your mysql database becomes ready to be connected by your spring-boot service. For this to work all the time you need to wait until mysql is ready and you can do that like this:

services:
  mysql:
    image: 'mysql:latest'
    environment:
      - 'MYSQL_DATABASE=twitch-bot'
      - 'MYSQL_PASSWORD=secret'
      - 'MYSQL_ROOT_PASSWORD=secret'
      - 'MYSQL_HOST=localhost'
    ports:
      - '3306:3306'
    healthcheck:
      test: ["CMD-SHELL", "timeout 10s bash -c ':> /dev/tcp/127.0.0.1/3306'"]
      interval: 5s
      timeout: 240s
      retries: 60
  spring-boot-kotlin:
    depends_on:
      mysql:
        condition: service_healthy
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '8080:8080'

The point is that spring-boot-kotlin now waits until mysql is healthy. And docker-compose now knows this when port 3306 is ready and available. There are more evolved ways to check if the mysql is ready to accept connections, for example, checking if a user can log in or if certain tables are ready, etc, but those are advanced configurations. But for a start and to test, I think this could explain the problem you are facing.

To debug these situations, you can always use docker-compose logs or docker logs <CONTAINER_ID>. You can also get the CONTAINER_ID by listing your running containers with docker ps.

In our healthcheck implementations we check to see if the port 3306 is available every 5 seconds and we will try 60 times until the 240s timeout occurs. If mysql fails to start before the 240s, everything will fail and docker-compose will not be able to start letting immediately know when something isn’t right.

Leave a Comment