Mise en place du déploiement automatique d'une application Springboot vers un serveur externe (VM mise à disposition) via CI/CD Gitlab.
Se connecter en root avec su :
su -l
Choisir une version compatible (supérieure ou égale à la verion java déclarée dans le pom.xml):
cd /tmp wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.deb dpkg -i jdk-17_linux-x64_bin.deb java -version
Ajouter un utilisateur tomcat :
useradd -m -d /opt/tomcat -U -s /bin/false tomcat
Télécharger et dézipper Tomcat :
cd /tmp wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.16/bin/apache-tomcat-10.1.16.tar.gz sudo tar xzvf apache-tomcat-10*tar.gz -C /opt/tomcat --strip-components=1
Définir les permissions sur les fichiers :
chown -R tomcat:tomcat /opt/tomcat/ chmod -R u+x /opt/tomcat/bin
Créer le tomcat-manager pour manager les sites à distance via l'interface web :
nano /opt/tomcat/conf/tomcat-users.xml
<!-- user manager can access only manager section --> <role rolename="manager-gui" /> <user username="manager" password="_SECRET_PASSWORD_" roles="manager-gui" /> <!-- user admin can access manager and admin section both --> <role rolename="admin-gui" /> <user username="admin" password="_SECRET_PASSWORD_" roles="manager-gui,admin-gui" />
Pour gérer tomcat plus facilement, créer un service Tomcat :
nano /etc/systemd/system/tomcat.service
[Unit] Description=Tomcat After=network.target [Service] Type=forking User=tomcat Group=tomcat Environment="JAVA_HOME=/usr/lib/jvm/jdk-17-oracle-x64" Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom" Environment="CATALINA_BASE=/opt/tomcat" Environment="CATALINA_HOME=/opt/tomcat" Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid" Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC" ExecStart=/opt/tomcat/bin/startup.sh ExecStop=/opt/tomcat/bin/shutdown.sh [Install] WantedBy=multi-user.target
Recharger le deamon service pour prendre en compte le nouveau service :
systemctl daemon-reload
Démarrer Tomcat :
systemctl start tomcat.service
Activer Tomcat pour qu'il redémarre automatiquement à chaque reboot :
systemctl enable tomcat.service
Afficher son statut :
systemctl status tomcat.service
Accéder à l'interface Web via l'adresse DNS fournie :
Créer un VHOST Tomcat correspondant à l'adresse DNS de votre VM :
A ajouter dans /opt/tomcat/conf/server.xml
<Engine> ... <Host name="srv2-vm-xxx.sts-sio-caen.info" appBase="webapps/paris-2024" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="xxx_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> ... </Engine>
Sur la VM :
adduser --quiet --shell $SHELL --disabled-password --gecos 'GitlabCI User' gitlab-ci usermod -a -G sudo gitlab-ci echo 'gitlab-ci:changeMyPassword' | chpasswd printf 'Match User gitlab-ci\n\tPasswordAuthentication yes\n' >> /etc/ssh/sshd_config systemctl restart sshd echo 'gitlab-ci ALL=(ALL) NOPASSWD: /bin/mv, NOPASSWD: /usr/bin/systemctl, NOPASSWD: /bin/cp' | sudo EDITOR='tee -a' visudo
Créer une variable dans Gitlab pour stocker le mot de passe de l'utilisateur gitlab-ci qui se connectera en SSH :
Dans Settings-CI/CD, créer la variable CI_USER_PASS :
Modifier pom.xml pour définir le nom du fichier WAR déployé :
<build> <finalName>ssh-deploy</finalName> </build>
Vérifiez que le déploiement sera bien fait en WAR :
<packaging>war</packaging>
Créer ou modifier le fichier .gitlab-ci.yml :
stages: - build - deploy maven-build: image: maven:3.9.5-amazoncorretto-17-debian stage: build script: "mvn package -B" artifacts: paths: - target/ssh-deploy.war deploy-master: variables: HOST: "149.202.94.223" PORT: "7839" USER: "gitlab-ci" WAR: "ssh-deploy.war" rules: - if: '$CI_COMMIT_BRANCH =~ /^main$/' before_script: - apt-get update -qq && apt-get install -y -qq sshpass sudo - echo "Host= $HOST" stage: deploy script: - sudo whoami # Vérifiez si sudo est disponible - which mv - sshpass -V - export SSHPASS=$CI_USER_PASS - sshpass -e scp -o StrictHostKeyChecking=no -P $PORT target/$WAR $USER@$HOST:/home/$USER - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST echo $PATH - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST sudo mv /home/$USER/$WAR /opt/tomcat/webapps/paris-2024/ROOT.war - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST sudo systemctl restart tomcat.service
Il est conseillé de mettre les valeurs HOST, USER et PORT dans des variables Gitlab.
Vérifier que les 2 jobs sont bien lancés sur Gitlab à chaque commit sur la branche main, et que l'application est bien déployée sur le serveur :
La création de profiles permet de gérer des configurations différentes, et des fichiers de configuration spécifiques à chaque profile.
Ajouter la section profiles suivante au fichier pom.xml
<profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <activeProfile>dev</activeProfile> </properties> </profile> <profile> <id>prod</id> <properties> <activeProfile>prod</activeProfile> </properties> </profile> <profile> <id>test</id> <properties> <activeProfile>test</activeProfile> </properties> </profile> </profiles>
Il est ensuite possible de créer des fichiers de configuration spécifiques à chaque profile, en plus du fichier de configuration de base application.properties.
spring.profiles.active=@activeProfile@ # Mustache Template engine spring.mustache.prefix=classpath:/templates/ spring.mustache.suffix=.html # H2 Database + JPA spring.datasource.username=sa spring.datasource.password= spring.datasource.driverClassName=org.h2.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect spring.jpa.properties.hibernate.globally_quoted_identifiers=true spring.h2.console.enabled=true spring.h2.console.settings.web-allow-others=true spring.h2.console.path=/h2-console servlet.context.path=/
spring.datasource.url=jdbc:h2:file:./data/paris-2024;DB_CLOSE_ON_EXIT=FALSE spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true
La base de données (le fichier db) pourra être déposée dans le dossier préalablement créé sur la VM : /data/h2/
via WinSCP.
spring.datasource.url=jdbc:h2:file:/data/h2/paris-2024;DB_CLOSE_ON_EXIT=FALSE spring.jpa.show-sql=false spring.jpa.properties.hibernate.format_sql=false
spring.datasource.url=jdbc:h2:file:/home/runner/work/myparis/paris-2024/target/data;DB_CLOSE_ON_EXIT=FALSE spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true server.servlet.context-path=/
Génération du package en production
stage: build script: "mvn clean package -P prod -DskipTests=true"
Génération du package pour les tests
stage: test script: "mvn --batch-mode --update-snapshots verify -P test -DskipTests=false"
Il est parfois indispensable, pour des raisons de sécurité, de stocker certaines constantes dans les variables CI de gitlab, pour les affecter au déploiement par l'intermédiaire de variables d'environnement plutôt que de les mettre en dur dans le code :
Il est nécessaire de modifier le service de démarrage de tomcat pour qu'il prenne en compte les variables d'environnement (via le fichier setenv.sh), en utilisant catalina.sh comme script de démarrage au lieu de startup.sh :
[Unit] Description=Tomcat After=network.target [Service] Type=simple User=tomcat Group=tomcat Environment="JAVA_HOME=/usr/lib/jvm/jdk-17-oracle-x64" Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom" Environment="CATALINA_BASE=/opt/tomcat" Environment="CATALINA_HOME=/opt/tomcat" Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid" Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC" ExecStart=/opt/tomcat/bin/catalina.sh run ExecStop=/opt/tomcat/bin/catalina.sh stop [Install] WantedBy=multi-user.target
Recharger le service et redémarer le :
systemctl daemon-reload systemctl start tomcat.service
Créer une variable CI_APP_KEY dans les variables CI de votre compte gitlab.
Le script de déploiement doit maintenant ajouter la variable d'environnement CI_APP_KEY dans le fichier setenv.sh du serveur :
stages: - build - deploy maven-build: image: maven:3.9.5-amazoncorretto-17-debian stage: build script: "mvn clean package -P prod -DskipTests=true" artifacts: paths: - target/paris-2024.war deploy-master: variables: HOST: "149.202.94.223" PORT: "78xx" USER: "gitlab-ci" WAR: "paris-2024.war" SITE_LOCATION: "/opt/tomcat/webapps/paris-2024" rules: - if: '$CI_COMMIT_BRANCH =~ /^main$/' before_script: - apt-get update -qq && apt-get install -y -qq sshpass sudo - echo "Host= $HOST" stage: deploy script: - sudo whoami # Vérifiez si sudo est disponible - which mv - sshpass -V - export SSHPASS=$CI_USER_PASS - sshpass -e scp -o StrictHostKeyChecking=no -P $PORT target/$WAR $USER@$HOST:/home/$USER - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST echo $PATH - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST sudo mv /home/$USER/$WAR $SITE_LOCATION/ROOT.war - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST "sudo chmod 755 /opt/tomcat/bin/setenv.sh" - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST "sudo sh -c 'echo export CI_APP_KEY=$CI_APP_KEY >> /opt/tomcat/bin/setenv.sh'" - sshpass -e ssh -tt -o StrictHostKeyChecking=no -p $PORT $USER@$HOST sudo systemctl restart tomcat.service
Pour utiliser la variable d'environnement CI_APP_KEY dans le projet SpringBoot :
Ajouter la ligne suivante à application.properties :
spring.data.encryption.key=${CI_APP_KEY}
Dans un contrôleur, un service ou autre :
@Value("${spring.data.encryption.key}") private String KEY;