Comment développer dans un conteneur Docker pour faciliter la collaboration ?

devindocker package logo for development in docker container
Author : Sébastien Rochette
Categories : développement, docker, package, rstudio, thinkrverse
Tags : devindocker, production, renv, thinkr-package
Date :

Pour assurer la reproductibilité de vos projets, vous pouvez développer dans le conteneur Docker que vous utiliserez pour partager votre travail. En effet, que faire quand vos analyses de données, publications, modèles sont pris en mains par des utilisateurs ayant des versions différentes de systèmes d’exploitation et de packages R ? Comment vous assurez que le Dockerfile livré avec votre package ou votre projet est fonctionnel ? N’avez-vous pas envie de développer dans le conteneur Docker que vous livrez pour la mise en production de votre application Shiny ? Ne souhaitez-vous pas reproduire localement l’environnement de votre intégration continue (CI) qui a échouée sans raison apparente ?

Docker est maintenant accessible en natif pour les utilisateurs de Windows Home grâce à l’installation de WSL2 sur Windows 10, et pas seulement pour Windows Pro.
Il est donc temps de vous présenter notre package {devindocker} ainsi que nos raisons de travailler dans les conteneurs Docker.

Utilisez {devindocker} pour démarrer un Docker avec une installation de package R persistante

{devindocker} a été créé pour réduire le temps de mise en place d’un conteneur Docker pour chacun de nos projets avec les bons réglages pour la persistance des packages installés à l’intérieur du conteneur, ainsi que des préférences de RStudio.
Cela nécessite l’utilisation d’un Docker avec RStudio server à l’intérieur.
Nous recommandons ceux de Rocker, en commençant par rocker/rstudio.
Les lignes de code suivantes doivent être lancées en dehors du projet lui-même.
En effet, ouvrir votre projet directement sur votre propre ordinateur tout en utilisant {renv} peut compromettre l’installation à l’intérieur du conteneur du Docker.
Le projet peut être un simple répertoire, un projet RStudio, un package, un golem…

Un exemple reproductible pour un projet simple

Essayons avec un exemple reproductible tel que présenté dans le README de {devindocker} :

Nous créons un dossier temporaire avec un fichier à l’intérieur.

# Temporary project
tempdir <- tempdir()
project_path <- file.path(tempdir, "myproject")
dir.create(project_path)
# Add a file inside
cat("# my R file", file = file.path(project_path, "my-file.R"))

Lancez un conteneur Docker avec votre dossier à l’intérieur. Il doit s’agir d’un conteneur avec un RStudio server à l’intérieur.
Notez que vous démarrez en dehors de votre projet, ce qui signifie que vous devrez démarrer un nouveau projet RStudio si c’est votre façon de travailler.
Notez que dans cet exemple, les packages que vous installez ne seront pas conservés une fois que vous aurez arrêté le conteneur, mais les préférences de RStudio le seront.

library(devindocker)
# Which path to your working directory / project
project_path <- file.path(tempdir, "myproject")
# Which container (with Rstudio inside) ? ----
# https://hub.docker.com/r/rocker/verse
container <- "rocker/geospatial:4.0.1"
# Which port ? ----
# _Useful if multiple Rstudio Server to launch
port <- 8788
# Start Docker project ----
launch_proj_docker(
  project_path = project_path,
  container = container,
  port = port)

Lorsque vous avez terminé, n’oubliez pas d’arrêter correctement le RStudio server : Cliquez sur le bouton en haut à droite pour quitter ou sur q() dans la console.

Ensuite, stoppez le conteneur.

# Stop Docker properly
stop_proj_docker(project_path = project_path)

Utiliser {renv} dans le Docker et conserver l’installation des packages

Notez que vous devez lancer votre projet avec {devindocker} depuis l’extérieur de votre projet. Ne l’ouvrez plus jamais localement (en dehors d’un conteneur Docker) si vous voulez éviter les problèmes liés à une mauvaise configuration locale et non compatible de {renv}. Il est recommandé de créer un projet dédié au lancement de vos projets {devindocker}.

Lancez un conteneur Docker avec votre dossier à l’intérieur. Ce doit être un conteneur avec RStudio server à l’intérieur.
Notez que vous démarrez en dehors de votre projet, ce qui signifie que vous devrez démarrer un nouveau projet RStudio si c’est votre façon de travailler.
Notez également que les packages que vous installez seront conservés après avoir arrêté le conteneur, ainsi que les préférences de RStudio.

Suivre les instructions dans le fichier "renv_instructions.Rmd" qui est créé à l’intérieur de votre projet.

# Which path to your working directory / project
project_path <- file.path(tempdir, "myproject")
# Which container (with Rstudio inside) ? ----
# https://hub.docker.com/r/rocker/verse
container <- "rocker/geospatial:4.0.1"
# Which port ? ----
# _Useful if multiple Rstudio Server to launch
port <- 8788
# My renv cache directory on my local computer
# Used as persistent drive for all you Docker container with {devindocker}
renv_cache <- "~/renv_cache"
# Start Docker project ----
devindocker::launch_proj_docker(
  project_path = project_path,
  container = container,
  port = port,
  renv_cache = renv_cache,
  renv_inst = TRUE, # Add an Rmd with instructions inside your project
)

Lorsque vous avez terminé, n’oubliez pas d’arrêter correctement le RStudio server : Cliquez sur le bouton en haut à droite pour quitter ou sur q() dans la console.

Ensuite, stoppez le conteneur.

# Stop Docker properly
stop_proj_docker(project_path = project_path)

Il existe une implémentation permettant la connexion avec un conteneur Docker local ayant une base de données mysql, qui est expérimentale. Elle peut nécessiter un conteneur RStudio avec des dépendances système pour les bases de données. Voir le paramètre with_mysql.

Nous améliorons également en permanence la documentation interne sur la mise en place de {renv} dans le conteneur Docker.
Vous pouvez la trouver ainsi :

file <- system.file("renv/renv_instructions.Rmd", package = "devindocker")
file.edit(file)

Pour plus d’options et les mises à jour, nous vous recommandons de lire notre documentation de package {devindocker}.
Notez qu’il est toujours en cours de développement.

Développer avec plusieurs développeurs avec plusieurs versions OS et R

Dans vos pages HTML d’analyses de données, vos rapports, vos projets d’applications Shiny impliquant plusieurs développeurs, vous pouvez facilement faire face à des problèmes de versions de packages, mais aussi à des spécificités d’OS qui compromettent la reproductibilité.
Chez ThinkR, chaque développeur dispose d’un ordinateur avec une architecture différente, une version R différente et bien sûr des versions de packages différentes. Pour les packages, nous pouvons utiliser {renv}, bien que les différentes versions R puissent poser problème. Pour les mauvaises aventures avec l’encodage (UTF-8, latin, …), les dépendances système, les caractères de fins de lignes (LF, CR/LF), vous aurez envie d’éviter d’utiliser à la fois Windows, MacOS et Linux sur le même projet.
C’est pourquoi nous avons décidé de développer tous nos projets privés dans des conteneur Docker identiques pour une architecture commune, une version R commune et d’utiliser {renv} pour un ensemble commun de packages R.
Comme nous développons régulièrement des applications Shiny pour nos clients, nous les mettons également en production, soit avec RStudio Connect car nous sommes des partenaires certifiés de RStudio, soit avec ShinyProxy + Docker. Comme toujours, nous développons avec notre package {golem} et dans le cas d’une production utilisant Docker, nous livrons un Dockerfile avec toutes les spécificités. Quoi de plus pratique que de développer à l’intérieur du conteneur Docker qui sera livré ?
Par ailleurs, lorsque nos productions sont des livres HTML ou des rapports d’analyse de données, il est également pratique de développer dans un environnement figé et commun. Nous avons pour habitude de créer des packages R pour tout type d’analyses afin d’assurer la robustesse et une documentation complète. La reproductibilité de nos rapports d’analyses peut être assurée grâce au développement dans un environnement Docker.

Réduire les problèmes de caractères de fin de lignes avec git entre OS

Une petite note pour nos chers développeurs et chères développeuses de packages R et au cas où vous ne développeriez pas à l’intérieur d’un conteneur Docker.
Si vous acceptez des propositions de modifications de plusieurs développeurs, vous ne pouvez pas garantir que les autres ont correctement défini le paramètre des caractères de fin de ligne pour la création de leurs fichiers.
Par conséquent, lorsque vous reconstruisez la documentation des fonctions, vous risquez de vous retrouver face à git qui affiche un important ensemble de fichiers à ajouter au commit.
Ceci est dû au fait que Linux, MacOS et Windows ont des spécificités différentes pour le caractère invisible de fin de ligne.
Pour réduire les risques, vous pouvez ajouter un fichier caché dans votre projet nommé ".gitattributes" avec ce contenu :

# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Declare files that will always have CRLF line endings on checkout.
*.Rd text eol=lf
*.R text eol=lf
*.Rmd text eol=lf
*.md text eol=lf
NAMESPACE text eol=lf
DESCRIPTION text eol=lf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

Recréer les conditions de votre CI localement pour tester le succès ou l’échec de votre flux de travail

Si vous n’avez jamais eu à envoyer une centaine de commits pour faire fonctionner votre CI correctement, alors vous n’avez pas besoin de lire cette section…
Parfois vous voulez reproduire l’environnement de votre CI pour être sûr que tous les tests passeront au prochain commit au lieu d’essayer de multiples modifications et d’attendre encore et encore la sortie du CI.
Dans ce cas, vous pouvez démarrer votre package à l’intérieur d’un conteneur Docker sans package persistant pour toujours utiliser un conteneur vierge.
Cependant, notez que vous ne devriez pas utiliser la console RStudio pour réaliser vos tests car elle est fournie avec certaines configurations spécifiques qui ne seront pas disponibles pour votre CI.
À la place, ouvrez l’onglet “Terminal” et lancez R à l’intérieur.
Ensuite, vous pouvez y envoyer les lignes de code de votre fichier yml de CI.
Notez que si vous voulez envoyer du code à partir d’un script R/Rmd, vous pouvez utiliser Ctrl/Cmd + Alt + Entrée et les lignes de code seront envoyées directement dans le Terminal.
Par opposition à Ctrl/Alt + Enter, qui envoie le code dans la Console.

Si vous utilisez GitLab et GitLab CI, notez que votre conteneur peut fonctionner en tant qu’utilisateur root.
Par conséquent, vous devrez lancer votre conteneur Docker avec {devindocker} en utilisant les mêmes droits avec is_root = TRUE.

# Start Docker project ----
launch_proj_docker(
  project_path = project_path,
  container = container,
  port = port,
  is_root = TRUE)

Ensuite, à l’intérieur du “Terminal”, vous pourrez lancer directement sudo R.

Après avoir réalisé vos tests, vous pourrez arrêter le conteneur.
Les paquets installés ne seront pas conservés à l’extérieur du conteneur, de sorte que vous pourrez rouvrir votre conteneur pour des tests ultérieurs avec une implémentation différente du CI.

Installer Docker sur votre OS

Voici la liste des ressources rédigées (en anglais) par Docker pour installer Docker sur votre ordinateur en fonction de votre système d’exploitation :

Si vous êtes sur Windows Home, je vous recommande les articles de Korben.info pour mettre en marche le WSL2 sur Windows 10 et installer Docker nativement sur Windows Home.

Essayez {devindocker} et donnez-nous votre avis

{devindocker} est en cours de développement.
Nous l’utilisons quotidiennement pour la production.
Nous l’utilisons depuis plusieurs mois maintenant, sur Linux, MacOS et Windows, ce qui nous rend confiants quant à sa stabilité.
Si vous souhaitez signaler des bogues ou proposer des fonctionnalités, vous pouvez le faire sur le dépôt GitHub de {devindocker}.


Comments


Also read