Skip to content

Commit

Permalink
Section sur l'intégration continue (#77)
Browse files Browse the repository at this point in the history
* nbconvert test notebook in gitlab CI

* to do docker

* premiers éléments CI

* python defined twice

* voilà encore des éléments

* explique commandes

* finalis&ation

* modif

* modif titre

* modif link

* modif link

* modif aussi ici

* modif url slug
  • Loading branch information
linogaliana committed Nov 9, 2020
1 parent a6e393e commit b47e1ae
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 4 deletions.
3 changes: 3 additions & 0 deletions content/evaluation/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Résumé :
[github](https://github.com/) <a href="https://github.com" class="github"><i class="fab fa-github"></i></a> ou [gitlab](https://gitlab.com/)__ <a href="https://gitlab.com" class="gitlab"><i class="fab fa-gitlab"></i></a>
(dépôt public ou dépôt privé à partager avec le chargé de TD)
* Les étudiants sont invités à proposer des sujets qui leur plaisent, à faire valider par le chargé de TD.
* Un exemple de configuration d'intégration continue est disponible [ici](/getting-started/pythonCI) pour aider à avoir un notebook reproductible (:warning: ce n'est pas une garantie)

## Attentes du projet

Expand Down Expand Up @@ -71,6 +72,8 @@ Même si le projet n’est pas celui du cours de stats, il faut que la démarche
* Le code contenu dans le rapport devra être un maximum propre (pas de copier coller de cellule, préférez des fonctions)

Le test à réaliser : faire tourner toutes les cellules de votre notebook et ne pas avoir d’erreur est une condition sine qua non pour avoir la moyenne.
Un exemple de configuration d'intégration continue est disponible [ici](/getting-started/pythonCI) pour aider à avoir un notebook reproductible (:warning: ce n'est pas une garantie)


## Barême approximatif

Expand Down
4 changes: 1 addition & 3 deletions content/getting-started/01_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ fournit un raccourci pour lancer le notebook dans un environnement dédié.

### Docker

Derrière ces outils pour exécuter de manière simple des scripts Python sur un serveur temporaire se cache
`Docker`. `Docker` est une technologie qui vise à permettre la construction de machines autosuffisantes
(que l'on nomme containeurs) répliquant un environnement contrôlé (que l'on nomme image).
**TO DO**

# Installer et configurer git

Expand Down
233 changes: 233 additions & 0 deletions content/getting-started/07_ci_python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
---
title: "Intégration continue avec Python"
date: 2020-07-22T12:00:00Z
draft: false
weight: 80
slug: pythonCI
---

## Qu'est-ce que l'intégration continue ?

L'intégration continue est une pratique consistant, de manière automatique,
à fréquemment tester les effets d'une modification faite à un code ou à un
document faisant parti d'un projet informatique.

Cette pratique permet ainsi de détecter de manière précoce des possibilités
de *bug* ou l'introduction d'un changement non anticipé. Tout comme `Git`,
cette pratique devient un standard dans les domaines collaboratifs.
L'intégration continue permet de sécuriser le travail, puisqu'elle offre un
filet de sécurité (par exemple un test sur une machine à la configuration
arbitraire), mais permet aussi de déployer en temps réel certaines
évolutions. On parle parfois de déploiement en continu, complémentaire de
l'intégration continue. Cette approche réduit ainsi
la muraille de Chine entre un
analyste de données et une équipe de développeurs d'application. Elle offre donc
plus de contrôle, pour le producteur d'une analyse statistique, sur la
valorisation de celle-ci.

L'intégration continue fonctionne très bien sur `Gitlab` et sur `Github`.
A chaque interaction avec le dépôt distant (`push`), une série d'instruction
définie par l'utilisateur est exécutée. `Python` et `R` s'intègrent très bien avec l'intégration continue grâce
à un certain nombre d'images de base (concept sur lequel nous allons revenir)
qui peuvent être customisées pour répondre à une certaine configuration
nécessaire pour exécuter des codes
([voir ici pour quelques éléments sur R](https://linogaliana.gitlab.io/collaboratif/package.html#utiliser-lint%C3%A9gration-continue-de-gitlab).
C'est une méthode idéale pour améliorer la reproductibilité d'un projet: les
instructions exécutées le sont dans un environnement isolé et contrôlé, ce qui
diffère d'une machine personnelle.


## Comment fonctionne l'intégration continue ?

L'intégration continue repose sur le système de la *dockerisation* ou *conteneurisation*.
La technologie sous jacente s'appelle `Docker`.
Il s'agit d'une technologie qui permet la construction
de machines autosuffisantes
(que l'on nomme **containeurs**) répliquant un environnement
contrôlé (que l'on nomme **image**).

On parle de *pipelines* pour désigner une suite de tâches pour partir de 0
(généralement une machine `Linux` à la configuration minimale) et aboutir
à l'issue d'une série d'instructions définies par l'utilisateur.

L'objectif est de trouver une image la plus
parcimonieuse possible, c'est-à-dire à la configuration minimale, qui permet
de tester de faire tourner le code voulu. Dans le domaine de la *datascience*,
les images de [JupyterHub](https://hub.docker.com/r/jupyterhub/jupyterhub/) constituent
un bon point de départ. Il est également très simple de construire son image
de rien, ce qui sera proposé par la suite.

Quand on utilise un dépôt `Github` ou `Gitlab`, des services automatiques
d'intégration continue peuvent être utilisés:

* `Gitlab CI`: solution pleinement intégrée à un dépôt Gitlab. Très généraliste
et permettant des *pipelines* très complexes
([voir l'intégration continue du projet utilitR, une documentation pour R](https://gitlab.com/linogaliana/documentationR/-/blob/master/.gitlab-ci.yml)).
Il est également possible de
l'utiliser avec un dépôt stocké sur `Github`. L'inconvénient de cette approche
est qu'elle est assez lente.
* `Github Actions`: c'est l'alternative (relativement récente) au service d'intégration continue de
Gitlab uniquement basée sur les technologies Github.
* `Travis CI`: un service externe d'intégration continue qui peut être connecté
à `Github` ou `Gitlab`. Les *pipelines* Travis ont l'avantage d'être assez
rapides. Cette solution convient néanmoins pour des *pipelines* moins complexes
que ceux de `Gitlab CI`


## Intégration continue avec `Python`: tester un notebook

Cette section n'est absolument pas exaustive. Au contraire, elle ne fournit
qu'un exemple minimal pour expliquer la logique de l'intégration continue. Il
ne s'agit ainsi pas d'une garantie absolue de reproductibilité d'un *notebook*.

### Lister les dépendances

Avant d'écrire les instructions à exécuter par `Travis`, il faut définir un
environnement d'exécution car `Travis` ne connaît pas la configuration `Python`
dont vous avez besoin.

Il convient ainsi de lister les dépendances nécessaires dans un fichier
`requirements`, comme expliqué dans la partie
[Bonnes pratiques](#bonnespratiques), ou un fichier `environment.yml`.
Ce fichier fait la liste des dépendances à installer.
Si on fait le choix de l'option `environment.yml`,
le fichier prendra ainsi la forme
suivante:

```yaml
channels:
- conda-forge

dependencies:
- python
- jupyter
- jupytext
- matplotlib
- nbconvert
- numpy
- pandas
- scipy
- seaborn
```

Le choix du *channel* `conda-forge` vise à contrôler le dépôt utilisé par
`Anaconda`.

Ne pas oublier de mettre ce fichier sous contrôle de version et de l'envoyer
sur le dépôt par un `push`.


### Connecter son compte `Github` à `Travis`

Les étapes sont expliquées dans
[la documentation Travis](https://docs.travis-ci.com/user/tutorial/#to-get-started-with-travis-ci-using-github)

1. Se rendre sur <travis-ci.com> et cliquer sur `Sign up with GitHub`.
2. Accepter l'autorisation (`OAuth`) demandée.
3. Après avoir été redirigé sur `Github` et suivi les instructions, retourner sur
<travis-ci.com>.
4. Cliquer, en haut à droite, sur la photo de profil. Cliquer sur `Settings`
puis `Activate` (bouton vert). Sélectionner le dépôt qui doit utiliser `Travis`

### Tester un notebook `myfile.ipynb`

Dans cette partie, on va supposer que le *notebook* à tester s'appelle `myfile.ipynb`
et se trouve à la racine du dépôt.

Le fichier qui contrôle les instructions exécutées dans l'environnement `Travis`
est le fichier `.travis.yml` (:warning: ne pas oublier le point au début du
nom du fichier).

Le modèle suivant, expliqué en dessous, fournit un modèle de recette pour
tester un notebook:

```shell
# Modèle de fichier .travis.yml
language: python
python:
- "3.7"

install:
- sudo apt-get update
# We do this conditionally because it saves us some downloading if the
# version is the same.
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh;
else
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
fi
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
# Useful for debugging any issues with conda
- conda info -a
- conda env create -n test-environment python=$TRAVIS_PYTHON_VERSION -f environment.yml
- source activate test-environment

script:
- jupytext --to py --execute myfile.ipynb
```

### Explications

Les lignes:

```shell
language: python
python:
- "3.7"
```

définissent la version de Python qui sera utilisée. Cependant, il convient
d'installer `Anaconda` (en fait une version minimaliste d'`Anaconda` nommée
`Miniconda`) ainsi que configurer la machine pour utiliser Anaconda plutôt
que la version de base de `Python`. Ce sont les lignes suivantes
qui contrôlent ces opérations:

```yaml
install:
- sudo apt-get update
# We do this conditionally because it saves us some downloading if the
# version is the same.
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh;
else
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
fi
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
# Useful for debugging any issues with conda
- conda info -a
```

Enfin, le reste de la tâche `install` est consacrée à la construction d'un
environnement Anaconda cohérent avec les packages définis dans `environment.yml`:

```yaml
- conda env create -n test-environment python=$TRAVIS_PYTHON_VERSION -f environment.yml
- source activate test-environment
```

Tout cela permet de construire un conteneur qui a vocation à être suffisant
pour exécuter `myfile.ipynb`. C'est l'objet de la tâche `script`:

```yaml
script:
- jupytext --to py --execute myfile.ipynb
```

`jupytext` est une extension de `jupyter` qui fournit des éléments pour passer d'un
notebook à un autre format. En l'occurrence, il s'agit de convertir
un *notebook* en
script `.py` et l'exécuter. Ce test pourrait également être fait en n'utilisant
que `Jupyter`:

```yaml
script:
- jupyter nbconvert --to notebook --execute --inplace myfile.ipynb
```
1 change: 0 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ dependencies:
- numpy
- pandas
- plotly
- python
- rasterio
- requests
- rtree
Expand Down
1 change: 1 addition & 0 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ else
echo "Converting $i"
# jupytext --to py --execute "$i"
jupytext --to ipynb "$i"
jupyter nbconvert --to notebook --execute --inplace ${i/$extension/ipynb}
done
fi

Expand Down

0 comments on commit b47e1ae

Please sign in to comment.