TP5 : Containériser son application R Shiny

BUT 3 - Domaines d’application

Auteur

Jean-Francois Rey

TP avancé

Ce TP est simple à mettre en oeuvre mais demande une compréhension de Docker et de son utilisation. Cette partie s’adresse plus au VCOD.
Si vous manquez de temps vous pouvez passer directement au TP6.

Objectif du TP

Nous allons apprendre à containériser et instancier automatiquement notre application R {Shiny}.

Pourquoi ?

Pour faciliter l’instanciation et le partage de votre application.

Prérequis

  • TP1
  • TP2
  • TP3
  • TP4
  • Disposer d’un projet package R + app Shiny sous Gitlab et Rstudio

Rappel

Note

Nous avons inclus une application R-Shiny dans notre package. Il est facile de partager ce package, ainsi que l’application Shiny.

Note

Ici nous allons utiliser Docker pour containériser notre application (c.f. cours)

Important

Un membre du binôme doit faire le TP sur sa session (différent du TP précédent). Au prochain TP vous changerez de membre.
Pensez à sauvegarder et à versionner votre travail aux étapes importantes.
Pensez bien à faire un pull avant de commencer à travailler.

L’issue du TP

  • Créer une issue dans votre projet avec pour nom TP5.
  • Y ajouter ceci :
# TP5 : Containériser son application R Shiny

## Tâches :   

1. [ ] Créer son Dockerfile
2. [ ] Build l'image docker 
3. [ ] Automatiser la création de l'image
4. [ ] Stocker l'image dans le registry du projet
5. [ ] Instancier un container de l'application sur Guacamole  
etc.

## Version

Le commit correspondant au rendu final du TP : <clé SHA>
  • Dans l’issue principal du projet Rendu de notre projet associer cette dernière issue dans Linked Items
    • utiliser le numéro de l’issue ou son nom

Dockerfile

Note

Le Dockerfile est la recette pour construire l’image docker de votre application. Cette image peut être stocké et partagé. Une fois cette image instancié elle devient un container, il est possible d’instancier plusieurs containers d’une même image.

  • Créer le ficher DOCKERFILE (sans extension) dans inst/shinyapps/monapp
  • copie-colle le contenu du fichier
DOCKERFILE
FROM rocker/r-ver:4.3.1

## Des informations optionnelles
ENV AUTHOR="BUT3 team"
LABEL   org.opencontainers.image.authors="${AUTHOR}" \
        org.opencontainers.image.licenses="GPL-2.0-or-later" \
        org.opencontainers.image.source="https://gitlab.paca.inrae.fr/cours/iut20232024/but3" \
        org.opencontainers.image.vendor="Mon projet Project" \
        org.opencontainers.image.description="A simple configuration to run a R-Shiny App"

## Ici vous pouvez ajouter les librairies systèmes dont dépdendes vos packages R
RUN apt-get update && apt-get install -y --no-install-recommends \
    sudo \
    gdebi-core \
    locales \
    git \
    openssh-client \
    libssh2-1-dev \
    libgit2-dev

## Change timezone
ENV CONTAINER_TIMEZONE Europe/Paris
ENV TZ Europe/Paris

RUN sudo echo "Europe/Paris" > /etc/timezone
RUN echo "fr_FR.UTF-8 UTF-8" >> /etc/locale.gen \
  && locale-gen fr_FR.UTF-8 \
  && /usr/sbin/update-locale LANG=fr_FR.UTF-8

ENV LC_ALL fr_FR.UTF-8
ENV LANG fr_FR.UTF-8

## List de package R dont dépend votre application
ENV R_PACKAGES="'shiny'"
RUN Rscript -e "install.packages(c(${R_PACKAGES}), repos='https://cloud.r-project.org/', ask=FALSE)"

## Change shiny user rights
## USER shiny
RUN useradd -ms /bin/bash shiny
RUN passwd shiny -d
WORKDIR /home/shiny

# Nom de l'application (sans espace et caratères spéciaux)
ENV APP_NAME "Ma_super_app"

COPY . /tmp
RUN R CMD INSTALL --no-docs /tmp

## Copie de l'application shiny dans l'image docker dans /home/shiny/${APP_NAME}
RUN mkdir -p /home/shiny/${APP_NAME}
ADD ./inst/shinyapps/monapp /home/shiny/${APP_NAME}

RUN chown -R shiny.shiny /home/shiny

## Clean unnecessary libraries
RUN apt-get clean \
  && rm -rf /var/lib/apt/lists/*

USER shiny

EXPOSE 3838

CMD ["sh", "-c", "Rscript -e \"shiny::runApp('/home/shiny/${APP_NAME}', port = 3838, host = '0.0.0.0' )\""]
Attention

Votre application shiny a surement des dépendances systèmes et nécessite des packages R. Vous devez ajouter ces derniers dans le DOCKERFILE pour que l’environnement d’exécution de votre application fonctionne.
Pour trouver les dépendances systèmes vous pouvez aller sur le packagemanager de posit rechercher vos package R et ajouter les librairies qui sont dans SYSTEM REQUIREMENTS.

Vous pouvez regarder du coté du package {renv} qui permet de gérer les dépendences aux package R (mais pas les dépendences systèmes)

Création de l’image docker

Connection au seveur docker

  • Depuis le terminal de Rstudio
ssh <mon_id>@docker.univ-avignon.fr

Création de l’image docker

cd /<monrepertoire>/<monpackage>
docker build --tag <monpackage>:latest -f inst/shinyapps/<monapp>/DOCKERFILE .

Pour configurer correctement le DOCKERFILE, vous pouvez faire comme déjà vu dans un autre cours, en installant les dépendances dans un container de test et en reportant ces dernières dans le Dockerfile.

Lancer un container

Si vous avez un container qui tourne encore vous pouvez le stopper pour pouvoir réutiliser votre port.

docker container ls
docker stop <nom_de_mon_container>
## pour le redémarrer par la suite
docker start <nom_de_mon_container>
Mon port d’accès

Vous devez avoir un ou deux ports d’accès au serveur docker.univ-avignon.fr donnés par vos encadrants.
Utiliser l’un des ports qui vous est affecté dans la commande suivante (celui d’un des membres du projet).

docker run -d --name <NomDe_MonProjet_Gitlab> -p <mon_port>:3838 <monpackage>:latest

Pour accéder à l’application : http://docker.univ-avignon.fr:<mon_port>

Automatisation de l’image Docker

Note

Ici nous allons automatiser : la création de l’image docker, la stocker dans le registry du projet GitLab et déployer le container.

Création de l’image docker

Ajouter ceci dans votre fichier d’automatisation .gitlab-ci.yml.

.gitlab-ci.yml
## Ajouter ce job

buildDocker:
  image: docker:20.10.12
  tags:
    - "BUT"
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  services:
    - docker:20.10.12-dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  stage: build
  script:
    - docker pull $CI_REGISTRY_IMAGE:latest || true
    - docker build --build-arg APP_NAME=$CI_PROJECT_NAME --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --tag $CI_REGISTRY_IMAGE:latest -f inst/shinyapps/monapp/DOCKERFILE .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest
  after_script:
    - docker logout $CI_REGISTRY
buildDocker

Ce job va créer l’image docker de votre application Shiny et là stocker dans le registry du projet.

Le registry est accessible dans le menu de gauche “Deploy” -> “Container Registry”. C’est un lieu de stockage des images de votre projet, accessible via une URL, par exemple gitlab.paca.inrae.fr:4567/<mon_uri_projet>.

Si votre projet est public vous pouvez partager cette URL pour que l’utilisateur puisse utiliser votre image docker directement sinon il faudra utiliser l’authentification pour cela.

Pour lancer un container public de votre application :

docker run -it -p 8080:3838 gitlab.paca.inrae.fr:4567/<mon_uri_projet>:latest

L’accès dans le navigateur web ce fait comme ceci http://localhost:8080.

Publication de l’application | instanciation d’un container

Ajouter ceci dans votre fichier d’automatisation .gitlab-ci.yml ( ! Modifier la variable <mon_port> !).

.gitlab-ci.yml
"Publication application":
  image: debian
  stage: deploy
  needs: ["buildDocker"]
  tags:
    - "BUT"
  before_script:
    - "apt-get update && apt-get install -y sshpass openssh-client"
    - "export SSHPASS=$BUT_PWD"
    - "ssh -o StrictHostKeyChecking=no -oServerAliveInterval=25 -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa -f $BUT_HOST_ID -L 127.0.0.1:58022:docker.univ-avignon.fr:22 -N"
  script:
    - pwd
    - sshpass -e ssh -o StrictHostKeyChecking=no -p 58022  $BUT_USER@127.0.0.1 "docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY && (docker container stop $CI_PROJECT_NAME || true) && (docker container rm $CI_PROJECT_NAME || true) && docker run -d -p <mon_port>:3838 --name $CI_PROJECT_NAME $CI_REGISTRY_IMAGE:latest && docker logout $CI_REGISTRY_IMAGE"
Publication application

Ce job se connecte au serveur docker (docker.univ-avignon.fr), y upload la dernière image de votre projet (pull), arrête et supprime (stop et rm) le container déjà instancié et instancie un nouveau container de la dernière image (run).

Variables secrétes

Avant de commit/push vous devez renseigner des variables “cachées” qui sont utilisées dans le CI/CD.
Les variables BUT_USER (votre identifiant) et BUT_PWD (votre mot de passe) permettent que le CI/CD se connecte à la machine docker.univ-avignon.fr.
Utiliser l’identifiant et mot de passe du même binôme qui a renseigné son numéro de port.

Note

Pour ajouter une variable secrets aller dans le menu de gauche -> settings -> CI/CD -> Variables.

Cliquer sur Add variable et mettre le nom de la variable BUT_USER ou BUT_PWD ainsi que sa valeur. Activer le Flags “Protect variable”.

Ces variables sont cachées lors de l’exécution des jobs dans le CI/CD et ne peuvent être affiché.

Observer

  • Maintenant vous pouvez commit/push vos modifications.
  • Le pipeline va se déclencher.
  • Observer ce que fait le job “buildDocker” (c’est long la premier fois)
  • Une fois le job fini, la publication va être lancé.
Astuce

Vous pouvez observer le changement du container sur la machine docker.univ-avignon.fr avec la commande suivante:

watch docker container ls
# Ctrl + C pour quitter
  • Connectez vous à http://docker.univ-avignon.fr:<mon_port> pour observer la mise à jour.

Maintenant vous disposez d’un package R et d’une application R Shiny. A chaque mise à jour du projet sous GitLab (commit/push) l’image docker de l’application est généré et déployer en production automatiquement


Avant d’aller plus loin

  • Faites constater la mise en production par le moniteur du TP
  • Vérifier que vous avez suivie les consignes.
  • Vérifier la liste des vérifications vu dans les TP précédents.
  • Vérifier que votre package est toujours valide et bien documenté.
  • Vérifier que le contenu des jobs GitLab ne comporte pas d’erreur.
  • Vérifier la clarté des commentaires et du code.

Questions:

  • Dans l’issue de ce TP (“TP5”).
  • Ajouter le message et la version du commit correspondant à ce TP
    (menu de gauche -> Code -> Commits) le commit correspond à la clé SHA.
  • Ajouter le Tags TP5 au commit
  • Répondez aux questions suivantes dans la description de l’issue :
    • Quels sont les avantages d’utiliser Docker pour une application R {Shiny} ?
    • Décrire simplement ce qu’est Docker et Dockerfile ?
    • Pourquoi la création de l’image Docker est longue ?
    • Comment est accéléré le processus de création de l’image ?
    • Décrire les étapes du job “buildDocker”
    • A quoi correspond le flag de variable “Protect variable” ?

Pour aller plus loin