
По моему опыту, все обновления Cisco ACI, начиная с мажорной версии 4 и далее, ставили только одну серьезную задачу — найти достаточно чая, чтобы пить его на протяжении обновления фабрики. Кроме шуток, процесс построен очень удачно, и справиться с ним может даже сотрудник с junior-подготовкой, естественно, если заранее ознакомится с Release notes и рекомендациями вендора. Но в этот раз все пошло не по плану.
На обновление фабрики у нас ушло несколько бессонных суток, в течение которых мы пережили частичный выход из строя кластера, выход из строя RAID контроллера одного из серверов и, потенциально, полный wipe топологии... Но все закончилось хорошо, мы обновили фабрику, решили проблему заказчика, а самое главное – получили по островку седых волос бесценный опыт.
Меня зовут Сергей Балдаков, в компании К2Тех наша команда занимается комплексной технической поддержкой мультивендорной инфраструктуры. В том числе производителей, ушедших из России. Надеюсь, наш опыт поможет инженерам, которые обслуживают оборудование без поддержки вендора и позволит избежать граблей, которые мы с лихвой насобирали в этой истории.
Часто слышу от коллег и заказчиков, что Cisco ACI для многих является сложным из-за его архитектуры и иного подхода к абстракции сетевой топологии по сравнению с классическими решениями для дата-центров. Действительно, на раннем этапе, когда продукт только делал первые шаги от простого управления по API к полноценной модели API-driven, возникло множество вопросов и к функционалу, и к реализации некоторых процессов. Сейчас, по моему мнению, Cisco ACI сильно опережает существующие решения на рынке и позволяет значительно снижать OpEX на содержание сети дата-центра.
Итак, нам прилетела на первый взгляд довольно рутинная задача по обновлению фабрики Cisco ACI. Процесс не затрагивал мажорную версию (5.2.3g - 5.3.2с), а также не требовалось обновление Multisite оркестратора для этого обновления. Несмотря на то, что работы по обновлению коммутаторов при соблюдении рекомендаций производителя и отсутствии orphan-портов на коммутаторах проходят без прерывания сервисов, заказчик решил провести их в ночное окно (как в воду глядел).
Коротко о построении самого процесса
Логика обновления Cisco ACI следующая:
Сначала обновляется группа APIC контроллеров, которая управляет работой данной фабрики и отвечает за ее control plane. Затем – коммутаторы, как правило, в два этапа: сначала нечетные, затем четные . Такой порядок позволяет избежать случая, когда оба коммутатора, составляющие VPC-пару, уходят в перезагрузку.
Этот процесс не быстрый, но при должной подготовке и выполнении инструкции вендора проходит хоть и медленно, но беспроблемно.
В нашем случае работы были поделены на 4 этапа:
- 0бновление APIC на Site1;
- обновление коммутаторов на Site1;
- обновление APIC на Site2;
- обновление коммутаторов на Site2.
Работы по первым двум пунктам прошли без проблем, и Site1 обновился ожидаемо без эксцессов. А дальше началось интересное.
Не видишь APIC ? А он есть!
Образы предзагружены на контроллеры, Release notes прочитаны, pre-upgrade script выполнен, чай налит. Action.
Первый звоночек прозвенел, когда после обновления APIC1 на втором сайте контроллер загрузился, однако не отобразился как полноценный член кластера. Соответственно, остальные члены кластера не спешили продолжать обновление, так как не видели первый контроллер в состоянии Fully Fit. В итоге кластер завис вот в таком состоянии:

При этом сам контроллер даже не отображался в списках.

Где бессильно GUI, всегда на выручку приходит CLI. Я зашел на контроллер APIC1 и попытался понять, что же с ним не так. Выяснилось, что он загрузился, запустил службы, однако контроллер не видел inband vlan. Вернее, он не был на нем создан.
Как должен выглядеть нормальный APIC:
DC2-APIC-02# ifconfig | grep bond0.
bond0: flags=5187<UP,BROADCAST,RUNNING,MASTER,MULTICAST> mtu 1500
bond0.245: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1496
bond0.4093: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1496
Как выглядел APIC у меня:
DC2-APIC-01# ifconfig | grep bond0.
bond0: flags=5187<UP,BROADCAST,RUNNING,MASTER,MULTICAST> mtu 1500
bond0.4093: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
Что вызвало вопрос: по какой причине APIC1 отказался поднимать inband vlan и быть частью существующего кластера? Первая мысль, которая пришла в голову - сравнить, как кластер видят «здоровый» контроллер и контроллер, который не подключается к нему.
Вот вывод со «здорового» контроллера
DC2-APIC-02# avread
Cluster:
-------------------------------------------------------------------------
fabricDomainName ACI_Fabric_2
discoveryMode PERMISSIVE
clusterSize 3
version apic-5.3(2c)
drrMode OFF
operSize 3
APICs:
-------------------------------------------------------------------------
APIC 1 APIC 2 APIC 3
version 5.2(3g) 5.2(3g)
address 0.0.0.0 X.X.0.2 X.X.0.3
oobAddress X.X.240.18/26 X.X.240.19/26 X.X.240.212/26
routableAddress 0.0.0.0 0.0.0.0 0.0.0.0
tepAddress 0.0.0.0 X.X.0.0/16 X.X.0.0/16
podId 0 1 1
chassisId -.- 762d6e7a-.-f7a8b0d2 1a9bca22-.-ab6c1ff8
cntrlSbst_serial (ERASED,) (APPROVED,WZPXXXXXXX2) (APPROVED,WZPXXXXXXX3)
active NO (zeroTime) YES YES
flags c--s cra- cra-
health 0 255 255
STANDBY APICs:
-------------------------------------------------------------------------
APIC 4 APIC 21
version 5.2(3g)
address X.X.0.4 0.0.0.0
oobAddress X.X.240.218/26 X.X.240.218/26
routableAddress 0.0.0.0 0.0.0.0
tepAddress X.X.0.0/16 0.0.0.0
podId 1 0
chassisId 1c3a0692-.-dbe660aa -.-
cntrlSbst_serial (APPROVED,WZPXXXXXXX4) (ERASED,)
active YES NO
flags cra- ----
health online 1
А вот как видит кластер контроллер обновленный:
DC2-APIC-01# avread
Appliance Director is not running locally hence below av information could be stale!
Cluster:
-------------------------------------------------------------------------
operSize 1
clusterSize 3
fabricDomainName ACI_Fabric_2
version 5.3(2c)
discoveryMode PERMISSIVE
drrMode OFF
kafkaMode OFF
APICs:
-------------------------------------------------------------------------
APIC 1
version 5.3(2c)
address X.X.0.1
oobAddress X.X.240.18/26
routableAddress 0.0.0.0
tepAddress X.X.0.0/16
podId 1
chassisId 688ad2ae-.-bae24bee
cntrlSbst_serial (APPROVED,123456789)
active YES
flags cra-
health 1
Больше всего смутил тот факт, что в группе контроллеров, на которых работала фабрика в тот момент, версия кластера уже была сменена на apic-5.3(2c), при этом контроллеры в нем находились версии 5.2(3g).
А так же серийник контроллера APIC1, который жил сам по себе в отрыве от кластера. Не смотря на то, что в данном кейсе серийные номера изменены, в выводе действительно была последовательность от 1 до 9 в поле серийного номера. Что явно намекало на некорректную работу.
После продолжительных обсуждений было принято следующее решение: версию кластера, который сейчас управляет фабрикой – это APIC2 и APIC3, – установить равной - 5.2(3g) в соответствии с текущими действующими прошивками контроллера, благо для этого не нужны root права доступа.
Процедура изменения версии контроллера в базе объектов делается стандартными инструментами APIC:
DC2-APIC-02# bash
DC2-APIC-02> cd /mit/uni/controller/ctrlrfwpol
DC2-APIC-02> moset version '5.2(3g)'
DC2-APIC-02> moconfig commit
Затем я сделал декомиссию проблемного сервера, который не хотел вставать в кластер.
В этот момент состояние кластера было следующим при проверке из GUI:

Версия кластера изменилась успешно, однако проблему это не решило, тем не менее натолкнуло на мысль. В выводах APIC2 и APIC3 заметил разницу в параметре cntrlSbst serial, один сервер считал, что серийник в кластере удален, что соответствует действительности, второй – что серийник не определен, что в нашем случае неверно. К тому же это хорошо билось с тем фактом, что серийник ноды APIC1, которая жила сама по себе, отображается в виде 123456789.
DC2-APIC-02# avread
Cluster:
-------------------------------------------------------------------------
fabricDomainName ACI_Fabric_2
discoveryMode PERMISSIVE
clusterSize 3
version apic-5.2(3g)
drrMode OFF
operSize 3
APICs:
-------------------------------------------------------------------------
APIC 1 APIC 2 APIC 3
version 5.2(3g) 5.2(3g)
address 0.0.0.0 X.X.0.2 X.X.0.3
oobAddress X.X.240.18/26 X.X.240.19/26 X.X.240.212/26
routableAddress 0.0.0.0 0.0.0.0 0.0.0.0
tepAddress 0.0.0.0 X.X.0.0/16 X.X.0.0/16
podId 0 1 1
chassisId -.- 762d6e7a-.-f7a8b0d2 1a9bca22-.-ab6c1ff8
cntrlSbst_serial (ERASED,) (APPROVED,WZPXXXXXXX2) (APPROVED,WZPXXXXXXX3)
active NO (zeroTime) YES YES
flags c--s cra- cra-
health 0 255 255
DC3-APIC-01# avread
Cluster:
-------------------------------------------------------------------------
fabricDomainName ACI_Fabric_2
discoveryMode PERMISSIVE
clusterSize 3
version apic-5.2(3g)
drrMode OFF
operSize 3
APICs:
-------------------------------------------------------------------------
APIC 1 APIC 2 APIC 3
version 5.2(3g) 5.2(3g)
address 0.0.0.0 X.X.0.2 X.X.0.3
oobAddress X.X.240.18/26 X.X.240.19/26 X.X.240.212/26
routableAddress 0.0.0.0 0.0.0.0 0.0.0.0
tepAddress 0.0.0.0 X.X.0.0/16 X.X.0.0/16
podId 0 1 1
chassisId -.- 762d6e7a-.-f7a8b0d2 1a9bca22-.-ab6c1ff8
cntrlSbst_serial (UNDEFINED,) (APPROVED,WZPXXXXXXX2) (APPROVED,WZPXXXXXXX3)
active NO (zeroTime) YES YES
flags ---s cra- cra-
health 1 255 255
Решили проверить, в каком состоянии находятся ноды в представлении Managed objects через запрос moquery
DC2-APIC-02# moquery -c infraWiNode
Total Objects shown: 6
# infra.WiNode
id : 1
addr : 0.0.0.0
adminSt : out-of-service
annotation :
apicMode : active
chassis :
childAction :
cntrlSbstState : erased
dn : topology/pod-1/node-2/av/node-1
extMngdBy :
failoverStatus : completed
health : never-known
lcOwn : local
mbSn :
modTs : 2024-10-16T18:37:03.637+03:00
monPolDn : uni/fabric/monfab-default
mutnTs : zerotime
name :
nameAlias :
nodeName : DC2-APIC-01
operSt : unregistered
podId : 0
rn : node-1
routableIpAddr : 0.0.0.0
status :
targetMbSn : WZPXXXXXXX4
uid : 0
userdom : all
DC3-APIC-01# moquery -c infraWiNode
Total Objects shown: 6
# infra.WiNode
id : 1
addr : 0.0.0.0
adminSt : out-of-service
annotation :
apicMode : active
chassis :
childAction :
cntrlSbstState : undefined
dn : topology/pod-1/node-3/av/node-1
extMngdBy :
failoverStatus : completed
health : never-known
lcOwn : local
mbSn :
modTs : 2024-10-16T18:36:25.828+03:00
monPolDn : uni/fabric/monfab-default
mutnTs : zerotime
name :
nameAlias :
nodeName : DC2-APIC-01
operSt : unregistered
podId : 0
rn : node-1
routableIpAddr : 0.0.0.0
status :
targetMbSn : WZPXXXXXXX4
uid : 0
userdom : all
И тут стала понятной проблема, из-за которой сервер не принимался самим кластером. По неизвестной причине (выяснить её в последствии так и не удалось, поскольку приоритетом было восстановление работоспособности, и диагностические данные потерлись при дальнейших работах) в поле targetMbSN прописался серийник standby контроллера, который все это время находился в этом же кластере. Соответственно, текущие ноды никак не могли принять в кластер контроллер, серийный номер которого не соответствует указанному в инфраструктурном MO.
На этом пункте было принято решение сделать паузу, составить план действий и дать передохнуть участникам забега. Благо, даже на двух активных контроллерах ACI полностью функциональна.
Что предстояло сделать? Во-первых, разобраться, как удалить залипший серийник из MO APIC2 и APIC3. Во-вторых, для надежности сделать Reimage контроллера APIC1, чтобы откатить его на версию 5.2(3g) и вернуть кластер в состояние «до обновления» – стандартной процедуры отката в данном случае не предусмотрено, только полный Reimage контроллера.
Unforeseen Consequences
После нескольких попыток поискать встроенные способы осуществить процедуру корректировки MO было решено попробовать воспользоваться широкими возможностями API Cisco ACI и использовать CURL.
В итоге у нас получилась следующая последовательность для контроллеров 2 и 3:
DC2-APIC-02# bash
DC2-APIC-02> echo '<infraWiNode id="1" targetMbSn="" status="modified"/>' > node1.xml
DC2-APIC-02> icurl -gX POST http://localhost:7777/api/node/mo/topology/pod-1/node-2/av.xml -d @node1.xml
DC2-APIC-02# bash
DC2-APIC-02> echo '<infraWiNode id="1" targetMbSn="" status="modified"/>' > node1.xml
DC2-APIC-02> icurl -gX POST http://localhost:7777/api/node/mo/topology/pod-1/node-3/av.xml -d @node1.xml
Также был успешно выполнен Reimage APIC1, который принес неутешительные результаты – RAID контроллер “приуныл” от всего этого и вышел из чата после перезагрузки сервера. Судя по криво прошедшему обновлению, предпосылки к этому уже были, хоть и без явных алертов.
А на этот случай у нас есть багор (с)
Хорошо, что заказчик не пренебрег рекомендациями вендора и использовал в своей инфраструктуре standby APIC контроллер. Таким образом мы смогли сэкономить время и не отправлять подменный контроллер из ЗИП. Быстро переобувшись, мы сделали Decomission standby APIC сервера, провели Clean Wipe и настроили его в качестве APIC1 с теми же системными настройками. А заказчик тем временем передал нашей логистической службе неисправный APIC для доставки его из дата-центра к нам в лабораторию для диагностики . Мы сделали Decomission standby APIC сервера. Провели Clean Wipe и перенастроили его в качестве APIC1 с теми же системными настройками. Ирония в том, что при таком сценарии могли бы вовсе не менять серийный номер этого APIC ранее.
Кластер собрался, мы получили замечательную картинку:

Однако, как выяснилось, я недооценивал инженеров Cisco, разрабатывающих Redundancy системы обновления контроллеров.
Спустя 5 минут после всеобщего ликования и радости от того, что практически бессонные сутки позади, пришла отбивка от системы мониторига заказчика о том, что недоступен APIC2.
Зайдя в GUI, я увидел неприглядную картину: APIC2 – Unavailible, а Health state двух живых находится в состоянии Data layer partitialy diverged. Здесь скриншот, к сожалению, не сохранился поскольку напряжение всех тканей тела, способных к сокращению, достигло пиковых значений и было уже не до истории.
В этот момент я почувствовал себя примерно как этот велосипедист на картинке и приготовился писать заявление на увольнение по собственному, так как потеря трех APIC серверов грозила полной потерей фабрики из 40 с лишним коммутаторов.

После минутного ступора мозг начал лихорадочно анализировать происходящее, и тут пришло понимание того, что скрипт обновления все время наших манипуляций спал, и не отваливался по таймауту, а терпеливо ждал, когда же у него появится первый контроллер и он наконец-то сможет продолжить заниматься обновлением. Что, собственно, и произошло: как только скрипт увидел нормальный здоровый первый контроллер, он начал обновлять второй и затем третий. И его мало волновало, что версия кластера в MO была изменена на 5.2(3g).
Спустя примерно 40 минут, и обновление APIC2 и APIC3 мы стали наблюдать следующую неприглядную картину. Кластер с версией 5.2(3g) имел два контроллера с более высокой версией, и один со старой. При этом они в GUI периодически перемаргивались сообщениями о том, что Data layer patitially diverged. Это говорило о том, что APIC никак не могут нормально раскидать полностью шарды между собой.
DC2-APIC-02# avread
Cluster:
-------------------------------------------------------------------------
fabricDomainName ACI_Fabric_2
discoveryMode PERMISSIVE
clusterSize 3
version apic-5.2(3g)
drrMode OFF
operSize 3
APICs:
-------------------------------------------------------------------------
APIC 1 APIC 2 APIC 3
version 5.2(3g) 5.3(2с) 5.3(2с)
address X.X.0.1 X.X.0.2 X.X.0.3
oobAddress X.X.240.218/26 X.X.240.19/26 X.X.240.212/26
routableAddress 0.0.0.0 0.0.0.0 0.0.0.0
tepAddress X.X.0.0/16 X.X.0.0/16 X.X.0.0/16
podId 1 1 1
chassisId 6a5264dc-.-61f22fc9 762d6e7a-.-f7a8b0d2 1a9bca22-.-ab6c1ff8
cntrlSbst_serial (APPROVED,WZPXXXXXXX4) (APPROVED,WZPXXXXXXX2) (APPROVED,WZPXXXXXXX3)
active YES YES YES
flags cra- cra- cra-
health 255 255 255
STANDBY APICs:
-------------------------------------------------------------------------
APIC 4 APIC 21
version
address 0.0.0.0 0.0.0.0
oobAddress X.X.240.218/26 X.X.240.218/26
routableAddress 0.0.0.0 0.0.0.0
tepAddress 0.0.0.0 0.0.0.0
podId 1 0
chassisId -.- -.-
cntrlSbst_serial (ERASED,) (ERASED,)
active NO NO
flags ---- ----
Свет в конце тоннеля
После наших приключений ранее дальнейшая задача уже не казалась невыполнимой.
Единственный минус заключался в том, что поскольку подобное состояние кластера, видимо, не предусматривалось вендором (в чем я с ними солидарен), то такого кадавра они не собирали даже в лаборатории).
Схема представлялась следующей:
- делаем decomission APIC1;
- принудительно меняем версию кластера на APIC2 и APIC3, как уже делали ранее в данном кейсе;
- отключаем порты в сторону APIC1 (скорее предосторожность, чтобы он не инициировал попытки Discovery фабрики по LLDP;
- сбрасываем APIC1 и заводим его как абсолютно левый контроллер под левым именем, не подключая к фабрике;
- обновляем APIC1 на целевую версию – 5.3(2c);
- сбрасываем ещё раз;
- настраиваем как корректный APIC1;
- включаем порты на Leaf коммутаторе в его сторону;
- делаем comission;
- PROFIT!
Причем, что интересно, он прекрасно обновился через GUI как кластер из одного контроллера. После того как мы выполнили обозначенные выше пункты плана, наконец-то мы получили нормальный кластер.
Ниже представлен вывод полностью здорового кластера контроллеров, с уже восстановленным Standby. Проблемный же сервер привезли в лабораторию. В нем была выявлена аппаратная неисправность RAID контроллера, после чего его заменили и вернули сервер в работу в качестве Standby в этой же фабрике.
DC2-APIC-01# avread
Cluster:
-------------------------------------------------------------------------
operSize 3
clusterSize 3
fabricDomainName ACI_Fabric_2
version apic-5.3(2c)
discoveryMode PERMISSIVE
drrMode OFF
kafkaMode ON
APICs:
-------------------------------------------------------------------------
APIC 1 APIC 2 APIC 3
version 5.3(2c) 5.3(2c) 5.3(2c)
address X.X.0.1 X.X.0.2 X.X.0.3
oobAddress X.X.240.218/26 X.X.240.19/26 X.X.240.212/26
routableAddress 0.0.0.0 0.0.0.0 0.0.0.0
tepAddress X.X.0.0/16 X.X.0.0/16 X.X.0.0/16
podId 1 1 1
chassisId 6a5264dc-.-61f22fc9 762d6e7a-.-f7a8b0d2 1a9bca22-.-ab6c1ff8
cntrlSbst_serial (APPROVED,WZPXXXXXXX4) (APPROVED,WZPXXXXXXX2) (APPROVED,WZPXXXXXXX3)
active YES YES YES
flags cra- cra- cra-
health 255 255 255
STANDBY APICs:
-------------------------------------------------------------------------
APIC 4 APIC 21
version 5.3(2c)
address X.X.0.4 0.0.0.0
oobAddress X.X.240.18/26 0.0.0.0
routableAddress 0.0.0.0 0.0.0.0
tepAddress X.X.0.0/16 0.0.0.0
podId 1 0
chassisId d6d5dce4-.-8bd9fd99 -.-
cntrlSbst_serial (APPROVED,WZPXXXXXXX1) (UNDEFINED,)
active YES NO
flags cra- ----
health online 0
Выводы
Что оказалось важным? Всегда при обновлении нужно быть готовым к тому, что что-то пойдет не по плану. Например, выйдет из строя RAID контроллер. Естественно, все предусмотреть невозможно, но моральная готовность тоже важна. В данном случае нас очень выручило наличие standby контроллера у заказчика уже на площадке. Мы сэкономили время на логистику и не пришлось тратить несколько часов на доставку сервера из нашего ЗИП.
Что я сделал бы по-другому:
Не стал бы всеми силами пытаться восстановить APIC1 до изначального состояния. Скорее всего, правильным решением было бы сразу использовать APIC-standby как замену, и потом уже разбираться с APIC1, на месте/в лабе.
Теперь я знаю, что есть специальная команда, которая позволяет прервать скрипт обновления фабрики, так как у него нет естественного тайм-аута.
Больше не буду заранее заваривать чай).
Если тема вам интересна, пишите в комментариях, о чем бы ещё хотели узнать. У нас есть много увлекательных историй про фабрики ACI. И не только про них. Будем рады поделиться именно техническим опытом поддержки решений, который успели накопить за время поддержки железа как совместно с вендором, так и самостоятельно.