Bonnes pratiques
Applicatifs
Une application Cloud π Native doit respecter les Twelve-Factor
D'autres bonnes pratiques à respecter impérativement :
Base de code
Le code de l'application et de l'infrastructure doit être versionné dans un dépôt de source de type Git (Public/Privée) accessible depuis internet.
Dépendances
TOUTES dépendances nécessaires à la construction de l'application (Libraries,Images, ...) doivent provenir des dépôts de librairies connues tels que Maven, Composer et Node. Il est aussi possible de construire les dépendances par l'offre Cloud π Native et les déposer dans son gestionnaire d'artefact.
Configuration / Service Externe
TOUTES la configuration applicative pouvant être amenée à être modifié, par exemple la configuration entre deux environnements applicatifs la plupart du temps différente. Elle doit donc être injectée par des variables d'environnement au runtime ou via un fichier de configuration dynamique via une ConfigMap
Port
Afin de respecter les préconisations de sécurité, les applications déployées doivent écouter sur des ports > 1024.
Logs
L'application NE DOIT PAS écrire dans un fichier de logs spécifique, mais écrire l'ensemble de ces logs dans la sortie standards (stdout) au format GELF ou à défaut JSON.
Les logs seront accessibles plus facilement de cette manière depuis les outils de supervisions.
Processus
Les applications doivent être STATELESS, si des données de session/cache doivent être utilisés et partagé par l'application alors elles doivent faire l'objet d'un service externe prévus à cet effet tel que Redis.
Processus d’administration
Les opérations d'administrations doivent être faites via des initContainer (Init/Migration bdd, ...) ou des CronJob (Backup bdd, ...) FAQ
L'ensemble de ces bonnes pratiques sont détaillés dans la documentation OpenShift ici
Architectures
L'application déployée doit être conteneurisée (sous la forme d'un ou plusieurs conteneurs).
- Les Dockerfiles doivent être dans le dépôt pour permettre à la chaine de reconstruire l'application.
- Les images de bases des Dockerfiles doivent être accessibles publiquement ou reconstuite par l'offre Cloud π Native .
- Les images doivent être rootless, l'utilisateur qui lance le processus au sein du conteneur ne doit pas être
root
. - L'utilisateur lançant le processus dans le conteneur doit avoir les droits adéquats en lecture / écriture sur le système de fichiers si l'application doit manipuler ce dernier.
- Des sondes de "Readiness"/"Liveness" doivent être implémentées.
- Des limits/requests doivent etre mise en place.
Déploiement
L'application doit se déployer à l'aide de fichiers d'Infrastructure As Code :
- Utiliser des manifestes kubernetes avec Kustomize pour variabliser vos manifestes (cf. tutoriels)
- Utiliser des charts helm (cf. tutoriels pour avoir des exemples de fichiers).
- Utiliser Kustomize
Labels
Les ressources doivent comporter des labels permettant de les identifier. Ils peuvent être décomposés de la façon suivante :
App : " "
Env : " "
Tier : " "
Criticality : " "
Component : " "
Tous les labels disponibles ici.
Tag d'images
Les images poussées dans le registry devront être unique et identifiés via un Sha ou Short-Sha qui pourrait être lié au commit Git. Grace à cela une gestion des releases et un rollback seront possibles.
Exemple de valeur pour le Tag de l'image :
CI_COMMIT_SHA
CI_COMMIT_SHORT_SHA
CI_COMMIT_TAG
CI_JOB_ID
Politiques de nommage
Les noms de toutes les ressources Openshift ne doivent jamais être trop longs, il est donc conseillé de choisir des noms courts. Il se pourrait que des ressources ne soient pas déployées si le nom est trop long. Côté exploitation, cela facilite grandement la gestion.
Exemple :
Service : env-ms-svc
Deployment : env-ms-dep
Statefulset : env-ms-sts
ConfigMap : env-ms-cm
Secret : env-secret
CronJob : env-name-cj
Route : env-route
PVC : env-name-pvc
Secrets
Les secrets comportent toutes les informations sensibles. Les différents types de secrets peuvent être :
- Passwords
- Certificats
- Usernames
- Tokens
Tous les secrets devront être contenus dans un Vault qui sera mis a disposition pour l'ensemble des projets. Les objets contenus dans le Vault sont séparés par projets (NS).
Liveness et Readiness
Il est très important de mettre en place ces checks afin de vérifier l'état de vos applications. Ceci est nécessaire pour assurer la haute disponibilité et la résilience de vos applications. Cela peut-être une fonctionnalité de l'application, une page d'un site web, une entrée en base de données, etc.
livenessProbe:
httpGet:
path: /
port: 80
httpHeaders:
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 3
periodSeconds: 3
SSL
Afin d'optimiser un flux sécurisé, il est préférable que cela soit de bout en bout.
Exemple du schéma de distribution de la requête.
Users --HTTPS-> ReverseProxy --HTTPS-> Ingress Kubernetes --HTTPS-> Container (Best Case)
Users --HTTPS-> ReverseProxy --HTTPS-> Ingress Kubernetes --HTTP-> Container (Usual Case)
HPA (Horizontal Pod Autoscaling)
Le scaling est très important afin de répondre aux besoins en termes d'affluence. Il est aujourd'hui un atout majeur pour avoir une application qui soit le plus disponible possible avec des performances élevées. Pour cela il est donc possible de définir des triggers afin d'upscale l'applicatif (CPU, RAM, Métriques Applicatives).
QOS
Il est important de définir les consommations de chaque POD (prévisionnelles), savoir si il serait intéressant que certains disposent d’une "request" égal a la "limit" afin d’assurer une réservation des ressources. (Guaranteed Class) L'utilisation du "Burstable" n'est pas pas une bonne pratique. Ll est vraiment nécessaire d'avoir une "limit" même si celle-ci n'est pas équivalente a la "request".
Exemple :
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
Taille des images
Il est très important de construire des images les plus légères possibles, c'est à dire utiliser uniquement les paquets nécessaires au bon fonctionnement de l'application ainsi que la meilleure image de base. C'est un gros vecteur de sécurité, de charge stockage et réseau.
Exemple d'image base Lightway : Alpine
Politiques réseau
Les "Network policies" sont par défaut en "Deny ALL". Il est donc à vous de définir les flux entrants et sortants sur les namespaces de vos projets.
ReverseProxy-->Networkpolicies-->Pods (Ingress)
Pods-->Networkpolicies-->Proxy (Egress)
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-external
spec:
podSelector:
matchLabels:
Tier: frontend
ingress:
- ports:
- port: 80