На прошлой неделе фонд 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, с которым скорее всего рано или поздно придётся встретиться.

Не забывайте также подписываться на хаб нашей компании, чтобы не пропустить новые статьи и рецепты по темам DevOps и системного администрирования GNU/Linux! ;-)
Поделиться с друзьями
-->

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


  1. ayurtaykin
    31.05.2017 14:32
    +1

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

    Правильно я понимаю что фактически это надстройки над VETH?
    Можно ли использовать CNI без внешнего контроллера (но скажем так что бы он работал например на уровне macvlan)? т.е. без calico, flannel, etc
    Я предполагаю что дальше там кругом openvswitch (т.е. в него вставляется второй конец VETH)?


    1. shurup
      31.05.2017 16:52
      +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 могут вставляться разные решения, что как раз и реализуется плагинами.


      1. ayurtaykin
        31.05.2017 18:04

        То есть даже не надстройки а конфигурилки :)

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