Utiliser des conteneurs pour le développement Java
Prérequis
Parcourez les étapes pour conteneuriser votre application dans Conteneuriser votre application.
Aperçu
Dans cette section, vous allez parcourir la configuration d'un environnement de développement local pour l'application que vous avez conteneurisée dans la section précédente. Cela inclut :
- L'ajout d'une base de données locale et la persistance des données
- La création d'un conteneur de développement pour connecter un débogueur
- La configuration de Compose pour mettre à jour automatiquement vos services Compose en cours d'exécution au fur et à mesure que vous modifiez et enregistrez votre code
Ajouter une base de données locale et persister les données
Vous pouvez utiliser des conteneurs pour configurer des services locaux, comme une base de données. Dans cette section, vous allez mettre à jour le fichier docker-compose.yaml
pour définir un service de base de données et un volume pour persister les données. De plus, cette application particulière utilise une propriété système pour définir le type de base de données, vous devrez donc mettre à jour le Dockerfile
pour passer la propriété système lors du démarrage de l'application.
Dans le répertoire du dépôt cloné, ouvrez le fichier docker-compose.yaml
dans un IDE ou un éditeur de texte. Votre fichier Compose contient un exemple de service de base de données, mais il nécessitera quelques modifications pour votre application unique.
Dans le fichier docker-compose.yaml
, vous devez effectuer les opérations suivantes :
- Décommentez toutes les instructions de la base de données. Vous utiliserez maintenant un service de base de données au lieu du stockage local pour les données.
- Supprimez l'élément
secrets
de niveau supérieur ainsi que l'élément à l'intérieur du servicedb
. Cet exemple utilise la variable d'environnement pour le mot de passe plutôt que les secrets. - Supprimez l'élément
user
du servicedb
. Cet exemple spécifie l'utilisateur dans la variable d'environnement. - Mettez à jour les variables d'environnement de la base de données. Celles-ci sont définies par l'image Postgres. Pour plus de détails, consultez l' Image Docker officielle de Postgres.
- Mettez à jour le test de santé pour le service
db
et spécifiez l'utilisateur. Par défaut, le test de santé utilise l'utilisateur root au lieu de l'utilisateurpetclinic
que vous avez défini. - Ajoutez l'URL de la base de données comme variable d'environnement dans le service
server
. Cela remplace la valeur par défaut définie dansspring-petclinic/src/main/resources/application-postgres.properties
.
Voici le fichier docker-compose.yaml
mis à jour. Tous les commentaires ont été supprimés.
services:
server:
build:
context: .
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
environment:
- POSTGRES_URL=jdbc:postgresql://db:5432/petclinic
db:
image: postgres
restart: always
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=petclinic
- POSTGRES_USER=petclinic
- POSTGRES_PASSWORD=petclinic
ports:
- 5432:5432
healthcheck:
test: ["CMD", "pg_isready", "-U", "petclinic"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
Ouvrez le Dockerfile
dans un IDE ou un éditeur de texte. Dans l'instruction ENTRYPOINT
,
mettez à jour l'instruction pour passer la propriété système comme spécifié dans le fichier
spring-petclinic/src/resources/db/postgres/petclinic_db_setup_postgres.txt
.
- ENTRYPOINT [ "java", "org.springframework.boot.loader.launch.JarLauncher" ]
+ ENTRYPOINT [ "java", "-Dspring.profiles.active=postgres", "org.springframework.boot.loader.launch.JarLauncher" ]
Enregistrez et fermez tous les fichiers.
Maintenant, exécutez la commande docker compose up
suivante pour démarrer votre application.
$ docker compose up --build
Ouvrez un navigateur et affichez l'application à http://localhost:8080. Vous devriez voir une application simple pour une clinique vétérinaire. Parcourez l'application. Accédez à Vétérinaires et vérifiez que l'application est connectée à la base de données en pouvant lister les vétérinaires.
Dans le terminal, appuyez sur ctrl
+c
pour arrêter l'application.
Dockerfile pour le développement
Le Dockerfile que vous avez maintenant est idéal pour une image de production petite et sécurisée avec uniquement les composants nécessaires pour exécuter l'application. Lors du développement, vous voudrez peut-être une image différente avec un environnement différent.
Par exemple, dans l'image de développement, vous voudrez peut-être configurer l'image pour démarrer l'application afin de pouvoir connecter un débogueur au processus Java en cours d'exécution.
Plutôt que de gérer plusieurs Dockerfiles, vous pouvez ajouter une nouvelle étape. Votre Dockerfile peut alors produire une image finale prête pour la production ainsi qu'une image de développement.
Remplacez le contenu de votre Dockerfile par ce qui suit.
# syntax=docker/dockerfile:1
FROM eclipse-temurin:21-jdk-jammy as deps
WORKDIR /build
COPY --chmod=0755 mvnw mvnw
COPY .mvn/ .mvn/
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
--mount=type=cache,target=/root/.m2 ./mvnw dependency:go-offline -DskipTests
FROM deps as package
WORKDIR /build
COPY ./src src/
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
--mount=type=cache,target=/root/.m2 \
./mvnw package -DskipTests && \
mv target/$(./mvnw help:evaluate -Dexpression=project.artifactId -q -DforceStdout)-$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout).jar target/app.jar
FROM package as extract
WORKDIR /build
RUN java -Djarmode=layertools -jar target/app.jar extract --destination target/extracted
FROM extract as development
WORKDIR /build
RUN cp -r /build/target/extracted/dependencies/. ./
RUN cp -r /build/target/extracted/spring-boot-loader/. ./
RUN cp -r /build/targe/extracted/snapshot-dependencies/. ./
RUN cp -r /build/target/extracted/application/. ./
ENV JAVA_TOOL_OPTIONS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000
CMD [ "java", "-Dspring.profiles.active=postgres", "org.springframework.boot.loader.launch.JarLauncher" ]
FROM eclipse-temurin:21-jre-jammy AS final
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser
COPY --from=extract build/target/extracted/dependencies/ ./
COPY --from=extract build/target/extracted/spring-boot-loader/ ./
COPY --from=extract build/target/extracted/snapshot-dependencies/ ./
COPY --from=extract build/target/extracted/application/ ./
EXPOSE 8080
ENTRYPOINT [ "java", "-Dspring.profiles.active=postgres", "org.springframework.boot.loader.launch.JarLauncher" ]
Enregistrez et fermez le Dockerfile
.
Dans le Dockerfile
, vous avez ajouté une nouvelle étape nommée development
basée sur l'étape extract
. Dans cette étape, vous copiez les fichiers extraits dans un répertoire commun, puis exécutez une commande pour démarrer l'application. Dans la commande, vous exposez le port 8000 et déclarez la configuration de débogage pour la JVM afin de pouvoir attacher un débogueur.
Utiliser Compose pour développer localement
Le fichier Compose actuel ne démarre pas votre conteneur de développement. Pour ce faire, vous devez mettre à jour votre fichier Compose pour cibler l'étape de développement. Mettez également à jour le mappage de port du service serveur pour donner accès au débogueur.
Ouvrez le docker-compose.yaml
et ajoutez les instructions suivantes dans le fichier.
services:
server:
build:
context: .
target: development
ports:
- 8080:8080
- 8000:8000
depends_on:
db:
condition: service_healthy
environment:
- POSTGRES_URL=jdbc:postgresql://db:5432/petclinic
db:
image: postgres
restart: always
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=petclinic
- POSTGRES_USER=petclinic
- POSTGRES_PASSWORD=petclinic
ports:
- 5432:5432
healthcheck:
test: ["CMD", "pg_isready", "-U", "petclinic"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
Maintenant, démarrez votre application et confirmez qu'elle est en cours d'exécution.
$ docker compose up --build
Enfin, testez votre point de terminaison d'API. Exécutez la commande curl suivante :
$ curl --request GET \
--url http://localhost:8080/vets \
--header 'content-type: application/json'
Vous devriez recevoir la réponse suivante :
{
"vetList": [
{
"id": 1,
"firstName": "James",
"lastName": "Carter",
"specialties": [],
"nrOfSpecialties": 0,
"new": false
},
{
"id": 2,
"firstName": "Helen",
"lastName": "Leary",
"specialties": [{ "id": 1, "name": "radiology", "new": false }],
"nrOfSpecialties": 1,
"new": false
},
{
"id": 3,
"firstName": "Linda",
"lastName": "Douglas",
"specialties": [
{ "id": 3, "name": "dentistry", "new": false },
{ "id": 2, "name": "surgery", "new": false }
],
"nrOfSpecialties": 2,
"new": false
},
{
"id": 4,
"firstName": "Rafael",
"lastName": "Ortega",
"specialties": [{ "id": 2, "name": "surgery", "new": false }],
"nrOfSpecialties": 1,
"new": false
},
{
"id": 5,
"firstName": "Henry",
"lastName": "Stevens",
"specialties": [{ "id": 1, "name": "radiology", "new": false }],
"nrOfSpecialties": 1,
"new": false
},
{
"id": 6,
"firstName": "Sharon",
"lastName": "Jenkins",
"specialties": [],
"nrOfSpecialties": 0,
"new": false
}
]
}
Connect a Debugger
You'll use the debugger that comes with the IntelliJ IDEA. You can use the community version of this IDE. Open your project in IntelliJ IDEA, go to the Run menu, and then Edit Configuration. Add a new Remote JVM Debug configuration similar to the following:


Set a breakpoint.
Open src/main/java/org/springframework/samples/petclinic/vet/VetController.java
and add a breakpoint inside the showResourcesVetList
function.
To start your debug session, select the Run menu and then Debug NameOfYourConfiguration.


You should now see the connection in the logs of your Compose application.


You can now call the server endpoint.
$ curl --request GET --url http://localhost:8080/vets
You should have seen the code break on the marked line and now you are able to use the debugger just like you would normally. You can also inspect and watch variables, set conditional breakpoints, view stack traces and a do bunch of other stuff.


Press ctrl+c
in the terminal to stop your application.
Automatically update services
Use Compose Watch to automatically update your running Compose services as you edit and save your code. For more details about Compose Watch, see Use Compose Watch.
Open your docker-compose.yaml
file in an IDE or text editor and then add the
Compose Watch instructions. The following is the updated docker-compose.yaml
file.
services:
server:
build:
context: .
target: development
ports:
- 8080:8080
- 8000:8000
depends_on:
db:
condition: service_healthy
environment:
- POSTGRES_URL=jdbc:postgresql://db:5432/petclinic
develop:
watch:
- action: rebuild
path: .
db:
image: postgres
restart: always
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=petclinic
- POSTGRES_USER=petclinic
- POSTGRES_PASSWORD=petclinic
ports:
- 5432:5432
healthcheck:
test: ["CMD", "pg_isready", "-U", "petclinic"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
Run the following command to run your application with Compose Watch.
$ docker compose watch
Open a web browser and view the application at http://localhost:8080. You should see the Spring Pet Clinic home page.
Any changes to the application's source files on your local machine will now be automatically reflected in the running container.
Open spring-petclinic/src/main/resources/templates/fragments/layout.html
in an IDE or text editor and update the Home
navigation string by adding an exclamation mark.
- <li th:replace="~{::menuItem ('/','home','home page','home','Home')}">
+ <li th:replace="~{::menuItem ('/','home','home page','home','Home!')}">
Save the changes to layout.html
and then you can continue developing while the container automatically rebuilds.
After the container is rebuilt and running, refresh http://localhost:8080 and then verify that Home! now appears in the menu.
Press ctrl+c
in the terminal to stop Compose Watch.
Summary
In this section, you took a look at running a database locally and persisting the data. You also created a development image that contains the JDK and lets you attach a debugger. Finally, you set up your Compose file to expose the debugging port and configured Compose Watch to live reload your changes.
Related information:
Next steps
In the next section, you'll take a look at how to run unit tests in Docker.