[TECH] Versioning d'un jeu vidéo avec GIT LFS

Le 08/12/2020

Le besoin initial

Comme dans le développement de tout logiciel, la mise en place du versioning est indispensable pour les jeux vidéo. Git est le système de contrôle de version le plus flexible et le plus populaire, c’est pourquoi nous souhaitons l’utiliser. En revanche, Git n’est pas encore parfait pour le développement de jeux. En effet, comme il est basé en local, il peut y avoir des conflits sur des fichiers qui ne peuvent pas être fusionnés, il est donc nécessaire d’avoir une organisation solide, mais c’est un autre sujet.

Pourquoi Git LFS ?

Le problème que nous voudrions aborder aujourd’hui est la taille du dépôt. La taille maximale recommandée pour les dépôts Git est de 1 Go. Les plateformes Git publiques bloquent même les dépôts de plus de 3 Go. En pratique, les sources de jeux vidéo contiennent des média artistiques de grande taille, du coup la limite est rapidement atteinte.

C’est là qu’entre Git LFS (Large File Storage), une extension Git open-source qui permet de faire des pointeurs dans votre dépôt qui référencent les gros fichiers qui sont hébergés ailleurs. Cela réduit considérablement la taille du dépôt.

Construire une solution à long terme

Les plateformes Git (Github, Bitbucket) offrent 1 Go de Git Lfs gratuitement, ce qui ne sera pas suffisant. Nous devons donc héberger les fichiers LFS nous-mêmes. Cela pourrait être fait sur un serveur local, mais le cloud n’est pas trop cher aujourd’hui et permet d’éviter de se poser les questions d’espace et de sauvegarde. J’ai trouvé un guide réalisé par Allan Edwardes pour héberger les fichiers GIT LFS sur Amazon Web Service S3. J’ai adapté sa solution pour héberger les fichiers sur OVH Object Storage à la place (un fournisseur français en qui j’ai plus confiance).

Il s’agit d’une application en Dotnet Core que vous pouvez trouver ici : https://github.com/MineoGames/Estranged.Lfs.

Le fonctionnement

Le dépôt git est configuré pour envoyer des fichiers LFS au SERVEUR GIT LFS qui gère la logique et envoie ensuite les données sur OVH Object Storage.

lfs add lfs push

Le serveur lfs peut être une application sur votre PC/un serveur ou il peut être serverless avec AWS Lambda.

Ce guide vous montrera comment construire la stack. Bien sûr, à la fin, les développeurs auront simplement à cloner le repo et push normalement : ce sera transparent pour eux !

Mettre en place la stack

AWS CLI

Avant d’utiliser une stack complexe, commencez par effectuer des opérations simples avec OVH et Amazon via le client API. OVH est compatible avec S3, ce qui simplifie le processus. Cela incluera la création de comptes et l’obtention des credentials, etc.

Suivez ce guide sans oublier de faire les prérequis. Attention, si vous utilisez AWS CLI V2, il est nécessaire de faire le workaround décrit ici afin que le plugin awscli_plugin_endpoint fonctionne. Assurez-vous que vous pouvez utiliser le client API à la fois pour AWS et OVH en utilisant des profils. Vos fichiers .aws devraient ressembler à ceci :

.aws/config

Config file

.aws/credentials

Credential file

Preparer le projet

Lorsque vous êtes sûr de pouvoir travailler à la fois avec OVH et AWS avec le CLI, vous pouvez constituer la stack.

  1. Créer un Object Storage in OVH

    Étant donné que les objets dans l’Object Storage ne sont pas facilement reconnaissables et ne sont pas automatiquement supprimés lorsqu’un dépôt git est supprimé, il est préférable d’avoir un Object Storage par projet.

    OVH Bucket

  2. Créer un nouveau dépôt privé sur bitbucket ou github

    Git LFS ne fonctionne que pour les nouveaux fichiers poussés, il est donc préférable de commencer à l’utiliser dans un nouveau projet.

    Repo bitbucket

  3. Cloner le dépôt du jeu sur votre PC
  4. Initialiser Git LFS dans le dépôt avec SourceTree par exemple (Dépôt > GIT LFS > Initialiser dépôt)
  5. Vous devez indiquer à Git les fichiers à traiter comme des binaires et à uploader dans LFS en modifiant le fichier .gitattributes à la racine du projet
     *.uasset filter=lfs diff=lfs merge=lfs -text
     *.umap filter=lfs diff=lfs merge=lfs -text
     *.bmp filter=lfs diff=lfs merge=lfs -text
     *.tga filter=lfs diff=lfs merge=lfs -text
     *.png filter=lfs diff=lfs merge=lfs -text
     *.jpg filter=lfs diff=lfs merge=lfs -text
     *.jpeg filter=lfs diff=lfs merge=lfs -text
     *.icns filter=lfs diff=lfs merge=lfs -text
     *.ico filter=lfs diff=lfs merge=lfs -text
     *.dll filter=lfs diff=lfs merge=lfs -text
     *.pdb filter=lfs diff=lfs merge=lfs -text
     *.psd filter=lfs diff=lfs merge=lfs -text
     *.pdn filter=lfs diff=lfs merge=lfs -text
     *.wav filter=lfs diff=lfs merge=lfs -text
     *.mp3 filter=lfs diff=lfs merge=lfs -text
     *.fbx filter=lfs diff=lfs merge=lfs -text
    

    Commiter et push ce fichier.

Vous devez maintenant choisir si vous voulez héberger le serveur sur votre PC/un serveur ou si vous voulez utiliser un AWS Lambda pour être serverless. La première option est moins chère mais doit être déployée sur tous les PC de développement. La seconde option ne nécessite qu’un seul déploiement (moins d’efforts) et est relativement bon marché (paiement à l’utilisation).

Serveur Git Lfs local

Pour accomplir cela, il faut utiliser la version AspNet de la solution : hosting\Estranged.Lfs.Hosting.AspNet.

  1. Modifier la ligne suivante du fichier Startup.cs afin de correspondre à votre environnement (en utilisant aws_access_key_id et aws_secret_access_key du profile ovh du fichier .aws/credential)

    services.AddLfsS3Adapter(new S3BlobAdapterConfig{Bucket = "objectContainerName"}, new AmazonS3Client("MyAccesKeyAWS", "MyAccesSecretAWS", new AmazonS3Config { ServiceURL = "https://s3.MyPublicRegionLowerCase.cloud.ovh.net" }));

    Modifier la ligne suivante du fichier Startup.cs pour restreindre l’accès au serveur GIT LFS services.AddSingleton<IAuthenticator>(x => new DictionaryAuthenticator(new Dictionary<string, string> { { "userAskedBySourceTree", "passwordAskedBySourceTree" } }));

  2. L’application peut être lancée dans VS en choisissant Estranged.Lfs.Hosting.AspNet (l’option par défaut IIS Express ne fonctionne pas)

    Start aspnet

  3. L’application peut également être publiée dans un répertoire, et démarrée via Estranged.Lfs.Hosting.AspNet.exe
  4. Il s’agit d’une application console qui écoute des requêtes LFS HTTP sur https://localhost:5001

    console app

  5. A la racine de votre projet de jeu, créer le fichier .lfsconfig pour envoyer des requêtes à l’application console
     [lfs]
     url = https://localhost:5001/
    

    Commiter et push ce fichier.

  6. Vous pouvez maintenant push des fichiers binaires, entrez le user/mot de passe définis précédemment lorque cela est demandé

  7. Le fichier poussé est maintenant présent et visible dans OVH Object Storage

    image

Serverless avec AWS Lambda

Pour accomplir cela, il faut utiliser la version Lambda de la solution : hosting\Estranged.Lfs.Hosting.Lambda.

  1. Cloner https://github.com/MineoGames/Estranged.Lfs sur votre PC
  2. Modifier Estranged.Lfs\hosting\Estranged.Lfs.Hosting.Lambda\aws-lambda-tools-defaults.json pour éditer les variables suivantes :

    Variable Définition Exemple
    LFS_USERNAME Utilisateur pour accéder au programme LfsUser
    LFS_PASSWORD Mot de passe pour accéder au programme (éviter les caractères spéciaux) Tezfz5615xqezef
    S3_ACCESS_KEY Access key pour OVH dans le profil ovh du fichier .aws/credentials istnkvsbetqxnypsipwx
    S3_ACCESS_SECRET Secret key pour OVH dans le profil ovh du fichier .aws/credentials istnkvsbetqxnypsipwx
    S3_REGION Région publique de cloud du OVH Object Storage sbg
    BITBUCKET_WORKSPACE Workspace Bitbucket du dépôt du jeu (Laisser vide)
    BITBUCKET_REPOSITORY Nom du dépôt Bitbucket du jeu (Laisser vide)
    AWS_STACK_NAME Nom de la stack Cloudformation LfsProject
    AWS_SHARED_BETWEEN_STACK_S3_NAME Nom du bucket S3 qui va héberger le build de code et le template de stack uploadés shared-lambda


  3. Ouvrir la console de développeur et aller dans hosting/Lambda

    Dev console access Dev console

  4. Éxécuter la commande suivante pour créer la stack CloudFormation, en choisissant les mêmes credentials que défini précédemment

    dotnet lambda deploy-serverless StackName --template-parameters GitLfsUsername=LfsUser;GitLfsPassword=Tezfz5615xqezef -t modele.yaml

    Create Cloudformation stack

  5. Éxécuter la commande suivante pour uploader le code dans la Lambda Function AWS

    dotnet lambda deploy-function

    Create Cloudformation stack

  6. Créer le fichier .lfsconfig à la racine du projet de jeu et le connecter à la lambda function (le endpoint a été affiché en 4. ) :
     [lfs]
     url = https://9w45qpo957.execute-api.eu-west-1.amazonaws.com/lfs
    

    Commiter et push ce fichier.

  7. C’est terminé. Commiter et push des fichiers binaires : ils seront visibles dans OVH et dans bitbucket sans prendre de place.

    push ok

    files pushed seen in server Size not affected by large files

Méthode d’authentication

Dans la configuration actuelle, l’authentification est de type utilisateur/mot de passe, identique pour tous. La solution permet d’utiliser une authentification Github ou Bitbucket.

pile

pile lambda

Changer les variables d’environnement de la lambda function:

var

Mot de la fin

Nous avons maintenant une solution long-terme facile à mettre en place qui permet d’utiliser Git sans se soucier de la limite de taille. Cela serait plus facile si nous pouvions avoir des fonctions Lambda dans OVH pour unifier la pile.

Cela m’a pris un certain temps pour le faire fonctionner, alors j’ai voulu le partager. J’espère que cela vous aidera. Si vous avez des questions, vous pouvez me contacter sur Discord ou d’autres réseaux sociaux. Bon développement !

Voir les autres posts