На прошлой неделе фонд 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! ;-)
Автор: shurup