logo Ludovic Arhiman
prj · homelab

Automatiser le déploiement d'un serveur GNS3 avec une pipeline CI/CD sur GNS3

Mise en place d'une pipeline CI/CD pour déployer GNS3 au sein d'un serveur GNS3.

1 mai 2026 9 min
Automatiser le déploiement d'un serveur GNS3 avec une pipeline CI/CD sur GNS3

Pendant mes études, j'ai eu besoin de déployer des VMs GNS3 sur mon cluster Proxmox. Pour rendre ce processus plus efficace, j'ai mis en place une solution complète d'automatisation qui utilise plusieurs outils DevOps modernes :

  • Packer pour la création d'images
  • Terraform pour le provisionnement d'infrastructure
  • Ansible pour l'installation et la configuration des services
  • Infisical pour la gestion des secrets
  • GitLab CI/CD pour l'automatisation

Ce qui m'a particulièrement plu dans cette approche, c'est que tout est automatisé :

  • L'image de base est créée automatiquement avec ma configuration (pas besoin de télécharger une ISO d'Ubuntu, de l'installer et de la configurer)
  • Le déploiement se fait en un clic grâce à la pipeline CI/CD
  • Les secrets sont gérés de manière sécurisée et centralisée
  • La configuration réseau est flexible et adaptable selon les besoins
  • Le tout est reproductible à l'identique

Rappel : GNS3 est un logiciel libre permettant l'émulation ou la simulation de réseaux informatiques.

La stack technique en détail

1. Packer : Création du template VM

Packer nous permet de créer une image VM standardisée qui servira de base pour notre serveur GNS3.

J'ai configuré ma template avec ces spécifications :

  • CPU : 10 cœurs (nécessaire pour la virtualisation imbriquée)
  • RAM : 48 GB (pour gérer plusieurs machines virtuelles)
  • Disque : 400 GB (stockage des images et machines virtuelles)
  • OS : Ubuntu 24.04 (Noble)
  • Réseau : Configuration réseau précise
    • VLAN : 10
      • Adresse IP : 10.10.10.249/24 (permet de fonctionner avec le reverse proxy / FQDN déjà déployé)

L'objectif est simple : une fois la VM déployée, je peux y accéder soit :

Ces deux paramètres ont déjà été configurés sur le reverse proxy (Traefik) et le DNS (PowerDNS).

Configuration existante :
Dans PowerDNS, nous avons les enregistrements DNS suivants :

  • gns3.reverse9.xyz: A: 10.10.10.249/24
  • webui.gns3.reverse9.xyz : CNAME : traefik.reverse9.xyz : A: 10.10.10.231

Dans Traefik, une configuration permet la redirection suivante :

Ce qui donne le schéma suivant :

Au lancement de la pipeline CI/CD, GitLab utilise le runner installé sur la VM "Provisionner" (où sont installés tous les outils) comme intermédiaire pour piloter les différents outils. Le processus se déroule comme suit :

  1. Le runner utilise Packer pour créer le template sur le cluster Proxmox
  2. Terraform clone ce template pour créer une nouvelle VM et la configure (réseau, utilisateur, clé SSH, etc.)

Ansible installe Docker et GNS3 server à l'aide de deux playbooks dédiés

Schéma du pipeline CI/CD : Packer construit le template, Terraform provisionne la VM, Ansible installe Docker et GNS3 server

Note : Une installation préalable de Docker est nécessaire, car une erreur survient lors de l'installation de GNS3 via Ansible à l'aide du script fourni, ce qui n'apparaît pas lors du lancement manuel du même script.

Configuration Packer détaillée

hcl
packer {
  required_plugins {
    proxmox = {
      version = "~ 1"
      source  = "github.com/hashicorp/proxmox"
    }
  }
}

source "proxmox-iso" "ubuntu-server-noble" {
  # Configuration Proxmox
  node                 = "pve"
  vm_id                = "555"
  vm_name              = "gns3-template"
  template_description = "GNS3VM Template from packer for Terraform"

  # Configuration matérielle
  cores   = "10"
  memory  = "49152"  # 48 GB
  disks {
    disk_size    = "400G"
    format       = "raw"
    storage_pool = "SSDK"
    type         = "virtio"
  }

  # Configuration réseau
  network_adapters {
    model    = "virtio"
    bridge   = "vmbr0"
    firewall = "false"
  }

  # Configuration Cloud-Init
  cloud_init              = true
  cloud_init_storage_pool = "local"
}

Cette configuration définit :

  • Les plugins requis pour Proxmox
  • Les spécifications matérielles de la VM
  • La configuration réseau
  • L'activation de Cloud-Init pour la configuration post-déploiement

Configuration Cloud-Init pour Packer

yaml
#cloud-config
fqdn: gns3.reverse9.xyz
hostname: gns3vm
preserve_hostname: true
autoinstall:
  version: 1
  locale: en_US
  keyboard:
    layout: fr
  ssh:
    install-server: true
    allow-pw: true
    disable_root: true
    ssh_quiet_keygen: true
    allow_public_ssh_keys: true
  packages:
    - qemu-guest-agent
    - sudo
  storage:
    layout:
      name: direct
    swap:
      size: 0
  user-data:
    package_upgrade: false
    timezone: Indian/Reunion
    users:
      - name: admin
        groups: [adm, sudo]
        lock-passwd: false
        sudo: ALL=(ALL) NOPASSWD:ALL
        shell: /bin/bash
        ssh_authorized_keys:
           - # Votre clé publique SSH

Cette configuration Cloud-Init :

  • Configure le hostname et le FQDN
  • Met en place l'accès SSH sécurisé
  • Installe les packages essentiels
  • Crée un utilisateur admin avec les droits sudo

2. Terraform : Déploiement automatisé

Configuration Infisical Provider

hcl
terraform {
  required_providers {
    proxmox = {
      source = "bpg/proxmox"
      version = "0.42.0"
    }  
    infisical = {
      source = "infisical/infisical"
    }
  }
}

provider "infisical" {
  host = "https://infisical.reverse9.xyz/"
  client_id = var.infisical_client_id
  client_secret = var.infisical_client_secret
}

Cette configuration :

  • Définit les providers nécessaires (ici Proxmox)
  • Configure l'accès à Infisical pour la gestion des secrets

Récupération des secrets

hcl
ephemeral "infisical_secret" "proxmox_endpoint" {
  name         = "PROXMOX_ENDPOINT"
  env_slug     = "prod"
  workspace_id = "8732dcc5-9548-4466-b2db-e837aecc54de"
  folder_path  = "/Terraform"
}

ephemeral "infisical_secret" "proxmox_api_token" {
  name         = "PROXMOX_API_TOKEN"
  env_slug     = "prod"
  workspace_id = "8732dcc5-9548-4466-b2db-e837aecc54de"
  folder_path  = "/Terraform"
}

Cette partie :

  • Récupère les credentials Proxmox depuis Infisical
  • Utilise des secrets éphémères pour plus de sécurité (pas de trace de credentials dans les tfstates)

Configuration de la VM

hcl
resource "proxmox_virtual_environment_vm" "vm" {
  name      = var.vm_hostname
  node_name = var.target_node

  cpu {
    type = "host"
    cores = 10
  }

  clone {
    vm_id = var.source_vm_id
    full  = true
  }

  network_device {
    model    = "virtio"
    bridge   = var.proxmox_bridge
    vlan_id  = var.vm_vlan_id
  }

  initialization {
    datastore_id = "SSDK"
    user_data_file_id = proxmox_virtual_environment_file.cloud_user_config.id
    ip_config {
      ipv4 {
        address = "${var.ip_address}/${var.netmask}"
        gateway = var.gateway
      }
    }
  }
}

Cette configuration :

  • Clone le template créé par Packer
  • Configure les ressources CPU
  • Met en place le réseau avec VLAN
  • Initialise la VM avec Cloud-Init

Cloud-Init pour Terraform

yaml
#cloud-config
hostname: gns3vm
fqdn: gns3.reverse9.xyz
users:
  - name: ${username}
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    ssh_authorized_keys:
      - ${ssh_key}

network:
  version: 2
  ethernets:
    eth0:
      nameservers:
        addresses: [10.10.10.246]
        search: [reverse9.xyz]

Cette configuration :

  • Définit les paramètres réseau
  • Configure les DNS
  • Met en place l'utilisateur avec sa clé SSH

Les secrets sont gérés dans Infisical avec une organisation "Projets", et dans les projets, j'ai des dossiers par outil.

text
Projet : gns3-autosetup
├── Packer
│   ├── Tous les secrets de Packer
└── Terraform
    └── Tous les secrets de Terraform

Les secrets sont structurés de la manière suivante dans l'application

On retrouve le projet

Capture d'écran du gestionnaire de secrets montrant l'entrée du projet

Puis les dossiers pour chaque outil

Capture d'écran du gestionnaire de secrets montrant un dossier par outil

Et enfin les secrets. Ici dans cet exemple les secrets de Packer

Capture d'écran des secrets Packer stockés dans le gestionnaire de secrets

Note : On remarque la possibilité de définir différents secrets suivant les environnement (Dev, Staging (ou la Pré-Prod), Prod)

3. Ansible : Installation et configuration

Installation de Docker

yaml
- name: Install docker
  hosts: vlan10_infra
  become: yes
  tasks:
    - name: Download docker install script
      ansible.builtin.get_url:
        url: https://get.docker.com
        dest: /tmp/get-docker.sh
        mode: '0755'

    - name: Run docker install script
      ansible.builtin.command: sh /tmp/get-docker.sh

Ce playbook :

  • Télécharge le script d'installation Docker
  • Exécute l'installation de manière automatisée

Installation de GNS3

yaml
- name: Install GNS3 with required components
  hosts: vlan10_infra
  become: yes
  tasks:
    - name: Download GNS3 remote install script
      ansible.builtin.get_url:
        url: https://raw.githubusercontent.com/GNS3/gns3-server/master/scripts/remote-install.sh
        dest: /tmp/gns3-remote-install.sh
        mode: '0755'

    - name: Execute GNS3 installation script
      ansible.builtin.command: bash /tmp/gns3-remote-install.sh --with-iou --with-i386-repository

Ce playbook :

  • Installe GNS3 avec ses composants
  • Active le support IOU
  • Configure les dépôts nécessaires

4. GitLab CI/CD : Orchestration

yaml
stages:
  - build
  - deploy
  - configure

variables:
  GIT_DEPTH: "1"

build_template:
  stage: build
  script:
    - echo "Building the VM template with Packer..."
    - chmod +x Packer/packer-entrypoint.sh
    - ./Packer/packer-entrypoint.sh

deploy_infrastructure:
  stage: deploy
  script:
    - echo "Deploying infrastructure with Terraform..."
    - chmod +x Terraform/terraform-entrypoint.sh
    - ./Terraform/terraform-entrypoint.sh build
  artifacts:
    paths:
      - Terraform/terraform.tfstate
    expire_in: 1 hour
  dependencies:
    - build_template

configure_vm:
  stage: configure
  script:
    - echo "Configuring VM with Ansible (Docker + GNS3)..."
    - chmod +x Ansible/ansible-entrypoint.sh
    - ./Ansible/ansible-entrypoint.sh
  dependencies:
    - deploy_infrastructure

Cette pipeline :

  1. Crée le template avec Packer
  2. Déploie l'infrastructure avec Terraform
  3. Configure la VM avec Ansible
  4. Conserve le tfstate comme artifact

On voit donc les étapes de la pipeline :

Capture d'écran des étapes du pipeline CI/CD : build, déploiement de l'infrastructure, configuration de la VM, sauvegarde du tfstate en artifact

Le processus de déploiement en détail

1. Création du template (Packer)

Le processus commence avec Packer qui :

  1. Télécharge l'ISO Ubuntu 24.04
  2. Crée une VM sur Proxmox avec :
    • Configuration matérielle optimisée pour GNS3
    • Cloud-Init activé
  3. Installe le système avec :
    • Les packages de base
    • L'agent QEMU
    • La configuration SSH
  4. Prépare le template pour Terraform

2. Déploiement de l'infrastructure (Terraform)

Terraform prend le relais pour :

  1. Récupérer les credentials depuis Infisical :
    • Endpoint Proxmox
    • Token API
    • Configurations sensibles
  2. Créer une nouvelle VM avec :
    • Clone du template
    • Configuration réseau personnalisée
    • Initialisation Cloud-Init
  3. Préparer la VM pour Ansible avec :
    • Configuration DNS
    • Accès SSH (user:publickey)

3. Configuration du serveur GNS3 (Ansible)

Finalement, Ansible :

  1. Installe Docker :
    • Configuration du repository
    • Installation des dépendances
    • Configuration du daemon
  2. Installe GNS3 :
    • Composants serveur
    • Support IOU
    • Dépendances système

Capture d'écran du playbook Ansible installant GNS3 server, le support IOU et les dépendances

Conclusion

Cette solution d'automatisation me permet de :

  • Déployer un nouveau serveur GNS3 en quelques minutes
  • Garantir une configuration cohérente et reproductible
  • Gérer les secrets de manière sécurisée et centralisée
  • Maintenir facilement l'infrastructure avec des outils modernes

Le code source complet est disponible sur GitLab, avec une documentation détaillée pour vous permettre de reproduire cette installation.

Capture d'écran du dépôt GitLab du projet

La topologie n'est pas complexe, mais on peut voir que GNS3 fonctionne parfaitement.

Pourquoi réinventer la roue ?

Après avoir fait tout cela, on peut se poser la question : pourquoi ne pas avoir simplement converti l'OVA GNS3 fourni par l'éditeur et importé le disque sur une VM dans Proxmox ?

Pour répondre à cette question, je vais peser le pour et le contre des deux approches.

Convertir la VM et l'importer

Avantages

  • Gain de temps immense : pas besoin de se casser la tête pour créer des playbooks Ansible, des configurations Terraform, un template Packer
  • Simplicité : en 2 commandes, c'est terminé

Dans les grandes lignes, il suffit de :

  1. Télécharger la VM depuis le site de GNS3
  2. Décompresser l'archive obtenue
  3. Créer une VM sur Proxmox
  4. Convertir le VMDK en QCOW2
  5. Importer le disque sur une VM

Inconvénients

  • Perte de flexibilité
    • Impossible de personnaliser la configuration réseau (VLAN, IP, identifiants) avant le déploiement
  • Apprentissage limité
    • La conversion de formats de disque virtuel est une compétence basique

Stack CI/CD

Avantages CI/CD

  • Personnalisation complète
  • Reproductibilité garantie
  • Gestion des secrets sécurisée
  • Apprentissage des outils DevOps modernes :
    • Packer
      • Terraform
      • Ansible
      • GitLab CI/CD
fren