diff --git a/.gitignore b/.gitignore index c189a0a8d34d58a3e5df2234a04c26827336dd0d..09150bb5aac55588daa5d42e28e1cabfc71024cb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ __pycache__/ *.so *.e +public/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 81ff6e9db533cd4e42757db93d167922503501b7..11c68d4315d153ef672b0031924458ac4be1cd0b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,47 +1,15 @@ -stages: - - build - - test - - release - -variables: - CONTAINER_TEST_IMAGE: boileaum/rosen:$CI_COMMIT_REF_NAME - CONTAINER_RELEASE_IMAGE: boileaum/rosen:latest - -before_script: - - echo $DOCKERHUB_PASSWD | docker login -u boileaum --password-stdin - -b:docker: - stage: build - tags: - - shell, docker - script: - - docker build --pull -t $CONTAINER_TEST_IMAGE -f ./docker/Dockerfile-rosen . - - docker push $CONTAINER_TEST_IMAGE - -t:helloworld: - stage: test - tags: - - shell, docker - script: - - docker pull $CONTAINER_TEST_IMAGE - - docker run $CONTAINER_TEST_IMAGE /bin/bash -c 'python test_helloworld.py' - -t:rosen: - stage: test - tags: - - shell, docker - script: - - docker pull $CONTAINER_TEST_IMAGE - - docker run $CONTAINER_TEST_IMAGE /bin/bash -c 'pytest -v' - -r:docker: - stage: release - tags: - - shell, docker - script: - - docker pull $CONTAINER_TEST_IMAGE - - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE - - docker push $CONTAINER_RELEASE_IMAGE +pages: + tags: + - pages, docker + image: boileaum/debian-jupyter + script: + - pip3 --no-cache-dir install bash_kernel + - python -m bash_kernel.install + - mkdir public + - ./make_slides.sh + artifacts: + paths: + - public only: - - master + - pages diff --git a/README.md b/README.md index c9adb36aeae2103a9e85403f4db0e8a879242d3d..70657cdd34d39e2c5902cf5b87fc01b60738458b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # TP GitLab CI -## Execution du notebook jupyter +Le contenu de cette session pratique est publié sur cette [page](https://boileau.pages.math.unistra.fr/tp-gitlab-ci/). + +### Execution du notebook jupyter - [Installer Anaconda](https://www.anaconda.com/download) pour disposer de `jupyter-notebook` - Ajouter le support du noyau bash : diff --git a/index.ipynb b/index.ipynb index acf05ed336e51f233a05d4ccef9ff0ab3383dd57..3c4e0b3d367bcd91b2f18355729360a34382c689 100644 --- a/index.ipynb +++ b/index.ipynb @@ -20,21 +20,14 @@ "\n", "## *Session pratique*\n", "\n", - "- [Notebook](http://nbviewer.jupyter.org/urls/)\n", - "- [Slideshow]()\n", + "- [Notebook](http://nbviewer.jupyter.org/urls/boileau.pages.math.unistra.fr/tp-gitlab-ci/tp-gitlab-ci.ipynb)\n", + "- [Slideshow](https://boileau.pages.math.unistra.fr/tp-gitlab-ci/tp-gitlab-ci.slides.html)\n", "---\n", "\n", "Matthieu Boileau - \n", "\n", "*Contenu sous licence [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0)*" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/launch_slide.sh b/launch_slide.sh index 3a7c43e3f012aead44214557736cd4b59adfdadf..5365c34d8a374cff3551fa8ce835812b6518f51b 100755 --- a/launch_slide.sh +++ b/launch_slide.sh @@ -2,4 +2,4 @@ set -x nbfile="tp-gitlab-ci.ipynb" -jupyter-nbconvert $nbfile --to slides --post serve $2 --allow-errors +jupyter-nbconvert $nbfile --to slides --post serve --execute --allow-errors diff --git a/make_slides.sh b/make_slides.sh new file mode 100755 index 0000000000000000000000000000000000000000..c8b3d841201340d7899a5ae62cb3b769ef8bdf1a --- /dev/null +++ b/make_slides.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -x + +notebooks="tp-gitlab-ci.ipynb" +revealprefix="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.3.0" + +jupyter-nbconvert $notebooks --to slides --reveal-prefix $revealprefix --output-dir=public --execute --allow-errors +jupyter-nbconvert index.ipynb --to html --output-dir=public +cp *.ipynb public/ +cp *.png public/ diff --git a/pipeline.png b/pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..f1588d7a54c3efea874c59762d85ba94a5be8705 Binary files /dev/null and b/pipeline.png differ diff --git a/tp-gitlab-ci.ipynb b/tp-gitlab-ci.ipynb index 7ac1bfb0273fdfc858f2d0ae17edf5485f9d3392..5a720fa5aebea923f58a8ca7e5c58df811ce0dfb 100644 --- a/tp-gitlab-ci.ipynb +++ b/tp-gitlab-ci.ipynb @@ -149,7 +149,7 @@ "outputs": [], "source": [ "export USERNAME=\"m.boileau\" # votre login sur git.unistra.fr\n", - "export TPBASEDIR=$HOME # le répertoire où vous souhaitez installer le TP\n", + "export TPBASEDIR=$HOME # le répertoire où vous souhaitez installer le TP\n", "export TPDIR=$TPBASEDIR/tp-gitlab-ci" ] }, @@ -271,8 +271,7 @@ "metadata": {}, "outputs": [], "source": [ - "cd $TPDIR\n", - "cd tp-gitlab-ci" + "cd $TPDIR" ] }, { @@ -282,7 +281,9 @@ "outputs": [], "source": [ "git pull\n", - "git checkout exo1" + "git stash\n", + "git checkout exo1\n", + "git checkout exo1-start .gitlab-ci.yml # Clean previous modifications" ] }, { @@ -405,7 +406,7 @@ } }, "source": [ - "Pousser vos modifications" + "Poussez vos modifications" ] }, { @@ -441,7 +442,7 @@ "source": [ "### Provoquez une erreur\n", "\n", - "Dans `.gitlab-ci.yml`, introduisez une erreur dans une des lignes du script et observer l'effet dans `CI / CD > Pipelines` après avoir pousser les modifications.\n", + "Dans `.gitlab-ci.yml`, introduisez une erreur dans une des lignes du script et observer l'effet dans `CI / CD > Pipelines` après avoir poussé les modifications.\n", "\n", "> **Note :** les fichiers peuvent s'éditer directement dans GitLab." ] @@ -473,7 +474,8 @@ "source": [ "cd $TPDIR\n", "git stash # si vous avez des modifications non enregistrées dans exo1\n", - "git checkout exo2" + "git checkout exo2\n", + "git rm .gitlab-ci.yml # Clean previous commits" ] }, { @@ -689,7 +691,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, "source": [ "On enregistre, on pousse et on vérifie l'exécution de la chaîne d'intégration continue dans `CI / CD > Pipelines`\n" ] @@ -721,38 +727,209 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, "source": [ "### Provoquez des erreurs\n", "\n", - "Modifier les fichiers\n", + "Modifier les fichiers pour provoquer des erreurs.\n", + "Notez que le test n'est pas exécuté si le build échoue." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Exo3 : Docker pour gérer les dépendances\n", "\n", + "À `helloworld`, on ajoute un programme en python `rosenbrock.py` qui calcule la [fonction de Rosenbrock](https://fr.wikipedia.org/wiki/Fonction_de_Rosenbrock). Ce programme nécessite [`pythran`](http://pythran.readthedocs.io/), un traducteur de python vers C++ qui permet d'accélérer le code python.\n", + "Cet exercice a pour but d'illustrer la gestion des dépendances de compilation avec les conteneurs Docker dans une chaîne GitLab CI.\n", "\n", - "- de build : notez que le test n'est pas exécuté\n", - "- de test : le\n" + "Pour le reproduire, il est nécessaire de :\n", + "1. créer un compte sur [DockerHub](https://hub.docker.com/)\n", + "2. y créer un dépôt vierge intitulé `rosen`\n", + "3. que Docker soit installé sur la machine qui héberge le runner (c'est le cas pour le runner partagé de ce TP)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "Dans votre clone local, basculez sur `exo3`" ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "bash: Récupérer: command not found\n" + "No local changes to save\n", + "Already on 'exo3'\n", + "Your branch is up-to-date with 'origin/exo3'.\n" ] - }, - { - "ename": "", - "evalue": "127", - "output_type": "error", - "traceback": [] } ], "source": [ - "Récupérer un artifact" + "cd $TPDIR\n", + "git stash # si vous avez des modifications non enregistrées dans exo2\n", + "git checkout exo3" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Entête et étape préliminaire du fichier `.gitlab-ci.yml`\n", + "\n", + "```yaml\n", + "stages:\n", + " - build\n", + " - test\n", + " - release\n", + "\n", + "variables:\n", + " CONTAINER_TEST_IMAGE: boileaum/rosen:$CI_COMMIT_REF_NAME\n", + " CONTAINER_RELEASE_IMAGE: boileaum/rosen:latest\n", + "\n", + "before_script:\n", + " - echo $DOCKERHUB_PASSWD | docker login -u boileaum --password-stdin\n", + "[...]\n", + "```\n", + "\n", + "Pour faire marcher l'exercice :\n", + "1. Remplacez `boileaum` par votre `username` sur DockerHub.\n", + "2. Sur GitLab dans `Settings > CI / CD > Secret variables`, créez une variable `DOCKERHUB_PASSWD` qui contient le mot de passe de votre compte DockerHub." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Etape de `build` :\n", + "\n", + "```yaml\n", + "[...]\n", + "b:docker:\n", + " stage: build\n", + " tags:\n", + " - shell, docker\n", + " script:\n", + " - docker build --pull -t $CONTAINER_TEST_IMAGE -f ./docker/Dockerfile-rosen .\n", + " - docker push $CONTAINER_TEST_IMAGE\n", + "[...]\n", + "```\n", + "\n", + "- on construit l'image de test à partir du fichier `./docker/Dockerfile-rosen`\n", + "- on pousse cette image sur DockerHub\n", + "\n", + "> **Note :** l'image `Dockerfile-rosen` est basée sur l'image construite avec `./docker/Dockerfile-pythran` et qui contient les dépendances." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Etapes de `test`\n", + "\n", + "```yaml\n", + "[...]\n", + "t:helloworld:\n", + " stage: test\n", + " tags:\n", + " - shell, docker\n", + " script:\n", + " - docker pull $CONTAINER_TEST_IMAGE\n", + " - docker run $CONTAINER_TEST_IMAGE /bin/bash -c 'python test_helloworld.py'\n", + "[...]\n", + "```\n", + "\n", + "- on tire l'image de test\n", + "- on lance les tests unitaires" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Etape de livraison\n", + "\n", + "```yaml\n", + "\n", + "[...]\n", + "r:docker:\n", + " stage: release\n", + " tags:\n", + " - shell, docker\n", + " script:\n", + " - docker pull $CONTAINER_TEST_IMAGE\n", + " - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE\n", + " - docker push $CONTAINER_RELEASE_IMAGE\n", + " only:\n", + " - exo3\n", + "[...]\n", + "```\n", + "\n", + "On ne fait que tirer l'image de test validée, la renommer, la pousser vers DockerHub." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Pipeline complet\n", + "\n", + "\n", + "![](pipeline.png)\n", + "\n", + "Comme le montre ce schéma, l'exécution de différents jobs d'une même étape peut être réalisée en parallèle par différents runners.\n", + "\n", + "Plus d'information " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Récupérer un artifact" ] }, {