Introducción

Gestionar logs en entornos Kubernetes distribuidos puede convertirse en un dolor de cabeza cuando los pods se escalan dinámicamente, los nodos fallan o los desarrolladores necesitan depurar problemas en tiempo real. Loki, el sistema de logs diseñado por Grafana Labs, ofrece una alternativa ligera y eficiente a soluciones tradicionales como ELK, especialmente cuando trabajas con clusters en AWS EKS donde el costo y la escalabilidad son críticos.

En esta guía, implementaremos un stack completo de logs en EKS usando:

  • Loki como backend de logs optimizado para Kubernetes
  • Grafana para visualización y dashboards
  • Promtail como agente de recolección
  • IAM para permisos seguros en AWS
  • S3 como almacenamiento persistente opcional

El resultado será un sistema capaz de manejar miles de logs por segundo con un footprint mínimo en tu cluster.

Qué es y para qué sirve

Loki: el «Prometheus de los logs»

Loki no indexa el contenido completo de los logs como hace Elasticsearch. En cambio, usa etiquetas (labels) similares a Prometheus para agrupar streams de logs y solo indexa esas etiquetas más timestamps. Esto lo hace 10x más económico en almacenamiento que soluciones tradicionales.

Casos de uso ideales:
  • Clusters Kubernetes con alta rotación de pods
  • Aplicaciones con logs estructurados (JSON, key=value)
  • Entornos donde el costo de almacenamiento es crítico
  • Equipos que ya usan Grafana para métricas (integración nativa)

Arquitectura propuesta

graph TD
    A[Pods en EKS] -->|Logs| B[Promtail]
    B --> C[Loki Distributor]
    C --> D[Loki Ingester]
    D --> E[Loki Querier]
    E --> F[Grafana]
    E --> G[S3 (opcional)]
    H[AWS IAM] -->|Permisos| B & C & D
Componentes clave:
ComponenteRolRequisitos mínimos
PromtailAgente que recolecta logs de pods1 vCPU, 256MB RAM
Loki DistributorBalancea carga de logs entrante2 vCPU, 2GB RAM
Loki IngesterEscribe logs a almacenamiento2 vCPU, 4GB RAM
Loki QuerierEjecuta consultas2 vCPU, 2GB RAM
GrafanaVisualización y dashboards1 vCPU, 1GB RAM
## Prerequisitos

Versiones probadas

ComponenteVersión mínimaComando de verificación
eksctl0.169+BLOCK24
kubectl1.28+BLOCK25
Helm3.14+BLOCK26
AWS CLI2.15+BLOCK27
Loki3.0.0BLOCK28
Grafana11.0.0BLOCK29
### Permisos necesarios
  1. Cluster EKS:
– Rol IAM con permisos AmazonEKSClusterPolicy

– Nodos con rol IAM con permisos:

     {
       "Version": "2012-10-17",
       "Statement": [
         {
           "Effect": "Allow",
           "Action": [
             "logs:CreateLogGroup",
             "logs:CreateLogStream",
             "logs:PutLogEvents",
             "logs:DescribeLogStreams"
           ],
           "Resource": "*"
         }
       ]
     }
     
  1. Accesos:
– Cuenta AWS con permisos para crear roles IAM y políticas

– Acceso a kubectl con contexto configurado para tu cluster

Espacio en disco

  • Almacenamiento local (default): ~5GB para 30 días de logs (ajustable)
  • Con S3: Costo variable según retención (recomendado para producción)

Guía paso a paso

1. Configurar permisos IAM para Loki

Creamos una política dedicada para Loki que solo acceda a los buckets necesarios:

# Crear política IAM
cat <<EOF > loki-storage-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:DeleteObject"
      ],
      "Resource": [
        "arn:aws:s3:::tu-bucket-de-logs/*",
        "arn:aws:s3:::tu-bucket-de-logs"
      ]
    }
  ]
}
EOF

aws iam create-policy \
  --policy-name EKSLokiStoragePolicy \
  --policy-document file://loki-storage-policy.json
Resultado esperado: Política creada con ARN similar a: arn:aws:iam::123456789012:policy/EKSLokiStoragePolicy
# Crear rol IAM para Loki (usando IRSA)
eksctl create iamserviceaccount \
  --name loki \
  --namespace monitoring \
  --cluster tu-cluster-eks \
  --attach-policy-arn arn:aws:iam::123456789012:policy/EKSLokiStoragePolicy \
  --approve \
  --override-existing-serviceaccounts
Verificación:
kubectl get sa -n monitoring loki -o yaml | grep annotations -A 2

Debería incluir:

annotations:
  eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/eksctl-tu-cluster-eks-addon-iamserviceaccount-moni-Role1-XXXX

2. Instalar Loki con Helm

Agregamos el repositorio de Grafana y configuramos Loki para usar almacenamiento local (cambiar a S3 en producción):

helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

cat <<EOF > loki-values.yaml
loki:
  auth_enabled: false
  storage:
    type: filesystem
  compactor:
    retention_enabled: true
  limits_config:
    retention_period: 30d
    enforce_metric_name: false
    reject_old_samples: true
    reject_old_samples_max_age: 168h
  serviceAccount:
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/eksctl-tu-cluster-eks-addon-iamserviceaccount-moni-Role1-XXXX
  podLabels:
    app: loki
EOF

helm install loki grafana/loki \
  --namespace monitoring \
  --values loki-values.yaml \
  --version 6.6.0
Verificación de pods:
kubectl get pods -n monitoring -l app.kubernetes.io/instance=loki

Deberías ver:

NAME                     READY   STATUS    RESTARTS   AGE
loki-0                  1/1     Running   0          2m
loki-1                  1/1     Running   0          2m

3. Instalar Promtail como DaemonSet

Promtail debe correr en cada nodo del cluster para recolectar logs de los pods:

cat <<EOF > promtail-values.yaml
config:
  clients:
    - url: http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push
  snippets:
    pipeline_stages:
      - docker: {}
serviceAccount:
  create: true
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/eksctl-tu-cluster-eks-addon-iamserviceaccount-moni-Role1-XXXX
EOF

helm install promtail grafana/promtail \
  --namespace monitoring \
  --values promtail-values.yaml \
  --version 6.15.0 \
  --set config.limits.kind=DaemonSet
Verificación:
kubectl get pods -n monitoring -l app.kubernetes.io/instance=promtail

Deberías ver un pod por nodo:

NAME             READY   STATUS    RESTARTS   AGE
promtail-abc12   1/1     Running   0          1m
promtail-xyz34   1/1     Running   0          1m
Logs de muestra recolectados:
# Obtener logs de un pod específico (ejemplo con nginx)
kubectl logs -n default mi-pod-123 -c nginx --tail=100 | head -n 20

4. Desplegar Grafana con autenticación básica

Configuramos Grafana para que acceda a Loki como datasource:

cat <<EOF > grafana-values.yaml
service:
  type: LoadBalancer
ingress:
  enabled: true
  hosts:
    - grafana.tudominio.com
datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
      - name: Loki
        type: loki
        url: http://loki.monitoring.svc.cluster.local:3100
        access: proxy
admin:
  existingSecret: grafana-admin
  userKey: admin-user
  passwordKey: admin-password
persistence:
  enabled: true
  size: 10Gi
EOF

kubectl create secret generic grafana-admin \
  --namespace monitoring \
  --from-literal=admin-user=admin \
  --from-literal=admin-password=$(openssl rand -base64 16)

helm install grafana grafana/grafana \
  --namespace monitoring \
  --values grafana-values.yaml \
  --version 8.0.0
Obtener la IP del LoadBalancer:
kubectl get svc -n monitoring grafana -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
Acceder a Grafana:
  1. Navega a http://<LOAD_BALANCER_IP>
  2. Inicia sesión con usuario admin y contraseña generada
  3. Ve a Configuration > Data Sources y verifica que Loki aparezca con estado «OK»

5. Validar el flujo completo

Ejemplo práctico:
  1. Deploy una aplicación de ejemplo:
   kubectl create deployment nginx --image=nginx:latest -n default
   kubectl expose deployment nginx --port=80 -n default
   
  1. Genera logs:
   kubectl exec -n default -it nginx-7c7d9fbd7-abc12 -- bash -c "echo 'Hola desde $(hostname)' >> /var/log/nginx/access.log"
   
  1. En Grafana:
– Ve a Explore

– Selecciona datasource «Loki»

– Ejecuta consulta:

     {pod="nginx-*"}
     

– Deberías ver los logs generados

6. (Opcional) Configurar almacenamiento en S3

Para entornos de producción, recomendamos usar S3 como almacenamiento duradero:

# Actualizar valores de Loki
cat <<EOF >> loki-values.yaml
loki:
  storage:
    type: s3
    s3:
      s3: http://minio.minio.svc.cluster.local:9000
      bucketnames: tu-bucket-de-logs
      region: us-east-1
      access_key_id: ${S3_ACCESS_KEY}
      secret_access_key: ${S3_SECRET_KEY}
      s3forcepathstyle: true
EOF

helm upgrade loki grafana/loki \
  --namespace monitoring \
  --values loki-values.yaml \
  --version 6.6.0
Nota: Para AWS S3 nativo, usa:
loki:
  storage:
    type: aws
    aws:
      s3: s3://tu-bucket-de-logs
      region: us-east-1

7. Configurar retención y alertas

Retención de logs (30 días por defecto):
# En loki-values.yaml
loki:
  limits_config:
    retention_period: 30d
    retention_stream:
      - selector: '{namespace="default"}'
        priority: 1
        period: 7d
Alertas en Grafana:
  1. Ve a Alerting > Alert Rules
  2. Crea una alerta para logs de error:
   {job="varlogs", level="error"} |~ `error`
   
  1. Configura notificaciones a Slack, PagerDuty o email

Consideraciones y buenas prácticas

Limitaciones conocidas

  1. Rendimiento:
– Loki escala bien hasta ~50K logs/segundo por instancia

– Para cargas mayores, escala horizontalmente los ingesters (agrega más pods)

Solución: Monitorea loki_distributor_received_lines_total y ajusta réplicas

  1. Almacenamiento:
Filesystem: No es tolerante a fallos de nodo (usa S3 en producción)

S3: Requiere configuración de IAM correcta (evita usar credenciales de usuario)

Tamaño de chunks: Por defecto 150MB. Ajusta con:

     loki:
       ingester:
         chunk_encoding: v4
         chunk_target_size: 104857600  # 100MB
     

Alternativas a considerar

SoluciónCaso de usoCosto mensual (1TB)
Loki (S3)Startups/equipos pequeños~$5-10
Amazon OpenSearchCompliance/analítica avanzada~$50-200
ELKEquipos con experiencia en Elastic~$100+
DatadogEquipos que ya lo usan~$300+
### Seguridad
  1. Autenticación:
– Habilita auth_enabled: true en Loki y usa IAM o OIDC

– Para Grafana, configura autenticación multifactor (MFA)

  1. Red:
– Usa Network Policies para restringir acceso a los servicios:
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
       name: allow-loki
       namespace: monitoring
     spec:
       podSelector:
         matchLabels:
           app: loki
       ingress:
       - from:
         - namespaceSelector:
             matchLabels:
               name: default
         ports:
         - protocol: TCP
           port: 3100
     
  1. Monitoreo de Loki:
– Configura dashboards para monitorear:

loki_request_duration_seconds

loki_distributor_received_lines_total

loki_ingester_chunks_created_total

Conclusión

Has implementado un stack de logs escalable, económico y fácil de mantener en AWS EKS usando Loki y Grafana. Este setup es ideal para:

  • Equipos DevOps que necesitan visibilidad en tiempo real
  • Aplicaciones con logs estructurados en Kubernetes
  • Entornos donde el costo de almacenamiento es una prioridad
Próximos pasos recomendados:
  1. Configurar dashboards predefinidos para tus aplicaciones
  2. Implementar políticas de retención por namespace
  3. Integrar con herramientas de ticketing (Jira, ServiceNow) para correlacionar logs con incidentes
  4. Monitorear métricas de Loki con Prometheus para ajustar recursos

Recuerda que Loki no es una solución «todo en uno» como ELK. Su mayor fortaleza es su simplicidad y bajo costo en entornos Kubernetes. Si necesitas capacidades avanzadas de búsqueda de texto completo o análisis de logs no estructurados, considera complementarlo con herramientas como Amazon OpenSearch o mantener un cluster secundario de ELK.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *