Workflow n8n

Automatisation n8n : gestion des images et notifications par email

Ce workflow n8n a pour objectif d'automatiser la gestion des images en ligne, notamment en récupérant et en organisant les tags associés à chaque image. Il est particulièrement utile pour les entreprises qui gèrent un grand nombre d'images et souhaitent maintenir une base de données organisée et à jour. Dans un contexte où la gestion des ressources numériques est cruciale, ce workflow permet de simplifier les processus de nettoyage et de notification, réduisant ainsi le temps consacré à ces tâches manuelles. Étape 1 : le flux est déclenché par un événement planifié grâce au noeud 'Scheduled Trigger'. Étape 2 : il commence par récupérer le manifeste des images à l'aide du noeud 'Fetch Manifest Digest', suivi par la récupération des tags d'images avec 'Retrieve Image Tags'. Étape 3 : les tags sont ensuite filtrés et les anciens tags sont supprimés via 'Remove Old Tags'. Étape 4 : les images sont listées et les noms extraits pour faciliter l'organisation. Étape 5 : des notifications par email sont envoyées pour informer les utilisateurs des mises à jour ou des échecs, grâce aux noeuds 'Send Notification Email' et 'Send Failure Notification Email'. Ce workflow offre une valeur ajoutée significative en réduisant les erreurs humaines, en optimisant le temps de gestion des images et en garantissant une communication efficace au sein des équipes. Tags clés : automatisation, email, images.

Catégorie: Scheduled · Tags: automatisation, email, images, n8n, gestion des ressources0

Vue d'ensemble du workflow n8n

Schéma des nœuds et connexions de ce workflow n8n, généré à partir du JSON n8n.

Détail des nœuds du workflow n8n

  • Fetch Manifest Digest

    Ce noeud effectue une requête HTTP pour récupérer le digest du manifeste.

  • Remove Old Tags

    Ce noeud envoie une requête HTTP pour supprimer les anciennes balises.

  • Retrieve Image Tags

    Ce noeud effectue une requête HTTP pour récupérer les balises d'image.

  • List Images

    Ce noeud envoie une requête HTTP pour lister les images disponibles.

  • Extract Image Names

    Ce noeud exécute un code JavaScript pour extraire les noms des images.

  • Identify Tags to Remove

    Ce noeud exécute un code JavaScript pour identifier les balises à supprimer.

  • Scheduled Trigger

    Ce noeud déclenche le workflow selon un calendrier prédéfini.

  • Send Notification Email

    Ce noeud envoie un email de notification avec les détails spécifiés.

  • Split Tags

    Ce noeud divise les balises en fonction des critères spécifiés.

  • Filter Valid Tags

    Ce noeud filtre les balises valides selon les conditions définies.

  • Fetch Manifest Digest for Blob

    Ce noeud effectue une requête HTTP pour récupérer le digest du manifeste pour un blob.

  • Update Fields

    Ce noeud met à jour les champs avec les valeurs spécifiées.

  • Group Tags by Image

    Ce noeud exécute un code JavaScript pour regrouper les balises par image.

  • Sort by Creation Date

    Ce noeud trie les éléments par date de création selon les critères spécifiés.

  • Send Failure Notification Email

    Ce noeud envoie un email de notification en cas d'échec avec les détails fournis.

  • Execute Garbage Collection

    Ce noeud exécute une commande de collecte des déchets via SSH.

Inscris-toi pour voir l'intégralité du workflow

Inscription gratuite

S'inscrire gratuitementBesoin d'aide ?
{
  "nodes": [
    {
      "id": "6b1865a7-f150-4d2b-b1f7-37c68b2173d6",
      "name": "Fetch Manifest Digest",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        920,
        -300
      ],
      "parameters": {
        "url": "={{\"https://<<your-registry-url>>/v2/\" + $json.name + \"/manifests/\" + $json.tag}}",
        "options": {
          "fullResponse": true
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "headerParametersUi": {
          "parameter": [
            {
              "name": "Accept",
              "value": "application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3c1daca9-3897-4596-b62d-db561f8cb047",
      "name": "Remove Old Tags",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        840,
        -40
      ],
      "parameters": {
        "url": "={{\"https://<<your-registry-url>>/v2/\" + $json.image + \"/manifests/\" + $json.tag.digest}}",
        "options": {},
        "requestMethod": "DELETE",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "headerParametersUi": {
          "parameter": [
            {
              "name": "Accept",
              "value": "application/vnd.docker.distribution.manifest.v2+json"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "6974749e-8c85-4334-a7e7-e964f057ed6f",
      "name": "Retrieve Image Tags",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        400,
        -300
      ],
      "parameters": {
        "url": "={{\"https://<<your-registry-url>>/v2/\" + $json[\"image\"] + \"/tags/list\"}}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "headerParametersUi": {
          "parameter": [
            {
              "name": "Accept",
              "value": "application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "30857c32-508e-4f95-8e26-c9f2fc84e074",
      "name": "List Images",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        40,
        -300
      ],
      "parameters": {
        "url": "https://<<your-registry-url>>/v2/_catalog",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth"
      },
      "typeVersion": 2
    },
    {
      "id": "c5965a6a-28e6-4217-a846-a849de153430",
      "name": "Extract Image Names",
      "type": "n8n-nodes-base.code",
      "position": [
        220,
        -300
      ],
      "parameters": {
        "jsCode": "const images = items[0].json.repositories;\nreturn images.map(image => ({ json: { image } }));"
      },
      "typeVersion": 2
    },
    {
      "id": "b13eb6e5-1a16-4992-b0bd-9b228559fecf",
      "name": "Identify Tags to Remove",
      "type": "n8n-nodes-base.code",
      "position": [
        600,
        -40
      ],
      "parameters": {
        "jsCode": "const result = [];\n\nfor (const item of items) {\n  const tags = item.json.tags;\n  if (tags) {\n    const latestTag = tags.includes('latest') ? 'latest' : null;\n    const sortedTags = tags.filter(tag => tag !== 'latest')\n                            .sort((a, b) => new Date(b.created) - new Date(a.created));\n    const keepTags = sortedTags.slice(0, 10);\n    if (latestTag) keepTags.push('latest');\n    const deleteTags = sortedTags.slice(10);\n    result.push(...deleteTags.map(tag => ({ json: { image: item.json.name, tag } })));\n  }\n}\n\nreturn result;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "da15ae49-09ee-4658-86a5-9b0a2180c637",
      "name": "Scheduled Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -140,
        -300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 1
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "bcc347be-5520-46c0-aac9-0b14ddd8b184",
      "name": "Send Notification Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        840,
        180
      ],
      "webhookId": "47f852c3-7136-4e6d-92f6-47322dbba5da",
      "parameters": {
        "text": "=Image : {{ $json.image }}\nTag : {{ $json.tag.tag }}\n\nRemoved",
        "options": {},
        "subject": "Docker Registry Cleaner Notification",
        "toEmail": "to@example.com",
        "fromEmail": "from@example.com",
        "emailFormat": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "2c3770ef-cb4c-4007-8897-f4eb7ad3b7cf",
      "name": "Split Tags",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        580,
        -300
      ],
      "parameters": {
        "include": "selectedOtherFields",
        "options": {
          "destinationFieldName": "tag"
        },
        "fieldToSplitOut": "tags",
        "fieldsToInclude": "name"
      },
      "typeVersion": 1
    },
    {
      "id": "4fffa947-02cf-4608-acab-8284250cf622",
      "name": "Filter Valid Tags",
      "type": "n8n-nodes-base.filter",
      "position": [
        740,
        -300
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "bb56b84e-e7cb-4867-93f8-ac40c71bde4f",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.tag }}",
              "rightValue": ""
            },
            {
              "id": "acd8e00c-5fa0-4c62-ba96-9e6f456f7703",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.name }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c023ba14-d12d-497c-9b30-97db04a34c1b",
      "name": "Fetch Manifest Digest for Blob",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -120,
        -40
      ],
      "parameters": {
        "url": "={{\"https://<<your-registry-url>>/v2/\" + $('Filter Valid Tags').item.json.name + \"/blobs/\" + $json.body.config.digest}}",
        "options": {
          "fullResponse": false
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "headerParametersUi": {
          "parameter": [
            {
              "name": "Accept",
              "value": "application/vnd.docker.distribution.manifest.v2+json"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "f054b91e-abd4-4854-9bfa-e4a2b70f7e2c",
      "name": "Update Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        60,
        -40
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c970bdb8-ddbf-486b-a716-c66274a248a7",
              "name": "name",
              "type": "string",
              "value": "={{ $('Filter Valid Tags').item.json.name }}"
            },
            {
              "id": "7ce79761-6557-413c-a9a6-5d1ca564a3df",
              "name": "tag",
              "type": "string",
              "value": "={{ $('Filter Valid Tags').item.json.tag }}"
            },
            {
              "id": "45948a25-d35c-4e3f-9556-3d52a1a89f80",
              "name": "created",
              "type": "string",
              "value": "={{ $json.created }}"
            },
            {
              "id": "c73a14ad-91f6-477f-b4c3-037db319b9ee",
              "name": "digest",
              "type": "string",
              "value": "={{ $('Fetch Manifest Digest').item.json.headers['docker-content-digest'] }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "54405505-8445-491a-8f5d-232da8c842d2",
      "name": "Group Tags by Image",
      "type": "n8n-nodes-base.code",
      "position": [
        420,
        -40
      ],
      "parameters": {
        "jsCode": "const groupedData = items.reduce((acc, item) => {\n  const name = item.json.name;\n  if (!acc[name]) {\n    acc[name] = [];\n  }\n  acc[name].push({\n    tag: item.json.tag,\n    created: item.json.created,\n    digest: item.json.digest\n  });\n  return acc;\n}, {});\n\nreturn Object.keys(groupedData).map(name => ({\n  json: { name, tags: groupedData[name] }\n}));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "980aab86-44cd-47d5-b3b7-42cbae26eb09",
      "name": "Sort by Creation Date",
      "type": "n8n-nodes-base.sort",
      "position": [
        240,
        -40
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "order": "descending",
              "fieldName": "created"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0561efb9-4903-4bec-bc1a-8131e5f5de67",
      "name": "Send Failure Notification Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1120,
        80
      ],
      "webhookId": "47f852c3-7136-4e6d-92f6-47322dbba5da",
      "parameters": {
        "text": "=Image : {{ $json.image }}\nTag : {{ $json.tag.tag }}\n\nFailed",
        "options": {},
        "subject": "[FAIL] Docker Registry Cleaner Notification",
        "toEmail": "to@example.com",
        "fromEmail": "from@example.com",
        "emailFormat": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "eaa28914-351c-4934-ba1c-0d39faf67ef3",
      "name": "Execute Garbage Collection",
      "type": "n8n-nodes-base.ssh",
      "position": [
        1120,
        -100
      ],
      "parameters": {
        "cwd": "/opt/services/",
        "command": "docker compose exec -it -u root registry bin/registry garbage-collect --delete-untagged /etc/docker/registry/config.yml",
        "authentication": "privateKey"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "Split Tags": {
      "main": [
        [
          {
            "node": "Filter Valid Tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Images": {
      "main": [
        [
          {
            "node": "Extract Image Names",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Fields": {
      "main": [
        [
          {
            "node": "Sort by Creation Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Old Tags": {
      "main": [
        [
          {
            "node": "Execute Garbage Collection",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Failure Notification Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Valid Tags": {
      "main": [
        [
          {
            "node": "Fetch Manifest Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scheduled Trigger": {
      "main": [
        [
          {
            "node": "List Images",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Image Names": {
      "main": [
        [
          {
            "node": "Retrieve Image Tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Group Tags by Image": {
      "main": [
        [
          {
            "node": "Identify Tags to Remove",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Retrieve Image Tags": {
      "main": [
        [
          {
            "node": "Split Tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Manifest Digest": {
      "main": [
        [
          {
            "node": "Fetch Manifest Digest for Blob",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort by Creation Date": {
      "main": [
        [
          {
            "node": "Group Tags by Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identify Tags to Remove": {
      "main": [
        [
          {
            "node": "Remove Old Tags",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Notification Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Manifest Digest for Blob": {
      "main": [
        [
          {
            "node": "Update Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Pour qui est ce workflow ?

Ce workflow s'adresse aux équipes marketing et aux gestionnaires de contenu au sein des entreprises de taille moyenne à grande, qui cherchent à automatiser la gestion de leurs ressources numériques. Les utilisateurs doivent avoir un niveau technique intermédiaire pour adapter le workflow à leurs besoins spécifiques.

Problème résolu

Ce workflow résout le problème de la gestion manuelle des images et des tags associés, qui peut être chronophage et sujet à des erreurs. En automatisant ce processus, les utilisateurs peuvent réduire le temps passé à organiser les images et à envoyer des notifications, tout en minimisant les risques d'erreurs humaines. À la suite de la mise en place de ce workflow, les utilisateurs bénéficient d'une base de données d'images propre et bien structurée, ainsi que d'une communication proactive sur les mises à jour.

Étapes du workflow

Étape 1 : le workflow est déclenché par un événement planifié. Étape 2 : il récupère le manifeste des images via 'Fetch Manifest Digest'. Étape 3 : les tags d'images sont récupérés avec 'Retrieve Image Tags'. Étape 4 : les anciens tags sont supprimés grâce à 'Remove Old Tags'. Étape 5 : les images sont listées et les noms extraits avec 'Extract Image Names'. Étape 6 : les tags sont filtrés pour ne conserver que ceux valides. Étape 7 : les champs sont mis à jour avec 'Update Fields'. Étape 8 : des notifications par email sont envoyées pour informer des succès ou des échecs.

Guide de personnalisation du workflow n8n

Pour personnaliser ce workflow, vous pouvez modifier l'URL des requêtes HTTP dans les noeuds 'Fetch Manifest Digest', 'Retrieve Image Tags', et 'Remove Old Tags' selon vos besoins. Il est également possible d'ajuster les paramètres d'email dans les noeuds 'Send Notification Email' et 'Send Failure Notification Email' pour cibler les bonnes personnes. Pensez à adapter les conditions dans le noeud 'Filter Valid Tags' pour mieux correspondre à vos critères de gestion des tags. Enfin, vous pouvez ajouter d'autres outils ou services en utilisant des noeuds supplémentaires pour enrichir le workflow.