Une liste exhaustive de bonnes pratiques à mettre en place avant de déployer une infrastructure en production sur AWS
Des bonnes pratiques pour créer un blog ultralight avec un générateur de site statique
Un rappel des différentes étapes pour scaler une application web de 1 à 10 millions d'utilisateurs sur une infra AWS.
Il est inutile de designer une architecture ultra-résiliente dès le début:
- l’architecture évoluera en même temps que le nombre d'utilisateur
- plus l’architecture sera simple à l'origine, plus elle sera facile à faire évoluer
- l'acquisition du trafic prend en général plus longtemps que l'évolution de l'architecture.
Given a version number MAJOR.MINOR.PATCH, increment the:
MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
1. Microservice First
Commencer par les microservices est non justifiable puisqu'ils ajoutent une complexité et des efforts supplémentaires aux développements.
Il faut plutôt débuter par des solutions monolithiques, ennuyeuses et classiques, pour évoluer selon le besoin vers des architectures microservices en identifiant les services qui nécessitent une refonte.
2. Gatekeeper et le versioning sémantique
Absence de stratégie de versioning : le partage des mêmes sources de données entre microservices peut ruiner la coordination, voire même ralentir les déploiements et freiner l'agilité.
"Gatekeeper" peut paraître à première vue la solution directe, n'est cependant qu’un déplacement du problème.
Le "Semantic Versioning" couplé à une bonne stratégie de gouvernance (héritage SOA) permettent la résolution de cette problématique.
3. Spiky load
Reste le partage des mêmes sources de données qui pose des soucis avec des charges non équilibrées entre services. L’exemple d’un microservice qui stresse une base de données commune et qui bloque les autres microservices.
L’utilisation des queues, pour amortir et absorber les pics et distribuer la charge, permet de résoudre le "Spiky load" entre services mais avec un coup supplémentaire de gestion du modèle asynchrone.
4. Discovery Service ou le centralised router
Le codage en dur des adresses et des ports IP simplifie le démarrage des projets. Mais très vite, il devient le cauchemar des Ops au moment du déploiement.
Tammer cite deux solutions :
La première est le "Discovery Service" comme consul ou etcd avec un effet de bord où les services seront obligés de comprendre les indirections de lookup.
Le "Centralised router" comme deuxième solution est considérée transparente et plus simple à mettre en place, étant la réplication d’un DNS.
5. Circuit Breaker pour les Dogpiles
Les "Dogpiles" : invoquer et continuer à stresser un microservice bien qu'il ne soit plus en état de répondre aux demandes, créant ainsi un effet boule de neige.
Une solution classique est l’introduction de "Circuit Breaker" qui jouera le rôle d'intermédiaire pour empêcher cet effet.
6. Correlation ID pour le débogage
Débogage : les microservices ajoutent des frais supplémentaires, y compris le débogage des services distribués et asynchrones. Ne pas concevoir une stratégie de logging dès le départ peut mettre en cause toute la solution.
L’utilisation de "Correlation ID" s'avère nécessaire pour tracer l’origine et le parcours des requêtes entre microservices. Évidemment, la gestion des id de corrélation ajoute un coût de développement et de coordination entre équipes.
7. Mocks
Lors de la phase de tests, les équipes ont tendance à créer des mocks pour les microservices utilisés. Ce qui finira par une prolifération des bouchons proportionnellement aux services consommés.
Une première solution serait de déléguer la création des mocks aux fournisseurs de services eux-mêmes, alors que les consommateurs doivent à leur tour savoir comment les invoquer. Pour répondre à cette limitation, il serait judicieux de développer une api qui, à la fois cache les détails d’implémentation et les protocoles de communication utilisés, mais aussi facilitant l’aiguillage entre les différentes implémentations pour les besoins de tests.
8. Flying Blind
"Flying Blind" ou l'expérience de s'aventurer en production sans avoir connaissance sur ce qui passe, ni sur les métriques d’utilisation de chaque microservice.
Les graphes, les alertes et les tableaux de bord sont les solutions classiques pour toute solution en production.
9. Snowflakes et Golden Image
"Snowflakes" : mettre à jour et installer les correctifs logiciels dans un univers microservices peut devenir ingérable, voire impossible.
"Golden Image" est une solution pour ce dilemme, avec l’utilisation d’une combinaison de base commune de frameworks et des runtimes avec des versions d’OS de références.
10. Doomsday et CI
Le "Doomsday", ou "La peur du jour J", le jour de la mise en production, est un problème récurrent pour les organisations qui ne déploient pas assez souvent. Déployer plus fréquemment augmente la confiance en son processus de déploiement, réduit les risques d'erreur, et améliore la rapidité à laquelle on peut délivrer de nouvelles fonctionnalités.
L'intégration continue résout cette problématique avec la mise en place d'une pipeline prédéfinie et qui donne confiance aux tests automatisés.
11. PaaS
L’explosion opérationnelle avec l’utilisation d’une grande variété de technologies, de langages et de solutions, ce qui rend leur gestion en post-production un fardeau poussant les Ops à bloquer le passage en production.
Automatiser le déploiement (CD) s'avère à première vue impossible. Mais c’est là où le rôle des platformes PaaS se confirme pour donner la souplesse et les moyens de gestion des microservices.
Une excellente explication du GELF driver Docker qui permet de centraliser les logs des containers dans un ELK, Graylog ou autre solution de centralisation de log du même type.
Bonnes pratiques pour gérer ses rôles avec Ansible Galaxy:
- utiliser la commande
ansible-galaxy init
pour créer la structure du rôle$ ansible-galaxy init test-role - test-role was created successfully $ tree . └── test-role ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml 9 directories, 8 files
- Isoler chaque rôle dans un repo git séparé (permet de gérer la version du rôle avec les tags git)
- Utiliser Ansible Galaxy pour installer les rôles privés avec un fichier requirements.yml:
$ cat requirements.yml - src: git+https://bitbucket.org/ursuad/sample_role_oracle-java version: v1.1.6 $ ansible-galaxy install -r requirements.yml
- Gérer les dépendances entre rôles dans meta/main.yml
$ cat meta/main.yml dependencies: - { role: 'git+https://bitbucket.org/ursuad/sample_role_launchpad-ppa-webupd8,v1.0.0'}
ansible-lint vérifie le playbook indiqué en argument et indique les tâches qui ne suivent pas les best-practices Ansible dans leur définitions.
L'installation se fait via pip:
pip2 install ansible-lint
Best practices pour Terraform:
- utiliser des modules contenant le code nécessaire au provisinning des services
- appeler les modules depuis les répertoires de configuration spécifiques aux environnements en passant en variables les données spécifiques aux environnements
- séparer les modules et la configuration spécifique aux environnements dans 2 repos git différents afin de pouvoir appeler des versions du module différent selon les environnements (en utilisant les tags git)
ex:
- infrastructure-live-repo
| - dev
| | - app1
| | - app2
| | - db1
| | - vpc
| - test
| | - ...
| - prod
| | - ...
| - mgmt
| | - bastion
| | - ...
| - global
| | - iam
| | - route53
| | - ...
- infrastructure-modules-repo (tags v0.0.1, v0.0.2, ...)
| - app1
| - app2
| - db1
| - vpc
| - bastion
| - ...
Suivre aveuglement les bonnes pratiques de développement au lieu de s'adapter aux besoins business peut parfois devenir contre productif.
Des bonnes/mauvaises pratiques pour le déploiement d'applications Python:
- packager sa propre version de python au lieu d'utiliser celle fournie par l'OS
- utiliser pip au lieu des packages fournis par l'OS pour toutes les librairies Python
- utiliser des virtualenvs pour tout, la seule librairie python installée au niveau global doit être virtualenv
- ne pas faire tourner les daemons dans un simple screen ou tmux, utiliser supervisord à la place
- séparer la configuration de l'application
- utiliser nginx/gunicorn au lieu de apache/mod_wsgi pour les applis web
- packager l'applis en .DEB ou .RPM au lieu de déployer via GIT et PIP (cf. https://hynek.me/articles/python-app-deployment-with-native-packages/)
Une conf sur les bonnes pratiques de dev pour optimiser une applis PHP. Une bonne partie des points sont valables aussi pour les applis web utilisant d'autres langages.
Entre autre:
- stocker uniquement le code dans le filesystem
- stocker les sessions en database (clé/valeur ou sql)
- gérer les logs avec syslog
- séparer les assets (fichiers statiques) du code en utilisant un système dédié (ex: S3) et un nom de domaine séparé
- ne jamais faire de hot fix directement sur le serveur
- utiliser git pour déployer
- utiliser un système de build (ex: composer pour php ou npm/grunt/browserify pour js)
- ne jamais commiter les dépendances avec le code
- l'application doit fonctionner sans les droits d'écriture sur le serveur
- utiliser les fast-cgi et php-fpm, ne plus utiliser mod_php
- utiliser les variables d'environnements pour la conf (ex: db host, ...)
- utiliser les uuid au lieu d'auto increment pour les id utilisateurs
bonnes pratiques pour les entrypoints docker
Cas d'utilisation d'une infra AWS / Docker / ECS
bonnes pratiques de sécurité pour une station de travail linux
- Write good commit messages
- Commit all the fucking time
- Rebase & —amend to get rid of “oops”-commits
Un livre blanc qui recense les bonnes pratiques des acteurs du web:
de la culture devops aux architectures big data/nosql en passant par le déploiement continu, l'organisation des équipes et la conception d'api ouvertes à l'extérieur
Pour le télécharger sans s'enregistrer: https://julien.mailleret.fr/pub/octo-les-geants-du-web.pdf
Un guide des bonnes pratiques Python écrit sur GitHub :https://github.com/kennethreitz/python-guide
1: Enable AWS VPC Flow Logs for your VPC or Subnet or ENI level
2: Use AWS Identity and Access Management (IAM) to control who in your organization has permission to create and manage security groups and network ACLs (NACL)
3: Enable AWS Cloud Trail logs for your account
4: Enable AWS App Config for your AWS account. App records all events related to your security group changes and can even send emails
5: Have proper naming conventions for the Amazon Web Services security group
7: Periodically detect, alert or delete AWS Security groups not following the organization naming standards strictly
8: Have automation in place to detect all EC2,ELB and other AWS assets associated with Security groups
9: Create your own security groups and specify them when you launch your instances
10: Alerts by email and cloud management dash board should be triggered whenever critical security groups or rules are added/modified/deleted in production
11 : Have automated programs detecting EC2 associated with multiple SG/rules and alert the SOC/MS periodically. Condense the same manually to 1-3 rules max as part of your operations.
12 : Do not create least restrictive security groups like 0.0.0.0/0 which is open to every one
13: Have a security policy not to launch servers with default ports like 3306, 1630, 1433, 11211, 6379 etc
15: Detection, alert and actions can be taken by parsing the AWS Cloud Trail logs based on usual patterns observed in your production environment. Detect anomalies on how long a change effected and reverted in security groups in production.
16: In case ports have to be opened in Amazon Web Services security groups or a permissive AWS security group needs to be applied, Automate this entire process as part of your operations
17: Make sure SSH/RDP connection is open in AWS Security Group only for jump box/bastion hosts for your VPC/subnets. Have stricter controls/policies avoid opening SSH/RDP to other instances of production environment
18: It is a bad practice to have SSH open to the entire Internet for emergency or remote support
20: Avoid allowing UDP or ICMP for private instances in Security groups
21: Open only specific ports, Opening range of ports in a security group is not a good practice.
22: Private Subnet instances can be accessed only from the VPC CIDR IP range
23: AWS CloudTrail log captures the events related security. AWS lambda events or automated programs should trigger alerts to operations when abnormal activities are detected
24: In case you are an enterprise make sure all security groups related activities of your production are part of your change management process. In case you are an agile Startup or SMB and do not have complicated Change management process, then automate most of the security group related tasks and events as illustrated above on various best practices
26: For some tiers of your application, use ELB in front your instance as a security proxy with restrictive security groups
Méthodologie pour construire des applications faites pour une utilisation de type cloud:
- 1 application = 1 repository de code et 1 seul
- toutes les dépendances doivent-être explicites et fournies avec l'application
- la configuration doit-être gérée dans des variables d'environnements
- tous les services externes (api, database, smtp, cache, messaging...) doivent-être gérés comme des ressources accessibles via une URL
- les étapes de build (compilation + dépendances), release (application configuration) et run (lancement de l'application) doivent être strictement séparées
- l'application doit-être stateless et "share-nothing" (aucune donnée en local)
- l'application doit gérer sa couche réseau sans dépendre d'un logiciel externe (ex: webserver embarqué pour ne pas dépendre d'apache)
- l'application doit-être composés de process instanciables sur le même serveur ou sur différents serveurs (scalabilité)
- les process ne doivent pas être démarrés en taches de font (démon) par l'application. la gestion des process (arrêt/relance, gestion logs et stdout, ...) doit être délégués à un process manager (systemd, runit, foreman, ...)
- les tâches administratives (ex: migration db, ...) doivent être traitées par des process séparées (scripts) mais fournis avec le code applicatif et lancé dans le même environnement applicatif