diff --git a/source/images/deployment/heroku-app-created.png b/source/images/deployment/heroku-app-created.png new file mode 100644 index 0000000..63d45ee Binary files /dev/null and b/source/images/deployment/heroku-app-created.png differ diff --git a/source/images/deployment/heroku-new-app.png b/source/images/deployment/heroku-new-app.png new file mode 100644 index 0000000..f6a876f Binary files /dev/null and b/source/images/deployment/heroku-new-app.png differ diff --git a/source/images/deployment/heroku.png b/source/images/deployment/heroku.png new file mode 100644 index 0000000..32a5a05 Binary files /dev/null and b/source/images/deployment/heroku.png differ diff --git a/source/part-1-workspace/django/_index.adoc b/source/part-1-workspace/django/_index.adoc index 1eb4899..97c209c 100644 --- a/source/part-1-workspace/django/_index.adoc +++ b/source/part-1-workspace/django/_index.adoc @@ -367,7 +367,11 @@ urlpatterns = [ <2> Champomy et cotillons! Nous avons une correspondance avec `wishes/details/91827` -Nous n'allons pas nous occuper de l'accès à la base de données pour le moment (nous nous en occuperons dans un prochain chapitre) et nous nous contenterons de remplir un canevas avec un ensemble de données. +TODO: En fait, il faudrait quand même s'occuper du modèle ici. +TODO: et de la mise en place de l'administration, parce que nous en aurons besoin pour les étapes de déploiement. + +[line-through]#Nous n'allons pas nous occuper de l'accès à la base de données pour le moment (nous nous en occuperons dans un prochain chapitre) et nous nous contenterons de remplir un canevas avec un ensemble de données.# + Le module `gwift.views` qui se trouve dans le fichier `gwift/views.py` peut ressembler à ceci: [source,python] @@ -474,11 +478,30 @@ Nous avons donc la strucutre finale pour notre environnement de travail: └── tox.ini ---- -=== - === Cookie cutter -* Créez systématiquement un environnement virtuel pour chaque projet sur lequel vous travaillez -* La description des dépendances utilisées pour un projet doivent faire partie intégrante des sources +Pfiou! Ca en fait des commandes et du boulot pour "juste" démarrer un nouveau projet, non? Sachant qu'en plus, nous avons dû modifier des fichiers, déplacer des dossiers, ajouter des dépendances, configurer une base de données, ... -C'est ici que le projet http://cookiecutter.readthedocs.io/en/latest/readme.html[CookieCutter] va être intéressant: les X premières étapes peuvent être *bypassées* par une simple commande. \ No newline at end of file +Bonne nouvelle! Il existe des générateurs, permettant de démarrer rapidement un nouveau projet sans (trop) se prendre la tête. Le plus connu (et le plus personnalisable) est https://cookiecutter.readthedocs.io/[Cookie-Cutter], qui se base sur des canevas _type https://pypi.org/project/Jinja2/[Jinja2]_, pour créer une arborescence de dossiers et fichiers conformes à votre manière de travailler. Et si vous avez la flemme de créer votre propre canevas, vous pouvez utiliser https://cookiecutter-django.readthedocs.io[ceux qui existent déjà]. + +Pour démarrer, créez un environnement virtuel (comme d'habitude): + +[source,bash] +---- +λ python -m venv .venvs\cookie-cutter-khana +λ .venvs\cookie-cutter-khana\Scripts\activate.bat +(cookie-cutter-khana) λ pip install cookiecutter + + Collecting cookiecutter + [...] + Successfully installed Jinja2-2.11.2 MarkupSafe-1.1.1 arrow-0.17.0 binaryornot-0.4.4 certifi-2020.12.5 chardet-4.0.0 click-7.1.2 cookiecutter-1.7.2 idna-2.10 jinja2-time-0.2.0 poyo-0.5.0 python-dateutil-2.8.1 python-slugify-4.0.1 requests-2.25.1 six-1.15.0 text-unidecode-1.3 urllib3-1.26.2 + +(cookie-cutter-khana) λ cookiecutter https://github.com/pydanny/cookiecutter-django + + [...] + + [SUCCESS]: Project initialized, keep up the good work! +---- + +Si vous explorez les différents fichiers, vous trouverez beaucoup de similitudes avec la configuration que nous vous proposions ci-dessus. +En fonction de votre expérience, vous serez tenté de modifier certains paramètres, pour faire correspondre ces sources avec votre utilisation ou vos habitudes. diff --git a/source/part-1-workspace/environment/_index.adoc b/source/part-1-workspace/environment/_index.adoc index 6250bf8..01ed60e 100644 --- a/source/part-1-workspace/environment/_index.adoc +++ b/source/part-1-workspace/environment/_index.adoc @@ -288,7 +288,8 @@ Found 4 errors in 1 file (checked 1 source file) Pour corriger ceci, nous devons: . Importer le type `Optional` et l'utiliser en sortie de notre fonction `first_int_elem` -. Eviter de lui donner de mauvais paramètres ;-) +. Eviter de lui donner de +mauvais paramètres ;-) [source,python] ---- @@ -458,9 +459,13 @@ Pour la petite histoire, `make` peu sembler un peu désuet, mais reste extrêmem ==== The Zen of Python -[source,text] +[source,python] ---- >>> import this +---- + +[source,text] +---- The Zen of Python, by Tim Peters Beautiful is better than ugly. diff --git a/source/part-2-deployment/_index.adoc b/source/part-2-deployment/_index.adoc index 2eda855..79b70e5 100644 --- a/source/part-2-deployment/_index.adoc +++ b/source/part-2-deployment/_index.adoc @@ -85,8 +85,6 @@ include::heroku.adoc[] include::docker.adoc[] - - WARNING: le serveur de déploiement ne doit avoir qu'un accès en lecture au dépôt source. On peut aussi passer par fabric, ansible, chef ou puppet. @@ -115,4 +113,3 @@ See https://mattsegal.dev/nginx-django-reverse-proxy-config.html * Let's Encrypt ! -include::database.adoc[] \ No newline at end of file diff --git a/source/part-2-deployment/ansible.adoc b/source/part-2-deployment/ansible.adoc deleted file mode 100644 index b9df47b..0000000 --- a/source/part-2-deployment/ansible.adoc +++ /dev/null @@ -1 +0,0 @@ -=== Ansible \ No newline at end of file diff --git a/source/part-2-deployment/database.adoc b/source/part-2-deployment/database.adoc deleted file mode 100644 index 213db97..0000000 --- a/source/part-2-deployment/database.adoc +++ /dev/null @@ -1,63 +0,0 @@ -== Bases de données - -On l'a déjà vu, Django se base sur un pattern type https://www.martinfowler.com/eaaCatalog/activeRecord.html[ActiveRecords] pour la gestion de la persistance des données et supporte les principaux moteurs de bases de données connus: - -* SQLite (en natif, mais Django 3.0 exige une version du moteur supérieure ou égale à la 3.8) -* MariaDB (en natif depuis Django 3.0), -* PostgreSQL au travers de psycopg2 (en natif aussi), -* Microsoft SQLServer grâce aux drivers [...à compléter] -* Oracle via https://oracle.github.io/python-cx_Oracle/[cx_Oracle]. - -CAUTION: Chaque pilote doit être utilisé précautionneusement ! Chaque version de Django n'est pas toujours compatible avec chacune des versions des pilotes, et chaque moteur de base de données nécessite parfois une version spécifique du pilote. Par ce fait, vous serez parfois bloqué sur une version de Django, simplement parce que votre serveur de base de données se trouvera dans une version spécifique (eg. Django 2.3 à cause d'un Oracle 12.1). - -Ci-dessous, quelques procédures d'installation pour mettre un serveur à disposition. Les deux plus simples seront MariaDB et PostgreSQL, qu'on couvrira ci-dessous. Oracle et Microsoft SQLServer se trouveront en annexes. - -=== PostgreSQL - -On commence par installer PostgreSQL. - -Par exemple, dans le cas de debian, on exécute la commande suivante: - -[source,bash] ----- -$$$ aptitude install postgresql postgresql-contrib ----- - -Ensuite, on crée un utilisateur pour la DB: - -[source,bash] ----- -$$$ su - postgres -postgres@gwift:~$ createuser --interactive -P -Enter name of role to add: gwift_user -Enter password for new role: -Enter it again: -Shall the new role be a superuser? (y/n) n -Shall the new role be allowed to create databases? (y/n) n -Shall the new role be allowed to create more new roles? (y/n) n -postgres@gwift:~$ ----- - -Finalement, on peut créer la DB: - -[source,bash] ----- -postgres@gwift:~$ createdb --owner gwift_user gwift -postgres@gwift:~$ exit -logout -$$$ ----- - -NOTE: penser à inclure un bidule pour les backups. - -=== MariaDB - -Idem, installation, configuration, backup, tout ça. -A copier de grimboite, je suis sûr d'avoir des notes là-dessus. - - -=== Microsoft SQL Server - - -=== Oracle - diff --git a/source/part-2-deployment/debian.adoc b/source/part-2-deployment/debian.adoc index d73a3ff..2bae1e8 100644 --- a/source/part-2-deployment/debian.adoc +++ b/source/part-2-deployment/debian.adoc @@ -42,6 +42,71 @@ sudo make altinstall <1> ---- <1> *Attention !* Le paramètre `altinstall` est primordial. Sans lui, vous écraserez l'interpréteur initialement supporté par la distribution, et cela pourrait avoir des effets de bord non souhaités. +==== Installation de la base de données + +On l'a déjà vu, Django se base sur un pattern type https://www.martinfowler.com/eaaCatalog/activeRecord.html[ActiveRecords] pour la gestion de la persistance des données et supporte les principaux moteurs de bases de données connus: + +* SQLite (en natif, mais Django 3.0 exige une version du moteur supérieure ou égale à la 3.8) +* MariaDB (en natif depuis Django 3.0), +* PostgreSQL au travers de psycopg2 (en natif aussi), +* Microsoft SQLServer grâce aux drivers [...à compléter] +* Oracle via https://oracle.github.io/python-cx_Oracle/[cx_Oracle]. + +CAUTION: Chaque pilote doit être utilisé précautionneusement ! Chaque version de Django n'est pas toujours compatible avec chacune des versions des pilotes, et chaque moteur de base de données nécessite parfois une version spécifique du pilote. Par ce fait, vous serez parfois bloqué sur une version de Django, simplement parce que votre serveur de base de données se trouvera dans une version spécifique (eg. Django 2.3 à cause d'un Oracle 12.1). + +Ci-dessous, quelques procédures d'installation pour mettre un serveur à disposition. Les deux plus simples seront MariaDB et PostgreSQL, qu'on couvrira ci-dessous. Oracle et Microsoft SQLServer se trouveront en annexes. + +===== PostgreSQL + +On commence par installer PostgreSQL. + +Par exemple, dans le cas de debian, on exécute la commande suivante: + +[source,bash] +---- +$$$ aptitude install postgresql postgresql-contrib +---- + +Ensuite, on crée un utilisateur pour la DB: + +[source,bash] +---- +$$$ su - postgres +postgres@gwift:~$ createuser --interactive -P +Enter name of role to add: gwift_user +Enter password for new role: +Enter it again: +Shall the new role be a superuser? (y/n) n +Shall the new role be allowed to create databases? (y/n) n +Shall the new role be allowed to create more new roles? (y/n) n +postgres@gwift:~$ +---- + +Finalement, on peut créer la DB: + +[source,bash] +---- +postgres@gwift:~$ createdb --owner gwift_user gwift +postgres@gwift:~$ exit +logout +$$$ +---- + +NOTE: penser à inclure un bidule pour les backups. + +===== MariaDB + +Idem, installation, configuration, backup, tout ça. +A copier de grimboite, je suis sûr d'avoir des notes là-dessus. + + +===== Microsoft SQL Server + + +===== Oracle + + + ==== Préparation de l'environnement utilisateur [source,bash] @@ -278,7 +343,7 @@ server { <2> Ce répertoire sera complété par la commande `collectstatic` que l'on verra plus tard. L'objectif est que les fichiers ne demandant aucune intelligence soit directement servis par Nginx. Cela évite d'avoir un processus Python (relativement lent) qui doive être instancié pour servir un simple fichier statique. <3> Afin d'éviter que Django ne reçoive uniquement des requêtes provenant de 127.0.0.1 -=== Mise à jour +==== Mise à jour Script de mise à jour. @@ -295,7 +360,7 @@ python manage.py collectstatic gunicorn reload -HUP ---- -=== Configuration des sauvegardes +==== Configuration des sauvegardes Les sauvegardes ont été configurées avec borg: `yum install borgbackup`. @@ -315,7 +380,7 @@ Et dans le fichier crontab : ---- -=== Rotation des jounaux +==== Rotation des jounaux [source,bash] ---- @@ -328,4 +393,6 @@ Et dans le fichier crontab : } ---- -Puis on démarre logrotate avec # logrotate -d /etc/logrotate.d/gwift pour vérifier que cela fonctionne correctement. \ No newline at end of file +Puis on démarre logrotate avec # logrotate -d /etc/logrotate.d/gwift pour vérifier que cela fonctionne correctement. + +==== Ansible \ No newline at end of file diff --git a/source/part-2-deployment/docker.adoc b/source/part-2-deployment/docker.adoc index c5c7ea3..06d9c20 100644 --- a/source/part-2-deployment/docker.adoc +++ b/source/part-2-deployment/docker.adoc @@ -17,4 +17,6 @@ image.png L'image de base python passe de 179 à 740 MB. Et là j'en ai pour presque 1,5 GB d'un coup. -Mais par contre, j'ai un python 3.7 direct et postgres 10 sans rien faire ou presque. \ No newline at end of file +Mais par contre, j'ai un python 3.7 direct et postgres 10 sans rien faire ou presque. + +La partie ci-dessous a été reprise telle quelle de https://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html[la documentation de cookie-cutter-django]. diff --git a/source/part-2-deployment/heroku.adoc b/source/part-2-deployment/heroku.adoc index 41457a2..03f9c52 100644 --- a/source/part-2-deployment/heroku.adoc +++ b/source/part-2-deployment/heroku.adoc @@ -1 +1,127 @@ === Heroku + +https://www.heroku.com[Heroku] est une _Plateform As A Service_ footnote:[Aussi abrégé "PaaS" pour les conaisseurs], où vous choisissez le _service_ dont vous avez besoin (une base de données, un service de cache, un service applicatif, ...), vous lui envoyer les paramètres nécessaires et le tout démarre gentiment sans que vous ne deviez superviser l'hôte. +Ce mode démarrage ressemble énormément aux 12 facteurs dont nous avons déjà parlé plus tôt - raison de plus pour que notre application soit directement prête à y être déployée, d'autant plus qu'il ne sera pas possible de modifier un fichier une fois qu'elle aura démarré: si vous souhaitez modifier un paramètre, cela reviendra à couper l'actuelle et envoyer de nouveaux paramètres et recommencer le déploiement depuis le début. + +.Invest in apps, not ops. Heroku handles the hard stuff — patching and upgrading, 24/7 ops and security, build systems, failovers, and more — so your developers can stay focused on building great apps. +image::images/deployment/heroku.png[] + +Pour un projet de type "hobby" et pour l'exemple de déploiement ci-dessous, il est tout à fait possible de s'en sortir sans dépenser un kopek, afin de tester nos quelques idées ou mettre rapidement un _Most Valuable Product_ en place. La seule contrainte consistera à pouvoir héberger des fichiers envoyés par vos utilisateurs - ceci pourra être fait en configurant un _bucket S3_ chez Amazon (beurk), Scaleway ou OVH footnote:[Entre autres.] + +Le fonctionnement est relativement simple: pour chaque application, Heroku crée un dépôt Git qui lui est associé. Au travers de la commande `heroku create`, vous associez en fait une nouvelle référence à votre code source: + +[source,bash] +---- +$ heroku create +Creating app... done, ⬢ young-temple-86098 +https://young-temple-86098.herokuapp.com/ | https://git.heroku.com/young-temple-86098.git + +$ cat .git/config +[core] + repositoryformatversion = 0 + filemode = false + bare = false + logallrefupdates = true + symlinks = false + ignorecase = true +[remote "heroku"] + url = https://git.heroku.com/still-thicket-66406.git + 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`. + +Prêt à vous lancer ? Commencez par créer un compte: https://signup.heroku.com/python. + +==== Configuration du compte Heroku + ++ Récupération des valeurs d'environnement pour les réutiliser ci-dessous. + +Vous aurez peut-être besoin d'un coup de pouce pour démarrer votre première application; heureusement, la documentation est super bien faite: + +.Heroku: Commencer à travailler avec un langage +image::images/deployment/heroku-new-app.png[] + +Installez ensuite la CLI (_Command Line Interface_) en suivant https://devcenter.heroku.com/articles/heroku-cli[la documentation suivante]. + +Au besoin, cette CLI existe pour: + +. macOS, _via_ `brew ` +. Windows, grâce à un https://cli-assets.heroku.com/heroku-x64.exe[binaire x64] (la version 32 bits existe aussi, mais il est peu probable que vous en ayez besoin) +. GNU/Linux, via un script Shell `curl https://cli-assets.heroku.com/install.sh | sh` ou sur https://snapcraft.io/heroku[SnapCraft]. + +Une fois installée, connectez-vous: + +[source,bash] +---- +$ heroku login +---- + +Et créer votre application: + +[source,bash] +---- +$ heroku create +Creating app... done, ⬢ young-temple-86098 +https://young-temple-86098.herokuapp.com/ | https://git.heroku.com/young-temple-86098.git +---- + +.Notre application est à présent configurée! +image::images/deployment/heroku-new-app-created.png[] + +Ajoutons lui une base de données, que nous sauvegarderons à intervalle régulier: + +[source,bash] +---- +$ heroku addons:create heroku-postgresql:hobby-dev +Creating heroku-postgresql:hobby-dev on ⬢ still-thicket-66406... free +Database has been created and is available + ! This database is empty. If upgrading, you can transfer + ! data from another database with pg:copy +Created postgresql-clear-39693 as DATABASE_URL +Use heroku addons:docs heroku-postgresql to view documentation + +$ heroku pg:backups schedule --at '14:00 Europe/Brussels' DATABASE_URL +Scheduling automatic daily backups of postgresql-clear-39693 at 14:00 Europe/Brussels... done +---- + +[source,bash] +---- +# Copié/collé de https://cookiecutter-django.readthedocs.io/en/latest/deployment-on-heroku.html +heroku create --buildpack https://github.com/heroku/heroku-buildpack-python + +heroku addons:create heroku-redis:hobby-dev + +heroku addons:create mailgun:starter + +heroku config:set PYTHONHASHSEED=random + +heroku config:set WEB_CONCURRENCY=4 + +heroku config:set DJANGO_DEBUG=False +heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production +heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)" + +# Generating a 32 character-long random string without any of the visually similar characters "IOl01": +heroku config:set DJANGO_ADMIN_URL="$(openssl rand -base64 4096 | tr -dc 'A-HJ-NP-Za-km-z2-9' | head -c 32)/" + +# Set this to your Heroku app url, e.g. 'bionic-beaver-28392.herokuapp.com' +heroku config:set DJANGO_ALLOWED_HOSTS= + +# Assign with AWS_ACCESS_KEY_ID +heroku config:set DJANGO_AWS_ACCESS_KEY_ID= + +# Assign with AWS_SECRET_ACCESS_KEY +heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY= + +# Assign with AWS_STORAGE_BUCKET_NAME +heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME= + +git push heroku master + +heroku run python manage.py createsuperuser + +heroku run python manage.py check --deploy + +heroku open +---- \ No newline at end of file