2: Run Springboot Petstore with Docker and Docker Compose

I am following a tutorial in docker.com, but it did not work as expected without modification. It also contains many redundant directions to learn Docker. I summarized what I had done and confirmed in this post.

1) Clone Spring PetcClinic on the local directory where you want to store

git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic
echo "target" > .dockerignore
  1. git clone https://github.com/spring-projects/spring-petclinic.git

    • This command is used to clone a Git repository. In this case, it's cloning the Spring PetClinic project from the GitHub repository with the URL https://github.com/spring-projects/spring-petclinic.git. After running this command, you'll have a local copy of the project on your machine.
  2. cd spring-petclinic

    • This command changes the current working directory to the one just created by cloning the Spring PetClinic repository. In other words, it navigates into the directory named "spring-petclinic."
  3. echo "target" > .dockerignore

    • This command is used to create a file named ".dockerignore" and add the text "target" to it. The echo command is often used to print text to the terminal, but when used with the > operator, it redirects the output to a file instead. In this case, it's creating a file named ".dockerignore" with the content "target." The ".dockerignore" file is typically used to specify files or directories that should be excluded when building a Docker image. In this case, it's telling Docker to ignore the "target" directory.

2) Create volumes and network to persist the data in the repository

docker volume create mysql_data
docker network create mysqlnet
  1. docker volume create mysql_data

    • This command creates a Docker volume named "mysql_data." Docker volumes are used to persist data generated by Docker containers. In this case, it's likely being created to store data related to a MySQL container, such as databases or configuration files.
  2. docker network create mysqlnet

    • This command creates a Docker network named "mysqlnet." Docker networks allow containers to communicate with each other. By creating a dedicated network, you can isolate communication between containers, which can be useful for organizing and securing your Dockerized applications. In this case, it seems like the network is being set up for containers related to MySQL, perhaps for better management and communication between MySQL containers.

3) Run a container of MySQL

docker run -it --rm -d -v mysql_data:/var/lib/mysql \
-v mysql_config:/etc/mysql/conf.d \
--network mysqlnet \
--name mysqlserver \
-e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic \
-e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic \
-p 3306:3306 mysql:8.0
  1. docker run

    • This is the command used to run a Docker container based on a specified image.
  2. -it

    • This option makes the container run in interactive mode and allocates a pseudo-TTY. It's often used when you want to interact with the container's shell.
  3. --rm

    • This option automatically removes the container when it exits. It's useful for temporary or disposable containers.
  4. -d

    • This option runs the container in the background (detached mode).
  5. -v mysql_data:/var/lib/mysql

    • This creates a Docker volume named "mysql_data" and mounts it to the "/var/lib/mysql" directory inside the container. It's used for persisting the MySQL data.
  6. -v mysql_config:/etc/mysql/conf.d

    • This creates a Docker volume named "mysql_config" and mounts it to the "/etc/mysql/conf.d" directory inside the container. It's used for providing custom MySQL configuration.
  7. --network mysqlnet

    • This connects the container to the Docker network named "mysqlnet," allowing it to communicate with other containers on the same network.
  8. --name mysqlserver

    • This assigns the name "mysqlserver" to the running container for easy reference.
  9. -e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic

    • These environment variables are passed to the MySQL container. They set up the initial user, password, root password, and database name during the MySQL container initialization.
  10. -p 3306:3306

    • This maps port 3306 on the host to port 3306 on the container. It allows external applications to connect to the MySQL server running inside the container.
  11. mysql:8.0

    • This specifies the Docker image to use for running the container, in this case, MySQL version 8.0.

In summary, this docker run command creates and runs a detached MySQL container with specific configurations, volumes for data and configuration, and network connections for communication. The MySQL server is configured with a user, password, root password, and a specific database name.

4) Create a docker file to run the spring boot java app

touch Dockerfile

The touch command is commonly used to update the access and modification timestamp of a file, but if the file doesn't exist, it will create an empty file with the specified name.

After running this command, you'll have an empty "Dockerfile" in the directory where the command was executed.

5) Copy the following into the docker file.

I did it with Vim as follows.

vim Dockerfile

In Vim, you can input anything by typing 'i'. You can copy anything by right-clicking on the mouse.

You can escape any command in Vim by typing 'esc',. You can save and quit the file by typing ':' + 'wq' + 'enter'. If you don't want to save anything and quit, click ':' + 'q' + '!'.

Here is the content of the docker file.

# syntax=docker/dockerfile:1

FROM eclipse-temurin:17-jdk-jammy

WORKDIR /app

COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:resolve

COPY src ./src
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.profiles=mysql"]
  1. # syntax=docker/dockerfile:1

    • This line specifies the Dockerfile syntax version to be used. In this case, it's using version 1 of the syntax. This declaration helps Docker understand how to parse and process the Dockerfile.
  2. FROM eclipse-temurin:17-jdk-jammy

    • This line sets the base image for the Dockerfile. It specifies that the image should be based on the "eclipse-temurin" image with JDK 17, and it uses the "jammy" distribution. This base image likely includes the necessary Java runtime environment for running the Spring Boot application.
  3. WORKDIR /app

    • This line sets the working directory inside the container to "/app." Subsequent commands in the Dockerfile will be executed relative to this directory.
  4. COPY .mvn/ .mvn

    • This command copies the ".mvn/" directory from the local build context (the directory where the Dockerfile is located) to the "/app/.mvn/" directory inside the container.
  5. COPY mvnw pom.xml ./

    • This command copies the "mvnw" script and "pom.xml" file from the local build context to the root directory inside the container.
  6. RUN ./mvnw dependency:resolve

    • This command runs the "mvnw" script inside the container, specifically executing the "dependency:resolve" Maven goal. This step resolves the project dependencies and downloads them into the container.
  7. COPY src ./src

    • This command copies the "src" directory (which likely contains the source code of the Spring Boot application) from the local build context to the "/app/src/" directory inside the container.
  8. CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.profiles=mysql"]

    • This line specifies the default command to run when a container based on this image is started. It runs the "spring-boot:run" Maven goal using the "mvnw" script and specifies the "mysql" profile.

In summary, this Dockerfile sets up a container environment for a Spring Boot application, including copying source code, resolving dependencies, and specifying the command to run the application. It is designed to be used with Maven and JDK 17.

6) Run the docker of the app

docker run --rm -d --name springboot-server --network mysqlnet -e MYSQL_URL=jdbc:mysql://mysqlserver/petclinic -p 8080:8080 java-docker
  1. docker run

    • This is the command used to run a Docker container based on a specified image.
  2. --rm

    • This option automatically removes the container when it exits. It's useful for disposable containers.
  3. -d

    • This option runs the container in the background (detached mode).
  4. --name springboot-server

    • This assigns the name "springboot-server" to the running container for easy reference.
  5. --network mysqlnet

    • This connects the container to the Docker network named "mysqlnet," allowing it to communicate with other containers on the same network.
  6. -e MYSQL_URL=jdbc:mysql://mysqlserver/petclinic

    • This sets an environment variable named "MYSQL_URL" inside the container with the JDBC URL pointing to the MySQL server. This environment variable is likely used by the Spring Boot application to connect to the MySQL database.
  7. -p 8080:8080

    • This maps port 8080 on the host to port 8080 on the container. It allows external applications to connect to the Spring Boot application running inside the container.
  8. java-docker

    • This specifies the Docker image to use for running the container, in this case, an image named "java-docker." This image likely contains a Spring Boot application written in Java.

In summary, this docker run command creates and runs a detached container named "springboot-server." The container is connected to the "mysqlnet" network, and it has an environment variable set for the MySQL connection URL. Additionally, it exposes port 8080 on the host to allow external access to the Spring Boot application. The image used for this container is based on the "java-docker" image, which presumably contains the Spring Boot application code.

Access localhost:8080 with a browser to check if the app is running. You can see the following page.

When you want to stop the docker containers, stop them with the following command. You can delete those only by stopping them because you set the -rm option when you run them.

docker stop $(docker ps -a -q)
  1. docker ps -a -q

    • This part of the command lists the IDs of all Docker containers, both running and stopped (-a flag includes all containers, and -q flag displays only the container IDs).
  2. $(...)

    • This is a command substitution. The output of the command inside the parentheses (docker ps -a -q) will be used as arguments for the outer command.
  3. docker stop $(docker ps -a -q)

    • This part of the command stops all Docker containers by taking the container IDs obtained from the docker ps -a -q command and passing them as arguments to the docker stop command.

If you want to delete all containers, change "stop" to "rm" in the above command.

Multi-stage Dockerfile for development

7) Create a new docker file to create and run containers

rm Dockerile
vim Dockerfile

8) Copy the following into the docker file

# syntax=docker/dockerfile:1

FROM eclipse-temurin:17-jdk-jammy as base
WORKDIR /app
COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:resolve
COPY src ./src

FROM base as development
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.profiles=mysql", "-Dspring-boot.run.jvmArguments='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000'"]

FROM base as build
RUN ./mvnw package

FROM eclipse-temurin:17-jre-jammy as production
EXPOSE 8080
COPY --from=build /app/target/spring-petclinic-*.jar /spring-petclinic.jar
CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/spring-petclinic.jar"]
  1. Base Stage (base):

    • Set the base image using Eclipse Temurin JDK 17 with the "jammy" distribution.

    • Set the working directory inside the container to "/app."

    • Copy the ".mvn/" directory to "/app/.mvn/" in the container.

    • Copy the "mvnw" script and "pom.xml" file to the root directory in the container.

    • Run the "mvnw" script to resolve project dependencies.

    • Copy the "src" directory to "/app/src/" in the container.

  2. Development Stage (development):

    • Use the "base" image as a starting point.

    • Set the default command to run when the container starts: ./mvnw spring-boot:run -Dspring-boot.run.profiles=mysql -Dspring-boot.run.jvmArguments='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000'

  3. Build Stage (build):

    • Use the "base" image as a starting point.

    • Run the "mvnw" script to build the Spring Boot application using the "package" goal.

  4. Production Stage (production):

    • Set a production image using Eclipse Temurin JRE 17.

    • Expose port 8080 inside the container.

    • Copy the JAR file generated in the "build" stage to the root directory in the production image.

    • Set the default command to run the Spring Boot application using the JAR file.

In summary, this Dockerfile is structured into multiple stages to support development, building, and production deployment of a Spring Boot application. The development stage allows running the application in debug mode, the build stage compiles the application, and the production stage creates a lightweight image for running the built JAR file.

9) Create Docker Compose configuration file.

vim docker-compose.dev.yml

Here is the content.

version: '3.8'
services:
  petclinic:
    build:
      context: .
      target: development
    ports:
      - "8000:8000"
      - "8080:8080"
    environment:
      - SERVER_PORT=8080
      - MYSQL_URL=jdbc:mysql://mysqlserver/petclinic
    volumes:
      - ./:/app
    depends_on:
      - mysqlserver

  mysqlserver:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=
      - MYSQL_ALLOW_EMPTY_PASSWORD=true
      - MYSQL_USER=petclinic
      - MYSQL_PASSWORD=petclinic
      - MYSQL_DATABASE=petclinic
    volumes:
      - mysql_data:/var/lib/mysql
      - mysql_config:/etc/mysql/conf.d
volumes:
  mysql_data:
  mysql_config:
  1. Version and Services:

    • Specifies the version of the Docker Compose file (version 3.8).

    • Begins the definition of services.

  2. Service: petclinic

    • Defines a service named "petclinic."

    • Specifies the build configuration using the current context (.) and the target stage "development" defined in the Dockerfile.

    • Maps ports 8000 and 8080 from the host to the corresponding ports inside the container.

    • Sets environment variables for the Spring Boot application, such as the server port and MySQL connection URL.

    • Mounts the current directory into the "/app" directory in the container.

    • Specifies that this service depends on the "mysqlserver" service.

  3. Service: mysqlserver

    • Defines a service named "mysqlserver."

    • Specifies to use the MySQL 8.0 image from Docker Hub.

    • Maps port 3306 from the host to the corresponding port inside the container.

    • Sets environment variables for MySQL configuration, including an empty root password, a user named "petclinic," and a database named "petclinic."

    • Mounts volumes for MySQL data and configuration.

  4. Volumes:

    • Defines named volumes "mysql_data" and "mysql_config" that can be used to persist data for the MySQL service.

In summary, this Docker Compose configuration sets up two services ("petclinic" and "mysqlserver") for a Spring Boot application and a MySQL database, respectively. It includes configurations for port mappings, environment variables, and volume mounts to ensure proper functioning and persistence of data. The "petclinic" service depends on the "mysqlserver" service.

10) Start Docker containers based on the configurations

docker compose -f docker-compose.dev.yml up --build
  • docker-compose: Invokes the Docker Compose command-line tool.

  • -f docker-compose.dev.yml: Specifies the Docker Compose configuration file to use, in this case, "docker-compose.dev.yml."

  • up: This command is used to start the services defined in the Docker Compose file.

  • --build: This option instructs Docker Compose to rebuild images even if they are already up-to-date. It ensures that the images are freshly built based on the latest code and configurations.

So, when you run this command, Docker Compose will read the configurations from "docker-compose.dev.yml," start the specified services (petclinic and mysqlserver), and rebuild the images if necessary.

Keep in mind that the success of this command depends on having Docker Compose installed and configured on your system, as well as having the necessary dependencies specified in your Docker Compose file. If there are any issues during the build or startup process, they will be displayed in the console.