'3.12.6 | packaged by conda-forge | (main, Sep 30 2024, 18:08:52) [GCC 13.3.0]'
Cette page sera actualisée prochainement, une version plus à jour et plus complète peut être trouvée sur https://ensae-reproductibilite.github.io/website/
L’un des apports principaux des innovations
récentes de la data science est la
manière dont des projets, malgré
leur complexité, peuvent facilement
être converti en projets pérennes
à partir
d’un prototype bien construit.
En s’inspirant de l’approche devops
,
méthode de travail qui consiste à adopter un certain
nombre de gestes pour
automatiser la production de livrables ou de tests
dès la
conception du produit, les data scientists
ont adopté une méthode de travail très efficace
pour favoriser la réutilisation de leur travail
par d’autres équipes que celles à l’origine de
la conception du protype initial.
Cette approche devops
a été reprise et étendue
pour donner un autre buzz-word, le MLops
.
Il s’agit d’une approche qui vise à créer
et mettre à disposition des modèles de machine
learning de manière fiable et automatisée
à chaque nouvelle étape du projet, en parallèle
de la mise à jour du code ayant produit ces
output.
Ces nouvelles méthodes de travail permettent des gains substantiels de productivité pour les équipes développant des modèles et réduit fortement le coût de reprise d’un code par une équipe en charge de sa pérenisation. Ce coût est en effet le principal frein à la mise en production de nouveaux projets ce qui peut représenter un gâchis non négligeable de temps et de ressources. Comme nous l’expliquons avec Romain Avouac dans un cours de dernière année de l’ENSAE (https://ensae-reproductibilite.github.io/website/), l’adoption de certaines bonnes pratiques de développement de code et d’une démarche exploitant les dernières innovations de la data science peut substantiellement augmenter les chances d’un succès d’un projet. Le nouveau paradigme, qui consiste à intégrer en amont du projet certaines contraintes de la production et tester continuellement la manière dont les livrables évoluent, évite que la mise en production d’un projet, qui est coûteuse en temps et en ressources, n’aboutisse qu’au moment où le projet est déjà caduc (car les données ou les besoins ont évolués…).
1 L’intégration continue: une opportunité pour les data scientists
On retrouve régulièrement l’acronyme CI/CD pour illustrer cette nouvelle méthode de travail dans le monde du développement logiciel :
l’intégration continue (CI pour continuous integration) 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.
le déploiement en continu (CD pour continuous delivery) consiste à intégrer de manière automatisée la production d’un ou plusieurs livrables (environnement portable, application, site web, etc.) à chaque modification du code associé à 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.
Cette approche consiste une excellente opportunité
pour les data scientists d’être en mesure
de valoriser leurs projets auprès de publics aux
exigences différentes. Pour des développeurs, le
data scientist pourra fournir une image Docker
(environnement portable où l’ensemble des dépendances
et des configurations systèmes pour faire tourner un code
sont contrôlés) permettant à d’autres d’exécuter
facilement le code d’un projet. Pour faciliter
la réutilisation d’un modèle par d’autres data scientists,
il devient de plus en plus fréquent d’exposer
un modèle sous forme d’API: les personnes désirant
réutiliser le modèle peuvent directement l’appliquer
en accédant à une prédiction par le biais d’une API
ce qui évite d’avoir à fournir le jeu d’entraînement
si ce dernier est sensible. Pour toucher
des publics moins
familiers du code, la mise à disposition de sites web
interactifs valorisant certains résultats d’un projet
peut être intéressante. Cette approche très exigeante
d’utiliser un même projet pour toucher des cibles
très différentes est grandement facilitée par le
déploiement en continu et la mise à disposition
de librairies ou d’infrastructures
dédiées dans le monde de l’open-source.
Tout en restant éco-responsable (voir partie XXX), cela permet de mieux valoriser des projets pour réduire les coûts à le maintenir et le faire évoluer. Le cours de dernière année de l’ENSAE que je développe avec Romain Avouac (ensae-reproductibilite.github.io/) présente beaucoup plus de détails sur cette question.
2 L’intégration continue en pratique
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 dans ce paradigme 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.
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.
4 Mettre à disposition en continu des valorisations du projet
Les projets de valorisation de données prennent des formes très variées et s’adressent à des publics multiples dont les attentes peuvent être très diverses. Ne pas attendre la finalisation d’un projet pour mettre en oeuvre certains livrables est une méthode efficace pour ne pas se retrouver noyé, au dernier moment, sous des demandes et de nouvelles contraintes.
La production en continu de livrables est donc une
méthode très prisée dans le monde de la donnée.
Les principaux fournisseurs de services
d’intégration continue, à commencer par
Github
et Gitlab
proposent des services
pour le déploiement en continu. Cependant,
ceux-ci ne sont adaptés qu’à certains types
de livrables, principalement la mise à disposition
de sites internet, et il peut être intéressant
d’utiliser des services externes ou une
infrastructures Kubernetes
selon les
moyens à dispositon et les besoins des utilisateurs.
4.1 Les services de mise à disposition de Github
et Gitlab
Github
et Gitlab
, les deux plateformes de partage
de code, proposent non seulement des services
gratuits d’intégration continue mais aussi des services
de mise à disposition de sites web pleinement intégrés
aux services de stockage de code.
Ces services, Gitlab Pages
et Github Pages
, auxquels
on peut associer le service externe Netlify
qui répond
au même principe9 permettent, à chaque modification
du code source d’un projet, de reconstruire le site web (le livrable)
qui peut être directement produit à partir de certains fichiers
(des slides revealJS
par exemple) ou qui
sert d’output à l’intégration continue après compilation
de fichiers plus complexes (des fichiers quarto
par exemple).
Chaque dépôt sur Github
ou Gitlab
peut ainsi être associé
à un URL de déploiement disponible sur internet. A chaque
commit
sur le dépôt, le site web qui sert de livrable
est ainsi mis à jour. La version déployée à partir de la
branche principale peut ainsi être considérée
comme la version de production alors que les branches
secondaires peuvent servir d’espace bac à sable pour
vérifier que des changements dans le code source
ne mettent pas en péril le livrable. Cette méthode,
qui sécurise la production d’un livrable sous forme
de site web, est ainsi particulièrement appréciable.
4.2 Les services externes disponibles sans infrastructure spéciale
Pour fonctionner, l’intégration continue
nécessite de mettre en oeuvre des environnements normalisés.
Comme évoqué précédemment,
la technologie sous-jacente est celle de la conteneurisation.
Les images qui servent de point de départ au lancement
d’un conteneur sont elles-mêmes mises à disposition
dans des espaces communautaires (des registres d’images).
Il en existe plusieurs, les plus connus étant
le dockerhub
ou le registry
de Gitlab
.
Ces registres servent d’espaces de stockage pour des images,
qui sont des objets volumineux (potentiellement plusieurs
Gigas) mais aussi d’espace de mutualisation en permettant
à d’autres de réutiliser une image prête à l’emploi ou,
au contraire, à partir de
laquelle on peut ajouter un certain nombre de couches
pour obtenir l’environnement minimal
de reproductibilité.
Il est possible d’utiliser certaines actions Github
prête à l’emploi pour constuire une image Docker
à partir d’un fichier Dockerfile
. Après avoir
crée une connexion entre un compte sur la
plateforme Github
et l’autre sur DockerHub
,
une mise à disposition automatisée d’un livrable
sous forme d’image Docker
est ainsi possible.
Une image Docker
peut offrir une grande variété
d’output. Elle peut servir uniquement à
mettre à disposition un environnement de
reproductibilité mais elle peut servir à mettre
à disposition, pour les personnes maîtrisant
Docker
, des output plus raffinés. Par exemple,
dans le cours que nous donnons à l’ENSAE, nous
montrons comment docker
peut servir à
mettre à disposition à un utilisateur tiers
une application minimaliste (construite avec flask
)
qu’il fera tourner
sur son ordinateur.
Si une image Docker
peut être très utile pour la mise
à disposition, elle nécessite pour sa réutilisation
un niveau avancé d’expertise en programmation.
Cela ne conviendra pas à tous les publics. Certains
ne désireront que bénéficier d’une application interactive
où ils pourrons visualiser certains résultats en fonction
d’actions comme des filtres sur des sous-champs ou le choix
de certaines plages de données. D’autres publics seront
plutôt intéressé par la réutilisation d’un programme
ou des résultats d’un modèle sous forme d’API mais n’auront
pas l’infrastructure interne pour faire tourner le code
d’origine ou une image Docker
. C’est pour répondre à ces
limites qu’il peut devenir intéressant, pour une équipe
de data science de développer une architecture
kubernetes
interne, si l’organisation en a les moyens, ou
de payer un fournisseur de service, comme AWS, qui permet
cela.
4.3 Kubernetes
: le sommet de la pente du déploiement
Kubernetes
est une technologie qui pousse la logique
de la conteneurisation à son paroxysme.
Il s’agit d’un système open-source, développé
par Google
, permettant
d’automatiser le déploiement, la mise à l’échelle
et la gestion d’applications conteneurisées.
Grâce à Kubernetes, une application, par exemple
un site web proposant de la réactivité,
peut être mise à disposition et reporter les calculs,
lorsqu’ils sont nécessaires, sur
un serveur. L’utilisation de Kubernetes
dans
un projet de data science permet ainsi
d’anticiper à la fois l’interface d’une application
valorisant un projet mais aussi le fonctionnement
du back-office, par exemple en testant la capacité
de charge de cette application. Une introduction
à Kubernetes
orienté donnée peut être trouvée dans
le cours dédié à la mise en production
que nous donnons avec Romain Avouac et dans ce
post de blog très bien fait.
Dans les grandes organisations, où les rôles sont
plus spécialisés que dans les petites structures,
ce ne sont pas nécessairement les data scientists
qui devront maîtriser Kubernetes
mais plutôt
les data-architect ou les data-engineer. Néanmoins,
les data scientists devront être capable de
dialoguer avec eux et mettre en oeuvre une méthode
de travail adaptée (celle-ci reposera en principe sur
l’approche CI/CD). Dans les petites structures, les
data scientist peuvent être en mesure
de mettre en oeuvre le déploiement en continu. En
revanche, il est plus rare, dans ces structures,
où les moyens humains de maintenance sont limités,
que les serveurs sur lesquels fonctionnent Kubernetes
soient détenus en propres. En général, ils sont loués
dans des services de paiement à la demande de type
AWS.
5 Références
- https://ensae-reproductibilite.github.io/website/
- https://towardsdatascience.com/from-jupyter-to-kubernetes-refactoring-and-deploying-notebooks-using-open-source-tools-19f99585e923
Informations additionnelles
environment files have been tested on.
Latest built version: 2024-11-20
Python version used:
Package | Version |
---|---|
affine | 2.4.0 |
aiobotocore | 2.15.1 |
aiohappyeyeballs | 2.4.3 |
aiohttp | 3.10.8 |
aioitertools | 0.12.0 |
aiosignal | 1.3.1 |
alembic | 1.13.3 |
altair | 5.4.1 |
aniso8601 | 9.0.1 |
annotated-types | 0.7.0 |
appdirs | 1.4.4 |
archspec | 0.2.3 |
asttokens | 2.4.1 |
attrs | 24.2.0 |
babel | 2.16.0 |
bcrypt | 4.2.0 |
beautifulsoup4 | 4.12.3 |
black | 24.8.0 |
blinker | 1.8.2 |
blis | 0.7.11 |
bokeh | 3.5.2 |
boltons | 24.0.0 |
boto3 | 1.35.23 |
botocore | 1.35.23 |
branca | 0.7.2 |
Brotli | 1.1.0 |
cachetools | 5.5.0 |
cartiflette | 0.0.2 |
Cartopy | 0.24.1 |
catalogue | 2.0.10 |
cattrs | 24.1.2 |
certifi | 2024.8.30 |
cffi | 1.17.1 |
charset-normalizer | 3.3.2 |
click | 8.1.7 |
click-plugins | 1.1.1 |
cligj | 0.7.2 |
cloudpathlib | 0.20.0 |
cloudpickle | 3.0.0 |
colorama | 0.4.6 |
comm | 0.2.2 |
commonmark | 0.9.1 |
conda | 24.9.1 |
conda-libmamba-solver | 24.7.0 |
conda-package-handling | 2.3.0 |
conda_package_streaming | 0.10.0 |
confection | 0.1.5 |
contextily | 1.6.2 |
contourpy | 1.3.0 |
cryptography | 43.0.1 |
cycler | 0.12.1 |
cymem | 2.0.8 |
cytoolz | 1.0.0 |
dask | 2024.9.1 |
dask-expr | 1.1.15 |
databricks-sdk | 0.33.0 |
debugpy | 1.8.6 |
decorator | 5.1.1 |
Deprecated | 1.2.14 |
diskcache | 5.6.3 |
distributed | 2024.9.1 |
distro | 1.9.0 |
docker | 7.1.0 |
duckdb | 0.10.1 |
en-core-web-sm | 3.7.1 |
entrypoints | 0.4 |
et_xmlfile | 2.0.0 |
exceptiongroup | 1.2.2 |
executing | 2.1.0 |
fastexcel | 0.11.6 |
fastjsonschema | 2.20.0 |
fiona | 1.10.1 |
Flask | 3.0.3 |
folium | 0.17.0 |
fontawesomefree | 6.6.0 |
fonttools | 4.54.1 |
frozendict | 2.4.4 |
frozenlist | 1.4.1 |
fsspec | 2023.12.2 |
gensim | 4.3.2 |
geographiclib | 2.0 |
geopandas | 1.0.1 |
geoplot | 0.5.1 |
geopy | 2.4.1 |
gitdb | 4.0.11 |
GitPython | 3.1.43 |
google-auth | 2.35.0 |
graphene | 3.3 |
graphql-core | 3.2.4 |
graphql-relay | 3.2.0 |
graphviz | 0.20.3 |
great-tables | 0.12.0 |
greenlet | 3.1.1 |
gunicorn | 22.0.0 |
h2 | 4.1.0 |
hpack | 4.0.0 |
htmltools | 0.6.0 |
hyperframe | 6.0.1 |
idna | 3.10 |
imageio | 2.36.0 |
importlib_metadata | 8.5.0 |
importlib_resources | 6.4.5 |
inflate64 | 1.0.0 |
ipykernel | 6.29.5 |
ipython | 8.28.0 |
itsdangerous | 2.2.0 |
jedi | 0.19.1 |
Jinja2 | 3.1.4 |
jmespath | 1.0.1 |
joblib | 1.4.2 |
jsonpatch | 1.33 |
jsonpointer | 3.0.0 |
jsonschema | 4.23.0 |
jsonschema-specifications | 2024.10.1 |
jupyter-cache | 1.0.0 |
jupyter_client | 8.6.3 |
jupyter_core | 5.7.2 |
kaleido | 0.2.1 |
kiwisolver | 1.4.7 |
langcodes | 3.5.0 |
language_data | 1.3.0 |
lazy_loader | 0.4 |
libmambapy | 1.5.9 |
locket | 1.0.0 |
lxml | 5.3.0 |
lz4 | 4.3.3 |
Mako | 1.3.5 |
mamba | 1.5.9 |
mapclassify | 2.8.1 |
marisa-trie | 1.2.1 |
Markdown | 3.6 |
markdown-it-py | 3.0.0 |
MarkupSafe | 2.1.5 |
matplotlib | 3.9.2 |
matplotlib-inline | 0.1.7 |
mdurl | 0.1.2 |
menuinst | 2.1.2 |
mercantile | 1.2.1 |
mizani | 0.11.4 |
mlflow | 2.16.2 |
mlflow-skinny | 2.16.2 |
msgpack | 1.1.0 |
multidict | 6.1.0 |
multivolumefile | 0.2.3 |
munkres | 1.1.4 |
murmurhash | 1.0.10 |
mypy-extensions | 1.0.0 |
narwhals | 1.14.1 |
nbclient | 0.10.0 |
nbformat | 5.10.4 |
nest_asyncio | 1.6.0 |
networkx | 3.3 |
nltk | 3.9.1 |
numpy | 1.26.4 |
opencv-python-headless | 4.10.0.84 |
openpyxl | 3.1.5 |
opentelemetry-api | 1.16.0 |
opentelemetry-sdk | 1.16.0 |
opentelemetry-semantic-conventions | 0.37b0 |
OWSLib | 0.28.1 |
packaging | 24.1 |
pandas | 2.2.3 |
paramiko | 3.5.0 |
parso | 0.8.4 |
partd | 1.4.2 |
pathspec | 0.12.1 |
patsy | 0.5.6 |
Pebble | 5.0.7 |
pexpect | 4.9.0 |
pickleshare | 0.7.5 |
pillow | 10.4.0 |
pip | 24.2 |
platformdirs | 4.3.6 |
plotly | 5.24.1 |
plotnine | 0.13.6 |
pluggy | 1.5.0 |
polars | 1.8.2 |
preshed | 3.0.9 |
prometheus_client | 0.21.0 |
prometheus_flask_exporter | 0.23.1 |
prompt_toolkit | 3.0.48 |
protobuf | 4.25.3 |
psutil | 6.0.0 |
ptyprocess | 0.7.0 |
pure_eval | 0.2.3 |
py7zr | 0.20.8 |
pyarrow | 17.0.0 |
pyarrow-hotfix | 0.6 |
pyasn1 | 0.6.1 |
pyasn1_modules | 0.4.1 |
pybcj | 1.0.2 |
pycosat | 0.6.6 |
pycparser | 2.22 |
pycryptodomex | 3.21.0 |
pydantic | 2.9.2 |
pydantic_core | 2.23.4 |
Pygments | 2.18.0 |
PyNaCl | 1.5.0 |
pynsee | 0.1.8 |
pyogrio | 0.10.0 |
pyOpenSSL | 24.2.1 |
pyparsing | 3.1.4 |
pyppmd | 1.1.0 |
pyproj | 3.7.0 |
pyshp | 2.3.1 |
PySocks | 1.7.1 |
python-dateutil | 2.9.0 |
python-dotenv | 1.0.1 |
python-magic | 0.4.27 |
pytz | 2024.1 |
pyu2f | 0.1.5 |
pywaffle | 1.1.1 |
PyYAML | 6.0.2 |
pyzmq | 26.2.0 |
pyzstd | 0.16.2 |
querystring_parser | 1.2.4 |
rasterio | 1.4.2 |
referencing | 0.35.1 |
regex | 2024.9.11 |
requests | 2.32.3 |
requests-cache | 1.2.1 |
retrying | 1.3.4 |
rich | 13.9.4 |
rpds-py | 0.21.0 |
rsa | 4.9 |
ruamel.yaml | 0.18.6 |
ruamel.yaml.clib | 0.2.8 |
s3fs | 2023.12.2 |
s3transfer | 0.10.2 |
scikit-image | 0.24.0 |
scikit-learn | 1.5.2 |
scipy | 1.13.0 |
seaborn | 0.13.2 |
setuptools | 74.1.2 |
shapely | 2.0.6 |
shellingham | 1.5.4 |
six | 1.16.0 |
smart-open | 7.0.5 |
smmap | 5.0.0 |
sortedcontainers | 2.4.0 |
soupsieve | 2.5 |
spacy | 3.7.5 |
spacy-legacy | 3.0.12 |
spacy-loggers | 1.0.5 |
SQLAlchemy | 2.0.35 |
sqlparse | 0.5.1 |
srsly | 2.4.8 |
stack-data | 0.6.2 |
statsmodels | 0.14.4 |
tabulate | 0.9.0 |
tblib | 3.0.0 |
tenacity | 9.0.0 |
texttable | 1.7.0 |
thinc | 8.2.5 |
threadpoolctl | 3.5.0 |
tifffile | 2024.9.20 |
toolz | 1.0.0 |
topojson | 1.9 |
tornado | 6.4.1 |
tqdm | 4.66.5 |
traitlets | 5.14.3 |
truststore | 0.9.2 |
typer | 0.13.1 |
typing_extensions | 4.12.2 |
tzdata | 2024.2 |
Unidecode | 1.3.8 |
url-normalize | 1.4.3 |
urllib3 | 1.26.20 |
wasabi | 1.1.3 |
wcwidth | 0.2.13 |
weasel | 0.4.1 |
webdriver-manager | 4.0.2 |
websocket-client | 1.8.0 |
Werkzeug | 3.0.4 |
wheel | 0.44.0 |
wordcloud | 1.9.3 |
wrapt | 1.16.0 |
xgboost | 2.1.1 |
xlrd | 2.0.1 |
xyzservices | 2024.9.0 |
yarl | 1.13.1 |
yellowbrick | 1.5 |
zict | 3.0.0 |
zipp | 3.20.2 |
zstandard | 0.23.0 |
View file history
SHA | Date | Author | Description |
---|---|---|---|
580cba7 | 2024-08-07 18:59:35 | Lino Galiana | Multilingual version as quarto profile (#533) |
c9f9f8a | 2024-04-24 15:09:35 | Lino Galiana | Dark mode and CSS improvements (#494) |
005d89b | 2023-12-20 17:23:04 | Lino Galiana | Finalise l’affichage des statistiques Git (#478) |
1f23de2 | 2023-12-01 17:25:36 | Lino Galiana | Stockage des images sur S3 (#466) |
a06a268 | 2023-11-23 18:23:28 | Antoine Palazzolo | 2ème relectures chapitres ML (#457) |
652009d | 2023-10-09 13:56:34 | Lino Galiana | Finalise le cleaning (#430) |
a771183 | 2023-10-09 11:27:45 | Antoine Palazzolo | Relecture TD2 par Antoine (#418) |
154f09e | 2023-09-26 14:59:11 | Antoine Palazzolo | Des typos corrigées par Antoine (#411) |
9a4e226 | 2023-08-28 17:11:52 | Lino Galiana | Action to check URL still exist (#399) |
9977c5d | 2023-08-28 10:43:36 | Lino Galiana | Fix bug path pandas (#397) |
3bdf3b0 | 2023-08-25 11:23:02 | Lino Galiana | Simplification de la structure 🤓 (#393) |
7adbea4 | 2023-06-12 11:25:40 | Lino Galiana | Update CI elements |
23cd4a1 | 2022-07-05 10:31:03 | Lino Galiana | Précisions supplémentaires dans la partie CI/CD (#246) |
bacb5a0 | 2022-07-04 19:05:20 | Lino Galiana | Enrichir la partie elastic (#241) |
Notes de bas de page
Ces services d’intégration continue étaient utilisés lorsque
Github
ne proposait pas encore de service intégré, comme le faisaitGitlab
. Ils sont de moins en moins fréquemment utilisés.↩︎Pour réduire le temps nécessaire pour construire le site web, ce pipeline s’appuie sur un environnement
Docker
construit sur un autre dépôt disponible également surGithub
. Celui-ci part d’une configuration systèmeLinux
et construit un environnementAnaconda
à partir d’un fichierenvironment.yml
qui liste toutes les dépendances nécessaires pour exécuter les morceaux de code du site web. Cet environnementAnaconda
est construit grâce à l’outilmamba
qui permet d’aller beaucoup plus vite dans la constitution d’environnements que ne le permetconda
.↩︎Sur la différence entre les environnements virtuels et les environnements conda, voir cette partie de cours plus avancé que nous donnons avec Romain Avouac sur la mise en production de projets data science.↩︎
Il est possible d’installer une partie des packages avec
pip
en définissant un champpip
dans le fichierenvironment.yml
. Néanmoins, les concepteurs d’Anaconda recommandent d’être prudent avec cette méthode qui présente certes l’avantage d’accélérer le temps de création de l’environnement mais peut créer des difficultés avec des librairies nécessitant d’autres langages système comme leC
.↩︎Le point de vue que nous défendons avec Romain Avouac dans notre cours sur la reproductibilité est qu’il s’agit d’un continuum dans lequel on investit plus ou moins en fonction de ses contraintes, de ses besoins, de ses compétences, du temps humain qu’on peut dédier à développer des output reproductibles et le temps gagné en développant une telle approche. Selon où on se trouve sur ce cursus, en fonction des solutions déjà existantes qu’on peut trouver sur internet, on va plus ou moins raffiner notre intégration et nos déploiements continus.↩︎
Il est recommandé de ne pas garder la période de rétention des artefacts par défaut car celle-ci est assez longue (90 jours). Les output pouvant être assez volumineux et expirant rapidement (en général ce qui nous intéresse est la dernière ou l’avant dernière version de l’_output), pour des raisons écologiques, il est recommandé de fixer des périodes courtes. Cela peut être fait directement dans le fichier configurant l’intégration continue comme ici ou dans les paramètres par défaut du dépôt pour que cette règle s’applique à toutes les productions faites par intégration continue.↩︎
Il est recommandé de ne pas garder la période de rétention des artefacts par défaut car celle-ci est assez longue (90 jours). Les output pouvant être assez volumineux et expirant rapidement (en général ce qui nous intéresse est la dernière ou l’avant dernière version de l’_output), pour des raisons écologiques, il est recommandé de fixer des périodes courtes. Cela peut être fait directement dans le fichier configurant l’intégration continue comme ici ou dans les paramètres par défaut du dépôt pour que cette règle s’applique à toutes les productions faites par intégration continue.↩︎
Il s’agit du service utilisé, par exemple, pour ce cours.
Netlify
est un service de mise à disposition qui offre des fonctionalités plus complètes que celles permises parGitlab Pages
etGithub Pages
. Outre cet avantage, il est plus facile à configurer queGithub Pages
qui nécessite l’usage d’une branche dédiée nomméegh-pages
, ce qui peut rebutant.↩︎Il s’agit du service utilisé, par exemple, pour ce cours.
Netlify
est un service de mise à disposition qui offre des fonctionalités plus complètes que celles permises parGitlab Pages
etGithub Pages
. Outre cet avantage, il est plus facile à configurer queGithub Pages
qui nécessite l’usage d’une branche dédiée nomméegh-pages
, ce qui peut rebutant.↩︎
Citation
@book{galiana2023,
author = {Galiana, Lino},
title = {Python pour la data science},
date = {2023},
url = {https://pythonds.linogaliana.fr/},
doi = {10.5281/zenodo.8229676},
langid = {fr}
}
3 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 faire tourner le code voulu. Les Actions Github consistuent un modèle sur lequel il est facile de s’appuyer lorsqu’on a des connaissances limitées concernant `Docker. Il est également très simple de construire son image de rien, ce qui est la démarche choisie dans l’autre cours de l’ENSAE que nous donnons avec Romain Avouac (https://ensae-reproductibilite.github.io/website/).
Quand on utilise un dépôt
Github
ouGitlab
, des services automatiques d’intégration continue peuvent être utilisés :Gitlab CI
: solution pleinement intégrée à un dépôtGitlab
. Très généraliste et permettant des pipelines très complexes (voir l’intégration continue du projet utilitR, une documentation pour R). Il est également possible de l’utiliser avec un dépôt stocké surGithub
. 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 technologiesGithub
. La très forte dynamique de développement a rendu ce service incontournable. Un grand nombre de scripts pré-définis et paramétrables facilitent l’entrée dans le monde de l’intégration continue.Historiquement, il existait d’autres services d’intégration continue, notamment
Travis CI
ouAppVeyor
13.1 Fonctionnement des actions Github
Les actions
Github
fonctionnent par couches successives au sein desquelles on effectue un certain nombre d’instructions. La meilleure manière d’apprendre les actionsGithub
est, certes, de lire la documentation officielle mais surtout, à mon avis, de regarder quelques pipelines pour comprendre la démarche.L’un des intérêts des
Github Actions
est la possibilité d’avoir un pipeline proposant une intrication de langages différents pour avoir une chaine de production qui propose les outils les plus efficaces pour répondre à un objectif en limitant les verrous techniques.Par exemple, le pipeline de ce cours, disponible sur
Github
{{< githubrepo >}} propose une intrication des langagesPython
etR
avec des technologiesAnaconda
(pour contrôler l’environnementPython
comme expliqué dans les chapitres précédents) etJavascript
(pour le déploiement d’un site web avec le service tiersNetlify
)2. Cette chaîne de production multi-langage permet que les mêmes fichiers sources génèrent un site web et des notebooks disponibles sur plusieurs environnements.Les couches qui constituent les étapes du pipeline portent ainsi le nom de
steps
. Un step peut comporter un certain nombre d’instructions ou exécuter des instructions pré-définies. L’une de ces instructions prédéfinies est, par exemple, l’installation de Python ou l’initialisation d’un environnement conda. La documentation officielle deGithub
propose un fichier qui peut servir de modèle pour tester un scriptPython
voire l’uploader de manière automatique surPypi
.3.2 Intégration continue avec
Python
: tester un notebookCette section n’est absolument pas exhaustive. 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.
Github
propose une action officielle pour utiliserPython
dans un pipeline d’intégration continue. Elle est disponible sur le MarketPlace Github. Il s’agit d’un bon point de départ, à enrichir.Le fichier qui contrôle les instructions exécutées dans l’environnement
Actions
doit se trouver dans le dossier.github/workflows/
(:warning: ne pas oublier le point au début du nom du dossier). Il doit être au formatYAML
avec une extension.yml
ou.yaml
. Il peut avoir n’importe quel nom néanmoins il vaut mieux lui donner un nom signifiant, par exempleprod.yml
pour un fichier contrôlant une chaîne de production.3.2.1 Lister les dépendances
Avant d’écrire les instructions à exécuter par
Github
, il faut définir un environnement d’exécution carGithub
ne connaît pas la configurationPython
dont vous avez besoin.Il convient ainsi de lister les dépendances nécessaires dans un fichier
requirements.txt
(si on utilise un environnement virtuel) ou un fichierenvironment.yml
(si on préfère utiliser un environnement conda). Bien que le principe sous-jacent soit légèrement différent, ces fichiers ont la même fonction : permettre la création d’un environnement ex-nihilo avec un certain nombre de dépendances pré-installées3.Si on fait le choix de l’option
environment.yml
, le fichier prendra ainsi la forme suivante, à enrichir en fonction de la richesse de l’environnement souhaité. :Le même fichier sous le format
requirements.txt
aura la forme suivante :Sous leur apparente équivalence, au-delà de la question du formatage, ces fichiers ont deux différences principales :
Python
est définie dans le fichierenvironment.yml
alors qu’elle ne l’est pas dans un fichierrequirements.txt
. C’est parce que le second installe les dépendances dans un environnement déjà existant par ailleurs alors que le premier peut servir à créer l’environnement avec une certaine configuration dePython
;environment.yml
on installera des packages via conda alors qu’avec unrequirements.txt
on privilégiera plutôtpip
4.Dans le cas de l’environnement
conda
, le choix du channelconda-forge
vise à contrôler le dépôt utilisé parAnaconda
.Hint
La
conda forge
est un dépôt de package alternatif au canal par défaut d’Anaconda qui est maintenu par l’équipe de développeurs officiels d’Anaconda. Comme cette dernière cherche en priorité à assurer la stabilité de l’écosystèmeAnaconda
, les versions de package évoluent moins vite que le rythme voulu par les développeurs de packages. Pour cette raison, un dépôt alternatif, où les montées de version sont plus simples parce qu’elles dépendent des développeurs de chaque package, a émergé. Il s’agit de laconda forge
. Lorsqu’on désire utiliser des fonctionalités récentes de l’écosystème de la data science, il est conseillé de l’utiliser.Ne pas oublier de mettre ce fichier sous contrôle de version et de l’envoyer sur le dépôt par un
push
.3.2.2 Créer un environnement reproductible dans Github Actions
Deux approches sont possibles à ce niveau, selon le degré de reproductibilité désiré5:
conda-incubator/setup-miniconda@v2
est un bon point de départ.Docker
.La deuxième solution permet de contrôler de manière beaucoup plus fine l’environnement dans lequel
Python
s’éxécutera ainsi que la manière dont l’environnement sera créé6. Néanmoins, elle nécessite des connaissances plus poussées dans la principe de la conteneurisation qui peuvent être coûteuses à acquérir. Selon l’ambition du projet, notamment les réutilisation qu’il désire, un data scientist pourra privilégier telle ou telle option. Les deux solutions sont présentées dans l’exemple fil-rouge du cours que nous donnons avec Romain Avouac (https://ensae-reproductibilite.github.io/website/application/).3.2.3 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. Les dépendances pour l’exécuter sont listées dans un fichierrequirements.txt
.Le modèle suivant, expliqué en dessous, fournit un modèle de recette pour tester un notebook. Supposons que ce fichier soit présent dans un chemin
.github/workflows/test-notebook.yml
Environnement virtuel
Environnement conda
Dans les deux cas, la démarche est la même:
checkout
) ;Python
;conda
, il est également nécessaire de faire quelques configurations supplémentaires (notamment ajouterconda
aux logiciels reconnus par la ligne de commande) ;Ces actions sont exécutées à chaque interaction avec le dépôt distant (
push
), quelle que soit la branche. A partir de ce modèle, il est possible de raffiner pour, par exemple, automatiquement faire un commit du notebook validé et le pusher via le robotGithub
8