Aller au contenu

Installation - Agents Alloy

Guide d'installation et d'intégration des agents Grafana Alloy dans vos applications.

Principe d'Intégration

L'agent Alloy s'ajoute à côté de votre application existante dans le même docker-compose.yml. Il collecte automatiquement les logs de tous les containers du même projet.

votre-app/
├── docker-compose.yml      # Votre app + Alloy agent
├── .env                    # Variables (incluant Loki credentials)
├── alloy/
│   └── config.alloy        # Configuration Alloy
└── src/                    # Votre code applicatif

Prérequis

  • Docker et Docker Compose installés
  • Accès réseau vers loki.monitoring.lyroh.com:443
  • Credentials Loki (demander à l'admin)

Méthode 1 : Ajout Direct au docker-compose.yml

Étape 1 : Créer le dossier de config Alloy

mkdir -p alloy

Étape 2 : Créer la configuration Alloy

# alloy/config.alloy
cat > alloy/config.alloy << 'EOF'
discovery.docker "containers" {
  host = "unix:///var/run/docker.sock"
}

discovery.relabel "docker_labels" {
  targets = discovery.docker.containers.targets

  rule {
    source_labels = ["__meta_docker_container_name"]
    regex         = "/(.*)"
    target_label  = "container"
  }

  rule {
    source_labels = ["__meta_docker_container_label_app"]
    target_label  = "app"
  }

  rule {
    source_labels = ["app"]
    regex         = ".+"
    action        = "keep"
  }
}

loki.source.docker "docker_logs" {
  host       = "unix:///var/run/docker.sock"
  targets    = discovery.relabel.docker_labels.output
  labels     = {
    "env"  = env("APP_ENV"),
    "host" = env("HOST_NAME"),
  }
  forward_to = [loki.process.pipeline.receiver]
}

loki.process "pipeline" {
  forward_to = [loki.write.loki_remote.receiver]

  stage.json {
    expressions = {
      level   = "level",
      message = "message",
    }
  }

  stage.labels {
    values = { level = "" }
  }

  stage.drop {
    expression = "^\\s*$"
  }
}

loki.write "loki_remote" {
  endpoint {
    url = env("LOKI_URL")
    basic_auth {
      username = env("LOKI_USER")
      password = env("LOKI_PASSWORD")
    }
  }
}
EOF

Étape 3 : Ajouter Alloy à votre docker-compose.yml

# Note: 'version' is obsolete in Docker Compose v2+

services:
  # ═══════════════════════════════════════════
  # VOTRE APPLICATION EXISTANTE
  # ═══════════════════════════════════════════
  app:
    build: .
    # ... votre config existante ...
    labels:
      - "app=mon-app-name"    # IMPORTANT: Ajouter ce label

  # ═══════════════════════════════════════════
  # ALLOY - Log Collection Agent
  # ═══════════════════════════════════════════
  alloy:
    image: grafana/alloy:latest
    container_name: ${COMPOSE_PROJECT_NAME:-app}-alloy
    restart: unless-stopped
    volumes:
      - ./alloy/config.alloy:/etc/alloy/config.alloy:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - alloy_data:/var/lib/alloy
    command:
      - run
      - --server.http.listen-addr=0.0.0.0:12345
      - --storage.path=/var/lib/alloy
      - /etc/alloy/config.alloy
    environment:
      - LOKI_URL=${LOKI_URL}
      - LOKI_USER=${LOKI_USER}
      - LOKI_PASSWORD=${LOKI_PASSWORD}
      - APP_ENV=${APP_ENV:-prod}
      - HOST_NAME=${HOST_NAME:-unknown}
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:12345/ready"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  alloy_data:

Étape 4 : Configurer le .env

# .env
# ... vos variables existantes ...

# Monitoring - Loki
LOKI_URL=https://loki.monitoring.lyroh.com/loki/api/v1/push
LOKI_USER=loki-push
LOKI_PASSWORD=votre_mot_de_passe_loki

# Identification
APP_ENV=prod
HOST_NAME=server-name

Étape 5 : Ajouter le label app à vos services

IMPORTANT : Chaque service dont vous voulez collecter les logs doit avoir le label app :

services:
  api:
    image: your-api
    labels:
      - "app=nestjs-backend"      # Label obligatoire
      - "service=api"             # Label optionnel

  worker:
    image: your-worker
    labels:
      - "app=nestjs-backend"      # Même app
      - "service=worker"          # Service différent

Méthode 2 : Via GitHub Actions CI/CD

Structure du Repository

your-app/
├── .github/
│   └── workflows/
│       └── deploy.yml
├── docker-compose.yml
├── docker-compose.prod.yml    # Override pour prod
├── alloy/
│   └── config.alloy
├── Dockerfile
└── src/

GitHub Actions Workflow

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

  deploy:
    needs: build
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Copy files to server
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          source: "docker-compose.yml,docker-compose.prod.yml,alloy/"
          target: "/opt/${{ github.event.repository.name }}"

      - name: Deploy on server
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          script: |
            cd /opt/${{ github.event.repository.name }}

            # Créer le .env si nécessaire
            if [ ! -f .env ]; then
              cat > .env << 'ENVEOF'
            LOKI_URL=${{ secrets.LOKI_URL }}
            LOKI_USER=${{ secrets.LOKI_USER }}
            LOKI_PASSWORD=${{ secrets.LOKI_PASSWORD }}
            APP_ENV=prod
            HOST_NAME=$(hostname)
            ENVEOF
            fi

            # Pull et redémarrer
            docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
            docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

            # Vérifier le déploiement
            sleep 10
            docker-compose ps

Secrets GitHub à Configurer

Dans votre repo GitHub : Settings > Secrets and variables > Actions

Secret Description Exemple
SERVER_HOST IP ou hostname du serveur 185.x.x.x
SERVER_USER Utilisateur SSH deploy
SERVER_SSH_KEY Clé privée SSH -----BEGIN OPENSSH...
LOKI_URL URL Loki push https://loki.monitoring.lyroh.com/loki/api/v1/push
LOKI_USER User Loki loki-push
LOKI_PASSWORD Password Loki ********

docker-compose.prod.yml (Override)

# docker-compose.prod.yml
# Note: 'version' is obsolete in Docker Compose v2+

services:
  app:
    image: ghcr.io/your-org/your-app:latest
    restart: unless-stopped
    labels:
      - "app=your-app-name"

  alloy:
    restart: unless-stopped

Vérification de l'Installation

1. Vérifier que Alloy tourne

docker-compose ps alloy
docker-compose logs -f alloy

2. Vérifier la connexion à Loki

# Doit retourner "ready"
docker-compose exec alloy wget -qO- http://localhost:12345/ready

3. Vérifier dans Grafana

Ouvrez https://grafana.monitoring.lyroh.com et exécutez :

{app="votre-app-name"}

Troubleshooting

Logs non reçus

  1. Vérifier le label app sur vos containers :

    docker inspect your-container | grep -A5 Labels
    

  2. Vérifier les credentials :

    curl -u "loki-push:PASSWORD" https://loki.monitoring.lyroh.com/ready
    

  3. Vérifier les logs Alloy :

    docker-compose logs alloy | grep -i error
    

Alloy ne démarre pas

# Vérifier la config
docker-compose exec alloy cat /etc/alloy/config.alloy

# Vérifier le socket Docker
ls -la /var/run/docker.sock