Les déploiements manuels ne sont pas sujets aux erreurs. De plus, elles consistent en un ensemble de tâches répétitives et complexes. Les équipes de développement ont peur de la complexité du déploiement d’une nouvelle version d’une application et des maux de tête que cela entraîne. Parfois, le déploiement d’une application nécessite des compétences avancées en matière de plateforme. C'est un processus fastidieux pour déboguer les problèmes de déploiement.
FluxCD vous aide à réduire l'effort dédié aux tâches manuelles et répétitives. Cela minimise également les erreurs de déploiement et les interactions humaines. Il propose des outils pour suivre et mettre à jour l'état de vos déploiements à l'aide de fichiers déclaratifs, facilitant ainsi le processus de déploiement et de débogage pour vos équipes de développement.
Cet article explore l'automatisation de vos processus de déploiement pour les transformer en processus de déploiement continu à l'aide de FluxCD , Flagger et Grafana .
Consultez le premier article pour en savoir plus sur la livraison continue d'une application :
Pratique CI/CD : un flux de travail d'intégration continue simple mais fonctionnel [Partie 1] .
Exemple GitHub : https://github.com/joan-mido-qa/continious-deployment-example
Utilisez KinD et Terraform pour configurer le cluster Kubernetes. Tout d'abord, créez le cluster et exportez la configuration Kubernetes pour définir le fournisseur Kubernetes :
$ kind create cluster --name develop $ kind export kubeconfig --name develop --kubeconfig kubeconfig
Créez un nouveau référentiel GitHub et un jeton de développeur avec les autorisations du référentiel, Terrafom en a besoin pour configurer FluxCD. Initialisez Terraform et appliquez les modifications :
$ terraform init $ terraform apply -var="github_owner=owner_name" -var="github_repository=repo_name" # Introduce your GitHub token
Une fois que Terraform a terminé le processus d'installation, FluxCD devrait être exécuté dans votre cluster KinD et un nouveau dossier nommé cluster dans votre référentiel.
Sous le capot, Terraform installe MetalLB et configure la plage IP. Vous pouvez en savoir plus sur la configuration de MetalLB dans la première partie de l'article :
resource "helm_release" "metallb" { name = "metallb" repository = "https://metallb.github.io/metallb" chart = "metallb" } data "docker_network" "kind" { name = "kind" } resource "kubectl_manifest" "kind-address-pool" { yaml_body = yamlencode({ "apiVersion" : "metallb.io/v1beta1", "kind" : "IPAddressPool", "metadata" : { "name" : "kind-address-pool" }, "spec" : { "addresses" : [replace(tolist(data.docker_network.kind.ipam_config)[0].subnet, ".0.0/16", ".255.0/24")] } }) depends_on = [helm_release.metallb] } resource "kubectl_manifest" "kind-advertisement" { yaml_body = <<YAML apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: kind-advertisement YAML depends_on = [helm_release.metallb] }
Ensuite, il installe FLuxCD Helm Chart et configure le référentiel GitHub pour utiliser FluxCD :
resource "helm_release" "flux" { repository = "https://fluxcd-community.github.io/helm-charts" chart = "flux2" name = "flux2" namespace = "flux-system" create_namespace = true version = "2.9.2" } resource "tls_private_key" "flux" { depends_on = [helm_release.flux] algorithm = "ECDSA" ecdsa_curve = "P256" } resource "github_repository_deploy_key" "flux" { depends_on = [tls_private_key.flux] title = "Flux" repository = var.github_repository key = tls_private_key.flux.public_key_openssh read_only = "false" } resource "flux_bootstrap_git" "this" { depends_on = [github_repository_deploy_key.flux] path = "clusters/develop" }
Suggestions de hook avant la validation :
FluxCD est un outil GitOps permettant de conserver un cluster Kubernetes avec les dernières modifications du contrôle de source (comme les référentiels Git). Flux automatise le déploiement du nouveau code.
Une fois Flux exécuté dans le cluster, voyons comment cela fonctionne. Nous déploierons ingress-nginx en tant que fournisseur d'entrée. Flux n'applique pas la structure des dossiers du projet. Vous pouvez le configurer comme vous le souhaitez ou suivre votre standard préféré.
Créez un dossier nommé base dans un dossier nommé infrastructure . Le dossier de base contient la configuration de l'infrastructure de base pour tous vos clusters. Ensuite, créez un dossier nommé ingress-nginx . Utilisez le nom de l'espace de noms comme nom de dossier.
--- apiVersion: v1 kind: Namespace metadata: name: ingress-ngnix --- apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmRepository metadata: name: ingress-nginx spec: interval: 2h url: https://kubernetes.github.io/ingress-nginx --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: ingress-nginx spec: interval: 15m chart: spec: chart: ingress-nginx version: 4.7.1 sourceRef: kind: HelmRepository name: ingress-nginx interval: 15m --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: ingress-ngnix resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml
Utilisez plusieurs fichiers pour définir vos objets : helmrelease.yaml , helmrepository.yaml , namespace.yaml , kustomization.yaml , etc.
La Kustomization lit et traite les ressources pour les appliquer. Enfin et surtout, vous devez créer un objet Kustomization pour synchroniser la configuration de votre cluster. Créez un fichier YAML nommé infrastructure.yaml dans le dossier cluster/cluster_name :
--- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: infra-base namespace: flux-system spec: interval: 1h retryInterval: 1m timeout: 5m sourceRef: kind: GitRepository name: flux-system path: ./infrastructure/base prune: true wait: true
Après avoir validé et transmis vos modifications à votre référentiel, Flux réconciliera l'état du cluster pour installer le Helm Chart ingress-nginx.
Flagger est un opérateur Kubernetes qui livre progressivement votre application à l'aide de déploiements bleu/vert, de versions Canary ou de tests A/B.
Vous pouvez utiliser le dossier de base pour installer votre pile dans tous vos clusters ou en utiliser un autre pour personnaliser votre installation en fonction du cluster. Par exemple, nous souhaitons installer Flagger uniquement dans le cluster de développement.
Créez un nouveau dossier en utilisant le nom de votre cluster dans le dossier d'infrastructure . Ensuite, créez un fichier nommé infrastructure.yaml dans votre cluster/cluster_name :
--- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: infra-cluster-name namespace: flux-system spec: dependsOn: - name: infra-base interval: 1h retryInterval: 1m timeout: 5m sourceRef: kind: GitRepository name: flux-system path: ./infrastructure/cluster_name prune: true
FluxCD synchronisera l'état du cluster après avoir appliqué la personnalisation de l'infra-base. Installez Flagger en créant le fichier YAML suivant dans le dossier infrastructure/cluster_name/flagger-system :
--- apiVersion: v1 kind: Namespace metadata: name: flagger-system --- apiVersion: source.toolkit.fluxcd.io/v1beta2 kind: HelmRepository metadata: name: flagger spec: interval: 1h url: https://flagger.app --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: flagger spec: interval: 1h install: crds: CreateReplace upgrade: crds: CreateReplace chart: spec: chart: flagger version: 1.xx interval: 6h sourceRef: kind: HelmRepository name: flagger --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: flagger-loadtester spec: interval: 1h chart: spec: chart: loadtester version: 0.xx interval: 6h sourceRef: kind: HelmRepository name: flagger --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: flagger-system resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml
Pour créer le pipeline de déploiement continu de l'application Podinfo , créez le fichier YAML d'installation dans le répertoire apps/cluster_name/podinfo *:*
--- apiVersion: v1 kind: Namespace metadata: name: podinfo --- apiVersion: source.toolkit.fluxcd.io/v1beta2 kind: HelmRepository metadata: name: podinfo spec: interval: 5m url: https://stefanprodan.github.io/podinfo --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: podinfo spec: releaseName: podinfo chart: spec: chart: podinfo version: 6.5.0 sourceRef: kind: HelmRepository name: podinfo interval: 50m install: remediation: retries: 3 values: ingress: enabled: true className: nginx hpa: enabled: true --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml
Vous pouvez utiliser le script Python update hosts pour mettre à jour les hôtes de votre environnement local, comme expliqué dans la première partie de l'article .
Ensuite, créez le fichier Kustomization dans le dossier cluster/cluster_name pour synchroniser vos applications :
--- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: apps namespace: flux-system spec: interval: 10m0s dependsOn: - name: infra-cluster-name sourceRef: kind: GitRepository name: flux-system path: ./apps/cluster_name prune: true wait: true timeout: 5m0s
Ensuite, nous pouvons configurer FluxCD pour mettre à jour automatiquement la version Helm Chart de l'image Podinfo. Pour configurer la mise à jour automatique de l'image, nous devons créer un référentiel d'images pour rechercher de nouvelles balises d'image, une politique de mise à jour d'image pour définir le modèle de version à mettre à jour et une mise à jour automatique d'image pour configurer le référentiel pour appliquer la modification.
--- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImageRepository metadata: name: podinfo-chart spec: image: ghcr.io/stefanprodan/charts/podinfo interval: 5m --- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImagePolicy metadata: name: podinfo-chart spec: imageRepositoryRef: name: podinfo-chart policy: semver: range: 6.xx --- apiVersion: image.toolkit.fluxcd.io/v1beta1 kind: ImageUpdateAutomation metadata: name: podinfo-chart spec: interval: 30m sourceRef: kind: GitRepository name: flux-system namespace: flux-system git: checkout: ref: branch: main commit: author: email: [email protected] name: fluxcdbot messageTemplate: 'chore(develop): update podinfo chart to {{range .Updated.Images}}{{println .}}{{end}}' push: branch: main update: path: ./apps/cluster_name/podinfo strategy: Setters --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: [...] - imagepolicy.yaml - imagerepository.yaml - imageautoupdate.yaml
Enfin, appliquez la politique de mise à jour de l'image à l'image ou à la balise que vous souhaitez mettre à jour :
apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: podinfo spec: releaseName: podinfo chart: spec: chart: podinfo version: 6.5.0 # {"$imagepolicy": "podinfo:podinfo-chart:tag"} sourceRef: kind: HelmRepository name: podinfo interval: 50m install: remediation: retries: 3
Chaque fois que Podinfo Chart dispose d'une nouvelle version de l'ordre de 6.xx, FluxCD envoie une validation au référentiel, mettant à jour la version actuelle avec la version la plus récente.
Publiez une nouvelle version de l'application à un petit sous-ensemble d'utilisateurs pour garantir que les fonctionnalités, les performances et la sécurité de l'application sont celles attendues. FluxCD met automatiquement à jour la version du graphique et la met à la disposition des utilisateurs. En cas d'échec, FluxCD restaure automatiquement la version de l'image à la précédente.
Flagger fournit progressivement la nouvelle version de l'application à un sous-ensemble d'utilisateurs et surveille l'état de l'application. Il crée un nouveau déploiement pour les nouvelles versions de l'application et redirige progressivement le trafic entrant vers le nouveau déploiement. Il favorisera le déploiement de Canary après une analyse réussie des métriques. En cas d'échec, Flagger supprime le nouveau déploiement et rétablit le flux de trafic vers l'ancien déploiement. Ce processus prétend détecter les défauts, les problèmes et les erreurs avant de fournir l'application à tous ses utilisateurs.
Tout d’abord, créez un modèle de métrique pour indiquer à Flagger quel est l’état de la candidature. Nous utilisons Prometheus pour mesurer le taux de réussite des requêtes :
--- apiVersion: flagger.app/v1beta1 kind: MetricTemplate metadata: name: podinfo-request-success-rate spec: provider: type: prometheus address: http://loki-stack-prometheus-server.loki-stack:80 query: | 100 - sum( rate( http_requests_total{ app_kubernetes_io_name="podinfo", namespace="{{ namespace }}", status!~"5.*" }[{{ interval }}] ) ) / sum( rate( http_requests_total{ app_kubernetes_io_name="podinfo", namespace="{{ namespace }}", }[{{ interval }}] ) ) * 100 --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: [...] - metrictemplate.yaml
Ensuite, définissez le processus de publication de Canary. Nous utilisons nginx comme fournisseur pour façonner le trafic entrant. Flagger propose plusieurs façons et outils pour configurer vos versions.
--- apiVersion: flagger.app/v1beta1 kind: Canary metadata: name: podinfo spec: provider: nginx targetRef: apiVersion: apps/v1 kind: Deployment name: podinfo ingressRef: apiVersion: networking.k8s.io/v1 kind: Ingress name: podinfo autoscalerRef: apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler name: podinfo progressDeadlineSeconds: 60 service: port: 9898 targetPort: 9898 analysis: interval: 10s threshold: 10 maxWeight: 50 stepWeight: 5 metrics: - name: podinfo-request-success-rate thresholdRange: min: 99 interval: 1m webhooks: - name: acceptance-test type: pre-rollout url: http://flagger-loadtester.flagger-system/ timeout: 30s metadata: type: bash cmd: curl -sd 'test' http://podinfo-canary.podinfo:9898/token | grep token - name: load-test url: http://flagger-loadtester.flagger-system/ timeout: 5s metadata: cmd: hey -z 1m -q 10 -c 2 http://podinfo-canary.podinfo:9898/healthz --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: [...] - canary.yaml
Flagger nécessite les références à votre déploiement, votre entrée et votre auto-scaler de pod. Chaque fois que Flagger détecte une nouvelle version, il intensifie le déploiement, crée un service principal et secondaire et configure nginx pour envoyer le trafic entrant au service correspondant. Utilisez les propriétés maxWeight et stepWeight pour configurer le pourcentage maximum de redirection du trafic et le pourcentage d'étape incrémentielle.
Testez en charge votre application à l’aide des hooks Flagger. Il possède plusieurs crochets. Les hooks d'acceptation vérifient l'état de préparation au déploiement de Canary et le hook de test de charge génère un trafic entrant constant.
Flagger surveillera l'état de la version Canary à l'aide de la métrique de taux de réussite prédéfinie pour décider du cas de promotion du déploiement Canary. Flagger s'attend à un taux de réussite des demandes de 99 % pour promouvoir le déploiement de Canary. Utilisez la propriété de seuil pour configurer un nombre maximum de vérifications de métriques ayant échoué avant la restauration.
Utilisez la pile Loki pour surveiller l'état des ressources du cluster à l'aide de Grafana + Loki + Prometheus. Installez la pile Loki en créant le fichier YAML suivant dans le dossier infrastructure/cluster_name/loki-stack :
--- apiVersion: v1 kind: Namespace metadata: name: loki-stack --- apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmRepository metadata: name: grafana spec: interval: 2h url: https://grafana.github.io/helm-charts --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: loki-stack spec: interval: 1h chart: spec: chart: loki-stack version: v2.9.11 sourceRef: kind: HelmRepository name: grafana interval: 1h values: grafana: enabled: true ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx hosts: - grafana.local prometheus: enabled: true nodeExporter: enabled: true --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: loki-stack resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml
L'installation de la pile Loki permet à Grafana Ingress d'accéder à Grafana, Prometheus pour collecter les métriques de votre environnement et Node Exporter pour exporter les métriques de votre nœud.
Vous pouvez utiliser le script Python update hosts pour mettre à jour les hôtes de votre environnement local, comme expliqué dans la première partie de l'article.
Connectez-vous à Grafana en utilisant le nom d'utilisateur et le mot de passe administrateur. Vous pouvez définir le mot de passe administrateur à l'aide des valeurs d'installation. Par défaut, le Chart crée un secret Kubernetes pour stocker un mot de passe aléatoire. Décrivez le secret pour obtenir la valeur du mot de passe base64 et décodez-le.
Vous pouvez importer votre tableau de bord préféré en utilisant son identifiant ou en copiant le JSON brut :
Le premier article expliquait comment fournir une application bien testée. Cet article explique comment déployer en continu un livrable et surveiller l'état du déploiement.
FluxCD et Flagger offrent plusieurs fonctionnalités pour tester, déployer et surveiller en continu l'état de votre application. Cet article en utilise certains, mais nous n'avons pas vu les fonctionnalités de webhooks et de notifications. Utilisez les fonctionnalités de notifications pour savoir quand un déploiement a échoué ou la fonctionnalité web-hooks pour promouvoir le déploiement vers un nouvel environnement ou lancer vos tests sur de nouvelles versions. Intégrez FluxCD à d’autres outils pour enrichir votre pipeline de déploiement.
Évitez les déploiements manuels. Ils sont complexes et peu sujets aux erreurs. Encouragez les équipes de développement à maintenir leurs applications, facilitant ainsi le processus de déploiement. Les déploiements automatiques réduisent les délais, la boucle de rétroaction et les coûts globaux. Les développeurs peuvent se concentrer sur ce qui compte vraiment.