skip to Main Content

I am a Java backend developer and i want to dockerize the backend part in order for my front end college to easily run in on his local machine. I will describe my problem based on demo project. So the demo project consists out of mysql and a spring boot web app. The app is works fine when i am using docker-compose, all the dependecies are download before the start and the endpoint "test" is returning "Some message". The problem occurse when i change the code and docker-compose down and docker-compose up the app, the code isnt changing. What i can do to solve this problem is to package the app on local machine and then deliver it to docker, but then the local machine has to has maven in order to compile it, and i dont want that, i want my college just to use docker and dont care about how all this thing works. Another solution could be not to cache, but then the dependencies have to be downloaded every time we restart the app, that is also not acceptable. So my question is "Is there a way to cache the dependecies (to download it once) but not the code, so that when i am starting the app, a fresh app ,with updated code, would compile?" (Sorry for my english). Here is the demo project that i am testing on:

The controller:

@RestController
@RequestMapping("message")
@RequiredArgsConstructor
public class Controller {

    private final MessageRepository messageRepository;


    @GetMapping("/{id}")
    public Message getById(@PathVariable Long id) {
        return messageRepository.findById(id).get();
    }

    @PostMapping
    public Message save(@RequestBody Message message){
        return messageRepository.save(message);
    }

    @GetMapping("/test")
    public String ss(){
        return "Some message";
    }

}

The model:

@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "messages")
public class Message {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", nullable = false)
    private Long id;
    @Column(name = "text")
    private String text;
}

The repository:

@Repository
public interface MessageRepository extends JpaRepository<Message,Long> {}

property file:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=yes&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    username: root
    password: 123456789
    driver-class-name: com.mysql.cj.jdbc.Driver
    sql-script-encoding: UTF-8
  jpa:
    database-platform: org.hibernate.dialect.MySQL8Dialect
    hibernate:
      ddl-auto: create-drop

Docker file that is in root of the spring project:

FROM maven:3.8.4-jdk-11
WORKDIR /demo
COPY . .
RUN mvn clean install package -Dmaven.test.skip
CMD mvn spring-boot:run

Docker compose file:

version: "3.8"

services:
  mysqldb:
    image: mysql:8.0.27
    restart: unless-stopped
    environment:
      - MYSQL_DATABASE=db
      - MYSQL_ROOT_PASSWORD=123456789
    ports:
      - 3307:3306
    volumes:
      - db:/var/lib/mysql
  app:
    depends_on:
      - mysqldb
    build: ./demo
    ports:
      - 8080:8080
    environment:
      SPRING_APPLICATION_JSON: '{
        "spring.datasource.url"  : "jdbc:mysql://mysqldb:3306/db?useUnicode=yes&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
        "spring.datasource.username" : "root",
        "spring.datasource.password" : "123456789",
        "spring.jpa.database-platform" : "org.hibernate.dialect.MySQL8Dialect",
        "spring.jpa.hibernate.ddl-auto" : "update"
      }'
    volumes:
      - .:/root
    stdin_open: true
    tty: true

volumes:
  db:

3

Answers


  1. Chosen as BEST ANSWER

    I found the solution. In order to not download the dependencies, i need to cache them in upper layer and code in lower layer so that when i change the code, i dont have to redownload the dependencies. The docker file looks like this.

    FROM maven:3.8.4-jdk-11-slim
    WORKDIR /opt/app
    COPY pom.xml .
    RUN mvn dependency:go-offline
    COPY src/ src/
    RUN mvn clean install -Dmaven.test.skip=true
    ENTRYPOINT ["java", "-jar", "/opt/app/target/demo-0.0.1-SNAPSHOT.jar"]
    

    And as @valerij-dobler said i need to remove my container in order for my code changes to take effect

    docker-compose down && docker image rm -f myapp && docker-compose up -d
    

  2. The image for your app is built and it reuses the same image for every next docker-compose up.

    If you want to force the rebuild you could use docker-compose up --build. Alternatively, you could remove the image by hand. But first, you should name your image, by using this property:

    services:
      #...
      app:
        #...
        build: ./demo
        image: my_app
    

    then by using docker image rm my_app you could remove it. After that, the docker-compose up should rebuild your app.
    So you could give your frontend colleague following one-liner:

    docker image rm my_app && docker-compose up -d
    

    Note that -d runs the docker-compose detached from the terminal.

    Login or Signup to reply.
  3. 1.In your project create a jar. since i use eclipse i just click maven install or maven build to create jar.

    1. In your docker file you must specified the jar file.
    2. In your docker compose specify also the jar, where is the jar, jar file name, the port and etc . And this will create container for you application.

    4.Inorder to run with updated code you must use this comman for docker docker-compose -f dockercomposeYourFile.yaml up --build.

    1. If there is other container in you docker compose just use depends_on then if the conatiner need to wait and cause to stop you need restart: always or anything about restart
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search