<?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-05-13T00:53:27Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<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>