Installation de la plateforme
Les commandes suivantes ont été lancées sur une distribution Debian 9.4 "stretch". Elles fonctionnent également sur une version 10 de debian.
Attention, le dépôt a été renommé en Esup-Pod, la récupération se fait donc maintenant via cette url : https://github.com/EsupPortail/Esup-Pod.git
Sommaire maxLevel 3
Pré-requis
Environnement
Creation de l'utilisateur Pod
user@pod:~$ sudo adduser pod
user@pod:~$ adduser pod sudo
user@pod:~$ su pod
Création de l'environnement virtuel
pod@pod:~$ sudo python3 -V
pod@pod:~$ sudo python -V
pod@pod:~$ sudo apt-get install -y python3-pip
pod@pod:~$ pip3 search virtualenvwrapper
pod@pod:~$ sudo pip3 install virtualenvwrapper
...
il est possible, depuis la v3.4 de python de faire autrement pour créer l'env virtuel, voir cette documentation : https://linuxconfig.org/how-to-set-up-a-python-virtual-environment-on-debian-10-buster
Récupération des sources
Concernant l'emplacement du projet, je conseille de le mettre dans /usr/local/django_projects
...
(django_pod) pod@pod:~/django_projects$ git clone https://github.com/EsupPortail/Esup-Pod.git podv2
Clonage dans 'podv2'...
remote: Counting objects: 4578, done.
remote: Compressing objects: 100% (378/378), done.
remote: Total 4578 (delta 460), reused 564 (delta 348), pack-reused 3847
Réception d'objets: 100% (4578/4578), 4.40 MiB | 3.88 MiB/s, fait.
Résolution des deltas: 100% (3076/3076), fait.
(django_pod) pod@pod:~/django_projects$ cd podv2/
Applications tierces
Installation de toutes les librairies python :
Il faut vérifier que l'on se trouve bien dans l'environnement virtuel (présence de "(django_pod)" au début l'invite de commande. Sinon, il faut lancer la commande $> workon django_pod
...
(django_pod) pod@pod:~/django_projects/podv2$ pip3 install --proxy="PROXY:PORT" -r requirements.txt
FFMPEG
Pour l'encodage des vidéos et la creation des vignettes, il faut installer ffmpeg, ffmpegthumbnailer et imagemagick (ne pas installer sur le serveur frontal si vous déportez l'encodage)
(django_pod) pod@pod:~/django_projects/podv2$ sudo apt-get install ffmpeg
(django_pod) pod@pod:~/django_projects/podv2$ sudo apt-get install ffmpegthumbnailer
(django_pod) pod@pod:~/django_projects/podv2$ sudo apt-get install imagemagick
Elasticsearch
Installation de Java
Pour utiliser Elasticsearch, il faut avoir java8 sur sa machine.
...
(django_pod) pod@pod:~/django_projects/podv2$ cd /usr/share/elasticsearch/
(django_pod) pod@pod:/usr/share/elasticsearch$ sudo bin/elasticsearch-plugin install analysis-icu
-> Downloading analysis-icu from elastic
[=================================================] 100%
-> Installed analysis-icu
(django_pod) pod@pod:/usr/share/elasticsearch$ sudo /etc/init.d/elasticsearch restart
[ ok ] Restarting elasticsearch (via systemctl): elasticsearch.service.
Creation de l'index Pod
Nous pouvons enfin vérifier le bon fonctionnement de l'ensemble (l'erreur affichée lors de la deletion est normal puisque l'indice n'existe pas mais nous devons supprimer avant de créer un index dans ES):
...
Python console ES_URL = ['http://elastic.domaine.fr:9200/']
Mise en route
Base de données SQLite intégrée
Lancer le script présent à la racine afin de créer les fichiers de migration, puis de les lancer afin de créer la base de données SQLite intégrée```console
- Pour Pod < 3.0 :
Bloc de code | ||
---|---|---|
| ||
console (django_pod) pod@Pod:~/django_projects/podv2$ sh create_data_base.sh |
- Pour Pod >= 3.0
Bloc de code | ||
---|---|---|
| ||
console (django_pod) pod@Pod:~/django_projects/podv2$ make createDB |
Fichier de configuration settings_local.py
Vous devez créer un fichier de configuration local dans le dossier pod/custom.
...
Configuration de la plateforme
(option) Base de donnée MySQL/MariaDB
Vous pouvez utiliser une base de donnée MySQL/MariaDB sur le serveur frontal (ou sur un serveur distant) il faut installer le moteur MySql/Python :
...
Attention : il faut créer la Base en spécifiant CHARACTER SET
CREATE DATABASE pod CHARACTER SET utf8;
sinon une erreur de type "Specified key was too long; max key length is" apparaitra
Il faut ensuite relancer le script présent à la racine afin de créer les fichiers de migration, puis de les lancer afin de créer la base de données :
```console
(django_pod) pod@Pod:~/django_projects/podv2$ sh create_data_base.sh
SuperUtilisateur
Il faut créer un premier utilisateur qui aura tous les pouvoirs sur votre instance.
(django_pod) pod@Pod:~/django_projects/podv2$ python manage.py createsuperuser
Tests
Enfin afin de vérifier que votre instance est opérationnelle, il faut lancer les tests unitaires :
(django_pod) pod@Pod:~/django_projects/podv2$ python manage.py test --settings=pod.main.test_settings
Serveur de développement
Le serveur de développement permet de tester vos futurs modifications facilement.
...
--> exemple : (django_pod) pod@pod:~/django_projects/podv2$ python manage.py runserver pod.univ.fr:8080
- Attention -
...
Quand le site est lancé, il faut se rendre dans la partie administration puis dans site pour renseigner le nom de domaine de votre instance de Pod (par défaut 'example.com').
Avant la mise en production, il faut vérifier le fonctionnement de la plateforme dont l'ajout d'une vidéo, son encodage et sa suppression.
Attention, pour ajouter une vidéo, il doit y avoir au moins un type de vidéo disponible. Si vous avez correctement peuplé votre base de données avec le fichier initial_data.json vous devez au moins avoir other/autres.
il faut vérifier l'authentification CAS, le moteur de recherche etc.
...
Mise en production
Toute la personnalisation et la configuration de votre instance de Pod peut se faire dans le répertoire pod/custom. Par exemple, pour votre configuration, il faut créer et renseigner le fichier settings_local.py :
...
La liste des paramètre ses trouve dans docs/configuration.md
Frontal Web NGINX / UWSGI et fichiers statiques
Pour plus de renseignement, d'explication que la documentation ci-dessous, voici le tutoriel que j'ai suivi pour mettre en place cette solution : doc{:target="_blank"}
...
(django_pod) pod@pod:~$ python manage.py collectstatic
Optionnel : Serveur FTP (enregistreur)
Lors de l'installation de Pod à l'unviersité de Lille, les fichiers vidéos sont stockés sur une partition montée sur "/data". Pour cela, le répertoire "media", qui contient les fichiers "utilisateurs" est créé sur "/data/media" en paramétrant la variable MEDIA_ROOT dans le fichier de configuration. De ce fait, pour des raisons de cohérence, le répertoire du serveur FTP est placé dans "/data/ftp-pod". Au niveau du logiciel, nous proposons d'utiliser vsftpd.
...
(django_pod) pod@pod:/data$ sudo /etc/init.d/vsftpd restart
Déporter l'encodage sur un autre serveur
Pré-requis :
- Il faut que votre répertoire ~/django_projects/podv2/pod/media soit partagé entre vos serveurs (montage NFS par exemple)
- Il faut utiliser une BD Mysql/MariaDB pour qu'elle soit partageable entre les serveurs Pod frontaux et encodages
Installation sur le frontal :
Il ne faut pas avoir installé ffmpeg, ffmpegthumbnailer et imagemagick. Si c'est le cas, les déinstaller :
...
Bloc de code | ||
---|---|---|
| ||
# Configuration Celery sur le frontal CELERY_TO_ENCODE = True # Active encode CELERY_BROKER_URL = "amqp://pod:mdp@localhost/rabbitpod" # Define a broker |
Installation sur le serveur d'encodage :
Il faut installer pod sans réinitialiser la base et sans nginx/uwsgi
Création du user pod
Bloc de code | ||
---|---|---|
| ||
root@pod:~$ adduser pod root@pod:~$ adduser pod sudo root@pod:~$ su - pod |
Créer le virtualenv
Bloc de code | ||
---|---|---|
| ||
pod@pod:~$ sudo python3 -V pod@pod:~$ sudo python -V pod@pod:~$ sudo apt-get install -y python3-pip pod@pod:~$ pip3 search virtualenvwrapper pod@pod:~$ sudo pip3 install virtualenvwrapper |
...
Bloc de code | ||
---|---|---|
| ||
pod@pod:~$ mkvirtualenv --system-site-packages --python=/usr/bin/python3 django_pod |
Récupérer les sources
Bloc de code | ||
---|---|---|
| ||
(django_pod)pod@pod:~$ sudo mkdir /usr/local/django_projects |
...
Bloc de code | ||
---|---|---|
| ||
(django_pod) pod@pod:~/django_projects$ git clone https://github.com/esupportail/podv2.git Clonage dans 'podv2'... remote: Counting objects: 4578, done. remote: Compressing objects: 100% (378/378), done. remote: Total 4578 (delta 460), reused 564 (delta 348), pack-reused 3847 Réception d'objets: 100% (4578/4578), 4.40 MiB | 3.88 MiB/s, fait. Résolution des deltas: 100% (3076/3076), fait. (django_pod) pod@pod:~/django_projects$ cd podv2/ |
Installation des pré-requis
Il faut vérifier que l'on se trouve bien dans l'environnement virtuel (présence de "(django_pod)" au début l'invite de commande. Sinon, il faut lancer la commande $> workon django_pod
...
$> pip install --proxy="PROXY:PORT" -r requirements.txt
Installation des librairies MySQL
(django_pod) pod@pod:/usr/local/django_projects/podv2$ sudo apt-get install python3-dev
(django_pod) pod@pod:/usr/local/django_projects/podv2$ sudo apt-get install default-libmysqlclient-dev
(django_pod) pod@pod:/usr/local/django_projects/podv2$ pip3 install mysqlclient==2.0.3
Installation des librairies d'encodage
(django_pod) pod@pod:~/django_projects/podv2$ sudo apt-get install ffmpeg ffmpegthumbnailer imagemagick
Rajouter la configuration de tout ça dans le fichier de configuration
(django_pod) pod@pod:/usr/local/django_projects/podv2$ vim pod/custom/settings_local.py
Bloc de code | ||
---|---|---|
| ||
CELERY_TO_ENCODE = True # Active encode
CELERY_BROKER_URL = "amqp://pod:mdp@ip.serveur.frontal/rabbitpod" # Definit le message broker.
CELERY_TASK_ACKS_LATE=True # permet de ne traiter que une tache à la fois
TIME_ZONE = 'Europe/Paris'
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'database_name', 'USER': 'user_anme', 'PASSWORD': 'password', 'HOST': 'mysql_host_ip', 'PORT': '3306', 'OPTIONS': { 'init_command': "SET storage_engine=INNODB, sql_mode='STRICT_TRANS_TABLES', innodb_strict_mode=1", }, } }
ES_URL = ['http://elastic.domaine.fr:9200/']
EMAIL_HOST = 'smtp.domaine.fr'
EMAIL_PORT = 25
DEFAULT_FROM_EMAIL = 'noreply@pod.domaine.fr'
SERVER_EMAIL = 'noreply@pod.domaine.fr'
ADMINS = ( ('Bob', 'bob@domaine.fr'), )
LANGUAGES = (
('fr', 'Français'),
('en', 'English')
)
MODELTRANSLATION_FALLBACK_LANGUAGES = ('fr', 'en')
USE_PODFILE = True |
Activer Celery sur le serveur d'encodage
Mettre le contenu de https://raw.githubusercontent.com/celery/celery/4.3/extra/generic-init.d/celeryd dans /etc/init.d/celeryd
...
Bloc de code | ||
---|---|---|
| ||
celery -A pod.main worker -l info |
Installation de Shibboleth SP pour l'authentification Shibboleth
Vous pouvez suivre le tutoriel suivant pour installer un SP Shibboleth sur une distribution Debian : https://tuakiri.ac.nz/confluence/display/Tuakiri/Install+Shibboleth+SP+on+Debian+Based+linux
Mise en place de l'encodage distant
- Générer une paire de clés pour l'utilisateur pod sur le serveur podv2
- Copier la clé publique sur le serveur d'encodage distant dans le fichier .ssh/authorized_key (hpc)
- L'utilisateur hpc doit aussi pouvoir se connecter via ssh sur le serveur podv2. Generer sa paire de clés puis copier sa clé public dans le fichier authorized_key du serveur podv2.
- Ouvrir les firewall de maniere à ce que les serveurs puissent communiquer.
- Configurer l'encodage distant via les settings de podv2:
ENCODE_VIDEO = "start_remote_encode" """ # pourl'encodage distant, il faut préciser le login, l'host et la clé pour appeler cet encodage # REMOTE ENCODING SETTINGS """ SSH_REMOTE_USER = "poduser" SSH_REMOTE_HOST = "encode-gpu.univ.fr" SSH_REMOTE_KEY = "/home/poduser/.ssh/id_rsa" SSH_REMOTE_CMD = "./script.sh"
- Redemarrez nginx et uwsgi-pod afin que la modif soit prise en compte.
- Copier le fichier encode_gpu.py present dans podv2 (/home/pod/django_projects/pod/video) sur le serveur hpc (donnez les droits d'execution) sur le serveur d'encodage distant.
- Copier le fichier script.sh sur le serveur d'encodage distant. C'est ce script qui va créer le job d'encodage
# Video encoding automation # # Cyrille TOULET <cyrille.toulet@univ-lille.fr> # Nicolas Can <nicolas.can@univ-lille.fr> # Define variables GPU_TYPE="RTX2080" BASE_DIR="/home/poduser/encoding" WORK_DIR="/tmp" HOME_DIR="/home/poduser" REMOTE_SERVER="pod@pod.univ.fr" REMOTE_MEDIA_PATH="/usr/local/django_projects/podv2/pod/media" POD_REMOTE_HOST="pod.univ.fr" JOB_NAME="undefined-job" INPUT_FILE="default-input.mp4" DEBUG=False while getopts n:i:v:u:d: option do case "${option}" in n) JOB_NAME=${OPTARG};; i) INPUT_FILE=${OPTARG};; v) VIDEO_ID=${OPTARG};; u) USER_ID=${OPTARG};; d) DEBUG=${OPTARG};; esac done # Step 1: Create encoding directory mkdir -p ${BASE_DIR}/${JOB_NAME} # Step 2: Generate batch file cp $(dirname $(readlink -f $0))/encode.template ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{GPU_TYPE}|${GPU_TYPE}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{BASE_DIR}|${BASE_DIR}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{WORK_DIR}|${WORK_DIR}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{JOB_NAME}|${JOB_NAME}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{REMOTE_SERVER}|${REMOTE_SERVER}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{REMOTE_MEDIA_PATH}|${REMOTE_MEDIA_PATH}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{INPUT_FILE}|${INPUT_FILE}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{VIDEO_ID}|${VIDEO_ID}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{USER_ID}|${USER_ID}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{POD_REMOTE_HOST}|${POD_REMOTE_HOST}|g" ${BASE_DIR}/${JOB_NAME}/encode.job sed -i "s|{DEBUG}|${DEBUG}|g" ${BASE_DIR}/${JOB_NAME}/encode.job # Step 2: Submit slurm job cd ${HOME_DIR}/slurm-encoding-out sbatch ${BASE_DIR}/${JOB_NAME}/encode.job
- Adapter les parametres suivants (exemple de paramétrages) :
# Define variables
GPU_TYPE="GTX1080" #Le type de carte graphique utilisée
BASE_DIR="/b/home/di/podtest" #dossier racine d'encodage
WORK_DIR="/b/home/di/podtest/tmp" #dossier temporaire de travail
HOME_DIR="/b/home/di/podtest" #dossier racine
REMOTE_SERVER="pod@podv272-test.di.unistra.fr" #connexion ssh au serveur podv2
REMOTE_MEDIA_PATH="/data/www/pod/media" #dossier media sur podv2
POD_REMOTE_HOST="podv272-test.di.unistra.fr" #url podv2
JOB_NAME="undefined-job" #valeur par defaut car au lancement du job un nom sera attribué
INPUT_FILE="default-input.mp4" #valeur par defaut car au lancement du job un nom sera attribué
DEBUG=True Copier le fichier encode.template sur le serveur d'encodage distant. Dans le même répertoire de base de script.sh qui va le transformer en encode.job (avec des sed) puis ce job va etre mis en attente
#!/bin/bash #SBATCH --nodes=1 #SBATCH --ntasks-per-node=12 #SBATCH --time=01:00:00 #SBATCH --job-name={JOB_NAME} #SBATCH --mem=16G #SBATCH --gres=gpu:{GPU_TYPE}:1 # Encoding job for POD platform # Cyrille TOULET <cyrille.toulet@univ-lille.fr> # Nicolas CAN <nicolas.can@univ-lille.fr> # Print job info echo "Job running at" $(date)" with following specs:" echo -e " - Job name: ${SLURM_JOB_NAME}" echo -e " - Job ID: ${SLURM_JOB_ID}" echo " - Allocated nodes: ${SLURM_JOB_NODELIST}" echo " - Allocated CPU cores: ${SLURM_NTASKS}" echo -e " - Allocated GPU: /dev/nvidia${CUDA_VISIBLE_DEVICES}\n" mkdir -p {WORK_DIR}/{JOB_NAME} # Step 1: Download input file echo "$> scp {REMOTE_SERVER}:{REMOTE_MEDIA_PATH}/videos/{USER_ID}/{INPUT_FILE} {WORK_DIR}/{JOB_NAME}/" scp {REMOTE_SERVER}:{REMOTE_MEDIA_PATH}/videos/{USER_ID}/{INPUT_FILE} {WORK_DIR}/{JOB_NAME}/ # Step 2: Encode video module load ffmpeg/4.2.3 nvidia/cuda/10.0/compilers module load anaconda3/2020.02 echo "$> python3 /home/nicolas.can/pod-encoding/encode_gpu.py --device ${CUDA_VISIBLE_DEVICES} --dir {WORK_DIR}/{JOB_NAME} --input {INPUT_FILE} --job ${SLURM_JOB_ID} --name {JOB_NAME}" python3 /home/nicolas.can/pod-encoding/encode_gpu.py --device ${CUDA_VISIBLE_DEVICES} --dir {WORK_DIR}/{JOB_NAME} --input {INPUT_FILE} --job ${SLURM_JOB_ID} --name {JOB_NAME} --debug {DEBUG} module purge # Step 3: Upload output files scp -r {WORK_DIR}/{JOB_NAME}/{VIDEO_ID} {REMOTE_SERVER}:{REMOTE_MEDIA_PATH}/videos/{USER_ID} # Step 4: Clear video files SIZE=$(du -sh {BASE_DIR}/{JOB_NAME}) rm -rf {BASE_DIR}/{JOB_NAME} echo "End of encoding job. Release ${SIZE} for job {JOB_NAME}" SIZE=$(du -sh {WORK_DIR}/{JOB_NAME}) rm -rf {WORK_DIR}/{JOB_NAME} echo "End of encoding job. Release ${SIZE} for job {JOB_NAME}" # Step 5: Call a custom API to report the end of encoding echo "ssh call import_encoded_video {VIDEO_ID}" echo "$> ssh {REMOTE_SERVER} \"cd /home/pod/django_projects/podv2 && /home/pod/.virtualenvs/django_pod/bin/python manage.py import_encoded_video {VIDEO_ID}\"" ssh {REMOTE_SERVER} "cd /home/pod/django_projects/podv2 && /home/pod/.virtualenvs/django_pod/bin/python manage.py import_encoded_video {VIDEO_ID}"
- Adaptez les parametres SBATCH à votre infrastructure slurm dans ce fichier
#SBATCH -p pod # utiliser la file hpc standard
#BATCH -N 1-1 # nombre de noeuds min-max
#SBATCH -t 24:00:00 # temps estimé utilisépar le scheduler slurm
#SBATCH --gres=gpu:4 # on exige 1 GPU
#SBATCH --exclusive Adaptez l'etape 2 en fonction des modules disponibles sur votre infrastructure hpc et du chemin du fichier encode_gpu.py
# Step 2: Encode video
module load ffmpeg/ffmpeg
module load python/python-3.6.2.i17echo "$> python3 /b/home/di/podtest/encode_gpu.py --device ${CUDA_VISIBLE_DEVICES} --dir {WORK_DIR}/{JOB_NAME} --input {INPUT_FILE} --job ${SLURM_JOB_ID} --name {JOB_NAME}"
python3 /b/home/di/podtest/encode_gpu.py --device ${CUDA_VISIBLE_DEVICES} --dir {WORK_DIR}/{JOB_NAME} --input {INPUT_FILE} --job ${SLURM_JOB_ID} --name {JOB_NAME} --debug {DEBUG}
module purge- Adaptez également les chemins de votre application podv2 pour l'étape 5
# Step 5: Call a custom API to report the end of encoding
echo "ssh call import_encoded_video {VIDEO_ID}"
echo "$> ssh {REMOTE_SERVER} \"cd /home/pod/django_projects && /data/www/pod/.virtualenvs/django_pod/bin/python manage.py import_encoded_video {VIDEO_ID}\""
ssh {REMOTE_SERVER} "cd /home/pod/django_projects && /data/www/pod/.virtualenvs/django_pod/bin/python manage.py import_encoded_video {VIDEO_ID}" Créer le répertoire d'encodage temporaire
${HOME_DIR}/tmp
- Créer le répertoire
${HOME_DIR}/slurm-encoding-out qui contiendra les logs d'encodage des jobs.
- Tester en lancant un encodage depuis votre serveur podv2.
...