Eksport i wizualizacja danych z kontrolera Cisco ACI APIC przy użyciu Graffana
Technologia Cisco ACI zdobyła dużą popularność jako nowoczesne rozwiązanie zapewniające wydajną i skalowalną infrastrukturę komunikacyjną dla aplikacji. Firmy i instytucje decydują się na wdrożenie Cisco ACI w swoich Data Center głównie ze względu na efektywność transportu danych, wbudowane mechanizmy bezpieczeństwa oraz łatwość skalowania zarówno pod względem wydajności, jak i zasięgu geograficznego.
ACI oferuje jednak znacznie więcej – jest przede wszystkim środowiskiem SDN (Software Defined Network), które umożliwia pełne zarządzanie poprzez narzędzia programistyczne, takie jak REST API. To rzadko wykorzystywana funkcja, która daje ogromne możliwości integracji, automatyzacji oraz budowania ekosystemu zarządzania Data Center opartego na ACI.
Jak wygląda zarządzanie przez API?
Zarządzanie za pomocą API jest jednym z trzech niezależnych sposobów na konfigurację środowiska SDN przez administratora. Standardowe interfejsy typu “command line” (CLI) czy interfejs graficzny (GUI) mogą zostać zastąpione oferującym te same możliwości interfejsem API. Jest to możliwe, ponieważ całość zarządzania konfiguracją ACI opiera się na dwóch fundamentalnych założeniach, które zostały dodane na etapie projektowania tej technologii przez Cisco:

Mechanizm zarządzania infrastrukturą ACI operuje na dwóch etapach konfiguracyjnych:
Zarządzanie w oparciu o model obiektowy
Wszystkie metody zarządzania (GUI, CLI, API) korzystają z tego samego API, a najlepiej obrazuje to poniższy rysunek:

Przykładowo, tworzenie instancji VRF za pomocą GUI, CLI czy API sprowadza się do stworzenia za pomocą protokołu REST obiektu klasy fvCtx
z odpowiednimi atrybutami. Przykładowe atrybuty obiektu klasy fvCtx w ACI odpowiadającego za przechowywanie konfiguracji sieci VRF (w formacie JSON):
"fvCtx": {
"attributes": {
"annotation": "",
"bdEnforcedEnable": "no",
"childAction": "",
"descr": "",
"dn": "uni/tn-common/ctx-prod",
"extMngdBy": "",
"ipDataPlaneLearning": "enabled",
"knwMcastAct": "permit",
"lcOwn": "local",
"modTs": "2022-03-22T12:12:33.092+02:00",
"monPolDn": "uni/tn-common/monepg-default",
"name": "prod",
"nameAlias": "",
"ownerKey": "",
"ownerTag": "",
"pcEnfDir": "ingress",
"pcEnfDirUpdated": "yes",
"pcEnfPref": "enforced",
"pcTag": "16386",
"scope": "2490369",
"seg": "2490369",
"status": "",
"uid": "15374"
}
}
Obiekty te są widziane konsystentnie, jako konfiguracja sieci VRF dokładnie tak samo pomiędzy wszystkimi trzema metodami zarządzania. Nie ma znaczenia za pomocą której metody obiekty te zostaną stworzone lub zmodyfikowane.
Przejdźmy teraz do metod dostępu do danych, które posiada w konfiguracji APIC. Są to dane opisujące konfigurację oraz dane zbierane z bieżącego działania infrastruktury (monitoring, stany tablic, wszystkie dynamiczne parametry operacyjne środowiska). Wszystkie te informacje są oczywiście zapisywane w tym samym modelu obiektowym, o którym wspomnieliśmy na początku. Czyli mamy pełny dostęp do tych informacji za pomocą interfejsu API, tak jak wcześniej mieliśmy możliwość zarządzania całą infrastrukturą.
W kontrolerze ACI oraz bezpośrednio z urządzeń, mamy do dyspozycji klasyczne metody używane do monitorowania sieci takie jak SNMP i Syslog. Pozwalają one na dostęp tylko do części informacji w odniesieniu do API, które pozwala na dostęp do wszystkich obiektów z liczącego ponad 6500+ klas modelu obiektowego. Poza tym, przez SNMP nie mamy dostępu do takich informacji jak choćby: model aplikacji czy parametry aplikacji komunikacji, bo jako takie nie są one dostępne z typowych urządzeniach sieciowych, z których to MIBy dla SNMP w ACI były zapożyczone.
Dostęp do danych poprzez API znakomicie ułatwia dostęp do informacji, gdyż nie ma potrzeby stosowania np. klasycznych i zawodnych metod parsowania rezultatów poleceń (stosowanych w anachronicznym podejściu Expect), czy ograniczonych wydajnościowo i jakościowo podejściu SNMP. Model dostępu do danych przez protokół REST zawiera jeszcze jedną ważną cechę, pozwala przenieść część przetwarzania danych na stronę serwera. To analogiczne podejście jakie mamy w typowym silniku bazy danych, gdzie zapytanie SQL zawiera filtry i agregatory, które wykonywane po stronie serwera na lokalnych danych. To powoduje znaczne zwiększenie szybkości przeszukiwania i zmniejsza ilość informacji, koniecznych do transportowania siecią. Przesyłamy wtedy tylko odfiltrowane rezultaty a nie pełną informację.
Przykład zapytania do serwera APIC które zwraca obiekt fvCtx spełniający warunek, że nazwa (atrybut “name”) będzie miała wartość “prod”, dane są dodatkowo posortowane malejąco po dacie ostatniej modyfikacji obiektu:/api/node/class/fvCtx.json?query-target-filter=eq(fvCtx.name,"prod")&order-by=fvCtx.modTs|desc
Przykładowa aplikacja wykorzystująca dostęp do danych za pomocą API
Jako praktyczny przykład powyższych możliwości, przedstawimy prostą aplikację, która za pomocą API będzie pobierać aktualną wartość parametru HealthScore dla obiektu reprezentującego Tenant. Tenant w ACI jest elementem separującym konfigurację i zawiera konfigurację polityki, aplikacji i zależnych obiektów. Parametr HealthScore jest numeryczną wartością z przedziału 0-100, informującą o stanie danego obiektu i obiektów zależnych (wchodzących w skład i będących niżej w hierarchii w modelu obiektowym). Czyli jest numeryczną reprezentacją poprawności działania i konfiguracji.
Strukturę aplikacji do zbierania danych z ACI i ich wizualizacji za pomocą Graffana i zależności jej komponentów przedstawia rysunek:
Składowymi aplikacji są następujące komponenty:
Przepływ informacji między komponentami odbywa się w większości za pomocą protokołu HTTP, w pierwszej kolejności za pomocą REST są pobierane dane z środowiska ACI. Do tego służy następujące zapytanie REST (technicznie jest to zapytanie GET HTTP na dany URL):
/api/mo/uni/tn-{tenant}.json?rsp-subtree-include=health,no-scoped’
Dane uzyskiwane są w postaci JSON i ich struktura wygląda następująco:
{'totalCount': '1', 'imdata': [{'healthInst': {'attributes': {'childAction': '', 'chng': '0', 'cur': '100', 'dn': 'uni/tn-common/health', 'maxSev': 'cleared', 'modTs': 'never', 'prev': '100', 'status': '', 'twScore': '100', 'updTs': ‘2022-07-31T19:41:53.113+02:00'}}}]}
Z tych informacji interesuje nas atrybut ‘cur’, który przechowuje aktualną wartość HealthScore. Czyli kod Python realizujący operację pobrania tych wartości wygląda następująco:
query_url = (f’/api/mo/uni/tn-{tenant}.json?rsp-subtree-include=health,no-scoped')
response = session.get(query_url)
health_inst = response.json()[‘imdata'][0]['healthInst']['attributes']
return health_inst[‘cur’]
Następnie instrukcje to definicja metryki Prometheus, dla której określimy funkcję zwracająca mierzoną wartość:
gauge = Gauge(f"tenant_{args.tenant}_health", f"Health score of the {args.tenant} tenant.")
gauge.set_function(lambda: get_tenant_health(args.tenant))
start_http_server(8000)
Skrypt następnie wchodzi w pętlę, w której będzie czekał na połączenia na porcie 8000 z bazy Prometheus z zapytaniami o metryki. Dane te są w formacie tekstowym. Przykładowy rezultat zapytania:
(snip)
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 2.8684288e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.65928927883e+09
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 1.15
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 8.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.048576e+06
# HELP tenant_common_health Health score of the common tenant.
# TYPE tenant_common_health gauge
tenant_common_health 100.0
Aplikacja exporter.py wymaga importu dwóch bibliotek Python, biblioteka obsługująca komunikację z APIC (głównie logowanie i obsługę sesji) oraz bibliotekę Prometheus:
import acitoolkit.acitoolkit as aci
from prometheus_client import start_http_server, Gauge
Obie biblioteki są dostępne w ramach managera ‘pip’ i można je zainstalować wraz z zależnościami poleceniem:
pip install acitoolkit prometheus-client
Aby uruchomić bazę danych Prometheus, potrzebujemy plik konfiguracyjny, który zawiera definicję skąd będą zbierane informacje i jak często będą one pobierane:
global:
scrape_interval: 15s
scrape_timeout: 5s
evaluation_interval: 15s
scrape_configs:
- job_name: 'aci'
scheme: 'http'
metrics_path: '/metrics'
static_configs:
- targets:
- ‘exporter:8000'
Po uruchomieniu bazy Prometheus za pomocą wbudowanego interfejsu graficznego możemy zapytaniem z poziomu konsoli Prometheus możemy sprawdzić poprawność zbierania informacji:

A także w widoku “Targets” widać, że informacje udostępnione przez skrypt są poprawnie zbierane:

Po zalogowaniu do Graffana możemy dodać “data source” zgodnie z danymi dostępowymi pod którymi została uruchomiona instancja Prometheus:

A następnie tworzyć dashboard’y z panelami zawieranymi zapytania do środowiska Prometheus:

Całość przedstawionej tu koncepcji, została rozbudowana i przygotowana do uruchomienia w postaci kontenerów środowiska Docker i jest dostępna do swobodnego wykorzystania w naszym publicznym repozytorium na GitHub (https://github.com/SoftFlowTech/aci-monitoring).
Powyższy przykład praktycznego zastosowania API, pokazuje jak łatwo można pobierać i wizualizować dane ze środowiska SDN. Ale to oczywiście tylko jedno z możliwych zastosowań. Odpowiednie przygotowane narzędzia pozwalają na pełne zarządzanie takim środowiskiem, skracając czas przygotowania konfiguracji, eliminując konieczność żmudnego powtarzania częstych operacji za pomocą tradycyjnych metod jak CLI i GUI. To pozwala na zaawansowaną integrację i automatyzację infrastruktury sieciowej, firmy mogą lepiej kontrolować i optymalizować swoje zasoby sieciowe, tworząc zintegrowany ekosystem zarządzania Data Center.
W SoftFlow jesteśmy pionierem tego podejścia programistycznego i wykorzystania API w projektach związanych z wdrażaniem technologii SDN u naszych klientów. Nasze narzędzia programistyczne, które tworzymy od lat znacznie skracają czas potrzebny na wdrożenie takich technologii jak Cisco ACI a także pozwalają na szybką i bezproblemową migrację istniejących środowisk do sieci SDN. Projekty realizowane przez nas w tym podejściu są bardziej powtarzalne, co eliminuje możliwość popełnienia błędów przy tworzeniu konfiguracji. To przekłada się na krótsze okna serwisowe i zapewnia ciągłość pracy migrowanych aplikacji, co jest kluczowe z perspektywy priorytetów naszych klientów.