cli


Journaux liées à cette note :

Journal du jeudi 24 juillet 2025 à 22:31 #échec, #network, #ipv6, #simulateur

Suite à ma note "J'ai découvert ContainerLab, un projet qui permet de simuler des réseaux", j'ai implémenté et publié containerlab-playground.

Mon but était d'utiliser Containerlab pour simuler deux réseaux IPv6 connectés entre eux : 3 serveurs sur le premier réseau et 2 serveurs sur le second.

Comme je l'observe fréquemment depuis quelques mois, Claude Sonnet 4 m'a produit une implémentation qui, en pratique, ne fonctionne pas (voir son contenu dans 2025-07-20_1241).

La note courante reprend principalement en français le contenu du README.md de mon playground .

Voici les instructions que j'ai exécutées pour installer Containerlab sous Fedora :

```sh
$ sudo dnf config-manager addrepo --set=baseurl="https://netdevops.fury.site/yum/" && \
$ echo "gpgcheck=0" | sudo tee -a /etc/yum.repos.d/netdevops.fury.site_yum_.repo
$ sudo dnf install containerlab
$ sudo usermod -aG clab_admins stephane && newgrp clab_admins
$ sudo semanage fcontext -a -t textrel_shlib_t $(which containerlab)
$ sudo restorecon $(which containerlab)

Pour le moment, je ne sais pas pourquoi j'ai l'erreur suivante si j'exécute un déploiement sans sudo :

$ containerlab deploy
11:25:54 INFO Containerlab started version=0.69.0

   ERROR 

  Failed to read topology file: stat /home/stephane/git/github.com/stephane-klein/containerlab-playground/network-a-
  b.clab.yaml: permission denied.

Voici le contenu de la topologie que j'ai souhaité déployer : network-a-b.clab.yaml

La commande de déploiement fonctionne correctement avec sudo :

$ sudo containerlab deploy
11:27:03 INFO Containerlab started version=0.69.0
11:27:03 INFO Parsing & checking topology file=network-a-b.clab.yaml
11:27:03 INFO Creating docker network name=net-custom IPv4 subnet="" IPv6 subnet=2001:db8:a::0/48 MTU=0
11:27:03 INFO Creating lab directory path=/home/stephane/git/github.com/stephane-klein/containerlab-playground/clab-network-a
11:27:04 INFO Creating container name=vm-b1
11:27:04 INFO Creating container name=vm-a1
11:27:04 INFO Creating container name=vm-a2
11:27:04 INFO Creating container name=vm-a3
11:27:04 INFO Adding host entries path=/etc/hosts
11:27:04 INFO Adding SSH config for nodes path=/etc/ssh/ssh_config.d/clab-network-a.conf
╭──────────────────────┬───────────────────┬─────────┬─────────────────╮
│         Name         │     Kind/Image    │  State  │  IPv4/6 Address │
├──────────────────────┼───────────────────┼─────────┼─────────────────┤
│ clab-network-a-vm-a1 │ linux             │ running │ 192.168.0.2     │
│                      │ mitchv85/ohv-host │         │ 2001:db8:a:1::1 │
├──────────────────────┼───────────────────┼─────────┼─────────────────┤
│ clab-network-a-vm-a2 │ linux             │ running │ 192.168.0.3     │
│                      │ mitchv85/ohv-host │         │ 2001:db8:a:1::2 │
├──────────────────────┼───────────────────┼─────────┼─────────────────┤
│ clab-network-a-vm-a3 │ linux             │ running │ 192.168.0.4     │
│                      │ mitchv85/ohv-host │         │ 2001:db8:a:1::3 │
├──────────────────────┼───────────────────┼─────────┼─────────────────┤
│ clab-network-a-vm-b1 │ linux             │ running │ 192.168.0.5     │
│                      │ mitchv85/ohv-host │         │ 2001:db8:a:2::5 │
╰──────────────────────┴───────────────────┴─────────┴─────────────────╯

Globalement, j'ai trouvé l'expérience utilisateur de la cli Containerlab très agréable à utiliser :

$ containerlab help

  deploy container based lab environments with a user-defined interconnections

  USAGE


    containerlab [command] [--flags]  


  COMMANDS

    completion [bash|zsh|fish]   Generate completion script
    config [command] [--flags]   Configure a lab
    deploy [--flags]             Deploy a lab
    destroy [--flags]            Destroy a lab
    exec [--flags]               Execute a command on one or multiple containers
    generate [--flags]           Generate a Clos topology file, based on provided flags
    graph [--flags]              Generate a topology graph
    help [command] [--flags]     Help about any command
    inspect [command] [--flags]  Inspect lab details
    redeploy [--flags]           Destroy and redeploy a lab
    save [--flags]               Save containers configuration
    tools [command]              Various tools your lab might need
    version [command]            Show containerlab version or upgrade

  FLAGS

     -d --debug                  Enable debug mode
     -h --help                   Help for containerlab
     --log-level                 Logging level; one of [trace, debug, info, warning, error, fatal] (info)
     --name                      Lab name
     -r --runtime                Container runtime
     --timeout                   Timeout for external API requests (e.g. container runtimes), e.g: 30s, 1m, 2m30s (2m0s)
     -t --topo                   Path to the topology definition file, a directory containing one, 'stdin', or a URL
     --vars                      Path to the topology template variables file
     -v --version                Version for containerlab

J'ai eu quelques difficultés à trouver une image Docker à utiliser qui fournit directement un serveur ssh :

    vm-a1:
      kind: linux
      # image: alpine-ssh
      # https://hub.docker.com/r/mitchv85/ohv-host
      image: mitchv85/ohv-host
      mgmt-ipv6: 2001:db8:a:1::1

Le déploiement de cette image permet de facilement se connecter à l'host en ssh:

$ ssh admin@clab-network-a-vm-a1
admin@vm-a1:~$ exit

Il est possible de facilement lancer une commande sur tous les hosts :

$ sudo containerlab exec -t network-a-b.clab.yaml --cmd 'ip addr'
11:29:52 INFO Parsing & checking topology file=network-a-b.clab.yaml
11:29:52 INFO Executed command node=clab-network-a-vm-a2 command="ip addr"
  stdout=
  │ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  │     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  │     inet 127.0.0.1/8 scope host lo
  │        valid_lft forever preferred_lft forever
  │     inet6 ::1/128 scope host
  │        valid_lft forever preferred_lft forever
  │ 2: eth0@if192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  │     link/ether aa:86:42:84:81:de brd ff:ff:ff:ff:ff:ff link-netnsid 0
  │     inet 192.168.0.3/20 brd 192.168.15.255 scope global eth0
  │        valid_lft forever preferred_lft forever
  │     inet6 2001:db8:a:1::2/48 scope global nodad
  │        valid_lft forever preferred_lft forever
  │     inet6 fe80::a886:42ff:fe84:81de/64 scope link
  │        valid_lft forever preferred_lft forever

11:29:52 INFO Executed command node=clab-network-a-vm-a3 command="ip addr"
  stdout=
  │ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  │     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  │     inet 127.0.0.1/8 scope host lo
  │        valid_lft forever preferred_lft forever
  │     inet6 ::1/128 scope host
  │        valid_lft forever preferred_lft forever
  │ 2: eth0@if193: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  │     link/ether b2:42:6c:2b:d0:9d brd ff:ff:ff:ff:ff:ff link-netnsid 0
  │     inet 192.168.0.4/20 brd 192.168.15.255 scope global eth0
  │        valid_lft forever preferred_lft forever
  │     inet6 2001:db8:a:1::3/48 scope global nodad
  │        valid_lft forever preferred_lft forever
  │     inet6 fe80::b042:6cff:fe2b:d09d/64 scope link
  │        valid_lft forever preferred_lft forever

11:29:52 INFO Executed command node=clab-network-a-vm-a1 command="ip addr"
  stdout=
  │ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  │     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  │     inet 127.0.0.1/8 scope host lo
  │        valid_lft forever preferred_lft forever
  │     inet6 ::1/128 scope host
  │        valid_lft forever preferred_lft forever
  │ 2: eth0@if191: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  │     link/ether 26:9f:87:52:d6:1c brd ff:ff:ff:ff:ff:ff link-netnsid 0
  │     inet 192.168.0.2/20 brd 192.168.15.255 scope global eth0
  │        valid_lft forever preferred_lft forever
  │     inet6 2001:db8:a:1::1/48 scope global nodad
  │        valid_lft forever preferred_lft forever
  │     inet6 fe80::249f:87ff:fe52:d61c/64 scope link
  │        valid_lft forever preferred_lft forever

11:29:52 INFO Executed command node=clab-network-a-vm-b1 command="ip addr"
  stdout=
  │ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  │     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  │     inet 127.0.0.1/8 scope host lo
  │        valid_lft forever preferred_lft forever
  │     inet6 ::1/128 scope host
  │        valid_lft forever preferred_lft forever
  │ 2: eth0@if194: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  │     link/ether e2:81:7b:c7:eb:64 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  │     inet 192.168.0.5/20 brd 192.168.15.255 scope global eth0
  │        valid_lft forever preferred_lft forever
  │     inet6 2001:db8:a:2::5/48 scope global nodad
  │        valid_lft forever preferred_lft forever
  │     inet6 fe80::e081:7bff:fec7:eb64/64 scope link
  │        valid_lft forever preferred_lft forever

Ou alors sur un host en particulier :

$ sudo containerlab exec -t network-a-b.clab.yaml --label clab-node-name=vm-a1 --cmd 'ip addr'
11:02:44 INFO Parsing & checking topology file=network-a-b.clab.yaml
11:02:44 INFO Executed command node=clab-network-a-vm-a1 command="ip addr"
  stdout=
  │ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  │     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  │     inet 127.0.0.1/8 scope host lo
  │        valid_lft forever preferred_lft forever
  │     inet6 ::1/128 scope host
  │        valid_lft forever preferred_lft forever

Par contre, je n'ai pas réussi à atteindre mon objectif 😟.

J'ai l'impression que pour le moment, Containerlab ne permet pas de créer plusieurs réseaux à partir d'un fichier topologie.

Je n'ai pas compris comment définir la longueur du prefix IPv6 des interfaces eth0 au niveau des nodes.

Pour le moment, tous les nodes appartiennent au même sous-réseau 2001:db8:a::0/48, alors que j'aimerais les séparer dans les deux sous-réseaux suivants :

  • 2001:db8:a:1
  • 2001:db8:a:2
# network-a-b.clab.yaml

...

topology:
  nodes:
    vm-a1:
      kind: linux
      # image: alpine-ssh
      # https://hub.docker.com/r/mitchv85/ohv-host
      image: mitchv85/ohv-host
      mgmt-ipv6: 2001:db8:a:1::1
      # <== ici je ne sais pas comment définir : 2001:db8:a:1::1/64

...

J'ai découvert l'issue suivante du principal développeur de Containerlab : « Multiple management networks ».
Je pense comprendre que ce que je cherche à faire n'est actuellement pas possible avec Containerlab.

Pour atteindre mon objectif, peut-être que je devrais plutôt m'orienter vers des alternatives mentionnées dans ce billet de blog : Open-source network simulation roundup 2024.

Je viens de poster le message suivant l'espace de discussion GitHub de Containerlab : « Does Containerlab support the creation of topologies with multiple subnets? ».
J'espère que le créateur de Containerlab pourra me suggérer une solution à mon problème, car je n'ai pas réussi à l'identifier dans la documentation 🤷‍♂️.

Journal du mercredi 30 octobre 2024 à 10:21 #DevOps, #dev-kit

Je garde trace dans cette notes de deux plugins Asdf / Mise que j'ai utilisé avec succès ces deux derniers jours.

Le premier, pour installer la cli de Hasura : asdf-hasura

$ mise plugin add hasura-cli https://github.com/gurukulkarni/asdf-hasura.git

Contenu de .mise.toml :

[tools]
hasura-cli = "2.43.0"
$ mise install
$ hasura version
INFO hasura cli                                    version=v2.43.0

Le second, pour installer Gitleaks : asdf-gitleaks

$ mise plugin add gitleaks https://github.com/jmcvetta/asdf-gitleaks.git

Contenu de .mise.toml :

[tools]
gitleaks = "8.21.2"
$ mise install
$ gitleaks --version
gitleaks version 8.21.2

Journal du mardi 24 septembre 2024 à 13:07 #JaiDécouvert, #JaiLu

#JaiLu un excellent article sur NATS : NATS de A à Y du blog Une tasse de café de Quentin Joly.

J'aime beaucoup les fonctionnalités cli de NATS, très pratiques pour faire des démos ou des tests.

J'y ai découvert les requêtes synchrones de NATS : Core NATS - Request-Reply.

À la fin de l'article, j'ai découvert Nex (NATS Execution Engine) :

The NATS Execution Engine (we'll just call it Nex most of the time) is an optional add-on to NATS that overlays your existing NATS infrastructure, giving you the ability to deploy and run workloads.

...

While you can build virtually any kind of application with Nex, the core building blocks are made up of two fundamental types of workloads: services and functions.

...

Nex functions are small and can be deployed either as Javascript functions or as WebAssembly modules.

Je découvre aussi que Nex utilise Firecracker.

Je suis un peu embêté, car je réalise que cela fait 2 ans que j'ai très envie d'utiliser NATS. J'espère ne pas tomber prochainement dans les travers du Resume Driven Development 🙈.

À la suite de la lecture de cet article, j'ai offert un petit café à Quentin Joly.