TP4 – MLOps avec Argo workflow, gitlab et k8s
Objectifs du TP
Utilisation de gitlab pour builder une pipeline de traitement et faire l’inférence du model sur
Argo.
Outils et Versions
• Kubernetes : v1.25.3
• Gitlab : v15.7.3
• Argo : v3.4.4
Gitlab :
GitLab CI/CD (Continuous Integration / Continuous Deployment) est une fonctionnalité
intégrée de GitLab qui permet aux utilisateurs de définir des pipelines d'intégration et de
déploiement automatisés pour leurs projets. Il vous permet de configurer des workflows de
développement pour automatiser les tâches telles que les tests, la construction, les
déploiements et les livraisons.
GitLab CI/CD se connecte à votre dépôt Git pour détecter les modifications et déclencher des
pipelines en conséquence. Les pipelines peuvent inclure des étapes telles que les tests
unitaires, les tests d'intégration, la construction de l'application, la validation des tests
utilisateurs, la mise en production, etc.
GitLab CI/CD est basé sur des runners qui sont des agents qui exécutent les tâches définies
dans les pipelines. Les runners peuvent être hébergés localement ou sur des services cloud
comme AWS, GCP, Azure,etc.
En utilisant GitLab CI/CD, les développeurs peuvent s'assurer que leur code est fonctionnel
et prêt à être déployé à tout moment, améliorant ainsi la qualité de leur logiciel et
accélérant les cycles de développement.
Argo :
Argo est un projet open-source qui vise à faciliter la gestion des workflows de conteneurs sur
Kubernetes. Il fournit une solution de workflow pour les applications basées sur des
conteneurs, permettant aux utilisateurs de définir et d'exécuter des pipelines d'application
de manière fiable et efficace sur Kubernetes. Argo permet de gérer des workflows multi-
étapes, de gérer les dépendances entre les étapes, de gérer les erreurs et de suivre les
exécutions. Il est conçu pour faciliter la collaboration entre les équipes de développement,
les équipes de DevOps et les équipes de recherche en offrant une interface utilisateur
graphique pour visualiser et gérer les workflows.
Kubernetes (k8s) :
Kubernetes est un système open-source pour la gestion de conteneurs d'applications. Il
permet de déployer, de scaler et de gérer des applications distribuées de manière efficace. Il
s'exécute sur une variété de plateformes, y compris les systèmes de cloud publics, les
centres de données privés et les ordinateurs de bureau. Kubernetes fournit une
infrastructure pour la orchestration des conteneurs, permettant aux développeurs de se
concentrer sur l'écriture de code sans avoir à se soucier de la gestion des machines sur
lesquelles leurs applications s'exécutent.
Installation
Nous allons utiliser tout au long de ce TP, 2 contenaires représentant respectivement une
instance gitlab et une instance k8s.
Vous devez pour cela avoir installé docker sur votre machine, et l'avoir correctement
configuré. Ouvrir la ligne de commande, et taper les instructions suivantes:
1. Télécharger l'image docker uploadée sur dockerhub:
$ docker pull totofunku/mlops-cours:[Link]
$ docker pull totofunku/mlops-cours:[Link]
2. Créer les 2 contenaires à partir des images téléchargées. Pour cela:
2.1. Créer un réseau qui permettra de relier les deux contenaires:
$ docker network create --driver=bridge mlops
2.2. Créer et lancer les 2 contenaires (les instructions -p permettent de faire un
mapping entre les ports de la machine hôte et ceux du contenaire):
$ docker run -itd --net=mlops -p 443:443 -p 80:80 -p 22:22 \
--name gitlab-ci --hostname gitlab-ci \
--volume /tmp/gitlab/config:/etc/gitlab \
--volume /tmp/gitlab/logs:/var/log/gitlab \
--volume /tmp/gitlab/data:/var/opt/gitlab \
totofunku/mlops-cours:[Link]
$ docker run -itd --privileged -p 8080:8080 -p 2746:2746 --net= mlops \
-e DOCKER_TLS_CERTDIR=/certs \
-v some-docker-certs-ca:/certs/ca \
-v some-docker-certs-client:/certs/client \
--name k8s-argo --hostname k8s-argo \
totofunku/mlops-cours:[Link]
Lancer vos machines grâce aux commandes suivantes:
$ docker start k8s-argo gitlab-ci
Puis entrer dans le contenaire k8s-argo :
$ docker exec -it k8s-argo sh
Lancer ensuite les démons minikube dans le but de simuler un cluster k8s :
$ root@k8s-argo:~# minikube start --force
Vous pourrez vérifier que minikube est lancé en tapant la commande:
$ root@k8s-argo:~# minikube kubectl -- get pods -A
Nous allons installer argo sur k8s. Nous allons d’abord créer un namespace dédié avec la
commande :
$ root@k8s-argo:~# kubectl create ns argo
Puis installer Argo :
$ root@k8s-argo:~# kubectl apply -n argo -f [Link]
o-workflows/releases/download/v3.4.4/[Link]
$ root@k8s-argo:~# kubectl patch deployment \
argo-server \
--namespace argo \
--type='json' \
-p='[{"op": "replace", "path": "/spec/template/spec/
containers/0/args", "value": [
"server",
"--auth-mode=server"
]}]'
Puis démarrer Argo :
$ root@k8s-argo:~# kubectl -n argo port-forward --address='[Link]' deploym
ent/argo-server 2746:2746
Vous pouvez désormais accéder à l’interphace d’argo sur le port 2746 de votre localhost.
Nous allons maintenant installer un contenaire registry sur l’instance k8s-argo.
$ root@k8s-argo:~# minikube ssh
$ docker@minikube:~$ docker run --restart=always -d -p 5000:5000 --name reg
istry registry:2
Vous pouvez vérifier que le registry est disponible en lançant la commande suivante :
$ root@k8s-argo:~# curl [Link]:5000/v2/_catalog
{"repositories":[]}
Nous allons maintenant démarrer un runner gitlab sur notre instance [Link] devez vous
connecter sur l’interphace gitlab sur le port 80 de votre localhost. Avec le login : root et le
mp : 5iveL!fe
Allez ensuite sur l’interphase d’admin pour ajouter un runner.
Allez ensuite sur l’onglet runner puis cliquer en haut à gauche sur « Register an instance
runner »
Récupérez le token et lancer la commande suivante sur l’instance k8s-argo
$ root@k8s-argo:~# gitlab-runner register --url [Link] --registr
ation-token <your_token>
Remplissez les informations demandées. Vous pouvez vérifier la configuration du runner
dans le fichier de config suivant.
$ root@k8s-argo:~# vi /etc/gitlab-runner/[Link]
concurrent = 1
check_interval = 0
shutdown_timeout = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "k8s-argo-test"
url = "[Link]
id = 1
token = "ycRJ9KjoDs-6vbc-zH4W"
token_obtained_at = 2023-01-17T[Link]Z
token_expires_at = 0001-01-01T[Link]Z
executor = "docker"
[runners.custom_build_dir]
[[Link]]
MaxUploadedArchiveSize = 0
[[Link].s3]
[[Link]]
[[Link]]
[[Link]]
tls_verify = false
image = "docker:stable"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/var/run/[Link]:/var/run/[Link]", "/cache"]
network_mode = "host"
shm_size = 0
Vous pouvez modifier la config du runner sur gitlab, pour pouvoir l’utiliser sans tag.
L’installation des composants est terminée.
Objectif du TP.
Le but du TP est de mettre en pratique ce que nous avons vu en cours. Vous allez donc
importer sur gitlab un projet data science sur lequel vous avez déjà travaillé ou un projet
disponible sur le web. Nous allons ensuite déployer cette application sur notre instance k8s
avec la CI/CD de gitlab dans le contenaire registry. Puis vous devrez déployer votre pipeline
sur Argo notre orchestrateur. Pour aller plus loin, vous pourrez installer DVC pour versionner
vos données d’entrainement et vos modèles. Il sera également intéressant de mettre en
place un system de monitoring des modèles et des données. Puis prévoir un système
d’amélioration continue.
Annexes :
Voici un exemple de fichier .[Link]
# This file is a template, and might need editing before it works on your p
roject.
# To contribute improvements to CI/CD templates, please follow the Developm
ent guide at:
# [Link]
# This specific template is located at:
# [Link]
s/[Link]
# Official language image. Look for the different tagged releases at:
# [Link]
image: docker:19-dind
# Change pip's cache directory to be inside the project directory since we
can
# only cache local items.
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
# Pip's cache doesn't store the python packages
# [Link]
#
# If you want to also cache the installed packages, you have to install
# them in a virtualenv and cache it as well.
cache:
paths:
- .cache/pip
- venv/
build image:
image: docker:19-dind
services:
- docker:19-dind
script:
- docker build -t [Link]:32770/testdockerbuild:latest .
- docker push [Link]:32770/testdockerbuild:latest
Voici un exemple de Dockerfile :
FROM python:3.10
RUN pip install pytest
COPY [Link] [Link]
RUN echo test
Voici un exemple de workflow argo :
spec:
templates:
- name: workflow
inputs: {}
outputs: {}
metadata: {}
dag:
tasks:
- name: iad-enhance
template: iad-enhance
arguments: {}
- name: iad-rescue
template: iad-rescue
arguments: {}
dependencies:
- iad-enhance
when: '{{[Link]}} == blurry_photo'
- name: iad-enhance
inputs: {}
outputs:
parameters:
- name: result
valueFrom:
path: /tmp/[Link]
default: 'false'
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: group
operator: In
values:
- gpu12xlarge
metadata: {}
container:
name: ''
image: >-
[Link]:32770/testdockerbuild:latest
command:
- python
- '-m'
- [Link]-workflow
- '--podname'
- '{{[Link]}}'
- '--msgatt'
- '{{[Link].message_attributes}}'
- '--token'
- '{{[Link]}}'
- '--s3env'
- production
- '--env'
- prd
- '--jobthread'
- '1'
- '--methods'
- '["qa", "sky_replacement"]'
env:
- name: s3_folder
value: enhance
resources:
limits:
cpu: '10'
memory: 64Gi
[Link]/gpu: '0'
requests:
cpu: '10'
memory: 64Gi
[Link]/gpu: '0'
imagePullPolicy: Always
- name: iad-rescue
inputs: {}
outputs: {}
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: group
operator: In
values:
- gpu12xlarge
metadata: {}
container:
name: ''
image: >-
[Link]:32770/testdockerbuild:latest
command:
- python
- '-m'
- [Link]-workflow
- '--podname'
- '{{[Link]}}'
- '--msgatt'
- '{{[Link].message_attributes}}'
- '--token'
- '{{[Link]}}'
- '--s3env'
- production
- '--env'
- prd
- '--jobthread'
- '0'
- '--methods'
- '["deblur"]'
resources:
limits:
cpu: '5'
memory: 8Gi
[Link]/gpu: '1'
requests:
cpu: '5'
memory: 8Gi
[Link]/gpu: '1'
entrypoint: workflow
arguments:
parameters:
- name: body
value: ''