Retour sur l’intervention de Vincent aux 6e Rencontres R d’Anglet : « Encapsuler une application R avec Docker ».
Une version plus récente de ce workflow est présentée dans cet article: « Développer une app Shiny dans un package [et déployer] »
Lorsque l’on cherche à développer puis à déployer une application R (typiquement une application shiny), plusieurs aspects sont à prendre en compte :
Note : Ce qui suit s’adapterait à n’importe quel « produit » basé sur R
- Que va devenir cette application ?
- Qui va être en charge de la déployer ?
- À combien d’utilisateurs s’adresse-t-elle ?
- Doit-elle être installée en local sur les postes des utilisateurs, ou accessible en ligne ?
- Sera elle publique ou privée ?
Les réponses à ces questions vont orienter directement des choix techniques, qu’il faudra parfois mettre en place très tôt dans la phase de développement de l’appli. En effet, il y a un gap énorme entre avoir un app.R qui tourne bien en local sur son poste, et avoir une application shiny en production accessible au plus grand nombre. Sans oublier que si on vous demande une application shiny et que vous livrez un fichier app.R… vous risquez d’avoir quelques soucis avec le SI de votre commanditaire 🙂
Ici je vais détailler une méthode qui permet de :
- Ne pas s’embêter avec les montées de version de R et des autres packages,
- Ne pas se poser la question de « sur quelle machine va tourner mon application »,
- Garantir que le produit sera encore viable dans x années,
- Se faire bien voir des SI,
- Déployer efficacement et simplement autant d’instances de l’application que l’on souhaite (vous savez, la scalabilité, tout ca…).
Cette méthode consiste à construire un container docker dont le job sera de lancer notre application.
Avec les idées claires, ça se fait vite et bien, j’en ai fait la démonstration en congrès en direct à Anglet.
Voici quelques étapes à suivre pour faire cela :
Sommaire
1 – Travailler en package
Dans R, le package est à la base de tout, il s’agit de l’unité de partage de code/fonction/documentation par excellence. Il ne faut pas voir le package comme une fin en soit, le Graal, un objectif ultime, mais au contraire comme la base de tout ce que vous devez entreprendre avec R. Qu’il s’agisse d’une étude ou une d’application, penser en package vous dotera d’un cadre de travail très peu contraignant, qui vous permettra de bénéficier d’une palette d’outils redoutablement efficaces et confortables à utiliser (documentation, contrôle de la validité du code, intégration continue, tests unitaires, gestion des dépendances… ).
Faire un package avec RStudio, c ‘est 5 minutes chronos — si c’est vrai!
Donc le matin, en arrivant au travail, lorsque l’on commence une nouvelle mission, il faut créer un package :
Un package est composé d’une arborescence spécifique, avec un dossier R dans lequel il faut mettre vos fichiers de fonctions et un fichier DESCRIPTION qui vous permet de préciser ce que fait le package. Les autres éléments tels que le fichier NAMESPACE ou le dossier man se rempliront tout seuls grâce au package {roxygen2} — pour cela, dans le menu build> configure build tools, veillez à cocher « Generate documentation with roxygen » ainsi que toutes les cases de la fenêtre d’options qui s’ouvre alors. En bref, faire un package c’est « simplement » mettre des fonctions dans le dossier R (oui, j’exagère un petit peu)…
2 – Mettre son application Shiny en package
En où mettre votre application shiny dans cette arborescence ?
Version courte : dans le dossier inst, à la racine de votre package.
Version plus longue : tout ce qui se trouve dans le dossier inst du package sera présent tel quel à la racine du dossier d’installation du package une fois installé sur le poste de l’utilisateur.
Et ensuite ? il suffit de coder une fonction qui est capable de lancer l’application Shiny.
L’arborescence va ressembler à ça :
Et la fonction, à mettre dans le dossier R :
shiny_mon_app <- function() { appDir <- system.file("mon_app", package = "demoshiny") ;shiny::runApp(appDir, display.mode = "normal")}
maintenant, une fois le package installé, l'application se lancera avec l'instruction demoshiny::shiny_mon_app()
.
3 - Construire une image docker
Docker, c 'est quoi?
C'est un logiciel, qui n'a rien à voir avec R en tant que tel, qui permet de créer et lancer des containers. Il s'utilise classiquement en ligne de commande.
Un container c'est quoi ?
Version courte et fausse : une sorte de petite machine virtuelle.
Version plus longue et plus rigoureuse : il s'agit d'un environnement isolé du reste de la machine qui contient tout ce qu'il faut pour faire tourner une application.
Docker est un outil qui cartonne et dont les potentialités sont énormes. Docker peut être installé sur tous ordinateurs 64bits (sous linux, mac, windows desktop, windows serveur). La documentation est foisonnante, et la encore en quelques instructions vous arriverez à terme à faire des choses extraordinaires.
Par exemple , cette instruction installera et lancera Rstudio Serveur !
docker run -d -p 80:8787 rocker/hadleyverse
Quelques notions importantes sont a connaitre :
- container : ce qui va faire tourner les applications,
- images : environnements pré-conçus qui décrivent ce que devront faire les containers,
- registry : dépôt qui regroupe les images de la communauté,
- Dockerfile : fichier texte qui correspond à la « recette » d’une image (permet de construire une image).
Donc très concrètement, nous devons rédiger un fichier Dockerfile, qui sera utilisé pour construire une image qui permettra de lancer un container
Voici le contenu du Dockerfile qui vous permettra d'encapsuler une application shiny :
FROM thinkr/rfull
COPY demoshiny_*.tar.gz /demoshiny.tar.gz
RUN R -e "install.packages('demoshiny.tar.gz', repos = NULL, type = 'source')"
COPY Rprofile.site /usr/local/lib/R/etc
EXPOSE 3838
CMD ["R", "-e demoshiny::shiny_mon_app()"]
La traduction littérale de ce fichier serait :
Prendre l'image rfull
préexistante de l'utilisateur thinkr, (disponible sur le registry), mettre dedans le tar.gz du package et demander à R de l’installer. Rajouter le fichier Rprofile.site
le mettre dans /usr/local/lib/R/etc (ce fichier impose a shiny de se lancer sur le port 3838), ouvrir le port 3838 et lancer la fonction shiny_mon_app
du package demoshiny
.
Limpide non? 🙂
Vous mettez dans un même dossier ce fichier Dockerfile, le tar.gz de votre package, et le fichier Rprofile.site suivant :
local({
options(shiny.port = 3838, shiny.host = "0.0.0.0")
})
Et vous pouvez construire votre image en une ligne :
docker build -t demoshiny .
4 - Deployer votre application
Vous pouvez lancer votre container :
docker run -d -p 3838:3838 demoshiny
Et rendez vous sur http://localhost:3838 pour voir votre application.
Et voilà, vous avez une image docker que vous pouvez dupliquer à l'envie. Cette image vous pouvez l'exporter, la rendre publique... libre à vous !
Vous pouvez maintenant utiliser tous les outils modernes dans le cloud qui servent à déployer des applications docker ( chez Amazon, chez Ovh, ... ). Personnellement je m'amuse beaucoup en auto hébergeant shinyproxy qui permet de lancer un container par utilisateur, ce qui permet de passer outre la limitation de shiny.
Nous serions ravis d'avoir vos retours d'expérience sur cette approche et/ou de vous aider dans vos déploiements, n'hésitez pas à en discuter avec nous par mail ou via twitter !