company_banner

Container Networking Interface (CNI) — сетевой интерфейс и стандарт для Linux-контейнеров



    На прошлой неделе фонд CNCF (Cloud Native Computing Foundation) объявил о принятии под своё крыло 10-го Open Source-проекта — CNI (Container Networking Interface). Его задача — обеспечить всё необходимое для стандартизированного управления сетевыми интерфейсами в Linux-контейнерах и гибкого расширения сетевых возможностей. В CNCF объяснили необходимость такого проекта активным распространением контейнеризированных приложений в мире production и утверждают, что «подобно тому, как Kubernetes позволяет разработчикам массово запускать контейнеры на тысячах машинах, этим контейнерам в больших масштабах требуется сетевое управление [и реализующий его фреймворк]».

    Как же появился CNI и что он предлагает?

    Предыстория CNI


    Проект Container Network Interface (CNI) зародился в компании CoreOS, известной по движку для контейнеров rkt (недавно был тоже передан в CNCF, одновременно с containerd), NoSQL-хранилищу etcd, активной работе над Kubernetes и другими Open Source-проектами, связанными с контейнерами и DevOps. Первая подробная демонстрация CNI состоялась ещё в конце 2015 года (см. видео в октябре, презентацию в ноябре). С самого начала проект позиционировался в качестве «предлагаемого стандарта для конфигурации сетевых интерфейсов для Linux-контейнеров», а использовать его первым делом начали, конечно же, в rkt. Первыми «сторонними пользователями» CNI стали Project Calico, Weaveworks, а в скором времени к ним примкнул Kubernetes.

    Адаптация CNI в платформе Kubernetes стоит отдельного внимания. Поскольку потребность в стандартизации сетевой конфигурации Linux-контейнеров была очевидной и всё более актуальной на тот момент (~2015 год), CNI оказался не единственным таким проектом. Конкурирующий продукт — Container Network Model (CNM) от Docker, представленный в том же 2015-м, — решал те же задачи и получил свою эталонную реализацию в виде libnetwork — библиотеки, которая выросла из сетевого кода в libcontainer и Docker Engine. И важным этапом в противостоянии CNI и CNM стал выбор, сделанный Kubernetes. В статье «Почему Kubernetes не использует libnetwork?» (январь 2016 года) разработчики подробно описывают все технические и иные причины, объясняющие их решение. Основная же суть (помимо ряда технических моментов) сводится к следующему:

    CNI ближе к Kubernetes с философской точки зрения. Он гораздо проще CNM, не требует демонов и его кроссплатформенность по меньшей правдоподобна (исполняемая среда контейнеров CoreOS rkt поддерживает его) [… а Kubernetes стремится поддерживать разные реализации контейнеров — прим. перев.]. Быть кроссплатформенным означает возможность использования сетевых конфигураций, которые будут одинаково работать в разных исполняемых средах (т.е. Docker, Rocket, Hyper). Этот подход следует философии UNIX делать одну вещь хорошо.

    По всей видимости, именно это (не только выбор Kubernetes, но и сторонний взгляд технических специалистов на существующие реализации) предопределило будущее CNI и его принятие в CNCF. Для сравнения, другие конкурирующие продукты CoreOS и Docker: среды исполнения контейнеров rkt и conatinerd — были приняты в фонд вместе и одновременно, а вот с CNI/CNM этого не произошло.


    Взгляд проекта Calico на сети для контейнеров в марте 2016 года

    Дополнительное сравнение CNI и CNM по состоянию на сентябрь 2016 года можно также найти в англоязычной статье на The New Stack.

    Устройство CNI


    Авторы CNI пошли путём создания минимально возможной спецификации, предназначение которой — стать лёгкой прослойкой между исполняемой средой контейнера и плагинами. Все необходимые сетевые функции реализуются именно в плагинах, взаимодействие с которыми определено схемой в формате JSON.



    CNI состоит из трёх частей:

    1. Спецификации (см. GitHub), определяющей API между исполняемой средой контейнера и сетевыми плагинами: обязательные поддерживаемые операции (добавление контейнера в сеть и удаление его оттуда), список параметров, формат конфигурации сети и их списков (хранятся в JSON), а также известных структур (IP-адресов, маршрутов, DNS-серверов).

    Пример конфигурации сети в CNI:

    {
      "cniVersion": "0.3.1",
      "name": "dbnet",
      "type": "bridge",
      "bridge": "cni0",
      "ipam": {
        "type": "host-local",
        "subnet": "10.1.0.0/16",
        "gateway": "10.1.0.1"
      },
      "dns": {
        "nameservers": [ "10.1.0.1" ]
      }
    }
    

    2. Официальных плагинов, предоставляющих сетевые конфигурации для разных ситуаций и служащих примером соответствия спецификации CNI. Они доступны в containernetworking/plugins и разбиты на 4 категории: main (loopback, bridge, ptp, vlan, ipvlan, macvlan), ipam (dhcp, host-local), meta (flannel, tuning), sample. Все написаны на Go. (Про сторонние плагины см. в следующем разделе статьи.)

    3. Библиотеки (libcni), предлагающей реализацию спецификации CNI (тоже на языке Go) для удобного использования в исполняемых средах контейнеров.

    Весь имеющийся код (и спецификация) опубликованы под свободной лицензией Apache License v2.0.

    Быстро попробовать CNI


    «Потрогать руками» CNI можно и без контейнеров. Для этого достаточно загрузить себе файлы из репозитория проекта (и, по желанию, нужных плагинов), собрать их с ./build.sh (или скачать уже бинарную сборку), после чего — воспользоваться исполняемым файлом плагина (например, ./bin/bridge), передав ему необходимые для функционирования аргументы через переменные окружения CNI_*, а сетевую конфигурацию — прямо JSON-данными через STDIN (так предусмотрено в спецификации CNI).

    Подробности о таком эксперименте можно найти в этой статье, автор которой делает приблизительно следующее (на хосте в Ubuntu):

    $ cat > mybridge.conf <<"EOF"
    {
        "cniVersion": "0.2.0",
        "name": "mybridge",
        "type": "bridge",
        "bridge": "cni_bridge0",
        "isGateway": true,
        "ipMasq": true,
        "ipam": {
            "type": "host-local",
            "subnet": "10.15.20.0/24",
            "routes": [
                { "dst": "0.0.0.0/0" },
                { "dst": "1.1.1.1/32", "gw":"10.15.20.1"}
            ]
        }
    }
    EOF
    $ sudo ip netns add 1234567890
    $ sudo CNI_COMMAND=ADD CNI_CONTAINERID=1234567890 \
     CNI_NETNS=/var/run/netns/1234567890 CNI_IFNAME=eth12 \
     CNI_PATH=`pwd` ./bridge <mybridge.conf
    $ ifconfig
    cni_bridge0 Link encap:Ethernet  HWaddr 0a:58:0a:0f:14:01
              inet addr:10.15.20.1  Bcast:0.0.0.0  Mask:255.255.255.0
              inet6 addr: fe80::3cd5:6cff:fef9:9066/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:8 errors:0 dropped:0 overruns:0 frame:0
              TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000
              RX bytes:536 (536.0 B)  TX bytes:648 (648.0 B)
    …
    

    Дополнительные примеры для быстрого запуска CNI и сетевых плагинов представлены в README проекта (раздел «How do I use CNI?»).

    Сторонние плагины для CNI


    Одной из главных ценностей CNI, конечно же, являются сторонние плагины, обеспечивающие поддержку различных современных решений для Linux-контейнеров. Среди них:

    • Project Calico (виртуальная сеть L3, интегрированная с инструментами оркестровки и облачными платформами);
    • Weave (простая сеть для multi-host Docker-инсталляций);
    • Contiv Netplugin (политики/ACL/QoS и другие возможности для контейнеров в кластерных установках типа multi-host);
    • Flannel (сетевая фабрика для контейнеров от CoreOS);
    • SR-IOV, Cilium (BPF/XDP), Multus (плагин Multi для Kubernetes от Intel), VMware NSX и другие…

    К сожалению, какого-либо каталога или постоянно обновляемого их списка пока нет, но для общего представления о текущем распространении CNI этого должно быть достаточно.

    Дополнительным индикатором зрелости проекта является его интеграция в существующие исполняемые среды для контейнеров: rkt и Kurma, — и платформы для работы с контейнерами: Kubernetes, OpenShift, Cloud Foundry, Mesos.

    Заключение


    Текущий статус CNI позволяет уже сейчас говорить не только о «больших перспективах» проекта, но и ощутимых реалиях его практической применимости. Принятие в CNCF — официальное признание индустрией и гарантия для дальнейшего развития. А всё это означает, что самое время как минимум узнать про CNI, с которым скорее всего рано или поздно придётся встретиться.

    P.S.


    Читайте также в нашем блоге:

    • +15
    • 11.7k
    • 3
    Флант
    481.86
    Специалисты по DevOps и Kubernetes
    Support the author
    Share post

    Comments 3

      +1
      Качественная статья, спасибо, никак руки не доходят нормально на это посмотреть.

      Правильно я понимаю что фактически это надстройки над VETH?
      Можно ли использовать CNI без внешнего контроллера (но скажем так что бы он работал например на уровне macvlan)? т.е. без calico, flannel, etc
      Я предполагаю что дальше там кругом openvswitch (т.е. в него вставляется второй конец VETH)?
        +1
        Надстройки над veth — да. Для контейнера создаётся network namespace, интерфейсы которого управляются с помощью плагинов CNI. Вот из спецификации:
        A CNI plugin is responsible for inserting a network interface into the container network namespace (e.g. one end of a veth pair) and making any necessary changes on the host (e.g. attaching other end of veth into a bridge).

        Calico, Flannel и т.п. — это просто дополнительные плагины, которых может и не быть. Вот есть просто «обычный» (встроенный в CNI плагин) macvlan.
        Во второй конец veth могут вставляться разные решения, что как раз и реализуется плагинами.
          0
          То есть даже не надстройки а конфигурилки :)

          Странно что нет vxlan плагина, вроде у linux с ним все хорошо даже без OVS.

      Only users with full accounts can post comments. Log in, please.