<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://isig-wiki.ens-lyon.fr/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lvaudor</id>
	<title>Wiki ISIG - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="https://isig-wiki.ens-lyon.fr/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lvaudor"/>
	<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/wiki/Sp%C3%A9cial:Contributions/Lvaudor"/>
	<updated>2026-08-28T13:37:33Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Packages_R:_d%C3%A9velopper_un_package&amp;diff=1259</id>
		<title>Packages R: développer un package</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Packages_R:_d%C3%A9velopper_un_package&amp;diff=1259"/>
		<updated>2026-07-20T07:30:20Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : Page créée avec « = Développer un package R avec RStudio = Ce tutoriel présente une démarche simple pour créer un package R moderne, documenté et testé. Il s&amp;#039;appuie sur les packages &amp;#039;&amp;#039;&amp;#039;devtools&amp;#039;&amp;#039;&amp;#039;, &amp;#039;&amp;#039;&amp;#039;usethis&amp;#039;&amp;#039;&amp;#039;, &amp;#039;&amp;#039;&amp;#039;roxygen2&amp;#039;&amp;#039;&amp;#039; et &amp;#039;&amp;#039;&amp;#039;testthat&amp;#039;&amp;#039;&amp;#039;, qui constituent aujourd&amp;#039;hui l&amp;#039;écosystème de référence pour le développement de packages.  == Prérequis == Installer les principaux outils de développement :  &amp;lt;code&amp;gt;install.packages(c(    &amp;quot;devtools&amp;quot;,    &amp;quot;usethis&amp;quot;,    &amp;quot;roxygen2... »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Développer un package R avec RStudio =&lt;br /&gt;
Ce tutoriel présente une démarche simple pour créer un package R moderne, documenté et testé. Il s&#039;appuie sur les packages &#039;&#039;&#039;devtools&#039;&#039;&#039;, &#039;&#039;&#039;usethis&#039;&#039;&#039;, &#039;&#039;&#039;roxygen2&#039;&#039;&#039; et &#039;&#039;&#039;testthat&#039;&#039;&#039;, qui constituent aujourd&#039;hui l&#039;écosystème de référence pour le développement de packages.&lt;br /&gt;
&lt;br /&gt;
== Prérequis ==&lt;br /&gt;
Installer les principaux outils de développement :&lt;br /&gt;
 &amp;lt;code&amp;gt;install.packages(c(&lt;br /&gt;
   &amp;quot;devtools&amp;quot;,&lt;br /&gt;
   &amp;quot;usethis&amp;quot;,&lt;br /&gt;
   &amp;quot;roxygen2&amp;quot;,&lt;br /&gt;
   &amp;quot;testthat&amp;quot;,&lt;br /&gt;
   &amp;quot;pkgdown&amp;quot;&lt;br /&gt;
 ))&amp;lt;/code&amp;gt;&lt;br /&gt;
Il est également recommandé d&#039;utiliser une version récente de R et RStudio.&lt;br /&gt;
&lt;br /&gt;
= 1. Créer le package =&lt;br /&gt;
Dans RStudio :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File &amp;gt; New Project &amp;gt; New Directory &amp;gt; R Package&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Choisir :&lt;br /&gt;
&lt;br /&gt;
* le nom du package (sans espaces ni caractères spéciaux)&lt;br /&gt;
* le dossier de création&lt;br /&gt;
&lt;br /&gt;
RStudio crée automatiquement toute l&#039;architecture du package.&lt;br /&gt;
&lt;br /&gt;
On obtient notamment :&lt;br /&gt;
 &amp;lt;code&amp;gt;monpackage/&lt;br /&gt;
 &lt;br /&gt;
 ├── DESCRIPTION&lt;br /&gt;
 ├── NAMESPACE&lt;br /&gt;
 ├── R/&lt;br /&gt;
 ├── man/&lt;br /&gt;
 └── monpackage.Rproj&amp;lt;/code&amp;gt;&lt;br /&gt;
Les rôles des principaux dossiers sont :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Élément&lt;br /&gt;
!Rôle&lt;br /&gt;
|-&lt;br /&gt;
|R/&lt;br /&gt;
|Contient toutes les fonctions du package&lt;br /&gt;
|-&lt;br /&gt;
|man/&lt;br /&gt;
|Documentation générée automatiquement&lt;br /&gt;
|-&lt;br /&gt;
|DESCRIPTION&lt;br /&gt;
|Métadonnées et dépendances&lt;br /&gt;
|-&lt;br /&gt;
|NAMESPACE&lt;br /&gt;
|Fonctions exportées et imports (généré automatiquement)&lt;br /&gt;
|}&lt;br /&gt;
Les fichiers &#039;&#039;&#039;NAMESPACE&#039;&#039;&#039; et &#039;&#039;&#039;man/&#039;&#039;&#039; ne doivent généralement pas être modifiés à la main lorsqu&#039;on utilise roxygen2.&lt;br /&gt;
&lt;br /&gt;
= 2. Initialiser le package =&lt;br /&gt;
Plusieurs outils peuvent être ajoutés immédiatement grâce à &#039;&#039;&#039;usethis&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Initialiser Git ==&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_git()&amp;lt;/code&amp;gt;&lt;br /&gt;
Éventuellement :&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_github()&amp;lt;/code&amp;gt;&lt;br /&gt;
pour créer directement un dépôt GitHub.&lt;br /&gt;
&lt;br /&gt;
== Ajouter une licence ==&lt;br /&gt;
Par exemple :&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_mit_license()&amp;lt;/code&amp;gt;&lt;br /&gt;
ou&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_gpl3_license()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ajouter un README ==&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_readme_rmd()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= 3. Écrire des fonctions =&lt;br /&gt;
Toutes les fonctions doivent être placées dans le dossier&lt;br /&gt;
 &amp;lt;code&amp;gt;R/&amp;lt;/code&amp;gt;&lt;br /&gt;
Par exemple :&lt;br /&gt;
 &amp;lt;code&amp;gt;R/calcul.R&amp;lt;/code&amp;gt;&lt;br /&gt;
contenant&lt;br /&gt;
 &amp;lt;code&amp;gt;addition &amp;lt;- function(x, y) {&lt;br /&gt;
   x + y&lt;br /&gt;
 }&amp;lt;/code&amp;gt;&lt;br /&gt;
Le nom du fichier est libre.&lt;br /&gt;
&lt;br /&gt;
En revanche, les fonctions doivent toujours être dans le dossier &#039;&#039;&#039;R/&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= 4. Documenter avec Roxygen =&lt;br /&gt;
Chaque fonction est précédée d&#039;un bloc de commentaires.&lt;br /&gt;
&lt;br /&gt;
Exemple :&lt;br /&gt;
 &amp;lt;code&amp;gt;#&#039; Addition de deux nombres&lt;br /&gt;
 #&#039;&lt;br /&gt;
 #&#039; Additionne deux valeurs numériques.&lt;br /&gt;
 #&#039;&lt;br /&gt;
 #&#039; @param x premier nombre&lt;br /&gt;
 #&#039; @param y second nombre&lt;br /&gt;
 #&#039;&lt;br /&gt;
 #&#039; @return Une valeur numérique.&lt;br /&gt;
 #&#039;&lt;br /&gt;
 #&#039; @export&lt;br /&gt;
 addition &amp;lt;- function(x, y) {&lt;br /&gt;
   x + y&lt;br /&gt;
 }&amp;lt;/code&amp;gt;&lt;br /&gt;
La documentation est ensuite générée automatiquement.&lt;br /&gt;
&lt;br /&gt;
Dans RStudio :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Build &amp;gt; More &amp;gt; Document&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ou&lt;br /&gt;
 &amp;lt;code&amp;gt;devtools::document()&amp;lt;/code&amp;gt;&lt;br /&gt;
Cette commande met à jour :&lt;br /&gt;
&lt;br /&gt;
* le dossier &amp;lt;code&amp;gt;man/&amp;lt;/code&amp;gt;&lt;br /&gt;
* le fichier &amp;lt;code&amp;gt;NAMESPACE&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ces fichiers ne doivent normalement jamais être édités manuellement.&lt;br /&gt;
&lt;br /&gt;
= 5. Gérer les dépendances =&lt;br /&gt;
Éviter de modifier directement le fichier DESCRIPTION.&lt;br /&gt;
&lt;br /&gt;
Préférer :&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_package(&amp;quot;sf&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
qui ajoute automatiquement&lt;br /&gt;
 &amp;lt;code&amp;gt;Imports:&lt;br /&gt;
     sf&amp;lt;/code&amp;gt;&lt;br /&gt;
Pour une dépendance utilisée uniquement pendant le développement :&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_package(&amp;quot;testthat&amp;quot;, type = &amp;quot;Suggests&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
Les types de dépendances les plus fréquents sont :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Type&lt;br /&gt;
!Utilisation&lt;br /&gt;
|-&lt;br /&gt;
|Imports&lt;br /&gt;
|Package nécessaire au fonctionnement&lt;br /&gt;
|-&lt;br /&gt;
|Suggests&lt;br /&gt;
|Package utilisé uniquement pour les tests ou des fonctionnalités optionnelles&lt;br /&gt;
|-&lt;br /&gt;
|Depends&lt;br /&gt;
|Rarement utilisé aujourd&#039;hui&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= 6. Charger le package pendant le développement =&lt;br /&gt;
Pendant le développement, il n&#039;est pas nécessaire de réinstaller le package après chaque modification.&lt;br /&gt;
&lt;br /&gt;
Utiliser :&lt;br /&gt;
 &amp;lt;code&amp;gt;devtools::load_all()&amp;lt;/code&amp;gt;&lt;br /&gt;
Cette commande :&lt;br /&gt;
&lt;br /&gt;
* charge toutes les fonctions ;&lt;br /&gt;
* recharge les données ;&lt;br /&gt;
* recharge les fichiers R modifiés ;&lt;br /&gt;
* permet de tester immédiatement les nouvelles fonctions.&lt;br /&gt;
&lt;br /&gt;
C&#039;est la commande utilisée en permanence pendant le développement.&lt;br /&gt;
&lt;br /&gt;
= 7. Différence entre &amp;lt;code&amp;gt;load_all()&amp;lt;/code&amp;gt; et le bouton Build =&lt;br /&gt;
Ces deux actions ont des objectifs très différents.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;code&amp;gt;devtools::load_all()&amp;lt;/code&amp;gt; ==&lt;br /&gt;
À utiliser pendant le développement.&lt;br /&gt;
&lt;br /&gt;
Il simule un package installé mais sans construire réellement le package.&lt;br /&gt;
&lt;br /&gt;
C&#039;est très rapide.&lt;br /&gt;
&lt;br /&gt;
Idéal pour :&lt;br /&gt;
&lt;br /&gt;
* tester une fonction ;&lt;br /&gt;
* lancer une application Shiny ;&lt;br /&gt;
* faire du débogage.&lt;br /&gt;
&lt;br /&gt;
== Build ==&lt;br /&gt;
Le bouton &#039;&#039;&#039;Build&#039;&#039;&#039; réalise une véritable construction du package.&lt;br /&gt;
&lt;br /&gt;
Selon l&#039;action choisie, RStudio peut :&lt;br /&gt;
&lt;br /&gt;
* documenter le package ;&lt;br /&gt;
* construire le fichier &amp;lt;code&amp;gt;.tar.gz&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* installer le package ;&lt;br /&gt;
* vérifier (&amp;lt;code&amp;gt;R CMD check&amp;lt;/code&amp;gt;) qu&#039;il respecte les standards CRAN.&lt;br /&gt;
&lt;br /&gt;
Cette étape est plus lente mais permet de détecter des erreurs qui ne sont pas visibles avec &amp;lt;code&amp;gt;load_all()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En pratique :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;load_all()&amp;lt;/code&amp;gt; est utilisé des dizaines de fois par jour ;&lt;br /&gt;
* Build est utilisé avant un commit important ou avant une diffusion.&lt;br /&gt;
&lt;br /&gt;
= 8. Tester avec testthat =&lt;br /&gt;
Initialiser les tests :&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_testthat()&amp;lt;/code&amp;gt;&lt;br /&gt;
Créer un premier fichier de test :&lt;br /&gt;
 &amp;lt;code&amp;gt;usethis::use_test(&amp;quot;addition&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
On obtient :&lt;br /&gt;
 &amp;lt;code&amp;gt;tests/testthat/test-addition.R&amp;lt;/code&amp;gt;&lt;br /&gt;
Exemple :&lt;br /&gt;
 &amp;lt;code&amp;gt;test_that(&amp;quot;addition fonctionne&amp;quot;, {&lt;br /&gt;
 &lt;br /&gt;
   expect_equal(addition(2,3),5)&lt;br /&gt;
 &lt;br /&gt;
 })&amp;lt;/code&amp;gt;&lt;br /&gt;
Exécuter tous les tests :&lt;br /&gt;
 &amp;lt;code&amp;gt;devtools::test()&amp;lt;/code&amp;gt;&lt;br /&gt;
Les tests permettent de vérifier que les fonctions continuent à produire les résultats attendus après des modifications.&lt;br /&gt;
&lt;br /&gt;
= 9. Vérifier le package =&lt;br /&gt;
Avant toute diffusion :&lt;br /&gt;
 &amp;lt;code&amp;gt;devtools::check()&amp;lt;/code&amp;gt;&lt;br /&gt;
Cette commande lance l&#039;équivalent de :&lt;br /&gt;
 &amp;lt;code&amp;gt;R CMD check&amp;lt;/code&amp;gt;&lt;br /&gt;
Elle détecte notamment :&lt;br /&gt;
&lt;br /&gt;
* erreurs ;&lt;br /&gt;
* avertissements ;&lt;br /&gt;
* notes ;&lt;br /&gt;
* documentation incomplète ;&lt;br /&gt;
* dépendances oubliées.&lt;br /&gt;
&lt;br /&gt;
Un package destiné au partage devrait idéalement être exempt d&#039;erreurs et d&#039;avertissements.&lt;br /&gt;
&lt;br /&gt;
= 10. Cas particulier : package contenant une application Shiny =&lt;br /&gt;
Un package peut également contenir une application Shiny.&lt;br /&gt;
&lt;br /&gt;
L&#039;organisation est généralement la suivante :&lt;br /&gt;
 &amp;lt;code&amp;gt;R/&lt;br /&gt;
     app.R&lt;br /&gt;
     server.R&lt;br /&gt;
     ui.R&lt;br /&gt;
     modules/&lt;br /&gt;
     utils.R&amp;lt;/code&amp;gt;&lt;br /&gt;
La fonction principale est par exemple :&lt;br /&gt;
 &amp;lt;code&amp;gt;run_app &amp;lt;- function() {&lt;br /&gt;
 &lt;br /&gt;
   shiny::shinyApp(&lt;br /&gt;
     ui = app_ui(),&lt;br /&gt;
     server = app_server&lt;br /&gt;
   )&lt;br /&gt;
 &lt;br /&gt;
 }&amp;lt;/code&amp;gt;&lt;br /&gt;
Pendant le développement :&lt;br /&gt;
 &amp;lt;code&amp;gt;devtools::load_all()&lt;br /&gt;
 &lt;br /&gt;
 run_app()&amp;lt;/code&amp;gt;&lt;br /&gt;
L&#039;application utilise alors directement les fonctions du package en cours de développement.&lt;br /&gt;
&lt;br /&gt;
Cette approche présente plusieurs avantages :&lt;br /&gt;
&lt;br /&gt;
* les fonctions sont réutilisables ;&lt;br /&gt;
* les tests peuvent porter sur la logique métier indépendamment de Shiny ;&lt;br /&gt;
* le code est mieux organisé ;&lt;br /&gt;
* il devient facile de documenter et partager les fonctions.&lt;br /&gt;
&lt;br /&gt;
Le package &#039;&#039;&#039;golem&#039;&#039;&#039; automatise une grande partie de cette architecture et constitue aujourd&#039;hui une référence pour le développement d&#039;applications Shiny complexes.&lt;br /&gt;
&lt;br /&gt;
= Bonnes pratiques =&lt;br /&gt;
&lt;br /&gt;
* Une fonction = une responsabilité.&lt;br /&gt;
* Documenter chaque fonction.&lt;br /&gt;
* Écrire des tests dès que possible.&lt;br /&gt;
* Utiliser &amp;lt;code&amp;gt;usethis&amp;lt;/code&amp;gt; plutôt que modifier les fichiers système à la main.&lt;br /&gt;
* Utiliser &amp;lt;code&amp;gt;load_all()&amp;lt;/code&amp;gt; pendant le développement.&lt;br /&gt;
* Lancer régulièrement &amp;lt;code&amp;gt;devtools::check()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Versionner le projet avec Git.&lt;br /&gt;
&lt;br /&gt;
En suivant cette démarche, on obtient un package facile à maintenir, documenté, testable et partageable.&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1227</id>
		<title>ShinyProxy</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1227"/>
		<updated>2026-04-21T12:33:49Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : /* To do list mise en ligne d&amp;#039;une nouvelle appli */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;big&amp;gt;Attention : Page en cours de rédaction&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ISIG-Apps passe sous ShinyProxy pour améliorer la stabilité et l&#039;isolation de vos applications pendant les montées en charge. Le fonctionnement est très différent par rapport à l&#039;ancien Shiny-Server et nécessite quelques bases dans l&#039;utilisation de Docker. L&#039;objectif de cette page est de vous guider, rapidement et simplement, dans le nouveau workflow dev &amp;gt; prod en partant du principe que vous ne connaissez encore pas grand-chose à Docker.&lt;br /&gt;
&lt;br /&gt;
== Principe de fonctionnement de ShinyProxy (et Docker) ==&lt;br /&gt;
ShinyProxy fonctionne comme un orchestrateur de conteneurs Docker. Chaque appli configurée doit avoir une image Docker associée présente sur le serveur qui exécute ShinyProxy. C&#039;est ShinyProxy qui s&#039;occupera ensuite de lancer et stopper un conteneur à chaque fois qu&#039;un internaute se connectera ou se déconnectera de votre appli.    &lt;br /&gt;
[[Fichier:Schéma Docker.png|centré|sans_cadre|1054x1054px]]    &lt;br /&gt;
&lt;br /&gt;
Afin que votre application puisse fonctionner sur ShinyProxy, il va donc falloir créer une &#039;&#039;&#039;image&#039;&#039;&#039; qui permettra au serveur ShinyProxy de lancer des &#039;&#039;&#039;containers&#039;&#039;&#039; de votre application.  &lt;br /&gt;
&lt;br /&gt;
Vous n&#039;aurez généralement pas besoin de volume pour stocker des données pérennes dans le cas d&#039;une application Shiny. Si votre application utilise une base de données, celle-ci devra être externalisée (hébergée sur le serveur de bases de données d&#039;ISIG par exemple). &lt;br /&gt;
&lt;br /&gt;
ShinyProxy fera en sorte qu&#039;un certain nombre de containers (à définir dans la configuration décrite à la fin de ce tutoriel) soient toujours disponibles pour de nouveaux utilisateurs qui se connecteraient à votre application. Il s&#039;occupera également de supprimer les containers quand vos utilisateurs se déconnectent. &lt;br /&gt;
&lt;br /&gt;
== Conteneurisation de votre appli Shiny ==&lt;br /&gt;
La conteneurisation peut se faire directement sur votre machine personelle si vous y avez installé Docker (https://docs.docker.com/engine/install/), ou sur le serveur isig-apps de dev via [https://rstudio.evs.ens-lyon.fr Rstudio server] et son terminal intégré.&lt;br /&gt;
&lt;br /&gt;
=== Fixer le port ===&lt;br /&gt;
Pour fonctionner en mode conteneurisé, votre application devra écouter toujours sur le même port (ce qui n&#039;est pas le comportement par défaut d&#039;une application Shiny). &lt;br /&gt;
&lt;br /&gt;
Afin de s&#039;en assurer, il faut : &lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un appli Shiny classique, ajouter dans &amp;lt;code&amp;gt;options(..)&amp;lt;/code&amp;gt;, avant l&#039;appel de &amp;lt;code&amp;gt;shinyApp(..)&amp;lt;/code&amp;gt;, les options suivantes : &amp;lt;code&amp;gt;&amp;quot;shiny.port&amp;quot;=3841&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;&amp;quot;shiny.host&amp;quot;=&amp;quot;0.0.0.0&amp;quot;&amp;lt;/code&amp;gt;. Par exemple :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;r&amp;quot;&amp;gt;&lt;br /&gt;
library(shiny)&lt;br /&gt;
library(glourbi)&lt;br /&gt;
&lt;br /&gt;
# Dans cet exemple, l&#039;application écoutera systématiquement sur le port 3838&lt;br /&gt;
options(&amp;quot;shiny.port&amp;quot; = 3838, &amp;quot;shiny.host&amp;quot; = &amp;quot;0.0.0.0&amp;quot;, &amp;quot;golem.app.prod&amp;quot; = TRUE)&lt;br /&gt;
&lt;br /&gt;
shinyApp(ui=glourbapp:::app_ui,server=glourbapp:::app_server)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un document Rmarkdown, ........&lt;br /&gt;
&lt;br /&gt;
=== Choisir l&#039;image source ===&lt;br /&gt;
La construction d&#039;une image Docker se fait sur la base... d&#039;une autre. On choisi en général son image de base en fonction de ce qu&#039;on va faire avec. Pour une application Shiny, nous aurons besoin d&#039;une image Docker spécialisée en R. &lt;br /&gt;
&lt;br /&gt;
Le [https://rocker-project.org/images/ projet Rocker] propose plusieurs images de base avec différentes quantités de packages pré-installés. Lorsque l&#039;on choisi son image de base, il faut trouver le bon compromis entre une image légère et une image avec suffisamment de dépendances pré-installées pour qu&#039;elle soit pratique.&lt;br /&gt;
&lt;br /&gt;
L&#039;image [https://eddelbuettel.github.io/r2u/ r2u] est une bonne base assez simple à utiliser, car elle va chercher des binaires précompilés des packages R que l&#039;on souhaite installer et toutes leurs dépendances, librairies système incluses ! Pratiquement rien n&#039;y est pré-installé, il faudra donc bien préciser toutes les dépendances dont vous avez besoin. En contrepartie, l&#039;image sera plutôt légère, ce qui est une bonne chose ! L&#039;inconvénient de cette fonctionnalité est (à ma connaissance) qu&#039;elle ne fonctionne qu&#039;avec la fonction &amp;lt;code&amp;gt;install.packages(...)&amp;lt;/code&amp;gt;. Il n&#039;est donc pas possible d&#039;installer une version spécifique d&#039;un package avec &amp;lt;code&amp;gt;remotes::install_version(...)&amp;lt;/code&amp;gt; par exemple (la fonction reste utilisable de manière classique). &lt;br /&gt;
&lt;br /&gt;
=== Écrire le Dockerfile ===&lt;br /&gt;
&lt;br /&gt;
La création d&#039;une image Docker repose sur l&#039;écriture d&#039;un fichier texte appelé &#039;&#039;&#039;Dockerfile&#039;&#039;&#039; (sans extension).&lt;br /&gt;
&lt;br /&gt;
Voici un exemple de Dockerfile pour l&#039;application GloUrb :&amp;lt;syntaxhighlight lang=&amp;quot;dockerfile&amp;quot;&amp;gt;&lt;br /&gt;
# On commence par définir l&#039;image sur laquelle va se baser la notre&lt;br /&gt;
FROM rocker/r2u:jammy&lt;br /&gt;
&lt;br /&gt;
# On précise quelques infos qui permettrons d&#039;identifier l&#039;image&lt;br /&gt;
LABEL org.opencontainers.image.authors=&amp;quot;Lise Vaudor &amp;lt;lise.vaudor@ens-lyon.fr&amp;gt;, Samuel Dunesme &amp;lt;samuel.dunesme@ens-lyon.fr&amp;gt;&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.source=&amp;quot;https://github.com/glourb/glourbapp&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.documentation=&amp;quot;https://evs-gis.github.io/glourbdoc/&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.version=&amp;quot;0.0.0.9000&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.description=&amp;quot;An app for the GloUrb project&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# On peut éventuellement générer des locales supplémentaires si notre appli utilise d&#039;autres langues que l&#039;anglais&lt;br /&gt;
RUN locale-gen fr_FR.UTF-8&lt;br /&gt;
&lt;br /&gt;
# On liste maintenant toutes les dépendances R à installer&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tidyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;shiny&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;config&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;testthat&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tibble&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;purrr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;dplyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;ggplot2&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;forcats&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;magrittr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;golem&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;sf&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;plotly&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;spelling&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;mclust&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;leaflet&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cluster&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cowplot&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;FactoMineR&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;glue&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;grDevices&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RColorBrewer&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;remotes&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cicerone&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RPostgres&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DBI&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DT&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
RUN Rscript -e &#039;remotes::install_github(&amp;quot;glourb/glourbi&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
# On copie l&#039;arborescence de fichiers dans un dossier app à la racine de l&#039;image. Ce sera le working directory des containers lancés avec notre image&lt;br /&gt;
RUN mkdir /app&lt;br /&gt;
ADD . /app&lt;br /&gt;
WORKDIR /app&lt;br /&gt;
&lt;br /&gt;
# Si besoin, on peut installer notre package&lt;br /&gt;
RUN R -e &#039;remotes::install_local()&#039;&lt;br /&gt;
&lt;br /&gt;
# On détermine le port qui sera exposé (attention à bien fixer le port sur lequel votre appli écoute, cf. ci-dessus)&lt;br /&gt;
EXPOSE 3838&lt;br /&gt;
&lt;br /&gt;
# Pour plus de sécurité, on fait en sorte que les containers ne se lancent pas avec l&#039;utilisateur &amp;quot;root&amp;quot;, mais avec un utilisateur &amp;quot;app&amp;quot; dédié&lt;br /&gt;
RUN groupadd -g 1010 app &amp;amp;&amp;amp; useradd -c &#039;app&#039; -u 1010 -g 1010 -m -d /home/app -s /sbin/nologin app&lt;br /&gt;
USER app&lt;br /&gt;
&lt;br /&gt;
# Enfin, on précise la commande qui permet de lancer notre appli. C&#039;est cette commande qui sera lancée par défaut par tout nouveau container lancé avec notre image&lt;br /&gt;
CMD  [&amp;quot;R&amp;quot;, &amp;quot;-f&amp;quot;, &amp;quot;app.R&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Construire l&#039;image Docker ===&lt;br /&gt;
Pour construire l&#039;image docker à l&#039;aide du Dockerfile, il faut lancer la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. C&#039;est à ce moment que l&#039;on va versionner l&#039;image en la taguant avec l&#039;argument &amp;lt;code&amp;gt;-t&amp;lt;/code&amp;gt;. On peut mettre directement plusieurs tags à une image, ou les ajouter à posteriori en relançant la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. Si le Dockerfile n&#039;a pas changé depuis le dernier build, &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt; ne fera qu&#039;ajouter les tags à l&#039;image existante. &lt;br /&gt;
&lt;br /&gt;
Pour que la CLI Docker trouve bien le Dockerfile, on lance le terminal dans le dossier ou ce Dockerfile est enregistré. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker build . -t ghcr.io/evs-gis/mapdoapp:latest -t ghcr.io/evs-gis/mapdoapp:2.0.1 -t ghcr.io/evs-gis/mapdoapp:$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remarquez que le tag doit contenir le chemin complet vers le registre où sera poussée l&#039;image (étape suivante). Si vous ne précisez pas le chemin (par exemple &amp;lt;code&amp;gt;mapdoapp:latest&amp;lt;/code&amp;gt;), le registre utilisé sera DockerHub. &lt;br /&gt;
&lt;br /&gt;
Notez le tag &amp;lt;code&amp;gt;$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt; qui permet de taguer l&#039;image avec le hash (la référence) du commit actuel (ne fonctionne que si vous êtes dans un dépôt git). Ce tag est bien pratique si vous n&#039;incrémentez pas un numéro de version par ailleurs (&amp;lt;code&amp;gt;2.0.1&amp;lt;/code&amp;gt; dans l&#039;exemple ci-dessus). &lt;br /&gt;
&lt;br /&gt;
Le tag &amp;lt;code&amp;gt;latest&amp;lt;/code&amp;gt; est à mettre sur la dernière version de votre image. Il sera automatiquement retiré de toutes les autres versions de votre image.  &lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;docker images&amp;lt;/code&amp;gt; permet ensuite de lister les tags disponibles localement. Si le build a réussi, vous devriez y voir votre image.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
~$ docker images&lt;br /&gt;
REPOSITORY                                                         TAG             IMAGE ID       CREATED         SIZE&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           2.0.1           b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           7ad814c         b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           latest          b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           642e23b         8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           latest          8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           502564d         9a2050fc09d4   4 days ago      1.38GB&lt;br /&gt;
semaphoreui/semaphore                                              v2.12.4         136bec584184   2 weeks ago     727MB&lt;br /&gt;
ghcr.io/mastergeonum/cartondes                                     main            a95ee654e34a   5 weeks ago     205MB&lt;br /&gt;
dockurr/windows                                                    latest          c3419fd6e55a   2 months ago    384MB&lt;br /&gt;
docker.osgeo.org/geoserver                                         2.26.1          a91188b23092   3 months ago    608MB&lt;br /&gt;
rocker/verse                                                       4.4.1           202c993befdc   3 months ago    3.77GB&lt;br /&gt;
ghcr.io/evs-gis/glourbee-ui                                        1.1.0           03e05bed5617   4 months ago    1.47GB&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Remarquez que &amp;lt;code&amp;gt;ghcr.io/evs-gis/mapdoapp&amp;lt;/code&amp;gt; est présente plusieurs fois avec des tags différents, mais le même IMAGE ID. Il s&#039;agit bien de la même image et elle n&#039;est pas dupliquée sur le disque.&lt;br /&gt;
&lt;br /&gt;
Pour supprimer un tag, on utilisera la commande &amp;lt;code&amp;gt;docker image rm ghcr.io/evs-gis/mapdoapp:2.0.1&amp;lt;/code&amp;gt;. Si plus aucun tag n&#039;existe pour l&#039;image, elle sera complètement supprimée du disque local. &lt;br /&gt;
&lt;br /&gt;
=== Tester l&#039;image ===&lt;br /&gt;
Pour tester son image, on peut utiliser la commande &amp;lt;code&amp;gt;docker run&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker run --rm -p 3838:3838 ghcr.io/evs-gis/mapdoapp:latest&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* --rm : Supprimer le container lorsqu&#039;il est arrêté.&lt;br /&gt;
* -p 3838:3838 : exposer le port 3838 local et le faire pointer vers le port 3838 dans le container.&lt;br /&gt;
&lt;br /&gt;
Les logs de l&#039;application s&#039;affichent dans le terminal et l&#039;application est accessible dans un navigateur à l&#039;adresse http://localhost:3838. Pour stopper le container, &#039;&#039;&#039;Ctrl+C&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Faire du ménage localement ===&lt;br /&gt;
Il arrive que des vieilles images sans tag, de vieux volumes et de vieux containers plantés restent sur le disque au fil du temps. Tester la commande &amp;lt;code&amp;gt;docker ps --all&amp;lt;/code&amp;gt; par exemple, pour lister tous les containers locaux (lancés ou stoppés). La commande &amp;lt;code&amp;gt;docker system prune&amp;lt;/code&amp;gt; permet de faire le grand ménage.&lt;br /&gt;
&lt;br /&gt;
=== Pousser l&#039;image sur un registre ===&lt;br /&gt;
Pour que le serveur ShinyProxy (ainsi que le monde entier !) puisse accéder à votre image, il faut la pousser sur un registre. Si vous ne souhaitez pas que votre image soit publique, vous pouvez utiliser le registre ghcr.io/evs-gis (le serveur ShinyProxy y a accès même si les images sont privées). &lt;br /&gt;
&lt;br /&gt;
Il faut d&#039;abord se loguer sur le registre avec son login GitHub habituel, et un &#039;&#039;Personal Access Token&#039;&#039; en guise de mot de passe. Pour [https://github.com/settings/tokens/new obtenir un &#039;&#039;Personal Access Token&#039;&#039;], rendez-vous [https://github.com/settings/tokens/new ici] et activez bien le droit &amp;lt;code&amp;gt;write:packages&amp;lt;/code&amp;gt; pour votre token.  &amp;lt;syntaxhighlight lang=&amp;quot;sh&amp;quot;&amp;gt;# La commande suivante est à lancer pour se loguer sur le registre. Il n&#039;est pas nécessaire de la relancer à chaque fois.&lt;br /&gt;
docker login ghcr.io&lt;br /&gt;
&lt;br /&gt;
# Pour pousser tous les tags de notre image sur le registre, on utilise ensuite la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp -a&lt;br /&gt;
&lt;br /&gt;
# Pour pousser seulement un tag spécifique, on préfèrera la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp:latest&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration de l&#039;application sur le serveur ShinyProxy de production ==&lt;br /&gt;
La configuration initiale de l&#039;application doit être faite par l&#039;administrateur du serveur.&lt;br /&gt;
&lt;br /&gt;
== Mise à jour d&#039;une appli ==&lt;br /&gt;
La mise à jour d&#039;une appli sur le serveur de prod ne nécessite généralement pas de modifier la configuration. Il suffit de &#039;&#039;&#039;pousser la nouvelle version de votre image sur votre registre&#039;&#039;&#039; (avec le tag latest), puis de &#039;&#039;&#039;lancer le job &#039;&#039;Mise à jour d&#039;une application en production sous ShinyProxy&#039;&#039; sur Jenkins&#039;&#039;&#039; pour forcer le redémarrage des containers d&#039;attente déjà lancés. Si l&#039;intégration continue a été correctement configurée, le job Jenkins de mise à jour devrait se lancer automatiquement dès que la nouvelle version de l&#039;image arrive sur le registre. &lt;br /&gt;
 &lt;br /&gt;
== Debug des applis en prod ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour accéder aux logs des applications sur le serveur de prod, se connecter en ssh aux archives:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh archives.evs.ens-lyon.fr&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Puis afficher le contenu des logs:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-stdout.log &lt;br /&gt;
# récupérer les 10 (option -n) dernières lignes de stdout &lt;br /&gt;
&lt;br /&gt;
tail -n 10 -f /data/echanges/ShinyProxyLogs/shinyapps-stderr.log &lt;br /&gt;
# voir stderr défiler en temps réel (option -f)&lt;br /&gt;
&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# voir les 10 dernières lignes de tous les logs (standard et erreur)&lt;br /&gt;
&lt;br /&gt;
tail -n 100 ... &lt;br /&gt;
# pour les 100 dernières lignes, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Tous les logs (quelque soit l&#039;appli) apparaissent. Pour chercher spécifiquement les lignes correspondant à une appli précise (par exemple mapdoapp):&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
grep mapdoapp /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# N&#039;affiche que les lignes qui concernent mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On peut aussi combiner défilement en live + grep&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -f /data/echanges/ShinyProxyLogs/shinyapps-std*.log | grep mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== To do list mise en ligne d&#039;une nouvelle appli ==&lt;br /&gt;
1) récupérer dans le dossier d&#039;une appli déjà mise en ligne sur ShinyProxy: run.R (si appli learnr), dockerfile, et le dossier .github qui contient un yaml qui permettra de build et push l&#039;image docker sur le ShinyProxy.&lt;br /&gt;
&lt;br /&gt;
2) modifier dans run.R (si appli learnr) le nom du Rmd à tricoter&lt;br /&gt;
&lt;br /&gt;
3) modifier dans le yaml le nom de l&#039;image docker (deux lignes à changer)&lt;br /&gt;
&lt;br /&gt;
4) modifier le dockerfile: infos sur l&#039;appli et noms des packages à installer&lt;br /&gt;
&lt;br /&gt;
5) build l&#039;image docker localement pour vérifier que tout est ok, par ex. &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker build . -t ghcr.io/lvaudor/learnr_exos_shiny:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;6) run un container pour vérifier que tout est ok, par ex.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --rm -p 3840:3840 ghcr.io/learnr_shiny_exos:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;7) Aller sur le repo github et changer paramètres: Settings =&amp;gt; Actions =&amp;gt; General =&amp;gt; Workflow permissions =&amp;gt; Cocher Read and write permissions&lt;br /&gt;
&lt;br /&gt;
8) Faire un commit et push des dernières modifs sur main =&amp;gt; Une image docker doit être créée dans les github Actions&lt;br /&gt;
&lt;br /&gt;
9) Prévenir Samuel pour qu&#039;il ajoute la nouvelle appli au registre&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== To do list mise à jour d&#039;une appli ==&lt;br /&gt;
1) build l&#039;image docker localement pour vérifier que tout est ok, par ex.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker build . -t ghcr.io/lvaudor/learnr_exos_shiny:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;2) run un container pour vérifier que tout est ok, par ex.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --rm -p 3840:3840 ghcr.io/learnr_shiny_exos:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;3) Faire le docker push pour mettre à jour le registre&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker push ghcr.io/lvaudor/learnr_shiny_exos:latest&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Catégorie:Tutoriel]]&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1226</id>
		<title>ShinyProxy</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1226"/>
		<updated>2026-04-10T09:01:38Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : /* To do list mise en ligne d&amp;#039;une nouvelle appli */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;big&amp;gt;Attention : Page en cours de rédaction&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ISIG-Apps passe sous ShinyProxy pour améliorer la stabilité et l&#039;isolation de vos applications pendant les montées en charge. Le fonctionnement est très différent par rapport à l&#039;ancien Shiny-Server et nécessite quelques bases dans l&#039;utilisation de Docker. L&#039;objectif de cette page est de vous guider, rapidement et simplement, dans le nouveau workflow dev &amp;gt; prod en partant du principe que vous ne connaissez encore pas grand-chose à Docker.&lt;br /&gt;
&lt;br /&gt;
== Principe de fonctionnement de ShinyProxy (et Docker) ==&lt;br /&gt;
ShinyProxy fonctionne comme un orchestrateur de conteneurs Docker. Chaque appli configurée doit avoir une image Docker associée présente sur le serveur qui exécute ShinyProxy. C&#039;est ShinyProxy qui s&#039;occupera ensuite de lancer et stopper un conteneur à chaque fois qu&#039;un internaute se connectera ou se déconnectera de votre appli.    &lt;br /&gt;
[[Fichier:Schéma Docker.png|centré|sans_cadre|1054x1054px]]    &lt;br /&gt;
&lt;br /&gt;
Afin que votre application puisse fonctionner sur ShinyProxy, il va donc falloir créer une &#039;&#039;&#039;image&#039;&#039;&#039; qui permettra au serveur ShinyProxy de lancer des &#039;&#039;&#039;containers&#039;&#039;&#039; de votre application.  &lt;br /&gt;
&lt;br /&gt;
Vous n&#039;aurez généralement pas besoin de volume pour stocker des données pérennes dans le cas d&#039;une application Shiny. Si votre application utilise une base de données, celle-ci devra être externalisée (hébergée sur le serveur de bases de données d&#039;ISIG par exemple). &lt;br /&gt;
&lt;br /&gt;
ShinyProxy fera en sorte qu&#039;un certain nombre de containers (à définir dans la configuration décrite à la fin de ce tutoriel) soient toujours disponibles pour de nouveaux utilisateurs qui se connecteraient à votre application. Il s&#039;occupera également de supprimer les containers quand vos utilisateurs se déconnectent. &lt;br /&gt;
&lt;br /&gt;
== Conteneurisation de votre appli Shiny ==&lt;br /&gt;
La conteneurisation peut se faire directement sur votre machine personelle si vous y avez installé Docker (https://docs.docker.com/engine/install/), ou sur le serveur isig-apps de dev via [https://rstudio.evs.ens-lyon.fr Rstudio server] et son terminal intégré.&lt;br /&gt;
&lt;br /&gt;
=== Fixer le port ===&lt;br /&gt;
Pour fonctionner en mode conteneurisé, votre application devra écouter toujours sur le même port (ce qui n&#039;est pas le comportement par défaut d&#039;une application Shiny). &lt;br /&gt;
&lt;br /&gt;
Afin de s&#039;en assurer, il faut : &lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un appli Shiny classique, ajouter dans &amp;lt;code&amp;gt;options(..)&amp;lt;/code&amp;gt;, avant l&#039;appel de &amp;lt;code&amp;gt;shinyApp(..)&amp;lt;/code&amp;gt;, les options suivantes : &amp;lt;code&amp;gt;&amp;quot;shiny.port&amp;quot;=3841&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;&amp;quot;shiny.host&amp;quot;=&amp;quot;0.0.0.0&amp;quot;&amp;lt;/code&amp;gt;. Par exemple :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;r&amp;quot;&amp;gt;&lt;br /&gt;
library(shiny)&lt;br /&gt;
library(glourbi)&lt;br /&gt;
&lt;br /&gt;
# Dans cet exemple, l&#039;application écoutera systématiquement sur le port 3838&lt;br /&gt;
options(&amp;quot;shiny.port&amp;quot; = 3838, &amp;quot;shiny.host&amp;quot; = &amp;quot;0.0.0.0&amp;quot;, &amp;quot;golem.app.prod&amp;quot; = TRUE)&lt;br /&gt;
&lt;br /&gt;
shinyApp(ui=glourbapp:::app_ui,server=glourbapp:::app_server)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un document Rmarkdown, ........&lt;br /&gt;
&lt;br /&gt;
=== Choisir l&#039;image source ===&lt;br /&gt;
La construction d&#039;une image Docker se fait sur la base... d&#039;une autre. On choisi en général son image de base en fonction de ce qu&#039;on va faire avec. Pour une application Shiny, nous aurons besoin d&#039;une image Docker spécialisée en R. &lt;br /&gt;
&lt;br /&gt;
Le [https://rocker-project.org/images/ projet Rocker] propose plusieurs images de base avec différentes quantités de packages pré-installés. Lorsque l&#039;on choisi son image de base, il faut trouver le bon compromis entre une image légère et une image avec suffisamment de dépendances pré-installées pour qu&#039;elle soit pratique.&lt;br /&gt;
&lt;br /&gt;
L&#039;image [https://eddelbuettel.github.io/r2u/ r2u] est une bonne base assez simple à utiliser, car elle va chercher des binaires précompilés des packages R que l&#039;on souhaite installer et toutes leurs dépendances, librairies système incluses ! Pratiquement rien n&#039;y est pré-installé, il faudra donc bien préciser toutes les dépendances dont vous avez besoin. En contrepartie, l&#039;image sera plutôt légère, ce qui est une bonne chose ! L&#039;inconvénient de cette fonctionnalité est (à ma connaissance) qu&#039;elle ne fonctionne qu&#039;avec la fonction &amp;lt;code&amp;gt;install.packages(...)&amp;lt;/code&amp;gt;. Il n&#039;est donc pas possible d&#039;installer une version spécifique d&#039;un package avec &amp;lt;code&amp;gt;remotes::install_version(...)&amp;lt;/code&amp;gt; par exemple (la fonction reste utilisable de manière classique). &lt;br /&gt;
&lt;br /&gt;
=== Écrire le Dockerfile ===&lt;br /&gt;
&lt;br /&gt;
La création d&#039;une image Docker repose sur l&#039;écriture d&#039;un fichier texte appelé &#039;&#039;&#039;Dockerfile&#039;&#039;&#039; (sans extension).&lt;br /&gt;
&lt;br /&gt;
Voici un exemple de Dockerfile pour l&#039;application GloUrb :&amp;lt;syntaxhighlight lang=&amp;quot;dockerfile&amp;quot;&amp;gt;&lt;br /&gt;
# On commence par définir l&#039;image sur laquelle va se baser la notre&lt;br /&gt;
FROM rocker/r2u:jammy&lt;br /&gt;
&lt;br /&gt;
# On précise quelques infos qui permettrons d&#039;identifier l&#039;image&lt;br /&gt;
LABEL org.opencontainers.image.authors=&amp;quot;Lise Vaudor &amp;lt;lise.vaudor@ens-lyon.fr&amp;gt;, Samuel Dunesme &amp;lt;samuel.dunesme@ens-lyon.fr&amp;gt;&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.source=&amp;quot;https://github.com/glourb/glourbapp&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.documentation=&amp;quot;https://evs-gis.github.io/glourbdoc/&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.version=&amp;quot;0.0.0.9000&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.description=&amp;quot;An app for the GloUrb project&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# On peut éventuellement générer des locales supplémentaires si notre appli utilise d&#039;autres langues que l&#039;anglais&lt;br /&gt;
RUN locale-gen fr_FR.UTF-8&lt;br /&gt;
&lt;br /&gt;
# On liste maintenant toutes les dépendances R à installer&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tidyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;shiny&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;config&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;testthat&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tibble&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;purrr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;dplyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;ggplot2&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;forcats&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;magrittr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;golem&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;sf&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;plotly&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;spelling&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;mclust&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;leaflet&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cluster&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cowplot&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;FactoMineR&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;glue&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;grDevices&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RColorBrewer&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;remotes&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cicerone&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RPostgres&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DBI&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DT&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
RUN Rscript -e &#039;remotes::install_github(&amp;quot;glourb/glourbi&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
# On copie l&#039;arborescence de fichiers dans un dossier app à la racine de l&#039;image. Ce sera le working directory des containers lancés avec notre image&lt;br /&gt;
RUN mkdir /app&lt;br /&gt;
ADD . /app&lt;br /&gt;
WORKDIR /app&lt;br /&gt;
&lt;br /&gt;
# Si besoin, on peut installer notre package&lt;br /&gt;
RUN R -e &#039;remotes::install_local()&#039;&lt;br /&gt;
&lt;br /&gt;
# On détermine le port qui sera exposé (attention à bien fixer le port sur lequel votre appli écoute, cf. ci-dessus)&lt;br /&gt;
EXPOSE 3838&lt;br /&gt;
&lt;br /&gt;
# Pour plus de sécurité, on fait en sorte que les containers ne se lancent pas avec l&#039;utilisateur &amp;quot;root&amp;quot;, mais avec un utilisateur &amp;quot;app&amp;quot; dédié&lt;br /&gt;
RUN groupadd -g 1010 app &amp;amp;&amp;amp; useradd -c &#039;app&#039; -u 1010 -g 1010 -m -d /home/app -s /sbin/nologin app&lt;br /&gt;
USER app&lt;br /&gt;
&lt;br /&gt;
# Enfin, on précise la commande qui permet de lancer notre appli. C&#039;est cette commande qui sera lancée par défaut par tout nouveau container lancé avec notre image&lt;br /&gt;
CMD  [&amp;quot;R&amp;quot;, &amp;quot;-f&amp;quot;, &amp;quot;app.R&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Construire l&#039;image Docker ===&lt;br /&gt;
Pour construire l&#039;image docker à l&#039;aide du Dockerfile, il faut lancer la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. C&#039;est à ce moment que l&#039;on va versionner l&#039;image en la taguant avec l&#039;argument &amp;lt;code&amp;gt;-t&amp;lt;/code&amp;gt;. On peut mettre directement plusieurs tags à une image, ou les ajouter à posteriori en relançant la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. Si le Dockerfile n&#039;a pas changé depuis le dernier build, &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt; ne fera qu&#039;ajouter les tags à l&#039;image existante. &lt;br /&gt;
&lt;br /&gt;
Pour que la CLI Docker trouve bien le Dockerfile, on lance le terminal dans le dossier ou ce Dockerfile est enregistré. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker build . -t ghcr.io/evs-gis/mapdoapp:latest -t ghcr.io/evs-gis/mapdoapp:2.0.1 -t ghcr.io/evs-gis/mapdoapp:$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remarquez que le tag doit contenir le chemin complet vers le registre où sera poussée l&#039;image (étape suivante). Si vous ne précisez pas le chemin (par exemple &amp;lt;code&amp;gt;mapdoapp:latest&amp;lt;/code&amp;gt;), le registre utilisé sera DockerHub. &lt;br /&gt;
&lt;br /&gt;
Notez le tag &amp;lt;code&amp;gt;$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt; qui permet de taguer l&#039;image avec le hash (la référence) du commit actuel (ne fonctionne que si vous êtes dans un dépôt git). Ce tag est bien pratique si vous n&#039;incrémentez pas un numéro de version par ailleurs (&amp;lt;code&amp;gt;2.0.1&amp;lt;/code&amp;gt; dans l&#039;exemple ci-dessus). &lt;br /&gt;
&lt;br /&gt;
Le tag &amp;lt;code&amp;gt;latest&amp;lt;/code&amp;gt; est à mettre sur la dernière version de votre image. Il sera automatiquement retiré de toutes les autres versions de votre image.  &lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;docker images&amp;lt;/code&amp;gt; permet ensuite de lister les tags disponibles localement. Si le build a réussi, vous devriez y voir votre image.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
~$ docker images&lt;br /&gt;
REPOSITORY                                                         TAG             IMAGE ID       CREATED         SIZE&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           2.0.1           b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           7ad814c         b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           latest          b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           642e23b         8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           latest          8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           502564d         9a2050fc09d4   4 days ago      1.38GB&lt;br /&gt;
semaphoreui/semaphore                                              v2.12.4         136bec584184   2 weeks ago     727MB&lt;br /&gt;
ghcr.io/mastergeonum/cartondes                                     main            a95ee654e34a   5 weeks ago     205MB&lt;br /&gt;
dockurr/windows                                                    latest          c3419fd6e55a   2 months ago    384MB&lt;br /&gt;
docker.osgeo.org/geoserver                                         2.26.1          a91188b23092   3 months ago    608MB&lt;br /&gt;
rocker/verse                                                       4.4.1           202c993befdc   3 months ago    3.77GB&lt;br /&gt;
ghcr.io/evs-gis/glourbee-ui                                        1.1.0           03e05bed5617   4 months ago    1.47GB&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Remarquez que &amp;lt;code&amp;gt;ghcr.io/evs-gis/mapdoapp&amp;lt;/code&amp;gt; est présente plusieurs fois avec des tags différents, mais le même IMAGE ID. Il s&#039;agit bien de la même image et elle n&#039;est pas dupliquée sur le disque.&lt;br /&gt;
&lt;br /&gt;
Pour supprimer un tag, on utilisera la commande &amp;lt;code&amp;gt;docker image rm ghcr.io/evs-gis/mapdoapp:2.0.1&amp;lt;/code&amp;gt;. Si plus aucun tag n&#039;existe pour l&#039;image, elle sera complètement supprimée du disque local. &lt;br /&gt;
&lt;br /&gt;
=== Tester l&#039;image ===&lt;br /&gt;
Pour tester son image, on peut utiliser la commande &amp;lt;code&amp;gt;docker run&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker run --rm -p 3838:3838 ghcr.io/evs-gis/mapdoapp:latest&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* --rm : Supprimer le container lorsqu&#039;il est arrêté.&lt;br /&gt;
* -p 3838:3838 : exposer le port 3838 local et le faire pointer vers le port 3838 dans le container.&lt;br /&gt;
&lt;br /&gt;
Les logs de l&#039;application s&#039;affichent dans le terminal et l&#039;application est accessible dans un navigateur à l&#039;adresse http://localhost:3838. Pour stopper le container, &#039;&#039;&#039;Ctrl+C&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Faire du ménage localement ===&lt;br /&gt;
Il arrive que des vieilles images sans tag, de vieux volumes et de vieux containers plantés restent sur le disque au fil du temps. Tester la commande &amp;lt;code&amp;gt;docker ps --all&amp;lt;/code&amp;gt; par exemple, pour lister tous les containers locaux (lancés ou stoppés). La commande &amp;lt;code&amp;gt;docker system prune&amp;lt;/code&amp;gt; permet de faire le grand ménage.&lt;br /&gt;
&lt;br /&gt;
=== Pousser l&#039;image sur un registre ===&lt;br /&gt;
Pour que le serveur ShinyProxy (ainsi que le monde entier !) puisse accéder à votre image, il faut la pousser sur un registre. Si vous ne souhaitez pas que votre image soit publique, vous pouvez utiliser le registre ghcr.io/evs-gis (le serveur ShinyProxy y a accès même si les images sont privées). &lt;br /&gt;
&lt;br /&gt;
Il faut d&#039;abord se loguer sur le registre avec son login GitHub habituel, et un &#039;&#039;Personal Access Token&#039;&#039; en guise de mot de passe. Pour [https://github.com/settings/tokens/new obtenir un &#039;&#039;Personal Access Token&#039;&#039;], rendez-vous [https://github.com/settings/tokens/new ici] et activez bien le droit &amp;lt;code&amp;gt;write:packages&amp;lt;/code&amp;gt; pour votre token.  &amp;lt;syntaxhighlight lang=&amp;quot;sh&amp;quot;&amp;gt;&lt;br /&gt;
# La commande suivante est à lancer pour se loguer sur le registre. Il n&#039;est pas nécessaire de la relancer à chaque fois.&lt;br /&gt;
docker login ghcr.io&lt;br /&gt;
&lt;br /&gt;
# Pour pousser tous les tags de notre image sur le registre, on utilise ensuite la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp -a&lt;br /&gt;
&lt;br /&gt;
# Pour pousser seulement un tag spécifique, on préfèrera la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration de l&#039;application sur le serveur ShinyProxy de production ==&lt;br /&gt;
La configuration initiale de l&#039;application doit être faite par l&#039;administrateur du serveur.&lt;br /&gt;
&lt;br /&gt;
== Mise à jour d&#039;une appli ==&lt;br /&gt;
La mise à jour d&#039;une appli sur le serveur de prod ne nécessite généralement pas de modifier la configuration. Il suffit de &#039;&#039;&#039;pousser la nouvelle version de votre image sur votre registre&#039;&#039;&#039; (avec le tag latest), puis de &#039;&#039;&#039;lancer le job &#039;&#039;Mise à jour d&#039;une application en production sous ShinyProxy&#039;&#039; sur Jenkins&#039;&#039;&#039; pour forcer le redémarrage des containers d&#039;attente déjà lancés. Si l&#039;intégration continue a été correctement configurée, le job Jenkins de mise à jour devrait se lancer automatiquement dès que la nouvelle version de l&#039;image arrive sur le registre. &lt;br /&gt;
 &lt;br /&gt;
== Debug des applis en prod ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour accéder aux logs des applications sur le serveur de prod, se connecter en ssh aux archives:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh archives.evs.ens-lyon.fr&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Puis afficher le contenu des logs:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-stdout.log &lt;br /&gt;
# récupérer les 10 (option -n) dernières lignes de stdout &lt;br /&gt;
&lt;br /&gt;
tail -n 10 -f /data/echanges/ShinyProxyLogs/shinyapps-stderr.log &lt;br /&gt;
# voir stderr défiler en temps réel (option -f)&lt;br /&gt;
&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# voir les 10 dernières lignes de tous les logs (standard et erreur)&lt;br /&gt;
&lt;br /&gt;
tail -n 100 ... &lt;br /&gt;
# pour les 100 dernières lignes, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Tous les logs (quelque soit l&#039;appli) apparaissent. Pour chercher spécifiquement les lignes correspondant à une appli précise (par exemple mapdoapp):&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
grep mapdoapp /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# N&#039;affiche que les lignes qui concernent mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On peut aussi combiner défilement en live + grep&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -f /data/echanges/ShinyProxyLogs/shinyapps-std*.log | grep mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== To do list mise en ligne d&#039;une nouvelle appli ==&lt;br /&gt;
1) récupérer dans le dossier d&#039;une appli déjà mise en ligne sur ShinyProxy: run.R (si appli learnr), dockerfile, et le dossier .github qui contient un yaml qui permettra de build et push l&#039;image docker sur le ShinyProxy.&lt;br /&gt;
&lt;br /&gt;
2) modifier dans run.R (si appli learnr) le nom du Rmd à tricoter&lt;br /&gt;
&lt;br /&gt;
3) modifier dans le yaml le nom de l&#039;image docker (deux lignes à changer)&lt;br /&gt;
&lt;br /&gt;
4) modifier le dockerfile: infos sur l&#039;appli et noms des packages à installer&lt;br /&gt;
&lt;br /&gt;
5) build l&#039;image docker localement pour vérifier que tout est ok, par ex. &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker build . -t ghcr.io/lvaudor/learnr_exos_shiny:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;6) run un container pour vérifier que tout est ok, par ex.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --rm -p 3840:3840 ghcr.io/learnr_shiny_exos:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;7) Aller sur le repo github et changer paramètres: Settings =&amp;gt; Actions =&amp;gt; General =&amp;gt; Workflow permissions =&amp;gt; Cocher Read and write permissions&lt;br /&gt;
&lt;br /&gt;
8) Faire un commit et push des dernières modifs sur main =&amp;gt; Une image docker doit être créée dans les github Actions&lt;br /&gt;
&lt;br /&gt;
9) Prévenir Samuel pour qu&#039;il ajoute la nouvelle appli au registre&lt;br /&gt;
[[Catégorie:Tutoriel]]&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1225</id>
		<title>ShinyProxy</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1225"/>
		<updated>2026-04-10T09:01:06Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : TODO ajout d&amp;#039;une nouvelle appli&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;big&amp;gt;Attention : Page en cours de rédaction&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ISIG-Apps passe sous ShinyProxy pour améliorer la stabilité et l&#039;isolation de vos applications pendant les montées en charge. Le fonctionnement est très différent par rapport à l&#039;ancien Shiny-Server et nécessite quelques bases dans l&#039;utilisation de Docker. L&#039;objectif de cette page est de vous guider, rapidement et simplement, dans le nouveau workflow dev &amp;gt; prod en partant du principe que vous ne connaissez encore pas grand-chose à Docker.&lt;br /&gt;
&lt;br /&gt;
== Principe de fonctionnement de ShinyProxy (et Docker) ==&lt;br /&gt;
ShinyProxy fonctionne comme un orchestrateur de conteneurs Docker. Chaque appli configurée doit avoir une image Docker associée présente sur le serveur qui exécute ShinyProxy. C&#039;est ShinyProxy qui s&#039;occupera ensuite de lancer et stopper un conteneur à chaque fois qu&#039;un internaute se connectera ou se déconnectera de votre appli.    &lt;br /&gt;
[[Fichier:Schéma Docker.png|centré|sans_cadre|1054x1054px]]    &lt;br /&gt;
&lt;br /&gt;
Afin que votre application puisse fonctionner sur ShinyProxy, il va donc falloir créer une &#039;&#039;&#039;image&#039;&#039;&#039; qui permettra au serveur ShinyProxy de lancer des &#039;&#039;&#039;containers&#039;&#039;&#039; de votre application.  &lt;br /&gt;
&lt;br /&gt;
Vous n&#039;aurez généralement pas besoin de volume pour stocker des données pérennes dans le cas d&#039;une application Shiny. Si votre application utilise une base de données, celle-ci devra être externalisée (hébergée sur le serveur de bases de données d&#039;ISIG par exemple). &lt;br /&gt;
&lt;br /&gt;
ShinyProxy fera en sorte qu&#039;un certain nombre de containers (à définir dans la configuration décrite à la fin de ce tutoriel) soient toujours disponibles pour de nouveaux utilisateurs qui se connecteraient à votre application. Il s&#039;occupera également de supprimer les containers quand vos utilisateurs se déconnectent. &lt;br /&gt;
&lt;br /&gt;
== Conteneurisation de votre appli Shiny ==&lt;br /&gt;
La conteneurisation peut se faire directement sur votre machine personelle si vous y avez installé Docker (https://docs.docker.com/engine/install/), ou sur le serveur isig-apps de dev via [https://rstudio.evs.ens-lyon.fr Rstudio server] et son terminal intégré.&lt;br /&gt;
&lt;br /&gt;
=== Fixer le port ===&lt;br /&gt;
Pour fonctionner en mode conteneurisé, votre application devra écouter toujours sur le même port (ce qui n&#039;est pas le comportement par défaut d&#039;une application Shiny). &lt;br /&gt;
&lt;br /&gt;
Afin de s&#039;en assurer, il faut : &lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un appli Shiny classique, ajouter dans &amp;lt;code&amp;gt;options(..)&amp;lt;/code&amp;gt;, avant l&#039;appel de &amp;lt;code&amp;gt;shinyApp(..)&amp;lt;/code&amp;gt;, les options suivantes : &amp;lt;code&amp;gt;&amp;quot;shiny.port&amp;quot;=3841&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;&amp;quot;shiny.host&amp;quot;=&amp;quot;0.0.0.0&amp;quot;&amp;lt;/code&amp;gt;. Par exemple :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;r&amp;quot;&amp;gt;&lt;br /&gt;
library(shiny)&lt;br /&gt;
library(glourbi)&lt;br /&gt;
&lt;br /&gt;
# Dans cet exemple, l&#039;application écoutera systématiquement sur le port 3838&lt;br /&gt;
options(&amp;quot;shiny.port&amp;quot; = 3838, &amp;quot;shiny.host&amp;quot; = &amp;quot;0.0.0.0&amp;quot;, &amp;quot;golem.app.prod&amp;quot; = TRUE)&lt;br /&gt;
&lt;br /&gt;
shinyApp(ui=glourbapp:::app_ui,server=glourbapp:::app_server)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un document Rmarkdown, ........&lt;br /&gt;
&lt;br /&gt;
=== Choisir l&#039;image source ===&lt;br /&gt;
La construction d&#039;une image Docker se fait sur la base... d&#039;une autre. On choisi en général son image de base en fonction de ce qu&#039;on va faire avec. Pour une application Shiny, nous aurons besoin d&#039;une image Docker spécialisée en R. &lt;br /&gt;
&lt;br /&gt;
Le [https://rocker-project.org/images/ projet Rocker] propose plusieurs images de base avec différentes quantités de packages pré-installés. Lorsque l&#039;on choisi son image de base, il faut trouver le bon compromis entre une image légère et une image avec suffisamment de dépendances pré-installées pour qu&#039;elle soit pratique.&lt;br /&gt;
&lt;br /&gt;
L&#039;image [https://eddelbuettel.github.io/r2u/ r2u] est une bonne base assez simple à utiliser, car elle va chercher des binaires précompilés des packages R que l&#039;on souhaite installer et toutes leurs dépendances, librairies système incluses ! Pratiquement rien n&#039;y est pré-installé, il faudra donc bien préciser toutes les dépendances dont vous avez besoin. En contrepartie, l&#039;image sera plutôt légère, ce qui est une bonne chose ! L&#039;inconvénient de cette fonctionnalité est (à ma connaissance) qu&#039;elle ne fonctionne qu&#039;avec la fonction &amp;lt;code&amp;gt;install.packages(...)&amp;lt;/code&amp;gt;. Il n&#039;est donc pas possible d&#039;installer une version spécifique d&#039;un package avec &amp;lt;code&amp;gt;remotes::install_version(...)&amp;lt;/code&amp;gt; par exemple (la fonction reste utilisable de manière classique). &lt;br /&gt;
&lt;br /&gt;
=== Écrire le Dockerfile ===&lt;br /&gt;
&lt;br /&gt;
La création d&#039;une image Docker repose sur l&#039;écriture d&#039;un fichier texte appelé &#039;&#039;&#039;Dockerfile&#039;&#039;&#039; (sans extension).&lt;br /&gt;
&lt;br /&gt;
Voici un exemple de Dockerfile pour l&#039;application GloUrb :&amp;lt;syntaxhighlight lang=&amp;quot;dockerfile&amp;quot;&amp;gt;&lt;br /&gt;
# On commence par définir l&#039;image sur laquelle va se baser la notre&lt;br /&gt;
FROM rocker/r2u:jammy&lt;br /&gt;
&lt;br /&gt;
# On précise quelques infos qui permettrons d&#039;identifier l&#039;image&lt;br /&gt;
LABEL org.opencontainers.image.authors=&amp;quot;Lise Vaudor &amp;lt;lise.vaudor@ens-lyon.fr&amp;gt;, Samuel Dunesme &amp;lt;samuel.dunesme@ens-lyon.fr&amp;gt;&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.source=&amp;quot;https://github.com/glourb/glourbapp&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.documentation=&amp;quot;https://evs-gis.github.io/glourbdoc/&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.version=&amp;quot;0.0.0.9000&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.description=&amp;quot;An app for the GloUrb project&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# On peut éventuellement générer des locales supplémentaires si notre appli utilise d&#039;autres langues que l&#039;anglais&lt;br /&gt;
RUN locale-gen fr_FR.UTF-8&lt;br /&gt;
&lt;br /&gt;
# On liste maintenant toutes les dépendances R à installer&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tidyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;shiny&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;config&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;testthat&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tibble&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;purrr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;dplyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;ggplot2&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;forcats&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;magrittr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;golem&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;sf&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;plotly&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;spelling&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;mclust&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;leaflet&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cluster&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cowplot&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;FactoMineR&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;glue&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;grDevices&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RColorBrewer&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;remotes&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cicerone&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RPostgres&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DBI&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DT&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
RUN Rscript -e &#039;remotes::install_github(&amp;quot;glourb/glourbi&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
# On copie l&#039;arborescence de fichiers dans un dossier app à la racine de l&#039;image. Ce sera le working directory des containers lancés avec notre image&lt;br /&gt;
RUN mkdir /app&lt;br /&gt;
ADD . /app&lt;br /&gt;
WORKDIR /app&lt;br /&gt;
&lt;br /&gt;
# Si besoin, on peut installer notre package&lt;br /&gt;
RUN R -e &#039;remotes::install_local()&#039;&lt;br /&gt;
&lt;br /&gt;
# On détermine le port qui sera exposé (attention à bien fixer le port sur lequel votre appli écoute, cf. ci-dessus)&lt;br /&gt;
EXPOSE 3838&lt;br /&gt;
&lt;br /&gt;
# Pour plus de sécurité, on fait en sorte que les containers ne se lancent pas avec l&#039;utilisateur &amp;quot;root&amp;quot;, mais avec un utilisateur &amp;quot;app&amp;quot; dédié&lt;br /&gt;
RUN groupadd -g 1010 app &amp;amp;&amp;amp; useradd -c &#039;app&#039; -u 1010 -g 1010 -m -d /home/app -s /sbin/nologin app&lt;br /&gt;
USER app&lt;br /&gt;
&lt;br /&gt;
# Enfin, on précise la commande qui permet de lancer notre appli. C&#039;est cette commande qui sera lancée par défaut par tout nouveau container lancé avec notre image&lt;br /&gt;
CMD  [&amp;quot;R&amp;quot;, &amp;quot;-f&amp;quot;, &amp;quot;app.R&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Construire l&#039;image Docker ===&lt;br /&gt;
Pour construire l&#039;image docker à l&#039;aide du Dockerfile, il faut lancer la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. C&#039;est à ce moment que l&#039;on va versionner l&#039;image en la taguant avec l&#039;argument &amp;lt;code&amp;gt;-t&amp;lt;/code&amp;gt;. On peut mettre directement plusieurs tags à une image, ou les ajouter à posteriori en relançant la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. Si le Dockerfile n&#039;a pas changé depuis le dernier build, &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt; ne fera qu&#039;ajouter les tags à l&#039;image existante. &lt;br /&gt;
&lt;br /&gt;
Pour que la CLI Docker trouve bien le Dockerfile, on lance le terminal dans le dossier ou ce Dockerfile est enregistré. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker build . -t ghcr.io/evs-gis/mapdoapp:latest -t ghcr.io/evs-gis/mapdoapp:2.0.1 -t ghcr.io/evs-gis/mapdoapp:$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remarquez que le tag doit contenir le chemin complet vers le registre où sera poussée l&#039;image (étape suivante). Si vous ne précisez pas le chemin (par exemple &amp;lt;code&amp;gt;mapdoapp:latest&amp;lt;/code&amp;gt;), le registre utilisé sera DockerHub. &lt;br /&gt;
&lt;br /&gt;
Notez le tag &amp;lt;code&amp;gt;$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt; qui permet de taguer l&#039;image avec le hash (la référence) du commit actuel (ne fonctionne que si vous êtes dans un dépôt git). Ce tag est bien pratique si vous n&#039;incrémentez pas un numéro de version par ailleurs (&amp;lt;code&amp;gt;2.0.1&amp;lt;/code&amp;gt; dans l&#039;exemple ci-dessus). &lt;br /&gt;
&lt;br /&gt;
Le tag &amp;lt;code&amp;gt;latest&amp;lt;/code&amp;gt; est à mettre sur la dernière version de votre image. Il sera automatiquement retiré de toutes les autres versions de votre image.  &lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;docker images&amp;lt;/code&amp;gt; permet ensuite de lister les tags disponibles localement. Si le build a réussi, vous devriez y voir votre image.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
~$ docker images&lt;br /&gt;
REPOSITORY                                                         TAG             IMAGE ID       CREATED         SIZE&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           2.0.1           b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           7ad814c         b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           latest          b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           642e23b         8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           latest          8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           502564d         9a2050fc09d4   4 days ago      1.38GB&lt;br /&gt;
semaphoreui/semaphore                                              v2.12.4         136bec584184   2 weeks ago     727MB&lt;br /&gt;
ghcr.io/mastergeonum/cartondes                                     main            a95ee654e34a   5 weeks ago     205MB&lt;br /&gt;
dockurr/windows                                                    latest          c3419fd6e55a   2 months ago    384MB&lt;br /&gt;
docker.osgeo.org/geoserver                                         2.26.1          a91188b23092   3 months ago    608MB&lt;br /&gt;
rocker/verse                                                       4.4.1           202c993befdc   3 months ago    3.77GB&lt;br /&gt;
ghcr.io/evs-gis/glourbee-ui                                        1.1.0           03e05bed5617   4 months ago    1.47GB&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Remarquez que &amp;lt;code&amp;gt;ghcr.io/evs-gis/mapdoapp&amp;lt;/code&amp;gt; est présente plusieurs fois avec des tags différents, mais le même IMAGE ID. Il s&#039;agit bien de la même image et elle n&#039;est pas dupliquée sur le disque.&lt;br /&gt;
&lt;br /&gt;
Pour supprimer un tag, on utilisera la commande &amp;lt;code&amp;gt;docker image rm ghcr.io/evs-gis/mapdoapp:2.0.1&amp;lt;/code&amp;gt;. Si plus aucun tag n&#039;existe pour l&#039;image, elle sera complètement supprimée du disque local. &lt;br /&gt;
&lt;br /&gt;
=== Tester l&#039;image ===&lt;br /&gt;
Pour tester son image, on peut utiliser la commande &amp;lt;code&amp;gt;docker run&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker run --rm -p 3838:3838 ghcr.io/evs-gis/mapdoapp:latest&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* --rm : Supprimer le container lorsqu&#039;il est arrêté.&lt;br /&gt;
* -p 3838:3838 : exposer le port 3838 local et le faire pointer vers le port 3838 dans le container.&lt;br /&gt;
&lt;br /&gt;
Les logs de l&#039;application s&#039;affichent dans le terminal et l&#039;application est accessible dans un navigateur à l&#039;adresse http://localhost:3838. Pour stopper le container, &#039;&#039;&#039;Ctrl+C&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Faire du ménage localement ===&lt;br /&gt;
Il arrive que des vieilles images sans tag, de vieux volumes et de vieux containers plantés restent sur le disque au fil du temps. Tester la commande &amp;lt;code&amp;gt;docker ps --all&amp;lt;/code&amp;gt; par exemple, pour lister tous les containers locaux (lancés ou stoppés). La commande &amp;lt;code&amp;gt;docker system prune&amp;lt;/code&amp;gt; permet de faire le grand ménage.&lt;br /&gt;
&lt;br /&gt;
=== Pousser l&#039;image sur un registre ===&lt;br /&gt;
Pour que le serveur ShinyProxy (ainsi que le monde entier !) puisse accéder à votre image, il faut la pousser sur un registre. Si vous ne souhaitez pas que votre image soit publique, vous pouvez utiliser le registre ghcr.io/evs-gis (le serveur ShinyProxy y a accès même si les images sont privées). &lt;br /&gt;
&lt;br /&gt;
Il faut d&#039;abord se loguer sur le registre avec son login GitHub habituel, et un &#039;&#039;Personal Access Token&#039;&#039; en guise de mot de passe. Pour [https://github.com/settings/tokens/new obtenir un &#039;&#039;Personal Access Token&#039;&#039;], rendez-vous [https://github.com/settings/tokens/new ici] et activez bien le droit &amp;lt;code&amp;gt;write:packages&amp;lt;/code&amp;gt; pour votre token.  &amp;lt;syntaxhighlight lang=&amp;quot;sh&amp;quot;&amp;gt;&lt;br /&gt;
# La commande suivante est à lancer pour se loguer sur le registre. Il n&#039;est pas nécessaire de la relancer à chaque fois.&lt;br /&gt;
docker login ghcr.io&lt;br /&gt;
&lt;br /&gt;
# Pour pousser tous les tags de notre image sur le registre, on utilise ensuite la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp -a&lt;br /&gt;
&lt;br /&gt;
# Pour pousser seulement un tag spécifique, on préfèrera la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration de l&#039;application sur le serveur ShinyProxy de production ==&lt;br /&gt;
La configuration initiale de l&#039;application doit être faite par l&#039;administrateur du serveur.&lt;br /&gt;
&lt;br /&gt;
== Mise à jour d&#039;une appli ==&lt;br /&gt;
La mise à jour d&#039;une appli sur le serveur de prod ne nécessite généralement pas de modifier la configuration. Il suffit de &#039;&#039;&#039;pousser la nouvelle version de votre image sur votre registre&#039;&#039;&#039; (avec le tag latest), puis de &#039;&#039;&#039;lancer le job &#039;&#039;Mise à jour d&#039;une application en production sous ShinyProxy&#039;&#039; sur Jenkins&#039;&#039;&#039; pour forcer le redémarrage des containers d&#039;attente déjà lancés. Si l&#039;intégration continue a été correctement configurée, le job Jenkins de mise à jour devrait se lancer automatiquement dès que la nouvelle version de l&#039;image arrive sur le registre. &lt;br /&gt;
 &lt;br /&gt;
== Debug des applis en prod ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour accéder aux logs des applications sur le serveur de prod, se connecter en ssh aux archives:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh archives.evs.ens-lyon.fr&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Puis afficher le contenu des logs:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-stdout.log &lt;br /&gt;
# récupérer les 10 (option -n) dernières lignes de stdout &lt;br /&gt;
&lt;br /&gt;
tail -n 10 -f /data/echanges/ShinyProxyLogs/shinyapps-stderr.log &lt;br /&gt;
# voir stderr défiler en temps réel (option -f)&lt;br /&gt;
&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# voir les 10 dernières lignes de tous les logs (standard et erreur)&lt;br /&gt;
&lt;br /&gt;
tail -n 100 ... &lt;br /&gt;
# pour les 100 dernières lignes, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Tous les logs (quelque soit l&#039;appli) apparaissent. Pour chercher spécifiquement les lignes correspondant à une appli précise (par exemple mapdoapp):&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
grep mapdoapp /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# N&#039;affiche que les lignes qui concernent mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On peut aussi combiner défilement en live + grep&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -f /data/echanges/ShinyProxyLogs/shinyapps-std*.log | grep mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== To do list mise en ligne d&#039;une nouvelle appli ==&lt;br /&gt;
1) récupérer dans le dossier d&#039;une appli déjà mise en ligne sur ShinyProxy: run.R (si appli learnr), dockerfile, et le dossier .github qui contient un yaml qui permettra de build et push l&#039;image docker sur le ShinyProxy.&lt;br /&gt;
&lt;br /&gt;
2) modifier dans run.R (si appli learnr) le nom du Rmd à tricoter&lt;br /&gt;
&lt;br /&gt;
3) modifier dans le yaml le nom de l&#039;image docker&lt;br /&gt;
&lt;br /&gt;
4) modifier le dockerfile: infos sur l&#039;appli et noms des packages à installer&lt;br /&gt;
&lt;br /&gt;
5) build l&#039;image docker localement pour vérifier que tout est ok, par ex. &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker build . -t ghcr.io/lvaudor/learnr_exos_shiny:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;6) run un container pour vérifier que tout est ok, par ex.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --rm -p 3840:3840 ghcr.io/learnr_shiny_exos:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;7) Aller sur le repo github et changer paramètres: Settings =&amp;gt; Actions =&amp;gt; General =&amp;gt; Workflow permissions =&amp;gt; Cocher Read and write permissions&lt;br /&gt;
&lt;br /&gt;
8) Faire un commit et push des dernières modifs sur main =&amp;gt; Une image docker doit être créée dans les github Actions&lt;br /&gt;
&lt;br /&gt;
9) Prévenir Samuel pour qu&#039;il ajoute la nouvelle appli au registre&lt;br /&gt;
[[Catégorie:Tutoriel]]&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1212</id>
		<title>ShinyProxy</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=ShinyProxy&amp;diff=1212"/>
		<updated>2026-03-04T13:21:04Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;big&amp;gt;Attention : Page en cours de rédaction&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ISIG-Apps passe sous ShinyProxy pour améliorer la stabilité et l&#039;isolation de vos applications pendant les montées en charge. Le fonctionnement est très différent par rapport à l&#039;ancien Shiny-Server et nécessite quelques bases dans l&#039;utilisation de Docker. L&#039;objectif de cette page est de vous guider, rapidement et simplement, dans le nouveau workflow dev &amp;gt; prod en partant du principe que vous ne connaissez encore pas grand-chose à Docker.&lt;br /&gt;
&lt;br /&gt;
== Principe de fonctionnement de ShinyProxy (et Docker) ==&lt;br /&gt;
ShinyProxy fonctionne comme un orchestrateur de conteneurs Docker. Chaque appli configurée doit avoir une image Docker associée présente sur le serveur qui exécute ShinyProxy. C&#039;est ShinyProxy qui s&#039;occupera ensuite de lancer et stopper un conteneur à chaque fois qu&#039;un internaute se connectera ou se déconnectera de votre appli.    &lt;br /&gt;
[[Fichier:Schéma Docker.png|centré|sans_cadre|1054x1054px]]    &lt;br /&gt;
&lt;br /&gt;
Afin que votre application puisse fonctionner sur ShinyProxy, il va donc falloir créer une &#039;&#039;&#039;image&#039;&#039;&#039; qui permettra au serveur ShinyProxy de lancer des &#039;&#039;&#039;containers&#039;&#039;&#039; de votre application.  &lt;br /&gt;
&lt;br /&gt;
Vous n&#039;aurez généralement pas besoin de volume pour stocker des données pérennes dans le cas d&#039;une application Shiny. Si votre application utilise une base de données, celle-ci devra être externalisée (hébergée sur le serveur de bases de données d&#039;ISIG par exemple). &lt;br /&gt;
&lt;br /&gt;
ShinyProxy fera en sorte qu&#039;un certain nombre de containers (à définir dans la configuration décrite à la fin de ce tutoriel) soient toujours disponibles pour de nouveaux utilisateurs qui se connecteraient à votre application. Il s&#039;occupera également de supprimer les containers quand vos utilisateurs se déconnectent. &lt;br /&gt;
&lt;br /&gt;
== Conteneurisation de votre appli Shiny ==&lt;br /&gt;
La conteneurisation peut se faire directement sur votre machine personelle si vous y avez installé Docker (https://docs.docker.com/engine/install/), ou sur le serveur isig-apps de dev via [https://rstudio.evs.ens-lyon.fr Rstudio server] et son terminal intégré.&lt;br /&gt;
&lt;br /&gt;
=== Fixer le port ===&lt;br /&gt;
Pour fonctionner en mode conteneurisé, votre application devra écouter toujours sur le même port (ce qui n&#039;est pas le comportement par défaut d&#039;une application Shiny). &lt;br /&gt;
&lt;br /&gt;
Afin de s&#039;en assurer, il faut : &lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un appli Shiny classique, ajouter dans &amp;lt;code&amp;gt;options(..)&amp;lt;/code&amp;gt;, avant l&#039;appel de &amp;lt;code&amp;gt;shinyApp(..)&amp;lt;/code&amp;gt;, les options suivantes : &amp;lt;code&amp;gt;&amp;quot;shiny.port&amp;quot;=3841&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;&amp;quot;shiny.host&amp;quot;=&amp;quot;0.0.0.0&amp;quot;&amp;lt;/code&amp;gt;. Par exemple :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;r&amp;quot;&amp;gt;&lt;br /&gt;
library(shiny)&lt;br /&gt;
library(glourbi)&lt;br /&gt;
&lt;br /&gt;
# Dans cet exemple, l&#039;application écoutera systématiquement sur le port 3838&lt;br /&gt;
options(&amp;quot;shiny.port&amp;quot; = 3838, &amp;quot;shiny.host&amp;quot; = &amp;quot;0.0.0.0&amp;quot;, &amp;quot;golem.app.prod&amp;quot; = TRUE)&lt;br /&gt;
&lt;br /&gt;
shinyApp(ui=glourbapp:::app_ui,server=glourbapp:::app_server)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Dans le cas d&#039;un document Rmarkdown, ........&lt;br /&gt;
&lt;br /&gt;
=== Choisir l&#039;image source ===&lt;br /&gt;
La construction d&#039;une image Docker se fait sur la base... d&#039;une autre. On choisi en général son image de base en fonction de ce qu&#039;on va faire avec. Pour une application Shiny, nous aurons besoin d&#039;une image Docker spécialisée en R. &lt;br /&gt;
&lt;br /&gt;
Le [https://rocker-project.org/images/ projet Rocker] propose plusieurs images de base avec différentes quantités de packages pré-installés. Lorsque l&#039;on choisi son image de base, il faut trouver le bon compromis entre une image légère et une image avec suffisamment de dépendances pré-installées pour qu&#039;elle soit pratique.&lt;br /&gt;
&lt;br /&gt;
L&#039;image [https://eddelbuettel.github.io/r2u/ r2u] est une bonne base assez simple à utiliser, car elle va chercher des binaires précompilés des packages R que l&#039;on souhaite installer et toutes leurs dépendances, librairies système incluses ! Pratiquement rien n&#039;y est pré-installé, il faudra donc bien préciser toutes les dépendances dont vous avez besoin. En contrepartie, l&#039;image sera plutôt légère, ce qui est une bonne chose ! L&#039;inconvénient de cette fonctionnalité est (à ma connaissance) qu&#039;elle ne fonctionne qu&#039;avec la fonction &amp;lt;code&amp;gt;install.packages(...)&amp;lt;/code&amp;gt;. Il n&#039;est donc pas possible d&#039;installer une version spécifique d&#039;un package avec &amp;lt;code&amp;gt;remotes::install_version(...)&amp;lt;/code&amp;gt; par exemple (la fonction reste utilisable de manière classique). &lt;br /&gt;
&lt;br /&gt;
=== Écrire le Dockerfile ===&lt;br /&gt;
&lt;br /&gt;
La création d&#039;une image Docker repose sur l&#039;écriture d&#039;un fichier texte appelé &#039;&#039;&#039;Dockerfile&#039;&#039;&#039; (sans extension).&lt;br /&gt;
&lt;br /&gt;
Voici un exemple de Dockerfile pour l&#039;application GloUrb :&amp;lt;syntaxhighlight lang=&amp;quot;dockerfile&amp;quot;&amp;gt;&lt;br /&gt;
# On commence par définir l&#039;image sur laquelle va se baser la notre&lt;br /&gt;
FROM rocker/r2u:jammy&lt;br /&gt;
&lt;br /&gt;
# On précise quelques infos qui permettrons d&#039;identifier l&#039;image&lt;br /&gt;
LABEL org.opencontainers.image.authors=&amp;quot;Lise Vaudor &amp;lt;lise.vaudor@ens-lyon.fr&amp;gt;, Samuel Dunesme &amp;lt;samuel.dunesme@ens-lyon.fr&amp;gt;&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.source=&amp;quot;https://github.com/glourb/glourbapp&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.documentation=&amp;quot;https://evs-gis.github.io/glourbdoc/&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.version=&amp;quot;0.0.0.9000&amp;quot;&lt;br /&gt;
LABEL org.opencontainers.image.description=&amp;quot;An app for the GloUrb project&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# On peut éventuellement générer des locales supplémentaires si notre appli utilise d&#039;autres langues que l&#039;anglais&lt;br /&gt;
RUN locale-gen fr_FR.UTF-8&lt;br /&gt;
&lt;br /&gt;
# On liste maintenant toutes les dépendances R à installer&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tidyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;shiny&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;config&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;testthat&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;tibble&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;purrr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;dplyr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;ggplot2&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;forcats&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;magrittr&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;golem&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;sf&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;plotly&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;spelling&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;mclust&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;leaflet&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cluster&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cowplot&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;FactoMineR&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;glue&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;grDevices&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RColorBrewer&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;remotes&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;cicerone&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;RPostgres&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DBI&amp;quot;)&#039;&lt;br /&gt;
RUN Rscript -e &#039;install.packages(&amp;quot;DT&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
RUN Rscript -e &#039;remotes::install_github(&amp;quot;glourb/glourbi&amp;quot;)&#039;&lt;br /&gt;
&lt;br /&gt;
# On copie l&#039;arborescence de fichiers dans un dossier app à la racine de l&#039;image. Ce sera le working directory des containers lancés avec notre image&lt;br /&gt;
RUN mkdir /app&lt;br /&gt;
ADD . /app&lt;br /&gt;
WORKDIR /app&lt;br /&gt;
&lt;br /&gt;
# Si besoin, on peut installer notre package&lt;br /&gt;
RUN R -e &#039;remotes::install_local()&#039;&lt;br /&gt;
&lt;br /&gt;
# On détermine le port qui sera exposé (attention à bien fixer le port sur lequel votre appli écoute, cf. ci-dessus)&lt;br /&gt;
EXPOSE 3838&lt;br /&gt;
&lt;br /&gt;
# Pour plus de sécurité, on fait en sorte que les containers ne se lancent pas avec l&#039;utilisateur &amp;quot;root&amp;quot;, mais avec un utilisateur &amp;quot;app&amp;quot; dédié&lt;br /&gt;
RUN groupadd -g 1010 app &amp;amp;&amp;amp; useradd -c &#039;app&#039; -u 1010 -g 1010 -m -d /home/app -s /sbin/nologin app&lt;br /&gt;
USER app&lt;br /&gt;
&lt;br /&gt;
# Enfin, on précise la commande qui permet de lancer notre appli. C&#039;est cette commande qui sera lancée par défaut par tout nouveau container lancé avec notre image&lt;br /&gt;
CMD  [&amp;quot;R&amp;quot;, &amp;quot;-f&amp;quot;, &amp;quot;app.R&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Construire l&#039;image Docker ===&lt;br /&gt;
Pour construire l&#039;image docker à l&#039;aide du Dockerfile, il faut lancer la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. C&#039;est à ce moment que l&#039;on va versionner l&#039;image en la taguant avec l&#039;argument &amp;lt;code&amp;gt;-t&amp;lt;/code&amp;gt;. On peut mettre directement plusieurs tags à une image, ou les ajouter à posteriori en relançant la commande &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt;. Si le Dockerfile n&#039;a pas changé depuis le dernier build, &amp;lt;code&amp;gt;docker build&amp;lt;/code&amp;gt; ne fera qu&#039;ajouter les tags à l&#039;image existante. &lt;br /&gt;
&lt;br /&gt;
Pour que la CLI Docker trouve bien le Dockerfile, on lance le terminal dans le dossier ou ce Dockerfile est enregistré. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker build . -t ghcr.io/evs-gis/mapdoapp:latest -t ghcr.io/evs-gis/mapdoapp:2.0.1 -t ghcr.io/evs-gis/mapdoapp:$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remarquez que le tag doit contenir le chemin complet vers le registre où sera poussée l&#039;image (étape suivante). Si vous ne précisez pas le chemin (par exemple &amp;lt;code&amp;gt;mapdoapp:latest&amp;lt;/code&amp;gt;), le registre utilisé sera DockerHub. &lt;br /&gt;
&lt;br /&gt;
Notez le tag &amp;lt;code&amp;gt;$(git rev-parse --short HEAD)&amp;lt;/code&amp;gt; qui permet de taguer l&#039;image avec le hash (la référence) du commit actuel (ne fonctionne que si vous êtes dans un dépôt git). Ce tag est bien pratique si vous n&#039;incrémentez pas un numéro de version par ailleurs (&amp;lt;code&amp;gt;2.0.1&amp;lt;/code&amp;gt; dans l&#039;exemple ci-dessus). &lt;br /&gt;
&lt;br /&gt;
Le tag &amp;lt;code&amp;gt;latest&amp;lt;/code&amp;gt; est à mettre sur la dernière version de votre image. Il sera automatiquement retiré de toutes les autres versions de votre image.  &lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;docker images&amp;lt;/code&amp;gt; permet ensuite de lister les tags disponibles localement. Si le build a réussi, vous devriez y voir votre image.&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
~$ docker images&lt;br /&gt;
REPOSITORY                                                         TAG             IMAGE ID       CREATED         SIZE&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           2.0.1           b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           7ad814c         b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/evs-gis/mapdoapp                                           latest          b2b999e7d781   3 days ago      1.27GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           642e23b         8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           latest          8a3daa97546e   4 days ago      1.38GB&lt;br /&gt;
ghcr.io/glourb/glourbapp                                           502564d         9a2050fc09d4   4 days ago      1.38GB&lt;br /&gt;
semaphoreui/semaphore                                              v2.12.4         136bec584184   2 weeks ago     727MB&lt;br /&gt;
ghcr.io/mastergeonum/cartondes                                     main            a95ee654e34a   5 weeks ago     205MB&lt;br /&gt;
dockurr/windows                                                    latest          c3419fd6e55a   2 months ago    384MB&lt;br /&gt;
docker.osgeo.org/geoserver                                         2.26.1          a91188b23092   3 months ago    608MB&lt;br /&gt;
rocker/verse                                                       4.4.1           202c993befdc   3 months ago    3.77GB&lt;br /&gt;
ghcr.io/evs-gis/glourbee-ui                                        1.1.0           03e05bed5617   4 months ago    1.47GB&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Remarquez que &amp;lt;code&amp;gt;ghcr.io/evs-gis/mapdoapp&amp;lt;/code&amp;gt; est présente plusieurs fois avec des tags différents, mais le même IMAGE ID. Il s&#039;agit bien de la même image et elle n&#039;est pas dupliquée sur le disque.&lt;br /&gt;
&lt;br /&gt;
Pour supprimer un tag, on utilisera la commande &amp;lt;code&amp;gt;docker image rm ghcr.io/evs-gis/mapdoapp:2.0.1&amp;lt;/code&amp;gt;. Si plus aucun tag n&#039;existe pour l&#039;image, elle sera complètement supprimée du disque local. &lt;br /&gt;
&lt;br /&gt;
=== Tester l&#039;image ===&lt;br /&gt;
Pour tester son image, on peut utiliser la commande &amp;lt;code&amp;gt;docker run&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;docker run --rm -p 3838:3838 ghcr.io/evs-gis/mapdoapp:latest&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* --rm : Supprimer le container lorsqu&#039;il est arrêté.&lt;br /&gt;
* -p 3838:3838 : exposer le port 3838 local et le faire pointer vers le port 3838 dans le container.&lt;br /&gt;
&lt;br /&gt;
Les logs de l&#039;application s&#039;affichent dans le terminal et l&#039;application est accessible dans un navigateur à l&#039;adresse http://localhost:3838. Pour stopper le container, &#039;&#039;&#039;Ctrl+C&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Faire du ménage localement ===&lt;br /&gt;
Il arrive que des vieilles images sans tag, de vieux volumes et de vieux containers plantés restent sur le disque au fil du temps. Tester la commande &amp;lt;code&amp;gt;docker ps --all&amp;lt;/code&amp;gt; par exemple, pour lister tous les containers locaux (lancés ou stoppés). La commande &amp;lt;code&amp;gt;docker system prune&amp;lt;/code&amp;gt; permet de faire le grand ménage.&lt;br /&gt;
&lt;br /&gt;
=== Pousser l&#039;image sur un registre ===&lt;br /&gt;
Pour que le serveur ShinyProxy (ainsi que le monde entier !) puisse accéder à votre image, il faut la pousser sur un registre. Si vous ne souhaitez pas que votre image soit publique, vous pouvez utiliser le registre ghcr.io/evs-gis (le serveur ShinyProxy y a accès même si les images sont privées). &lt;br /&gt;
&lt;br /&gt;
Il faut d&#039;abord se loguer sur le registre avec son login GitHub habituel, et un &#039;&#039;Personal Access Token&#039;&#039; en guise de mot de passe. Pour [https://github.com/settings/tokens/new obtenir un &#039;&#039;Personal Access Token&#039;&#039;], rendez-vous [https://github.com/settings/tokens/new ici] et activez bien le droit &amp;lt;code&amp;gt;write:packages&amp;lt;/code&amp;gt; pour votre token.  &amp;lt;syntaxhighlight lang=&amp;quot;sh&amp;quot;&amp;gt;&lt;br /&gt;
# La commande suivante est à lancer pour se loguer sur le registre. Il n&#039;est pas nécessaire de la relancer à chaque fois.&lt;br /&gt;
docker login ghcr.io&lt;br /&gt;
&lt;br /&gt;
# Pour pousser tous les tags de notre image sur le registre, on utilise ensuite la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp -a&lt;br /&gt;
&lt;br /&gt;
# Pour pousser seulement un tag spécifique, on préfèrera la commande suivante.&lt;br /&gt;
docker push ghcr.io/evs-gis/mapdoapp:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration de l&#039;application sur le serveur ShinyProxy de production ==&lt;br /&gt;
La configuration initiale de l&#039;application doit être faite par l&#039;administrateur du serveur.&lt;br /&gt;
&lt;br /&gt;
== Mise à jour d&#039;une appli ==&lt;br /&gt;
La mise à jour d&#039;une appli sur le serveur de prod ne nécessite généralement pas de modifier la configuration. Il suffit de &#039;&#039;&#039;pousser la nouvelle version de votre image sur votre registre&#039;&#039;&#039; (avec le tag latest), puis de &#039;&#039;&#039;lancer le job &#039;&#039;Mise à jour d&#039;une application en production sous ShinyProxy&#039;&#039; sur Jenkins&#039;&#039;&#039; pour forcer le redémarrage des containers d&#039;attente déjà lancés. Si l&#039;intégration continue a été correctement configurée, le job Jenkins de mise à jour devrait se lancer automatiquement dès que la nouvelle version de l&#039;image arrive sur le registre. &lt;br /&gt;
 &lt;br /&gt;
== Debug des applis en prod ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour accéder aux logs des applications sur le serveur de prod, se connecter en ssh aux archives:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh archives.evs.ens-lyon.fr&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Puis afficher le contenu des logs:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-stdout.log &lt;br /&gt;
# récupérer les 10 (option -n) dernières lignes de stdout &lt;br /&gt;
&lt;br /&gt;
tail -n 10 -f /data/echanges/ShinyProxyLogs/shinyapps-stderr.log &lt;br /&gt;
# voir stderr défiler en temps réel (option -f)&lt;br /&gt;
&lt;br /&gt;
tail -n 10 /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# voir les 10 dernières lignes de tous les logs (standard et erreur)&lt;br /&gt;
&lt;br /&gt;
tail -n 100 ... &lt;br /&gt;
# pour les 100 dernières lignes, etc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Tous les logs (quelque soit l&#039;appli) apparaissent. Pour chercher spécifiquement les lignes correspondant à une appli précise (par exemple mapdoapp):&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
grep mapdoapp /data/echanges/ShinyProxyLogs/shinyapps-std*.log &lt;br /&gt;
# N&#039;affiche que les lignes qui concernent mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On peut aussi combiner défilement en live + grep&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -f /data/echanges/ShinyProxyLogs/shinyapps-std*.log | grep mapdoapp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Catégorie:Tutoriel]]&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Woody.png&amp;diff=1043</id>
		<title>Fichier:Woody.png</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Woody.png&amp;diff=1043"/>
		<updated>2025-01-31T08:52:46Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:WaveleT.png&amp;diff=1042</id>
		<title>Fichier:WaveleT.png</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:WaveleT.png&amp;diff=1042"/>
		<updated>2025-01-31T08:52:35Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Riviewlet.png&amp;diff=1041</id>
		<title>Fichier:Riviewlet.png</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Riviewlet.png&amp;diff=1041"/>
		<updated>2025-01-31T08:52:23Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Riverbed.png&amp;diff=1040</id>
		<title>Fichier:Riverbed.png</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Riverbed.png&amp;diff=1040"/>
		<updated>2025-01-31T08:52:10Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:MapdO.png&amp;diff=1039</id>
		<title>Fichier:MapdO.png</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:MapdO.png&amp;diff=1039"/>
		<updated>2025-01-31T08:51:55Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:GloUrb.png&amp;diff=1038</id>
		<title>Fichier:GloUrb.png</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:GloUrb.png&amp;diff=1038"/>
		<updated>2025-01-31T08:51:45Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
	<entry>
		<id>https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Glitter.png&amp;diff=1037</id>
		<title>Fichier:Glitter.png</title>
		<link rel="alternate" type="text/html" href="https://isig-wiki.ens-lyon.fr/index.php?title=Fichier:Glitter.png&amp;diff=1037"/>
		<updated>2025-01-31T08:51:22Z</updated>

		<summary type="html">&lt;p&gt;Lvaudor : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Lvaudor</name></author>
	</entry>
</feed>