dans Programmation

Déployer une application Django avec Docker sur AWS

Aujourd’hui est un grand jour ! Enfin hier aussi, mais c’est aujourd’hui que ça a marché. J’ai déployé un petit site bidon réalisé avec Django, conteneurisé par Docker, sur AWS. Ça n’a pas été une partie de plaisir parce que les ressources tant francophones qu’anglophones ne sont pas forcément claires ni précises. Je tiens donc à vous partager le fruit de mes recherches. Les prérequis sont simples.

  • Avoir un compte AWS.
  • Connaître les bases des bases de Django (créer un projet, modifier un template).
  • Savoir c’est quoi Docker.

Attention ! Cet article n’a pas pour but de vous apprendre à déployer en production ! Le serveur de développement n’est pas désactivé et il n’est pas remplacé par nginx ou compagnie, pas plus que Gunicorn ou wsgi ne sont mis en place.

Un projet Django bidon

Commençons par là. Je tiens à préciser que je débute avec Django donc le code n’est pas forcément propre, n’est pas commenté et n’est absolument pas destiné à évoluer ni même à servir à quoi que ce soit d’autre que d’éclairer votre lanterne. Pour les courageux qui ont tenu jusqu’ici, le code, c’est par là.

Le projet consiste simplement à générer un nombre au hasard, puis l’insérer dans une URL qui retourne une des images me servant d’avatars. Je l’avais dis, c’est complètement bidon. Le code important se résume à ça, dans le fichier core/views.py.

On s’assure que le projet fonctionne correctement en lançant un petit python manage.py migrate suivi de python manage.py runserver à la racine du projet. Notre site doit se lancer à l’adresse 127.0.0.1:8000, où l’on peut voir de charmantes images. Tout va bien jusque là.

Conteneurisons ça

Maintenant, on va tout embarquer dans un conteneur Docker. Étant donné que la base est un SQLite local, on ne va pas se casser la tête à créer deux conteneurs ni faire mumuse avec docker-compose. On va juste créer un seul conteneur tout simple et ce à l’aide d’un Dockerfile. On ne se casse pas la tête (contrairement à ce que j’ai fais au début) et on suit les instructions du hub Docker. Notre fichier sera donc court et concis.

  • La première ligne indique que l’on veut se baser sur l’image Django fournie par Docker. Celle-ci va notamment copier le code dans le répertoire /usr/src/app, lancer pip pour installer les dépendances et ouvrir le port 8000.
  • La deuxième ligne est purement informative et ne sert qu’à indiquer l’auteur de l’image ainsi que son mail. Oui, le nom d’auteur est totalement improbable donc pas la peine d’en discuter plus longtemps.
  • La troisième ligne indique ce qui sera lancé au démarrage du conteneur. Ici, c’est une unique ligne qui lance notre application Django, mais ça peut très bien être un script contenant plusieurs instructions.

Ceux qui suivent ont remarqué que j’ai parlé de l’installation des dépendances par pip. Il faut donc un fichier requirements.txt au même niveau que notre Dockerfile (ici la racine). Sans ça, le build du conteneur va échouer.

Maintenant, testons ce fameux conteneur. D’abord, il faut le créer. On va donc lancer la commande docker build -t aws_gloves . qui cherche un Dockerfile dans le dossier courant (le dossier .) pour créer une image nommée aws_gloves. Cette opération peut être un peu longue la toute première fois, puisque Docker va télécharger les images dont il a besoin. On ne s’inquiète pas, ça sera beaucoup plus rapide après.

Quand c’est fait, soyons fous, lançons-le avec docker run -d -p 8000:8000 aws_gloves. Le -d indique que l’on lance le conteneur en mode détaché afin que son exécution ne nous empêche pas de continuer à utiliser le terminal. Quand à -p, c’est pour réaliser un mapping entre le port 8000 de l’hôte (à gauche) et le port 8000 du conteneur (à droite). Pour tester, il suffit de se rendre sur http://localhost:8000 et d’admirer le résultat.

Déployons sur AWS avec Elastic Beanstalk

Qu’est-ce qu’on est content, tout marche. Mais bon, c’est du local tout ça. On aimerait que le monde entier puisse en profiter. On va faire ça aujourd’hui en utilisant AWS Elastic Beanstalk. Avant-propos, voici la vidéo d’Amazon pour introduire leur produit ; c’est moins facile à utiliser en vrai, bien entendu.

Ouvrons la console AWS et cliquons en haut à gauche, en orange, sur Elastic Beanstalk.

La console principale d’AWS.

Pourquoi choisir Elastic Beanstalk et non une simple instance EC2 ? Parce que le premier est une offre PaaS alors que le deuxième, une offre IaaS. Avec Elastic Beanstalk, on peut choisir plusieurs plateformes pré-configurées telles que Tomcat, Python ou Docker. En interne, il utilise des instances EC2 mais joint également un load-balancer (pour répartir automatiquement la charge entre plusieurs instances EC2) et de l’autoscaling (pour augmenter ou diminuer automatiquement la puissance d’une instance).

À l’inverse, une simple instance EC2 nous laisse à charge de choisir le système d’exploitation et d’installer toute la suite logicielle dont on a besoin. Si certains veulent comparer la difficulté, Nick Polet a écrit un article sur le déploiement d’une application Django sur une instance EC2.

Ce qui nous intéresse le plus, c’est la catégorie Environment Type. Dans Predefined configuration, on va choisir Docker générique. Dans l’option juste en-dessous, peu importe si on choisit Single Instance ou Load balancing, auto scaling. Le projet est vraiment petit, à priori on n’aura pas besoin de rajouter des serveurs pour tenir la charge (quoi que je ne sais pas, vous allez peut-être devenir fan de mes avatars).

Section suivante, Application Version, on va choisir de déployer notre code à travers une archive .zip que l’on va créer nous-mêmes manuellement pour les besoins du test. Il suffit de se rendre à la racine du projet et de tout compresser. Le projet étant vraiment petit, on ne dépasse pas les 512 MB de limite pour l’archive donc pas de soucis à se faire pour l’instant.

Ensuite, on valide la création de l’environnement et on attend un peu qu’il soit prêt. Enfin, dernière étape, on ouvre le port 8000 en se rendant sur la page de gestion des instances EC2, puis en cliquant sur Security Groups (encadré en rouge sur l’image) dans la section Network & Security. Là, on sélectionne le groupe qui correspond à notre instance Elastic Beanstalk lancée, puis en bas sur l’onglet Inbound pour pouvoir créer une règle TCP personnalisée pour ouvrir le port 8000 (encadré en vert sur l’image).

 

Il faut ouvrir les ports pour accéder à notre instance.

Ne reste qu’à admirer le résultat qui se trouve à l’URL indiquée en haut à droite sur la page principale de l’environnement (sur la page de notre environnement Elastic Beanstalk). Et pour prouver que ça marche bien, j’ai même fais une capture vidéo ! Parce que oui, j’ai désactivé l’instance après.

L’URL se trouve en haut à droite de la console.

Allez plus loin

Certaines choses pourraient être améliorées. Par exemple, le déploiement manuel à coup de .zip peut être source d’erreurs, d’oublis et de prises de tête. Une autre idée serait de créer le conteneur Docker à chaque commit sur Github, à travers Jenkins par exemple. L’idée serait de permettre l’intégration continue, voire même le déploiement continu.

Un autre défi serait de faire une application multi-conteneurs. Ici, j’ai pris une application Django simple avec du SQLite intégré. Une idée serait de conteneuriser une base de données PostgreSQL par exemple. Et même en restant sur un modèle à un conteneur, pourquoi ne pas essayer d’autres offres cloud supportant Docker ? Je prévois d’ailleurs de faire des tests avec Microsoft Azure. Mais ça, ça sera une autre fois.

Laisser un commentaire