diff --git a/source/images/deployment/disallowed_hosts.png b/source/images/deployment/disallowed_hosts.png new file mode 100644 index 0000000..b6301ba Binary files /dev/null and b/source/images/deployment/disallowed_hosts.png differ diff --git a/source/images/deployment/gwift-cloud-s3.png b/source/images/deployment/gwift-cloud-s3.png new file mode 100644 index 0000000..4003c61 Binary files /dev/null and b/source/images/deployment/gwift-cloud-s3.png differ diff --git a/source/images/deployment/heroku-vars-reveal.png b/source/images/deployment/heroku-vars-reveal.png new file mode 100644 index 0000000..e85339a Binary files /dev/null and b/source/images/deployment/heroku-vars-reveal.png differ diff --git a/source/images/deployment/scaleway-api-key.png b/source/images/deployment/scaleway-api-key.png new file mode 100644 index 0000000..2539779 Binary files /dev/null and b/source/images/deployment/scaleway-api-key.png differ diff --git a/source/images/deployment/scaleway-object-storage-bucket.png b/source/images/deployment/scaleway-object-storage-bucket.png new file mode 100644 index 0000000..a9c74bc Binary files /dev/null and b/source/images/deployment/scaleway-object-storage-bucket.png differ diff --git a/source/main.adoc b/source/main.adoc index 3df7d17..c1d50e3 100644 --- a/source/main.adoc +++ b/source/main.adoc @@ -111,12 +111,12 @@ WARNING: Les avertissements indiquent un (potentiel) danger ou des éléments po include::part-1-workspace/_main.adoc[] +include::part-3-data-model/_index.adoc[] + include::part-2-deployment/_main.adoc[] include::part-4-services-oriented-applications/_main.adoc[] -include::part-3-data-model/_index.adoc[] - include::part-5-go-live/_index.adoc[] include::part-9-resources/_index.adoc[] diff --git a/source/part-2-deployment/heroku.adoc b/source/part-2-deployment/heroku.adoc index 6010a4d..f89c64f 100644 --- a/source/part-2-deployment/heroku.adoc +++ b/source/part-2-deployment/heroku.adoc @@ -10,11 +10,13 @@ Pour un projet de type "hobby" et pour l'exemple de déploiement ci-dessous, il La seule contrainte consistera à pouvoir héberger des fichiers envoyés par vos utilisateurs - ceci pourra être fait en configurant un _bucket compatible S3_, par exemple chez Amazon, Scaleway ou OVH. Le fonctionnement est relativement simple: pour chaque application, Heroku crée un dépôt Git qui lui est associé. -Il suffit donc d'envoyer les sources de votre application pour qu'Heroku les interprête comme étant une nouvelle version, et déploie les nouvelles fonctionnalités, sous réserve que tous les tests passent correctement. +Il suffit donc d'envoyer les sources de votre application vers ce dépôt pour qu'Heroku les interprête comme étant une nouvelle version, déploie les nouvelles fonctionnalités - sous réserve que tous les tests passent correctement - et les mettent à disposition. +Dans un fonctionnement plutôt manuel, chaque déploiement est initialisé par le développeur ou par un membre de l'équipe. +Dans une version plus automatisée, chacun de ces déploiements peut être placé en fin de _pipeline_, lorsque tous les tests unitaires et d'intégration auront été réalisés. -Au travers de la commande `heroku create`, vous associez en fait une nouvelle référence à votre code source: +Au travers de la commande `heroku create`, vous associez donc une nouvelle référence à votre code source, comme le montre le contenu du fichier `.git/config` ci-dessous: -[source,bash] +[source,bash,highlight=13-15] ---- $ heroku create Creating app... done, ⬢ young-temple-86098 @@ -33,7 +35,20 @@ $ cat .git/config fetch = +refs/heads/*:refs/remotes/heroku/* ---- -Pour envoyer une nouvelle version, il suffit dès lors (après l'avoir paramétrée), de pousser la référence grâce à la commande `git push heroku master`. +IMPORTANT: +---- +Pour définir de quel type d'application il s'agit, Heroku nécessite un minimum de configuration. +Celle-ci se limite aux deux fichiers suivants: + +* Déclarer un fichier `Procfile` qui va simplement décrire le fichier à passer au protocole WSGI +* Déclarer un fichier `requirements.txt` (qui va éventuellement chercher ses propres dépendances dans un sous-répertoire, avec l'option `-r`) +---- + +Après ce paramétrage, il suffit de pousser les changements vers ce nouveau dépôt grâce à la commande `git push heroku master`. + +WARNING: Heroku propose des espaces de déploiements, mais pas d'espace de stockage. +Il est possible d'y envoyer des fichiers utilisateurs (typiquement, des media personnalisés), mais ceux-ci seront perdus lors du redémarrage du container. +Il est donc primordial de configurer correctement l'hébergement des fichiers média, de préférences sur un stockage compatible S3. (((s3))) Prêt à vous lancer ? Commencez par créer un compte: https://signup.heroku.com/python. @@ -130,4 +145,96 @@ heroku run python manage.py createsuperuser heroku run python manage.py check --deploy heroku open ----- \ No newline at end of file +---- + +=== Configuration + +Pour qu'Heroku comprenne le type d'application à démarrer, ainsi que les commandes à exécuter pour que tout fonctionne correctement. +Pour un projet Django, cela comprend, à placer à la racine de votre projet: + +1. Un fichier `requirements.txt` (qui peut éventuellement faire appel à un autre fichier, *via* l'argument `-r`) +2. Un fichier `Procfile` ([sans extension](https://devcenter.heroku.com/articles/procfile)!), qui expliquera la commande pour le protocole WSGI. + +Dans notre exemple: + +[source] +---- +# requirements.txt +django==3.2.8 +gunicorn +boto3 +django-storages +---- + +[source,bash] +---- +# Procfile +release: python3 manage.py migrate +web: gunicorn gwift.wsgi +---- + +=== Hébergement S3 + +Pour cette partie, nous allons nous baser sur l'https://www.scaleway.com/en/object-storage/[Object Storage de Scaleway]. +Ils offrent 75GB de stockage et de transfert par mois, ce qui va nous laisser suffisament d'espace pour jouer un peu 😉. + +image:images/deployment/scaleway-object-storage-bucket.png[] + +L'idée est qu'au moment de la construction des fichiers statiques, Django aille simplement les héberger sur un espace de stockage compatible S3. +La complexité va être de configurer correctement les différents points de terminaison. +Pour héberger nos fichiers sur notre *bucket* S3, il va falloir suivre et appliquer quelques étapes dans l'ordre: + +1. Configurer un bucket compatible S3 - je parlais de Scaleway, mais il y en a - *littéralement* - des dizaines. +2. Ajouter la librairie `boto3`, qui s'occupera de "parler" avec ce type de protocole +3. Ajouter la librairie `django-storage`, qui va elle s'occuper de faire le câblage entre le fournisseur (*via* `boto3`) et Django, qui s'attend à ce qu'on lui donne un moteur de gestion *via* la clé [`DJANGO_STATICFILES_STORAGE`](https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-STATICFILES_STORAGE). + +La première étape consiste à se rendre dans [la console Scaleway](https://console.scaleway.com/project/credentials), pour gérer ses identifiants et créer un jeton. + +image:images/deployment/scaleway-api-key.png[] + +Selon la documentation de https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings[django-storages], de https://boto3.amazonaws.com/v1/documentation/api/latest/index.html[boto3] et de https://www.scaleway.com/en/docs/tutorials/deploy-saas-application/[Scaleway], vous aurez besoin des clés suivantes au niveau du fichier `settings.py`: + +[source,python] +---- +AWS_ACCESS_KEY_ID = os.getenv('ACCESS_KEY_ID') +AWS_SECRET_ACCESS_KEY = os.getenv('SECRET_ACCESS_KEY') +AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME') +AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME') + +AWS_DEFAULT_ACL = 'public-read' +AWS_LOCATION = 'static' +AWS_S3_SIGNATURE_VERSION = 's3v4' + +AWS_S3_HOST = 's3.%s.scw.cloud' % (AWS_S3_REGION_NAME,) +AWS_S3_ENDPOINT_URL = 'https://%s' % (AWS_S3_HOST, ) + +DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' +STATICFILES_STORAGE = 'storages.backends.s3boto3.S3ManifestStaticStorage' + +STATIC_URL = '%s/%s/' % (AWS_S3_ENDPOINT_URL, AWS_LOCATION) + +# General optimization for faster delivery +AWS_IS_GZIPPED = True +AWS_S3_OBJECT_PARAMETERS = { + 'CacheControl': 'max-age=86400', +} +---- + +Configurez-les dans la console d'administration d'Heroku: + +image:images/deployment/heroku-vars-reveal.png[] + +Lors de la publication, vous devriez à présent avoir la sortie suivante, qui sera confirmée par le *bucket*: + +[source,bash] +---- +remote: -----> $ python manage.py collectstatic --noinput +remote: 128 static files copied, 156 post-processed. +---- + +image:images/deployment/gwift-cloud-s3.png[] + +Sources complémentaires: + +* [How to store Django static and media files on S3 in production](https://coderbook.com/@marcus/how-to-store-django-static-and-media-files-on-s3-in-production/) +* [Using Django and Boto3](https://www.simplecto.com/using-django-and-boto3-with-scaleway-object-storage/)