Network as Code w praktyce: zarządzanie konfiguracją sieci z Git i CI/CD

0
96
3/5 - (1 vote)

Nawigacja:

Od ręcznej konfiguracji do Network as Code – zmiana paradygmatu

Tradycyjne zarządzanie siecią: SSH, CLI i kopiuj-wklej

Klasyczny sposób pracy inżyniera sieci wygląda podobnie w większości organizacji: logowanie po SSH na router czy przełącznik, kilka komend w CLI, szybki zapis konfiguracji i przejście do następnego urządzenia. Nierzadko zmiany są przygotowywane w notatniku lub Excelu, a potem ręcznie przenoszone do urządzeń. Jeśli sieć liczy kilkanaście urządzeń, daje się to jeszcze jakoś utrzymać. Przy kilkudziesięciu lub kilkuset – chaos jest tylko kwestią czasu.

Manualna konfiguracja opiera się zwykle na intuicji i pamięci administratora. Ktoś pamięta, że „na oddziale X VLAN 30 to goście”, ktoś inny wie, że „na tym routerze jest nietypowy NAT, lepiej go nie ruszać”. Dokumentacja, jeśli istnieje, bywa przeterminowana. Takie środowisko jest bardzo wrażliwe na rotację pracowników: odejście jednej kluczowej osoby potrafi sparaliżować możliwość wprowadzania zmian.

Ręczne podejście ma jeszcze jedną cechę: jest trudne do odtworzenia. Jeśli trzeba zbudować podobną konfigurację dla innej lokalizacji, najczęściej kopiuje się fragmenty z istniejącego urządzenia i modyfikuje „na oko”. W efekcie powstają drobne różnice, które później trudno wytropić, gdy coś nie działa tak samo w dwóch oddziałach.

Główne problemy: brak historii, niespójność i konfiguracje śmieciowe

Manualne zarządzanie konfiguracją sieci generuje konkretne, powtarzalne problemy:

  • Brak rzetelnej historii zmian – nawet jeśli logi syslog częściowo pokazują, kto wykonał jaką komendę, nie ma prostego porównania „przed i po” ani szybkiego sposobu przywrócenia poprzedniej wersji konfiguracji.
  • Niespójność konfiguracji – podobne urządzenia w różnych lokalizacjach mają delikatnie inne polityki ACL, odrobinę inne QoS lub inny sposób numeracji interfejsów. W małej skali to nie przeszkadza, w większej – powoduje trudne do diagnozowania anomalie.
  • „Konfiguracje śmieciowe” – po kolejnych zmianach w konfiguracji pozostają nieużywane ACL-e, route-mapy, access-listy, nieużywane VLAN-y. Trudno ocenić, co można bezpiecznie usunąć. W efekcie konfiguracje puchną i stają się coraz mniej czytelne.
  • Brak spójnych standardów – nazewnictwo interfejsów, opis portów, struktura ACL czy sposób definiowania VRF-ów zmienia się w zależności od osoby wprowadzającej zmiany i momentu w historii sieci.

W konsekwencji wdrażanie nowych funkcji lub urządzeń staje się coraz bardziej ryzykowne. Im więcej długów technicznych w konfiguracji, tym większa szansa, że niewielka modyfikacja doprowadzi do poważnej awarii.

Network as Code w praktyce: traktowanie konfiguracji jak kodu

Network as Code oznacza przesunięcie zarządzania siecią do świata znanego z programowania i DevOps. Konfiguracje urządzeń nie są już „tym, co siedzi na routerze”, ale stają się kodem przechowywanym w repozytorium (np. Git), z pełną historią zmian, wersjonowaniem i procesem przeglądu.

Fundamentem jest założenie, że repozytorium jest źródłem prawdy. To, co jest w Git, definiuje docelowy stan sieci. Urządzenia powinny być konfigurowane w sposób automatyczny, tak aby odzwierciedlały ten stan. Zmiana w sieci to zmiana w repozytorium, a nie bezpośrednia komenda na routerze. Nawet jeśli w pewnych sytuacjach trzeba wykonać ręczną korektę, docelowo i tak powinna zostać odzwierciedlona w repozytorium.

Network as Code łączy kilka elementów: automatyzację (Ansible, Terraform, Nornir), zarządzanie wersjami (Git), proces CI/CD (testy i automatyczne wdrażanie) oraz dobre praktyki inżynierskie (przeglądy kodu, standardy, dokumentację blisko kodu). Największy zysk pojawia się wtedy, gdy te elementy działają razem, a zmiany w sieci mają swój pełny cykl życia w systemach do zarządzania kodem.

Skrypty do sieci a świadome Network as Code

Wiele zespołów sieciowych używa skryptów – prostych plików Python, procedur Expect czy „one-linerów” w Bashu – do masowej zmiany haseł, dodania VLAN-u na wielu przełącznikach czy aktualizacji opisu portów. To często pierwszy krok do automatyzacji, ale nie jest to jeszcze Network as Code w pełnym znaczeniu.

Różnica polega na tym, że:

  • Skrypty zwykle opisują co zrobić (imperatywne polecenia), ale nie definiują pełnego, docelowego stanu sieci. Są jednorazowe, trudne do ponownego użycia i niekoniecznie spięte z procesem zarządzania zmianą.
  • Network as Code dąży do deklaratywnego opisu stanu: np. „ten router ma mieć takie interfejsy i takie trasy statyczne, a te ACL-e mają mieć konkretną listę reguł”. Narzędzia odpowiadają za doprowadzenie urządzeń do tak opisanego stanu oraz za weryfikację, czy się to udało.

W praktyce oznacza to przejście z myślenia „napiszę skrypt, który doda te trzy komendy” do „zdefiniuję szablon konfiguracji routera WAN, a skrypt wygeneruje i zastosuje pełną konfigurację zgodnie z danymi inwentarzowymi”. To zmiana paradygmatu, która na początku wymaga od inżynierów sieci trochę innego podejścia do pracy, ale daje znacznie większą powtarzalność.

Mały przykład: repozytorium Git porządkuje konfiguracje małej sieci

Wyobraź sobie firmę z kilkunastoma oddziałami: w każdym router VPN, kilka przełączników dostępowych, jeden kontroler Wi-Fi. Dotychczas każdą zmianę wprowadza się ręcznie. Po kilku latach konfiguracje tych samych typów urządzeń różnią się detalami, a nikt nie jest w stanie szybko powiedzieć, która lokalizacja ma jakie ACL-e.

Pierwszy krok w stronę Network as Code może być zaskakująco prosty:

  • zrzucenie aktualnych konfiguracji wszystkich urządzeń do plików tekstowych,
  • umieszczenie ich w repozytorium Git z czytelną strukturą katalogów,
  • od tej pory – każda zmiana najpierw w pliku, commit, opis, a dopiero potem wdrożenie na urządzenia (nawet jeszcze ręczne).

Nawet bez pełnej automatyzacji wdrażania, samo przechowywanie konfiguracji w Git daje natychmiastowe korzyści: historię zmian, łatwe porównanie wersji, możliwość przywrócenia poprzedniej konfiguracji, lepszą współpracę w zespole. To często moment, w którym widać, że podejście „jak do kodu” jest dla sieci po prostu bardziej efektywne.

Fundamenty – Git, IaC i GitOps w kontekście sieci

Git w praktyce inżyniera sieci

Git to rozproszony system kontroli wersji, dominujący standard w świecie programistów. W kontekście Network as Code zastępuje „folder z backupami konfigów” i pojedyncze pliki Word/Excel. Kluczowe pojęcia:

  • Commit – migawka zmian. Każdy commit zawiera informację, jakie linie konfiguracji doszły, zostały usunięte lub zmodyfikowane. Zawiera też opis tekstowy („message”), w którym można wyjaśnić cel zmiany.
  • Branch – gałąź rozwoju. Zmiany w sieci można przygotowywać w oddzielnych branchach (np. feature/new-site-krakow) i dopiero po przetestowaniu łączyć z główną gałęzią (np. main).
  • Tag – etykieta przypisana do konkretnego commita. Można oznaczać nimi „wydania” konfiguracji, np. 2024-05-rollout-vlan-standardization.

Dla inżyniera sieci Git staje się narzędziem do:

  • porównywania konfiguracji pomiędzy lokalizacjami i w czasie,
  • śledzenia, kto i dlaczego zmodyfikował dany fragment,
  • wprowadzania zmian w bezpieczniejszy, kontrolowany sposób (branch + pull request),
  • automatycznego wyzwalania pipeline’ów CI/CD po każdej zmianie w plikach.

Przy niewielkiej praktyce Git przestaje być „narzędziem dla programistów”, a zaczyna po prostu wspierać codzienną pracę z konfiguracją.

Infrastructure as Code w sieciach: deklaratywnie vs imperatywnie

Infrastructure as Code (IaC) zakłada opisywanie infrastruktury (serwery, sieci, usługi) w formie plików tekstowych, które można versionować, testować i automatycznie wdrażać. W przypadku sieci kluczowa jest różnica między dwoma podejściami:

  • Imperatywne – „jak wykonać zmianę”: sekwencja komend typu interface Gi0/1, switchport access vlan 20. Typowe dla ręcznego CLI i prostych skryptów.
  • Deklaratywne – „jaki ma być efekt”: opis, że hosty w danym oddziale mają mieć VLAN 20 jako sieć użytkowników, VLAN 30 jako sieć gościnna, a ruch z VLAN 30 ma być filtrowany według zdefiniowanej polityki. Narzędzie samo generuje odpowiednie komendy.

W praktyce dużo rozwiązań Network as Code łączy oba style. Często szablony konfiguracji są w dużej mierze deklaratywne, ale pewne sekwencje zmian nadal wymagają imperatywnej logiki (np. migracja BGP bez przerwy w ruchu). Kluczowe jest jednak, aby źródłem prawdy był opis stanu, a nie pojedyncze skrypty.

Popularne narzędzia IaC dla sieci (Ansible, Terraform, Nornir) przechowują definicje sieci w postaci plików YAML, HCL lub Python. Samo zapisanie konfiguracji w takich formatach nie wystarcza – sedno IaC to powtarzalność i przewidywalność. Jeśli ten sam opis zostanie zastosowany jutro lub za miesiąc, efekt ma być spójny.

GitOps dla sieci: repozytorium jako źródło prawdy

GitOps rozwija idee IaC o konkretną praktykę operacyjną. Zakłada, że Git jest jedynym źródłem prawdy na temat tego, jak ma wyglądać infrastruktura, a zmiany stanu są wykonywane wyłącznie poprzez zmiany w repozytorium. Dla sieci oznacza to kilka ważnych zasad:

  • Nie ma „tajnych” zmian na urządzeniu, które nie zostały odzwierciedlone w repozytorium. Jeśli ktoś z konieczności naprawił coś ręcznie, musi później wprowadzić tę zmianę do Git.
  • Wdrożenia są ciągłe: każda zmiana w repo wyruchamia pipeline, który testuje i w razie akceptacji wdraża konfigurację.
  • Repozytorium odzwierciedla aktualny stan oczekiwany. Jeśli rzeczywisty stan urządzeń odbiega, pipeline powinien to wykryć i zgłosić.

GitOps sprawdza się szczególnie dobrze w środowiskach, gdzie topologia i konfiguracja są zbliżone między lokalizacjami – np. sieci sklepów, punktów sprzedaży czy oddziałów banku. Standaryzacja pozwala budować szablony konfiguracji i minimalizuje liczbę wyjątków.

Konwencje repozytorium: struktura, nazewnictwo, segregacja

Źle zaprojektowane repozytorium szybko staje się śmietnikiem plików, w którym trudno cokolwiek znaleźć. Porządek w strukturze katalogów to fundament. Najczęściej spotykane podejścia:

  • Per lokalizacja – korzeń repozytorium zawiera katalogi oddziałów (np. sites/warszawa, sites/krakow), a w nich pliki specyficzne dla danej lokalizacji.
  • Per rola urządzenia – katalogi typu core, distribution, access, wan.
  • Per technologia – np. bgp, ospf, acl, qos, jeśli konfiguracja jest mocno modularna.
  • Per klient/segment – w środowiskach MSP lub z wyraźnym podziałem biznesowym (np. customers/bankX).

Dobrym kompromisem dla średniej organizacji jest kombinacja lokalizacja + rola, np. sites/warszawa/access, sites/warszawa/wan, sites/krakow/access. Dzięki temu łatwo znaleźć konkretny router czy przełącznik, ale można też objąć jednym wzrokiem wszystkie urządzenia warstwy dostępowej.

Poza strukturą katalogów warto ustalić standardy nazewnictwa plików (np. hostname-config.yaml, hostname-interfaces.yaml) oraz rozróżnić:

  • pliki szablonów (np. w Jinja2),
  • pliki zmiennych/inwentarza (YAML, CSV),
  • pliki wygenerowane (gotowa konfiguracja, której zwykle nie commitujemy, chyba że pełni rolę archiwum).

Definiowanie stanu docelowego: szablony, inwentarz i zmienne

Żeby Network as Code działało na większą skalę, trzeba oddzielić logikę konfiguracji od danych specyficznych dla urządzeń i lokalizacji. Najczęściej odbywa się to przez:

Rozdział logiki i danych: praktyczny model

Rozsądny model dzieli repozytorium na trzy główne warstwy:

  • Logika / szablony – opisują, jak ma wyglądać konfiguracja danego typu urządzenia (np. router WAN, przełącznik dostępowy), ale nie zawierają konkretnych IP czy nazw VLAN.
  • Inwentarz – opisuje, jakie urządzenia są w sieci, gdzie stoją, jakimi mają nazwami i adresami zarządczymi (np. inventory/hosts.yaml).
  • Dane biznesowe / zmienne – opisują wymagania funkcjonalne: jakie VLAN-y w danej lokalizacji, jaka przepustowość łącza, jakie prefiksy BGP, które porty są wykorzystywane.

Szablon przełącznika dostępowego może być jeden dla całej organizacji. Zmienia się jedynie zestaw zmiennych, które wchodzą do templatu, np.:

sites:
  warszawa:
    access:
      sw1:
        uplink_port: Gi1/0/48
        user_vlans:
          - id: 20
            name: USERS
          - id: 30
            name: GUEST
        management_ip: 10.10.0.11/24
  krakow:
    access:
      sw1:
        uplink_port: Gi1/0/48
        user_vlans:
          - id: 120
            name: USERS_KRK
          - id: 130
            name: GUEST_KRK
        management_ip: 10.20.0.11/24

Szablon Jinja2 może potem wyglądać następująco:

{% for vlan in user_vlans %}
vlan {{ vlan.id }}
 name {{ vlan.name }}
{% endfor %}

interface {{ uplink_port }}
 description Uplink to distribution
 switchport trunk allowed vlan {{ user_vlans | map(attribute="id") | join(",") }}

Ten sam kod szablonu generuje różne konfiguracje w zależności od danych. Dzięki temu zmiana standardu (np. dodanie VLAN-u 40 dla IoT) wymaga modyfikacji zmiennych i ewentualnie jednego szablonu, a nie ręcznego dotykania setek plików konfiguracyjnych.

Wybór narzędzi – od prostych skryptów po platformy Network as Code

Kryteria wyboru narzędzia do automatyzacji sieci

Dobór narzędzia zależy od kilku twardych czynników. Najważniejsze z nich:

  • Różnorodność producentów – jeśli sieć to głównie jeden vendor, wygodne bywają narzędzia lub platformy specyficzne (np. Cisco NSO, Juniper Apstra). Przy wielu dostawcach lepiej sprawdzają się narzędzia ogólne.
  • Kompetencje zespołu – jeśli ludzie znają Ansible, szkoda to marnować; jeśli jest silny zespół Python, można śmiało sięgać po Nornir lub własne frameworki.
  • Interfejsy urządzeń – telnet/SSH + CLI wymusza inne podejście niż bogate API w stylu NETCONF/RESTCONF czy gNMI. Warto najpierw inwentaryzować, jakie interfejsy udostępniają urządzenia.
  • Skala i częstotliwość zmian – jeśli konfiguracje zmieniają się rzadko, proste playbooki Ansible wystarczą. Jeśli codziennie wchodzą setki zmian, warto myśleć o platformie, kolejce zadań i rozbudowanym monitoring-u.

Ansible – punkt startowy dla wielu zespołów

Ansible jest często pierwszym krokiem w stronę Network as Code, bo dobrze łączy prostotę z możliwościami. Przygotowuje się playbooki, które opisują, co ma zostać zrobione, oraz pliki inwentarza i zmiennych.

Typowy scenariusz dla sieci:

  • inwentarz hostów w YAML (inventory/hosts.yaml),
  • role Ansible dla poszczególnych typów urządzeń (roles/router_wan, roles/access_switch),
  • moduły typu ios_config, nxos_config, junos_config do wgrywania zmian.

Przykładowy fragment playbooka aktualizującego bannery i dane kontaktowe na routerach WAN Cisco:

- name: Update WAN routers banners
  hosts: wan_routers
  gather_facts: no
  vars_files:
    - vars/global.yaml
  tasks:
    - name: Render banner template
      template:
        src: templates/banner.j2
        dest: /tmp/{{ inventory_hostname }}-banner.cfg

    - name: Apply banner configuration
      ios_config:
        src: /tmp/{{ inventory_hostname }}-banner.cfg
        match: line
        replace: line

Playbook można uruchamiać ręcznie lub z poziomu pipeline’u CI/CD; w obu przypadkach bazuje na tych samych plikach w Git i generuje przewidywalny efekt.

Terraform i providerzy sieciowi

Terraform jest kojarzony głównie z chmurą, ale coraz częściej ma zastosowanie w sieciach, zwłaszcza w integracji z SD-WAN, firewallami NGFW czy sieciami w chmurze (VPC, Transit Gateway, ExpressRoute/Direct Connect).

Na poziomie praktyki:

  • definiuje się zasoby typu „VPN site”, „BGP peer”, „firewall policy” w HCL,
  • używa się providerów producentów (np. Cisco, Palo Alto, F5) lub community,
  • Terraform zarządza zależnościami i stanem wdrożenia.

Przykładowy fragment definiujący prosty tunel VPN site-to-site w usłudze firewallowej może wyglądać tak:

resource "vendor_vpn_tunnel" "site_warszawa" {
  name         = "site-warszawa"
  local_cidr   = "10.10.0.0/16"
  remote_cidr  = "10.100.0.0/16"
  preshared_key = var.vpn_psk

  ike_profile  = "standard_ike"
  ipsec_profile = "standard_ipsec"
}

Plusem jest silne wsparcie dla planowania zmian: terraform plan pokazuje, co się stanie, zanim zostanie wykonane terraform apply. W sieci daje to dodatkową warstwę kontroli – pipeline może blokować wdrożenie, jeśli plan jest szerszy niż oczekiwano.

Nornir, Netmiko i własne frameworki w Pythonie

Dla zespołów komfortowo czujących się w Pythonie naturalnym kierunkiem jest Nornir oraz biblioteki typu Netmiko, Paramiko czy NAPALM. To elastyczne podejście, które pozwala budować dokładnie taką logikę, jakiej brakuje w gotowych narzędziach.

Nornir oddziela inwentarz, zadania i pluginy wykonywane dla urządzeń. Przykładowe zadanie:

from nornir import InitNornir
from nornir_netmiko.tasks import netmiko_send_config
from nornir_jinja2.plugins.tasks import template_file

nr = InitNornir(config_file="config.yaml")

def deploy_access_switch(task):
    r = task.run(
        task=template_file,
        template="access_switch.j2",
        path="templates",
    )
    cfg = r.result.splitlines()
    task.run(
        task=netmiko_send_config,
        config_commands=cfg
    )

nr.run(task=deploy_access_switch, groups=["access_switches"])

Takie podejście daje możliwość wplecenia bardzo specyficznych warunków (np. „jeśli na porcie jest aktywny STP loop guard, zmień kolejność komend”), ale wymaga większej dyscypliny wpisania tego w zasady IaC i GitOps, aby nie skończyć z zawiłym, nieudokumentowanym kodem.

Dedykowane platformy Network as Code

Dla większych środowisk i organizacji, które wolą gotowy produkt niż budowanie wszystkiego samodzielnie, pojawiły się platformy skupione na automatyzacji sieci: Cisco NSO, Itential, Glueware, Apstra i inne. Łączy je kilka cech:

  • modelowanie usług sieciowych (np. „site”, „MPLS VPN”, „L2VPN”) zamiast pojedynczych komend,
  • wsparcie dla wielu vendorów poprzez adaptery,
  • graficzne interfejsy i API do automatyzacji,
  • często wbudowane mechanizmy walidacji i dry-run.

Takie platformy dobrze sprawdzają się, gdy sieć jest duża, a procesy formalne (change management, audyt) są rozbudowane. Wymagają jednak świadomej integracji z Git: szablony, definicje usług i polityk powinny nadal być przechowywane w repozytorium, a platforma powinna konsumować konfigurację z Git lub eksportować ją do niego.

Okulary odbijające kod na monitorze podczas pracy nad siecią
Źródło: Pexels | Autor: Kevin Ku

Projekt repozytorium konfiguracji sieci – wzorce i praktyka

Podział repozytoriów: monorepo czy wiele repo?

Jedno z pierwszych pytań brzmi: trzymać wszystko w jednym repozytorium (monorepo), czy rozdzielić konfigurację na kilka mniejszych?

Monorepo ma sens, gdy:

  • zespół jest niewielki i pracuje nad całą siecią,
  • narzędzia i pipeline’y są wspólne dla wszystkich segmentów,
  • sieć jest spójnie zarządzana (jedne standardy, jeden zespół change management).

Wiele repozytoriów sprawdza się, gdy:

  • są niezależne domeny odpowiedzialności (np. „DC”, „WAN”, „retail branches”),
  • część konfiguracji jest poufna (np. konfiguracje klientów w MSP),
  • różne zespoły używają innych narzędzi czy pipeline’ów.

Rozdział można poprowadzić po domenach technicznych (DC vs WAN), po obszarach biznesowych (klienci, segmenty) albo po krytyczności (sieć produkcyjna vs lab). Niezależnie od wyboru warto wymusić spójne konwencje nazewnictwa i struktury, tak aby inżynier mógł łatwo przenosić się między repozytoriami.

Warstwy konfiguracji: globalna, per region, per site

Konfiguracja sieci zwykle wynika z kilku poziomów polityk. Dobry projekt repozytorium powinien to odzwierciedlać. Można wyróżnić co najmniej trzy warstwy:

  • Globalna – zasady obowiązujące wszędzie: standardy haseł, bannery, globalne parametry SNMP, NTP, AAA.
  • Regionalna – parametry zależne od regionu / kraju: serwery syslog, DNS, lokalne prefiksy, wymagania prawne.
  • Site-specific – szczegóły konkretnej lokalizacji: adresacja, nazwy VLAN, numery portów dla uplinków.

Przekłada się to na strukturę, np.:

config/
  global/
    ntp.yaml
    aaa.yaml
    snmp.yaml
  regions/
    eu/
      dns.yaml
      syslog.yaml
    us/
      dns.yaml
      syslog.yaml
  sites/
    warszawa/
      vlans.yaml
      wan.yaml
    krakow/
      vlans.yaml
      wan.yaml

Szablony mogą łączyć dane z kilku warstw: np. konfiguracja routera w Warszawie powstaje z global/* + regions/eu/* + sites/warszawa/*. Taki układ ułatwia wprowadzanie globalnych zmian bez grzebania w plikach każdej lokalizacji.

Oddzielenie danych wrażliwych

Hasła, klucze prywatne, pre-shared keys do VPN czy dane dostępowe do API nie powinny lądować w repozytorium w formie jawnej. Do ich przechowywania używa się:

  • Ansible Vault,
  • mechanizmów CI/CD (sekrety w GitLab CI, GitHub Actions, Jenkins credentials),
  • zewnętrznych sejfów (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault).

Praktyczny model to przechowywanie w repozytorium referencji do sekretów (np. identyfikatorów w sejfie), a nie samych wartości. Pipeline pobiera wartości w czasie wykonywania, wstrzykuje do procesu templating-u, ale nie zapisuje ich w plikach outputu commitowanych do Git.

Repozytorium „tylko do odczytu” vs repo „operacyjne”

W wielu firmach istnieje już repozytorium z backupami konfiguracji. Można je:

  • pozostawić jako archiwum „read-only” – dla historii i szybkich porównań,
  • założyć osobne repo „operacyjne” – w którym znajdują się definicje stanu docelowego, szablony i dane inwentarza.

Różnica jest istotna: repo archiwalne odzwierciedla to, co jest, a repo operacyjne – to, co ma być. Pipeline może okresowo porównywać oba światy i raportować rozjazdy (dryft konfiguracji), co pomaga wychwycić „ciche” ręczne zmiany na urządzeniach.

Budowa pipeline’u CI/CD dla konfiguracji sieci

Ogólny przepływ: od commita do wdrożenia

Pipeline CI/CD dla sieci można podzielić na kilka kroków logicznych:

  1. Walidacja syntaktyczna – sprawdzenie, czy pliki YAML/HCL/JSON są poprawne, czy nie ma literówek w kluczach, czy struktura jest spójna.
  2. Linting i reguły stylu – wymuszenie konwencji: nazwy VLAN, standardowe opisy interfejsów, brak zabronionych komend.
  3. Generowanie konfiguracji – wyrenderowanie szablonów do postaci gotowych configów dla poszczególnych urządzeń.
  4. Testy logiki – analiza gotowych konfiguracji, np. wyszukiwanie niepożądanych patternów, sprawdzanie spójności routingu.
  5. Dry-run / pre-check – opcjonalne porównanie z aktualnym stanem urządzeń (co się zmieni), ewentualnie symulacja w labie.
  6. Wdrożenie – wykonanie zmian na urządzeniach, najczęściej etapami.
  7. Rozbicie pipeline’u na etapy i środowiska

    Nawet jeśli w sieci nie ma klasycznego podziału na „dev / test / prod”, pipeline powinien mieć wyraźne etapy oraz możliwość kierowania zmian do różnych środowisk. Typowy schemat:

    • CI – weryfikacja zmiany: linting, generowanie konfiguracji, testy logiki, ewentualnie uruchomienie symulacji (np. w EVE-NG, labie wirtualnym, digital twin).
    • CD do środowiska testowego: automatyczne wdrożenie na labie lub niewielkiej, kontrolowanej grupie urządzeń (canary).
    • CD do produkcji: wdrożenie na produkcji, zwykle z dodatkowymi blokadami (manualne zatwierdzenie, okna serwisowe, powiadomienia).

    Przepływ w narzędziach typu GitLab CI / GitHub Actions / Jenkins można udokumentować jako serię jobów i stage’y. Przykładowo w GitLab CI:

    stages:
      - validate
      - generate
      - test
      - deploy_lab
      - deploy_prod
    
    validate:lint:
      stage: validate
      script:
        - yamllint config/
        - ansible-lint playbooks/
      only:
        - merge_requests
    
    generate:configs:
      stage: generate
      script:
        - ansible-playbook generate_configs.yaml
      artifacts:
        paths:
          - out/configs/
      only:
        - merge_requests
    
    deploy:lab:
      stage: deploy_lab
      script:
        - ansible-playbook deploy.yaml -i inventory/lab.yaml
      when: manual
      only:
        - main
    
    deploy:prod:
      stage: deploy_prod
      script:
        - ansible-playbook deploy.yaml -i inventory/prod.yaml --limit "@batch1"
      when: manual
      only:
        - tags

    Taki podział wymusza porządek: każda zmiana musi przejść walidację, wygenerować gotowe konfiguracje (do wglądu reviewerów), przejść testy, a dopiero potem może być wdrożona – najpierw w labie, a potem na produkcji.