Gitlab CI/CD sur un projet python microservice : retour sur 5 ans d’évolutions

A presentation at Meetup Python Rennes in November 2023 in Rennes, France by Jean-Luc Tromparent

Slide 1

Slide 1

NOTRE JOB, VOUS AIDER À CHOISIR LE VÔTRE

Slide 2

Slide 2

GitLab CI/CD sur un projet python microservice Retour sur 5 ans d’évolutions Jean-Luc Tromparent Antoine Coeur-Quetin

Slide 3

Slide 3

GitLab (des débuts à nos jours) 2011 2012 Dmitriy Zaporozhets lance Sytse Sijbrandij rejoint le un projet de partage de projet code Dmitriy créé la première 2014 2015 Gitlab Inc. GitLab 8.0 version de GitLab CI https://handbook.gitlab.com/handbook/company/history/ 2018 Microsoft rachete GitHub 2023 GitLab 16.4

Slide 4

Slide 4

Un projet Python (de la préhistoire à nos jours) TARS : Totally Awesome Recommendation System 2014 2015 2017 svn > git premier algo de migration azure portage en python hellowork.com monorepo redmine > gitlab recommandation lambda architecture microservice poetry réduction de la dette infogérance stack: c#, mongodb, redis stack: eventhub, stack: python, k8s v6 des sites emploi régionsjob stack tracking: nodejs, mongodb hdfs/spark 2018 2022 2023

Slide 5

Slide 5

Get started fichier .gitlab-ci.yml configuration d’un pipeline de CI séquence de stages et de jobs https://docs.gitlab.com/ee/ci/quick_start/

Slide 6

Slide 6

Un job de test test-job: stage: test script: - poetry install - poetry run python -m pytest -v coverage: ‘/^TOTAL.\s+(\d+%)\s$/’ artifacts: paths: - htmlcov/ coverage 77.00% —cov-report html:htmlcov —cov-fail-under $COVERAGE_MINIMUM_THRESHOLD_PERCENT

Slide 7

Slide 7

Architecture type de nos projets data un sous-projet librairie métier périmètre datascientist tests fonctionnels un sous-projet API (ou worker) périmetre data-ingé gestion des erreurs scalabilité containerization

Slide 8

Slide 8

Les livrables de notre projet de recommandation → des librairies Python publish-job: stage: release script: - poetry version $CI_COMMIT_TAG - poetry publish -r papaye —build only: - tags

Slide 9

Slide 9

Les livrables de notre projet de recommandation → des images Docker publish-job: stage: release script: - docker login ${NEXUS_URI} -u ${NEXUS_USER} -p ${NEXUS_PWD} - docker pull “${CI_PROJECT_NAME}:latest” || true - docker tag “${CI_PROJECT_NAME}:latest” “${NEXUS_URI}/${CI_PROJECT_NAME}:${CI_COMMIT_TAG}” - docker push “${NEXUS_URI}/${CI_PROJECT_NAME}:${CI_COMMIT_TAG}” only: - tags

Slide 10

Slide 10

Multi-project pipelines mylib/.gitlab-ci.yml trigger-job: myapi/.gitlab-ci.yml update_lib_version: stage: .post variables: LIB_VERSION: ${CI_COMMIT_TAG} stage: .pre script: - echo “Switch to lib version $LIB_VERSION” trigger: project: DataScience/myProject/myApi

  • poetry add mylib@$LIB_VERSION —lock artifacts: branch: master strategy: depend only: - tags paths: - poetry.lock - pyproject.toml rules: - if: $LIB_VERSION

Slide 11

Slide 11

Versioning release-job: stage: release script: # bumps the patch number of the semantic version of the project - poetry version patch - export NEW_VERSION=$(poetry version —short) 🔖

pushes the commit (asks the CI not to trigger a pipeline) and the tag after the version update - git add -A && git commit -m ” Release $NEW_VERSION” - git push -o ci.skip -u origin HEAD:$CI_COMMIT_BRANCH - git tag -a $NEW_VERSION -m “Release $NEW_VERSION” - git push —tags origin $NEW_VERSION # pass version as artifact - echo $NEW_VERSION > .version artifacts: paths: - .version only: - master

Slide 12

Slide 12

Architecture du projet REKO

Slide 13

Slide 13

Déploiement environnement de production image: infra k8s dispatch: 1.3.31 packaging: 1.3.38 template helm jadexplorer: 1.0.6 déploiement depuis gitlab offer2offer: 1.3.40 offer2user: 1.3.59 user2offer: 1.3.23 distributor: 1.3.15 feedcool: 1.3.8 feedcroo: 1.3.1 feedlsq: 1.3.12 reporter: 1.3.35 shipper: 1.3.32 watchdog: 1.3.5 feedjade: 1.3.31 upgradejade: 1.3.5 newusers: 1.3.15 refreshcache: 1.3.14 batchupjade: 1.3.11 keepintouch: 1.0.22 regurgitor: 0.0.12

Slide 14

Slide 14

Bilan 2018 - 2022 🍏 Le projet scale bien 🍏 Projet modulaire 🍎 MR portant sur plusieurs projets 🍎 Onboarding compliqué 🍎 Le déploiement n’est pas vraiment continuous

Slide 15

Slide 15

Gitlab CI/CD Migration vers un monorepo Pourquoi ?

Slide 16

Slide 16

Pourquoi un monorepo 40 projets Gitlab Duplication CI Beaucoup de trigger Pas de tag commun sur plusieurs projets Pourquoi maintenant Dette technique (Python 3.7) Projets transverses en étude : Log JSON, Lint, Sonarqube Migration Poetry Impose : modifications de la CI Permet : Imports relatifs dans la codebase

Slide 17

Slide 17

Le monorepo avec python Gerben Oostra (Gitlab) https://gitlab.com/gerbenoostra/poetry-monorepo David Vujic (Poetry) https://github.com/DavidVujic/pythonpolylith

Slide 18

Slide 18

Procédure de migration 1. Récupération de la codebase avec l’historique 2. Migration Poetry 3. Variables de CI 4. Template Helm (kubernetes) 5. Déploiement en preprod 6. Mise en production

Slide 19

Slide 19

Structure du repository TARS/ ├─ common/ ├─ k8s/ ├─ worker/ │ │ │ ├─ jade/ │ ├─ app/ │ ├─ core/ │ │ │ │ ├─ README.md │ └─ pyproject.toml └─ watchdog/ ├─ .gitlab-ci.yml ├─ pyproject.toml └─ README.md [tool.poetry] name = “jade” version = “1.5.0” readme = “README.md” packages = [ { include = “jade”, from = “core/” }, ] [tool.poetry.dependencies] python = “~3.10” requests = “2.25.1” workerrq = {path=”../../common/workerrq”}

Slide 20

Slide 20

pyproject.toml root Contient le paramétrage du formatter/LINT Permet de consolider les versions de dépendance Ne permet pas d’installer tous les projets [tool.poetry.group.worker.dependencies] jade = {path=”worker/jade”} watchdog = {path=”worker/watchdog”} [tool.poetry.group.api.dependencies] dispatch = {path=”api/dispatch”} packaging = {path=”api/packaging”} [tool.poetry.group.cronjob.dependencies] refreshcache = {path=”cronjob/refreshcache”} [tool.poetry.group.dev.dependencies] isort = “5.11.5” yapf = “^0.40.1” ruff = “^0.0.275” [tool.isort] line_length = 120 multi_line_output = 5 balanced_wrapping = false 😢

Slide 21

Slide 21

Gitlab CI/CD Migration vers un monorepo Le gitlab-ci.yml

Slide 22

Slide 22

🧪 🎨 👷 - deploy preprod 🏗️ - release 🔖 stages: - test - check - build

  • deploy production 🚀 👷 .build: stage: build extends: - .docker rules: - changes: - ${PROJECT_TYPE}/${PROJECT_NAME}/**/* - k8s/${PROJECT_NAME}/**/* - common/**/* before_script: .jade: variables: PROJECT_NAME: jade PROJECT_REGEX: /^jade/./ PROJECT_TYPE: worker NEED_VARS: “REDIS_RQ MONGODB_JADE_RW API_DISPATCH_URL JO .watchdog: variables: PROJECT_NAME: watchdog PROJECT_REGEX: /^watchdog/./ PROJECT_TYPE: worker NEED_VARS: “REDIS_RQ SLACK_WEBHOOK” 👷 jade : extends: - .build 🧪
  • .jade
  • *bump-version jade : - export VERSION=$(poetry -C ${PROJECT_TYPE}/${PROJECT_N extends: .docker:
  • .test - .jade 🏗️ script: jade : - docker login -u $GITLAB_USER -p $GITLAB_PASSWORD $ACR_ extends: - docker build . —build-arg PROJECT_PATH=${PROJECT_TYPE - docker push “$DOCKER_PATH/${PROJECT_NAME}:$VERSION”
  • .preprod - .deploy - .jade

Slide 23

Slide 23

Slide 24

Slide 24

Difficultés 😭 Bien passé 😁 Fusion des projets Bonne généricité Alignement des versions de lib Fonctionnement ISO multi-repo Montée de version Python 3.8 globale Dé-duplication Mise en place de la CI RAF Revoir la fusion de certains projets Manque les projets de la datascience De la CI Des charts Des dockerfiles Merci les tests Poetry (Imports relatif, Bump2version, Tests …) Repo light (15 Mo) 15 projets déployables facilement

Slide 25

Slide 25

Merci Des questions ?

Slide 26

Slide 26

NOTRE JOB S’ARRÊTE LÀ OÙ COMMENCE LE VÔTRE