В Krakensystems мы работаем с различными устройствами IoT. Они являются нашей основной инфраструктурой для сбора данных и отправки их для дальнейшего агрегирования трубопроводов. На данный момент они реализованы как черные устройства Beaglebone, процессор ARMV7L Hard Float, AM335X 1 ГГц ARM® Cortex-A8 и только 512 МБ ОЗУ. В этом блоге мы освещаем вариант использования и обоснование использования Kubernetes на таких недостаточных устройствах.
Эти устройства выполняют простые услуги. Чтение Modbus Registers, или протокола XBEE, или прикрепление к OBD (встроенная диагностика для транспортных средств), анализ данных, сериализация в формате ProtoBuf и отправка на автобус.
Критерии дизайна и реализация
Формат развертывания
Мы хотим развернуть программное обеспечение в качестве неизменного бинарного/контейнера. Из -за процесса сборки C ++ загадочная настройка в Krakensystems и множество общих библиотечных зависимостей, настройка контейнера имеет наибольший смысл для этого варианта использования. Статический двоичный файл также является жизнеспособной альтернативой, но это потребует рефакторирования C ++, наша текущая система сборки, написанная как коллекция сценариев Bash/Makefile, работающая около 15 минут от 0, и около нескольких минут на CI после кэширования.
Другим решением было развертывание услуг голой металл. В этой настройке наследия была специальная общая библиотечная папка на услугу, и мы сделали Ld_library_path
Объединение для управления общим управлением библиотекой, победив в первую очередь общие библиотеки. Тем не менее, из -за создания системы текущего состояния, создаваемого статическим бинарным был (DEV) трудоемким.
Kubernetes с решением для управления контейнерами идеально подходит для нашего варианта использования. Nomad или Plain Old Docker/Cri-O/RKT также удовлетворит этот критерий дизайна. Статические двоичные файлы с SystemD также являются удовлетворительным выбором, если это было просто сделать в настоящем состоянии кодовой базы.
Мониторинг
Узел и сервис мониторинг Aliveny имеет решающее значение. Нам требуется какой -то агент, работающий на узле и отправив, что я жив в какую -то систему, вместе со зрелым конвейером оповещения. Консул является одним из решений. У Kubernetes есть этот вне коробки, и вместе с Правилами оповещения Прометея казались естественным соответствием. Мы также используем Prometheus/Grafana/Alertmanager на протяжении всей нашей инфраструктуры, что сделало этот вариант более привлекательным.
Кроме того, проверка здоровья и готовности к готовности не особенно полезна для устройств Edge, так как сбой процесса сигнализирует о проблеме. Они не являются серверным компонентом, требующим принятия клиентских подключений.
Тем не менее, в будущем мы планируем представить проверки на сфере услуг в качестве механизма сбоя в случае, если служба не отправляет данные на шину сообщения — ее основная цель.
Оставшаяся инфраструктура Ascalia находится на Kubernetes, поэтому она имела смысл повторно использование тех же инструментов и настройки для наших устройств Edge. Менее разные движущиеся части всегда лучше и приводят к эксплуатационной простоте, несмотря на то, что Kubernetes не прост в эксплуатации.
Обновления
Устройства Edge — это не статичные острова, которые навсегда отдыхают в Тихом океане. Код часто изменяется, и конфигурация еще чаще.
Услуги предназначены для простоты. Их конфигурация сохраняется как файл YAML в рамках Инотифицировать
Следите за изменениями. Таким образом, любой механизм обновления возможна в будущем как коляска, но контролирует сложность развития. Кроме того, это легче отлаживать.
Конфигурация устройства на крае хранится в RDBMS, Postgres в этом случае. Наличие оправы с краями 100 -х или 1000 -х годов, опрашивавших RDBMS для простых паров ключей/значения, не получится. Кроме того, нет уведомлений о стиле Push от RDBMS в обновлении ключей. Таким образом, нам нужен дополнительный слой между ними.
Мы повторно используем сервер API Kubernetes, и он поддерживает ключ/значение и т. Д. Мы определили каждое устройство Edge как объект CRD (определение пользовательского ресурса), поддерживающую богатую и специфичную для домена информацию. Kubernetes также сервер как примитивное управление запасами, дополняющее реальную поддержку Django для операций (т. Е. Мне все равно, что Django делает, пока обновляет правильные конечные точки отдыха в API Kubernetes)
В будущем, возможно, службы Edge должны наблюдать за самим хранилищем ключей/значения, будь то сервер API Kube и т. Д., Консул, Riak, Redis или любая другая реализация общих ключей/значения.
Наконец, нам нужны асинхронные обновления. Устройства могут быть офлайн во время приложения обновления. Это исключает все неагментные решения для управления конфигурацией. Ansible, наш любимый инструмент управления конфигурацией для его простоты и мощности используется только для начальной настройки, а не процедуры обновления (обновление службы).
Настройка Wireguard VPN
Поскольку мы используем решение VPN Wireguard, нам нужно, чтобы IP/общедоступный IP -адрес клиентского сервера синхронизировал асинхронно. Это влечет за собой наличие дополнительного агента на Edge Device, который вы должны следить, отслеживать и убедиться, что он жив.
Нам также нужно хранить общедоступный ключ автономного устройства и легкий осмотр для этих ключей/настроек. CRD Kubernetes естественны для этой роли. Мы повторно используем магазин поддержки ETCD, имеем хороший RBAC на этих объектах, и мы определили пользовательские столбцы принтера для более легкого управления узлами VPN.
Мы использовали следующие внутренние инструменты с открытым исходным кодом:
Короче говоря, мы загрузили в Wireguard VPN с помощью WG-CNI-роли. Это также установило CNI на основе Wireguard для использования в нашем кластере Kubernetes.
Роль WG-CNI создала наши пользовательские CRD-манифесты, представляющие клиента/серверы в топологии VPN Wireguard.
После применения манифестов мы запустили оператор Wireguard Daemonset, поддерживая узлы синхронизации с дальнейшими дополнениями/удалением.
Первоначальное развертывание
Это не без проблем. Мы использовали Kubespray как зрелое решение для развертывания Kubernetes. Это единственное полное решение для развертывания металла. Будучи на основе Ansible, мы знакомы с этим и можем легко расширить его, если это необходимо … и это было необходимо.
Мы столкнулись с множеством проблем:
- Отсутствующая поддержка на руке
- По умолчанию изображение паузы не поддерживает руку
- Отсутствует CPUSET (обновление ядра до 4.19 LTS решило его)
- Становитесь в проблемах космоса несколько раз
- Фланелевая не хватает многоартной поддержки в Kubespray ((до того, как мы перешли на Wireguard CNI навсегда))
- …
Большинство из них отслеживаются в следующем выпуске/PRS:
Вопросы:
PRS:
- Добавьте поддержку изображений ARM для Hyperkube, Kubeadm и CNI_BININE
- Поддержка фланелевой кросс -платформы
После успешного применения времени выполнения контейнера по умолчанию, Docker, пришло время для базового анализа производительности.
Первоначальный анализ производительности
Основной контрольный список
- EMMC монтируется без Atime
- Использование Binary Armhf (
readelf -a $ (который kubelet | grep TAG_ABI_VFP_ARGS
) - кошка
/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
ИСПОЛЬЗОВАТЬ
debian@bbb-test:~$ vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 4 0 0 6088 19916 271064 0 0 25 20 17 32 18 12 69 0 0 0 0 0 6120 19916 271064 0 0 0 0 1334 4098 13 20 67 0 0 0 0 0 6120 19916 271064 0 0 0 0 1554 4046 13 19 68 0 0 0 0 0 6120 19924 271056 0 0 0 16 929 2443 10 8 81 1 0 0 0 0 6120 19924 271064 0 0 0 0 1611 4128 24 20 56 0 0 0 0 0 6120 19924 271064 0 0 0 0 919 2443 6 11 83 0 0 0 0 0 5996 19924 271064 0 0 0 0 1240 3312 29 28 42 0 0 0 0 0 5996 19924 271064 0 0 0 0 958 2417 13 9 77 0 0 3 0 0 5996 19924 271064 0 0 0 0 1915 5693 28 25 46 0 0 0 0 0 5996 19924 271064 0 0 0 0 1089 3296 12 18 70 0 0
debian@bbb-test:~$ pidstat 30 1 Linux 4.19.9-ti-r5 (bbb-test) 02/25/2019 _armv7l_ (1 CPU) 04:59:26 PM UID PID %usr %system %guest %CPU CPU Command 04:59:56 PM 0 26749 3.54 1.62 0.00 5.16 0 dockerd 04:59:56 PM 0 26754 0.44 0.37 0.00 0.81 0 docker-containe 04:59:56 PM 0 26784 0.00 0.07 0.00 0.07 0 kworker/u2:2-flush-179:0 04:59:56 PM 0 28814 10.08 10.79 0.00 20.88 0 kubelet 04:59:56 PM 0 29338 0.51 1.15 0.00 1.65 0 kube-proxy 04:59:56 PM 997 29734 1.42 0.37 0.00 1.79 0 consul 04:59:56 PM 0 30867 0.03 0.00 0.00 0.03 0 docker-containe 04:59:56 PM 0 30885 0.47 0.67 0.00 1.15 0 flanneld 04:59:56 PM 1000 31776 0.30 0.07 0.00 0.37 0 mosh-server
Около 30% процессора находится на Kubernetes без какой -либо значимой работы.
iostat -xz 1 sar -n DEV 1 sar -n TCP,ETCP 1
Не показывают значительное давление в сети. SpeedTest-CLI показывает скорости загрузки/загрузки 30 мит, которые более чем достаточно для нашего варианта использования.
Таким образом, есть высокое использование ЦП с низким диском, памятью и сетью.
Анализ производительности
Строка Kubelet показывает, что в замках тратится около 66%:
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 65.66 1.671983 5006 334 60 futex 11.77 0.299775 967 310 epoll_wait 9.24 0.235263 364 647 nanosleep 2.58 0.065766 31 2136 clock_gettime 1.75 0.044623 38 1180 68 read ... ------ ----------- ----------- --------- --------- ---------------- 100.00 2.546516 10290 356 total
Хотя использование PPROF и профили трассировки показали более полезную информацию:
debian@bbb-test:~$ wget http://127.0.0.1:10248/debug/pprof/profile?seconds=120 debian@bbb-test:~$ wget http://127.0.0.1:10248/debug/pprof/trace?seconds=120
Оттуда мы заключили:
- 25% времени тратится на домашнее хозяйство
- Изменение по умолчанию 10 с
- Увеличение периода обновления узлов не значительно повлияло на использование ЦП
Эта домашняя работа предназначена в основном для метрик контейнеров, которые нам на самом деле не нужны каждые 10, время от времени вполне отлично подходит для нашего варианта использования.
GODEBUG=gctrace=1,schedtrace=1000 gc 80 @1195.750s 0%: 0.070+217+0.19 ms clock, 0.070+57/63/59+0.19 ms cpu, 24->24->12 MB, 25 MB goal, 1 P SCHED 1196345ms: gomaxprocs=1 idleprocs=1 threads=18 spinningthreads=0 idlethreads=6 runqueue=0 [0]
В процессе Kubelet нет больших проблем с GC GC GC, таким образом, не проанализировал это дальше. o
debian@bbb-test:~$ sudo perf stat -e task-clock,cycles,instructions,branches,branch-misses,instructions,cache-misses,cache-references ^C Performance counter stats for 'system wide': 16,203.12 msec task-clock # 1.000 CPUs utilized 4,332,572,389 cycles # 267393.223 GHz (71.42%) 911,023,486 instructions # 0.21 insn per cycle (71.40%) 98,098,648 branches # 6054350.923 M/sec (71.41%) 30,116,184 branch-misses # 30.70% of all branches (71.44%) 885,259,275 instructions # 0.20 insn per cycle (71.45%) 6,967,361 cache-misses # 1.836 % of all cache refs (57.16%) 379,417,471 cache-references # 23416495.155 M/sec (57.14%) 16.202385758 seconds time elapsed
Мы наблюдаем 30% частота ошибок в филиале в процессе Кубеле. После дальнейшего анализа это общеобразовательное. Этот дешевый процессор Arm имеет ужасные алгоритмы прогнозирования филиалов.
Улучшения
Мы выполнили следующие улучшения:
- порезал докер и заменил его плагином CRI. Конкретно мы использовали контейнер
- Увеличение интервала домашнего хозяйства с 10 до 10 м
- Выбросьте фланель для Wireguard CNI (в основном нативная маршрутизация)
Average: 0 9 0.00 0.14 0.00 0.24 0.14 - ksoftirqd/0 Average: 0 10 0.00 0.17 0.00 0.35 0.17 - rcu_preempt Average: 0 530 0.00 0.03 0.00 0.00 0.03 - jbd2/mmcblk1p1- Average: 0 785 0.00 0.07 0.00 0.21 0.07 - haveged Average: 0 818 0.03 0.00 0.00 0.00 0.03 - connmand Average: 0 821 4.64 4.47 0.00 0.00 9.12 - kubelet Average: 0 1416 0.14 0.07 0.00 0.03 0.21 - fail2ban-server Average: 0 1760 0.42 0.69 0.00 0.35 1.11 - kube-proxy Average: 0 3436 1.70 0.90 0.00 0.00 2.60 - containerd Average: 0 4274 0.07 0.03 0.00 0.07 0.10 - systemd-journal Average: 0 17442 0.00 0.38 0.00 0.17 0.38 - kworker/u2:2-events_unbound Average: 0 19070 0.00 0.03 0.00 0.00 0.03 - kworker/0:2H-kblockd Average: 0 26772 0.00 0.24 0.00 0.28 0.24 - kworker/0:1-wg-crypt-wg0 Average: 0 28212 0.00 0.31 0.00 0.28 0.31 - kworker/0:3-events_power_efficient
А в устойчивом состоянии у нас есть заповедник использования ЦП ~ 15% для пособий по мониторингу. Тем не менее, довольно немного, хотя и пригодно для жизни. Возможно, у Cri-O будет более низкий накладной, хотя у Containerd тоже довольно тонкие. Мы исследуем, как мы можем оптимизировать Kubelet для еще более низкого потребления ресурсов, отключив ненужные функции.
Резюме
Подводя итог, запускают ли kubernetes на Edge Devices Sane Choice? Может быть.
Для нас пока все хорошо, все работает с некоторыми значительными, хотя и пригодными для жизни.
Например, попытка установить только прометею node_exporter стреляет в ваш процессор каждый царапев и замедляет все, чтобы ползал для этих нескольких миллисекундов 100 -х годов.
Это оборудование довольно недостаточно, и с плохим прогнозом филиала делает любое программное обеспечение, работающее на нем слабее, чем на сопоставимых архитектурах ARMV8 или x86_64.
В будущем мы постараемся оптимизировать вещи еще дальше, надеясь, что сократит накладные расходы на ЦП Кубеле до более разумного процента. Мы попробовали K3S Rancher без большой разницы ((на самом деле худшая производительность, так как мы не могли изменить интервал домашнего хозяйства))
Есть также Kubeedge Проект, который выглядит многообещающе для Kubernetes на IoT.
использованная литература
- https://www.cnx-software.com/2013/04/22/how-to-detect-if-an-arm-elf-binary-is-hard-float-armhf-or-soft-float-armel/
- https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/
- https://github.com/rancher/k3s
- https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/
Оригинал: «https://dev.to/nmiculinic/kubernetes-on-arm-a-case-study-5ha4»