Вступление

Часто сетевая лаба представляет собой довольно сложную конструкцию, состоящую из множества устройств, соединенных между собой. В этом помогает виртуализация, благо всякие маршрутизаторы и т.п. могут запускаться в виде контейнеров (скажем, Quagga) или виртуальных машин (здесь я рассмотрю Mikrotik).

Тем не менее развернуть лабу из нескольких устройств с множеством сетевых интерфейсов и подключений, к примеру, для проверки BGP, в том числе между устройствами разных производителей, задача нетривиальная.  Можно, конечно, писать плейбуки Ansible для развертывания виртуалок на ESXi и последующей конфигурации устройств, но это само по себе достойная задача. Может быть что-то с vagrant изобразить…

Но недавно я узнал о проекте ContainerLab.dev и весьма впечатлился. Попробовал, оценил, впечатлился еще больше. Полез на Хабр почитать тонкости и хитрости, но, к удивлению, не нашел ни единого поста на эту тему.

Решил исправить. Вдруг кому-то еще облегчит жизнь.

ContainerLab.dev

Как пишут создатели, Containerlab предоставляет простой интерфейс командной строки для оркестрации и управления сетевыми лабами на основе контейнеров. Запускает, строит между ними виртуальные линки. Причем все это богатство описывается в простом и понятном YAML файле.

«Containerlab provides a CLI for orchestrating and managing container-based networking labs. It starts the containers, builds a virtual wiring between them to create lab topologies of users choice and manages labs lifecycle».

Мой пример файла:

name: lab
prefix: ""

mgmt:
  network: statics
  ipv4_subnet: 172.20.20.0/24

topology:
  kinds:
    vr-ros:
    # https://hub.docker.com/r/iparchitechs/chr
      image: iparchitechs/chr:long-term # :7.5beta8 :long-term

  nodes:
    ubuntu:
      kind: linux
      image: ubuntu:latest
      memory: 256MB
      cpu: 0.5
      mgmt_ipv4: 172.20.20.21
      binds:
        - setup_ubuntu.sh:/tmp/setup.sh
      exec:
        - bash /tmp/setup.sh
        - ip addr add dev eth1 10.2.2.21/24
        - ip route add 10.2.0.0/16 via 10.2.2.1

    alpine1:
      kind: linux
      image: alpine:latest
      memory: 64MB
      cpu: 0.5
      mgmt_ipv4: 172.20.20.31
      binds:
        - setup_alpine.sh:/tmp/setup.sh
      exec:
        - sh /tmp/setup.sh
        - ip addr add dev eth1 10.2.3.31/24
        - ip route add 10.2.0.0/16 via 10.2.3.1

    ros1:
      kind: vr-ros
      mgmt_ipv4: 172.20.20.11
      memory: 512MB
      cpu: 1
      ports:
        - 10122:22
        - 10180:80
#      startup-config: ros1.cfg
      binds:
        - setup_mikrotik.sh:/tmp/setup.sh
      exec:
        - sh /tmp/setup.sh 192.168.122.1 10.2.2 10.2.3

  links:
    - endpoints: ["ubuntu:eth1","ros1:eth1"]
    - endpoints: ["ros1:eth2","alpine1:eth1"]

Фактически задействованные устройства описываются в секции nodes, а связи между ними в links. Минимальное описание:

    ubuntu:
      kind: linux
      image: ubuntu:latest

или

    ros1:
      kind: vr-ros
      image: iparchitechs/chr:long-term # :7.5beta8 :long-term

А как задаются связи между ними и так понятно.

Дальше я более детально поясню важные моменты, в том числе начальную конфигурацию. А для затравки: этот файл с виртуалками Ubuntu, Alpine и маршрутизатором Mikrotik между ними разворачивается простой командой containerlab deploy (ну или с указанием фала топологии, если их несколько, как у меня).

На выходе получили три контейнера. Посмотреть их IP также можно с помощью команды containerlab inspect.

Для удобства я создал alias clab='sudo containerlab', так что на скриншотах будет clab.

С помощью clab graph можно построить топологию.  При этом поднимется веб-сервер. Скриншт ниже именно с него, я только IP адреса добавил для понятности.

(Нюанс: при использовании бриджа топология рисуется кривовато, не знаю пока, что с этим делать)

Теперь можно подключаться к развернутым устройствам (docker exec, ssh…) и проверять, что душе угодно.

Подробности

Сеть

Коли вы заинтересовались описанным, подробнее освещу важные моменты.

Развертывается элементарно (bash -c "$(curl -sL https://get.containerlab.dev)").

IP адреса для контейнеров можно не указывать, получат автоматическию. Хотя я предпочитаю  указывать явно (mgmt_ipv4, mgmt_ipv6). Из какой подсети выдавать адреса настраивается: ipv4_subnet.

Это речь об интерфейсе управления – eth0. По этому адресу вы можете обращаться к своим виртуальным устройствам. Через него же они могут выходить в интернет, получать апдейты…

Но для данных вы создадите дополнительные интерфейсы. И уже их будете соединять друг с другом. В моем случае

  links:
    - endpoints: ["ubuntu:eth1","ros1:eth1"]
    - endpoints: ["ros1:eth2","alpine1:eth1"]

Т.е. у Ubuntu помимо интерфейса управления (eth0) будет eth1, подключенный к Mikrotik (eth1). Другой интерфейс  Микротика (eth2) будет подключен к alpine (eth1). IP адреса для этих интерфейсов (eth1 и т.п.) задаются внутри виртуализированного устройства.

Подключить к одному интерфейсу (ros1:eth2) несколько контейнеров нельзя. Но можно создать бридж (сначала на хосте обычным образом, потом в YAML файле). Пример с дополнительным контейнером alpine2 также за eth2 Микротика есть в репозитории (ros-br.clab.yml).

Фактически описываем дополнительное устройство (бридж) br-clab и связываем его:

    br-clab:
      kind: bridge
  links:
    - endpoints: ["ubuntu:eth1","ros1:eth1"]
    - endpoints: ["ros1:eth2","br-clab:eth1"]
    - endpoints: ["alpine1:eth1","br-clab:eth2"]
    - endpoints: ["alpine2:eth1","br-clab:eth3"]

Виртуальные машины

С Ubuntu все понятно. Берешь контейнер и наслаждаешься. В том числе есть контейнеризиванные маршрутизаторы и т.п. Но что, если хочется поиграть виртуальной копией аппаратного устройства, для которого нет контейнера, но есть виртуальная машина?

К счастью, имеются проекты, позволяющие «обернуть» виртуалку так, чтобы сделать ее совместимой по сетевой части со средой Containerlab.

Здесь я в качестве примера взял Mikrotik. Другие готовые решения можно посмотреть в разделе kinds. Juniper, Cisco…

Микротик был адаптирован с помощью проекта vrnetlab. Для недавно добавленного Check Point CloudGuard использовался более новый boxen. Если будет интерес, могу отдельно описать, как из скаченного с официального сайта qcow2 (образа для KVM) собрать контейнер.

Сравните описания:

https://containerlab.dev/manual/kinds/linux/ позволяет использовать ваш любимый образ. Я взял Ubuntu и Alpine с традиционного Docker Hub.

https://containerlab.dev/manual/kinds/vr-ros/: MikroTik RouterOS cloud hosted router is identified with vr-ros or vr-mikrotik_ros kind in the topology file. It is built using vrnetlab project and essentially is a Qemu VM packaged in a docker container format.

https://containerlab.dev/manual/kinds/checkpoint_cloudguard/: Check Point Cloudguard virtualized security appliance is identified with checkpoint_cloudguard kind in the topology file. It is built using boxen project and essentially is a Qemu VM packaged in a docker container format.

Понимание отличия «настоящего» контейнера от «не настоящего» очень важно. Команда docker exec для настоящего контейнера работает привычным образом. А вот в случае «не настоящего» вы подключитесь в «контейнер-обертку», а не в свою виртуальную машину с желаемым устройством. Я тут поначалу оторопел, почему не та ОС и куда делись ожидаемые команды.

Я в «обертке» (обычно это не требуется): docker exec --it ros1 bash

А вот ssh казалось бы на IP контейнера пробросит действительно внутрь искомой виртуальной машины: ssh admin@ros1

Магия!

И обратите внимание на IP адрес интерфейса управления ether1: 172.31.255.30/30, хотя SSH мы делали на 172.20.20.11. Это тоже особенность «обертки», которую просто нужно знать (и не портить этот IP при настройке Микротика или другой системы).

Сразу приведу скриншоты, как все работает, как с Ubuntu я могу пингануть Alpine через Микротик (и обратно).

Понятно, что для этого внутри Ubuntu я прописал дополнительный статический маршрут в сторону 10.2.2.1 (mikrotik:eth1), а на alpine в сторону 10.2.3.1 (mikrotik:eth2).

Как задать IP для дополнительных интерфейсов, маршруты и прочие настройки? Да любым привычным способом. Хоть CLI, хоть Web-интерфейс. Хоть автоматизировать :)

Настройки контейнеров

Во-первых, поддерживаются традиционные для контейнеров параметры: image, memory, cpu… Доступны bind, exec. Я использую их для автоматизации первоначальной настройки.

В данном примере я монтирую в контейнер скрипты с «универсальными» настройками и запускаю их через exec. Также через exec я сразу же на этапе развертывания лабы задаю параметры, специфичные для конкретного контейнера (IP адреса, маршруты…)

Можно опубликовать порты. Скажем, для Микротика:

      ports:
        - 10122:22
        - 10180:80

Как в традиционном контейнерном мире: это позволит подключиться к основному хосту, на котором развернут Containerlab (http://CLab:10180) и увидеть web-интерфейс Микротика.

Хотя я предпочитаю прописать маршрут для сети управления (172.20.20.0 в моем случае) на CLab. Это позволит обращаться к Микротику напрямую, без публикации портов на хосте (http://172.20.20.11, как задано в YAML файле конфигурации лабы).

Настройки «не настоящих контейнеров»

Помните, docker exec пробрасывает не в виртуальную машину, а в «контейнер-обертку»? Так же и exec выполнит команды в контейнере vrnetlab или boxen, но не там, где хотелось бы. Так что придется действовать хитрее.

Итак,

    ros1:
      kind: vr-ros
      mgmt_ipv4: 172.20.20.11
#      startup-config: ros1.cfg
      binds:
        - setup_mikrotik.sh:/tmp/setup.sh
      exec:
        - sh /tmp/setup.sh 192.168.122.1 10.2.2 10.2.3

По идее Микротику можно «скормить» файл конфигурации, но я опишу более универсальный подход (строчка startup-config закомментирована).

Фактически я выполняю скрипт setup_mikrotik.sh в «обертке», и изнутри этого контейнера делаю ssh внутрь виртуальной машины с Микротиком.

#!/bin/bash
intIP=172.31.255.30

wait_ssh() {
    printf "Waiting for ssh: "
    SSH_UP=0
    while [ $SSH_UP -eq 0 ]
    do
        printf "."
        SSH_UP=$(wget --timeout=1 --tries=1 $intIP:22 2>&1 | grep -c Read);
    done
    printf " SSH UP"
}

apt-get update > /dev/null
apt-get install -y sshpass > /dev/null

wait_ssh

cat <<EOF | sshpass -p admin ssh -tt -o StrictHostKeyChecking=no admin@$intIP
/ip dns set servers=$1;
/ip address add address=$2.1/24 interface=ether2 network=$2.0;
/ip address add address=$3.1/24 interface=ether3 network=$3.0;
/ip route add distance=1 gateway=172.31.255.29;
EOF

Через ssh я выполню ряд команд Микротика (/ip dns set и т.п.). В качестве параметров передаю ему индивидуальные настройки (IP, DNS…). Для подстановки пароля я предварительно устанавливаю sshpass. (expect в «обертке» ожидаемо отсутствует). Потом можно и ключ ssh загрузить, но на первом этапе так.

Еще из интересного – после того, как контейнер стартовал, это не значит, что виртуальная машина с Микротиком сразу готова к работе, ей нужно немного времени. Поэтому я написал функцию wait_ssh, ожидающую готовности SSH в виртуальной машине. Проверку делаю через wget, поскольку он уже установлен. Во избежание зависания, я ограничиваю timeout. Ничего толкового я не получу, код возврата будет «Ошибка» в любом случае. Но с помощью grep я отличить Read в случае успешного подключения от полной ошибки подключения (не готовности виртуальной машины).

Заключение

Разумеется, так можно создавать весьма сложные топологии (скажем, много интерфейсов, BGP, VPN, переключения на резервные линки…).

Для Check Point CloudGuard вы получите традиционное:

В данном случае у меня Standalone конфигурация (Management + Gateway) и дополнительный шлюз.

Было бы очень интересно узнать, знакомы ли вы с ContainerLab, представляет ли это для вас интерес.

Упомянутые в статье и другие файлы можно найти на GitHub.

Комментарии (17)


  1. leorikz
    16.08.2022 22:58

    @helltавтор

    с продуктом знаком шапочно, не более чем щупал, интересовался, смотрел доклад автора

    https://youtu.be/qigCla1qY3k

    спасибо, что напомнили про тулу


    1. Antra Автор
      17.08.2022 08:38

      Спасибо! Люблю такие видео для первого знакомства, чтобы быстро понять возможности и решить, насколько подходит и стоит ли ставить и глубже разбираться.

      И при этом много "внутренностей", которые бегло на сайте не найдешь.


  1. estet
    16.08.2022 22:59

    mininet пробовали?


    1. t0xa
      17.08.2022 08:25

      Ну там как минимум вам необходимо разворачивать платформу!


    1. Antra Автор
      17.08.2022 08:35

      Нет, не слышал.
      Сейчас глянул - не увидел списка поддерживаемых "устройств". Это потому что любое поддерживается, лишь бы можно было запустить в виртуальной машине (VMware, virtualbox...)?


  1. N0RD3X
    16.08.2022 23:58

    Посмотрите еще https://pnetlab.com/


    1. Karroplan
      17.08.2022 00:18

      какая замечательная доработка eve-ng


      1. Pinkbyte
        17.08.2022 14:24

        Настолько замечательная, что на форуме Eve-NG у одного из авторов бомбануло и он заклеймил авторов PNetlab скаммерами


        1. leorikz
          17.08.2022 14:29

          смысля скамеры? там про плагиат было насколько я помню


          1. Pinkbyte
            17.08.2022 14:30

            За что купил - за то и продаю:
            https://www.eve-ng.net/forum/viewtopic.php?f=4&t=16925


            1. leorikz
              17.08.2022 14:36

              ок, спасибо за уточнение.

              Полагаю автор поста использовал термин scammer в значении "<SNIP> or participates in a dishonest scheme"

              А в теле уже пишет - PNETLAB is illegal copy (fork) made from EVE Community


        1. N0RD3X
          19.08.2022 01:24

          Ну конечно, они взяли бесплатную версию и добавили туда почти все фичи из Pro, которая стоит больших денег. У любого бы бомбануло от такой наглости :)


    1. Antra Автор
      17.08.2022 08:49

      Круто!
      Но мне это больше Cisco Modeling Labs напомнило по классу продукта.


  1. net_racoon
    17.08.2022 09:42
    +1

    А почему бы просто в GNS3 не натыкать эту схему и вот она у вас наглядно перед глазами и конфиги не надо писать. Или речь идет про очень большие лабы? Но опять же, конфиг то все равно писать надо. Это только если его генерировать... Короч слабо понимаю в чем смысл?


    1. Antra Автор
      17.08.2022 11:53

      В данном случае было требование крупного заказчика, уже использующего ContainerLab, сделать, чтобы Check Point CloudGuard там же можно было гонять.

      Так что сервисов много. "А почему не CML2" - тоже вполне резонный вопрос. И мы его задавали :) Но "так заведено", или еще по каким-то причинам, но попросили CLab.


  1. hellt
    17.08.2022 13:04

    Спасибо за статью, получился хороший практический пример с интересной реализацией стартап конфига для vrnetlab виртуалок

    PS/ я мэйнтейнер проекта


    1. Antra Автор
      17.08.2022 13:59

      Спасибо вам за суперский продукт!

      Пожалуй, единственная хотелка у меня - для таких вот vrnetlab/boxen делать снапшоты, чтобы восстанавливать конфигурацию полностью (а не заново настраивать, пусть даже автоматически). Для настоящих контейнеров, наверное, docker save сгодится. А для VM не придумал пока.