Cette application est un backend Java listant des données en base de données. Les données présentes dans le fichier src\main\resources\db\data\demo.csv
sont automatiquement chargées lors du premier démarrage de l'application :
id;name
1;Alice
2;Bob
3;Charles
4;Denis
5;Emily
Le concept de "multistage build" dans Docker permet de définir plusieurs étapes de construction dans un même Dockerfile. Chaque étape utilise une image de base différente et peut exécuter des commandes spécifiques. L'intérêt principal est de séparer la phase de compilation (qui nécessite souvent de nombreux outils et dépendances) de la phase d'exécution (qui n'a besoin que de l'artefact final, comme un fichier .jar).
Ainsi, l'image finale est plus légère, plus sécurisée et ne contient que ce qui est strictement nécessaire pour faire tourner l'application. Dans l'exemple ci-dessus, la première étape utilise une image Maven pour compiler le projet, puis la seconde étape ne récupère que le .jar généré dans une image Java minimaliste, sans outils de build.
# First stage: complete build environment
FROM maven:3.9.7-eclipse-temurin-21 AS builder
# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./src src/
RUN mvn clean package -Dmaven.test.skip=true
FROM gcr.io/distroless/java21:nonroot
WORKDIR /app
COPY --from=builder target/*.jar /app/app.jar
CMD ["-jar", "/app/app.jar"]
EXPOSE 8080
La construction de l'image applicative s'effectue donc par les étapes suivantes :
- Construction de l'image Docker
docker build
- Envoi de l'image construire dans le référentiel d'image
docker push
Nous allons détailler l'intégration de cette application de démo à l'offre Cloud Pi Native sur la plateforme d'accéleration.
Dans un premier temps il est nécessaire de créer un projet, puis d'ajouter le repo de code :
- Depuis un projet, aller dans l'onglet Dépôt, puis ajouter un nouveau dépôt :
- Nom du dépôt Git interne : demo-java
Le repo ne contient pas de code d'infrastructure et il possède des sources donc laisser les valeurs par défaut de la case à cocher et du radio bouton correspondant.
- Renseigner l'URL du repo externe https://github.com/cloud-pi-native/tuto-java.git. Le repo est public, laissez donc décocher la case Dépôt de source privé
Cliquez sur le bouton Ajouter le dépôt et attendre que le dépôt apparaisse dans la console.
- depuis l'onglet Services externes vérifier en cliquant sur le service Gitlab que le dépôt demo-java est bien présent dans ses projets gitlab.
Gitlab est configurée pour utiliser un fichier gitlab-ci nommé .gitlab-ci-dso.yml à la racine du projet.
Pour des raisons de facilité, nous allons travailler à partir du repo de code de gitlab et non depuis la source, dans un mode projet, il conviendrait de travailler depuis le repo externe et de procéder à des synchronisation repo externe -> repo interne.
-
Depuis Gitlab, aller dans le projet demo-java et choisir la branche tuto puis sur le bouton edit -> web IDE créer un fichier .gitlab-ci-dso.yml
-
Ajouter la première partie suivante :
include:
- project: $CATALOG_PATH
file:
- vault-ci.yml
- kaniko-ci.yml
ref: main
- local: "/includes/java-mvn.yml"
Cette partie permet de charger les taches pré-définies et pré-paramétrée pour s'exécuter dans CPiN. Pour plus d'information sur le catalogue, voir le repo dédié
Ajouter ensuite la partie suivante qui permet de définir les valeurs à mettre en cache, les variables et les étapes de construction:
cache:
paths:
- .m2/repository/
- node_modules
variables:
TAG: "${CI_COMMIT_REF_SLUG}"
DOCKERFILE: Dockerfile
REGISTRY_URL: "${IMAGE_REPOSITORY}"
stages:
- read-secret
- test-app
- docker-build
la construction du projet se fait en plusieurs étapes :
- Lecture des secrets du projet (token gitlab, Nexus, Sonarqube etc.) par la tache vault-ci
- Exécution des tests unitaires
- Construction de l'image docker et push vers Harbor par la tache kaniko-ci
Ajouter le bloc suivant pour lire les secrets du projet depuis Vault :
read_secret:
stage: read-secret
extends:
- .vault:read_secret
Ajouter la partie test unitaire sur le même principe :
test-app:
variables:
BUILD_IMAGE_NAME: maven:3.8-openjdk-17
WORKING_DIR: .
stage: test-app
extends:
- .java:sonar
allow_failure: true
Ajouter enfin le bloc suivant pour construire et déployer l'image Docker sur Harbor :
docker-build:
variables:
WORKING_DIR: "."
IMAGE_NAME: java-demo
stage: docker-build
extends:
- .kaniko:simple-build-push
Pour information, le bloc ci-dessus est une extension de la tache suivante issue du catalogue:
.kaniko:simple-build-push:
variables:
DOCKERFILE: Dockerfile
WORKING_DIR: .
IMAGE_NAME: $IMAGE_NAMES
EXTRA_BUILD_ARGS: ""
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
# CA
- if [ ! -z $CA_BUNDLE ]; then cat $CA_BUNDLE >> /kaniko/ssl/certs/additional-ca-cert-bundle.crt; fi
- mkdir -p /kaniko/.docker
- echo "$DOCKER_AUTH" > /kaniko/.docker/config.json
- /kaniko/executor --build-arg http_proxy=$http_proxy --build-arg https_proxy=$https_proxy --build-arg no_proxy=$no_proxy $EXTRA_BUILD_ARGS --context="$CI_PROJECT_DIR" --dockerfile="$CI_PROJECT_DIR/$WORKING_DIR/$DOCKERFILE" --destination $REGISTRY_URL/$IMAGE_NAME:$TAG
Le fichier .gitlab-ci-dso.yml complet est le suivant :
include:
- project: $CATALOG_PATH
file:
- vault-ci.yml
- kaniko-ci.yml
ref: main
- local: "/includes/java-mvn.yml"
# default:
# tags:
# - ADD_CUSTOM_TAG_HERE
cache:
paths:
- .m2/repository/
- node_modules
variables:
TAG: "${CI_COMMIT_REF_SLUG}"
DOCKERFILE: Dockerfile
REGISTRY_URL: "${IMAGE_REPOSITORY}"
stages:
- read-secret
- test-app
- docker-build
read_secret:
stage: read-secret
extends:
- .vault:read_secret
test-app:
variables:
BUILD_IMAGE_NAME: maven:3.8-openjdk-17
WORKING_DIR: .
stage: test-app
extends:
- .java:sonar
allow_failure: true
docker-build:
variables:
WORKING_DIR: "."
IMAGE_NAME: java-demo
stage: docker-build
extends:
- .kaniko:simple-build-push
Une fois que ce fichier est créé et commit / push sur le repos git, retourner sur le projet gitlab demo-java puis dans le menu build -> pipelines puis cliquez sur le bouton Run pipeline
Le pipeline cherche automatiquement le fichier .gitlab-dso.yaml à la racine du projet et lance le pipeline.
Bravo vous avez terminé le tutoriel de construction applicatif ! Prochaine étape le déploiement ici