Las implementaciones manuales no son propensas a errores. Además, consisten en un montón de tareas repetitivas y complejas. Los equipos de desarrollo temen la complejidad de implementar una nueva versión de una aplicación y los dolores de cabeza que conlleva. A veces, implementar una aplicación requiere habilidades avanzadas en la plataforma. Es un proceso tedioso para depurar problemas de implementación.
FluxCD te ayuda a reducir el esfuerzo dedicado a tareas manuales y repetitivas. También minimiza los errores de implementación y las interacciones humanas. Ofrece herramientas para rastrear y actualizar el estado de sus implementaciones mediante archivos declarativos, lo que facilita el proceso de implementación y depuración para sus equipos de desarrollo.
Este artículo explora la automatización de sus procesos de implementación para transformarlos en procesos de implementación continua utilizando FluxCD , Flagger y Grafana .
Consulte el primer artículo para obtener más información sobre cómo entregar continuamente una aplicación:
Práctica de CI/CD: un flujo de trabajo de integración continua simple pero funcional [Parte 1] .
Ejemplo de GitHub: https://github.com/joan-mido-qa/continious-deployment-example
Utilice KinD y Terraform para configurar el clúster de Kubernetes. En primer lugar, cree el clúster y exporte la configuración de Kubernetes para configurar el proveedor de Kubernetes:
$ kind create cluster --name develop $ kind export kubeconfig --name develop --kubeconfig kubeconfig
Cree un nuevo repositorio de GitHub y un token de desarrollador con permisos de repositorio, Terrafom lo requiere para configurar FluxCD. Inicialice Terraform y aplique los cambios:
$ terraform init $ terraform apply -var="github_owner=owner_name" -var="github_repository=repo_name" # Introduce your GitHub token
Una vez que Terraform finalice el proceso de instalación, debería tener FluxCD ejecutándose en su clúster KinD y una nueva carpeta llamada clúster en su repositorio.
Debajo del capó, Terraform instala MetalLB y configura el rango IP. Puedes leer más sobre la configuración de MetalLB en la primera parte del artículo :
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] }
Luego, instala FLuxCD Helm Chart y configura el repositorio de GitHub para usar 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" }
Sugerencias de gancho previo a la confirmación:
FluxCD es una herramienta GitOps para mantener un clúster de Kubernetes con los últimos cambios en el control de fuente (como los repositorios de Git). Flux automatiza la implementación de código nuevo.
Una vez que Flux se esté ejecutando en el clúster, veamos cómo funciona. Implementaremos ingress-nginx como proveedor de entrada. Flux no aplica la estructura de carpetas del proyecto. Puedes configurarlo como desees o seguir tu estándar preferido.
Cree una carpeta llamada base dentro de una carpeta llamada infraestructura . La carpeta base tiene la configuración de infraestructura básica para todos sus clústeres. A continuación, cree una carpeta llamada ingress-nginx . Utilice el nombre del espacio de nombres como nombre de la carpeta.
--- 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
Utilice varios archivos para definir sus objetos: helmrelease.yaml , helmrepository.yaml , namespace.yaml , kustomization.yaml , etc.
La Kustomización lee y procesa los recursos para aplicarlos. Por último, pero no menos importante, debe crear un objeto de personalización para sincronizar la configuración de su clúster. Cree un archivo YAML llamado infraestructura.yaml dentro de la carpeta 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
Después de confirmar y enviar sus cambios a su repositorio, Flux conciliará el estado del clúster para instalar ingress-nginx Helm Chart.
Flagger es un operador de Kubernetes que entrega progresivamente su aplicación mediante implementaciones blue/green, canary release o pruebas A/B.
Puede usar la carpeta base para instalar su pila en todos sus clústeres o usar una diferente para personalizar su instalación según el clúster. Por ejemplo, queremos instalar Flagger sólo en el clúster de desarrollo.
Cree una nueva carpeta usando el nombre de su clúster dentro de la carpeta de infraestructura . Luego, cree un archivo llamado i nfrastructure.yaml en su 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 sincronizará el estado del clúster después de aplicar la personalización de la infraestructura. Instale Flagger, creando el siguiente archivo YAML dentro de la carpeta infraestructura/nombre_clúster/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
Para crear la canalización de implementación continua de la aplicación Podinfo , cree el archivo YAML de instalación en 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
Puede utilizar el script Python de actualización de hosts para actualizar los hosts de su entorno local, como se explica en la primera parte del artículo .
Luego, cree el archivo de personalización en la carpeta cluster/cluster_name para sincronizar sus aplicaciones:
--- 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
A continuación, podemos configurar FluxCD para que actualice automáticamente la versión de Helm Chart de la imagen Podinfo. Para configurar la actualización automática de imágenes, necesitamos crear un repositorio de imágenes para buscar nuevas etiquetas de imágenes, una política de actualización de imágenes para definir el patrón de versión a actualizar y una actualización automática de imágenes para configurar el repositorio para impulsar el cambio.
--- 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
Finalmente, aplica la política de actualización de imágenes a la imagen o etiqueta que deseas actualizar:
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
Siempre que Podinfo Chart tenga una nueva versión en el rango de 6.xx, FluxCD enviará una confirmación al repositorio, actualizando la versión actual con la más nueva.
Lanzar una nueva versión de la aplicación para un pequeño subconjunto de usuarios para garantizar que la funcionalidad, el rendimiento y la seguridad de la aplicación sean los esperados. FluxCD actualiza automáticamente la versión de Chart y la pone a disposición de los usuarios. En caso de falla, FluxCD revierte automáticamente la versión de la imagen a la anterior.
Flagger entrega progresivamente la nueva versión de la aplicación a un subconjunto de usuarios y monitorea el estado de la aplicación. Crea una nueva implementación para las nuevas versiones de la aplicación y redirige progresivamente el tráfico entrante a la nueva implementación. Impulsará el despliegue canario tras un análisis exitoso de las métricas. En caso de falla, Flagger elimina la nueva implementación y restablece el flujo de tráfico hacia la implementación anterior. Este proceso pretende detectar defectos, problemas y errores antes de entregar la aplicación a todos sus usuarios.
Primero, cree una plantilla de métricas para que Flagger sepa cuál es el estado de la solicitud. Usamos Prometheus para medir la tasa de éxito de la solicitud:
--- 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
Luego, defina el proceso de liberación del canario. Usamos nginx como proveedor para dar forma al tráfico entrante. Flagger ofrece múltiples formas y herramientas para configurar sus lanzamientos.
--- 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 requiere referencias a su implementación, ingreso y escalador automático de pod. Cada vez que Flagger detecta una nueva versión, ampliará la implementación, creará un servicio primario y secundario y configurará nginx para enviar el tráfico entrante al servicio correspondiente. Utilice las propiedades maxWeight y stepWeight para configurar el porcentaje máximo de redirección de tráfico y el porcentaje de pasos incrementales.
Pruebe la carga de su aplicación utilizando ganchos Flagger. Tiene múltiples ganchos. Los ganchos de aceptación verifican la preparación del despliegue canary y el gancho de prueba de carga genera tráfico entrante constante.
Flagger monitoreará el estado de la versión canary utilizando la métrica de tasa de éxito predefinida para decidir el caso de promoción de implementación canary. Flagger espera una tasa de éxito de las solicitudes del 99 % para promover la implementación canary. Utilice la propiedad de umbral para configurar una cantidad máxima de comprobaciones de métricas fallidas antes de la reversión.
Utilice la pila de Loki para monitorear el estado de los recursos del clúster usando Grafana + Loki + Prometheus. Instale la pila de Loki creando el siguiente archivo YAML dentro de la carpeta infraestructura/nombre_clúster/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
La instalación de la pila de Loki permite que Grafana Ingress acceda a Grafana, Prometheus para recopilar las métricas de su entorno y Node Exporter para exportar las métricas de su nodo.
Puede utilizar el script Python de actualización de hosts para actualizar los hosts de su entorno local, como se explica en la primera parte del artículo.
Inicie sesión en Grafana con el nombre de usuario y la contraseña de administrador. Puede definir la contraseña de administrador utilizando los valores de instalación. De forma predeterminada, Chart crea un secreto de Kubernetes para almacenar una contraseña aleatoria. Describe el secreto para obtener el valor de la contraseña base64 y decodificarlo.
Puede importar su panel favorito usando su ID o copiando el JSON sin formato:
El primer artículo exploró cómo entregar una aplicación bien probada. Este artículo explora cómo implementar continuamente un entregable y monitorear el estado de la implementación.
FluxCD y Flagger ofrecen múltiples funciones para probar, implementar y monitorear continuamente el estado de su aplicación. Este artículo utiliza algunos de ellos, pero no vimos las funciones de webhooks ni notificaciones. Utilice las funciones de notificaciones para saber cuándo falló una implementación o la función de web-hooks para promover la implementación en un nuevo entorno o iniciar sus pruebas con nuevas versiones. Integre FluxCD junto con otras herramientas para enriquecer su proceso de implementación.
Evite implementaciones manuales. Son complejos y no propensos a errores. Incentivar a los equipos de desarrollo a mantener sus aplicaciones, facilitando el proceso de implementación. Las implementaciones automáticas reducen el tiempo de entrega, el ciclo de retroalimentación y los costos generales. Los desarrolladores pueden centrarse en lo que realmente importa.