Posted in

Ansible Execution Environment w automatyzacji IBM Power.

Każdy, kto próbował utrzymać spójne środowisko do uruchamiania playbooków, czy to na dedykowanym Ansible Control Node, czy na dowolnym innym serwerze, godząc wymagania różnych kolekcji, wersji Pythona i całej masy zależności, wie, jak szybko potrafi się to zamienić w koszmar. Na szczęście odpowiedzią na ten chaos są środowiska uruchomieniowe (execution environments). Zamiast instalować wszystko na jednym hoście, zamykamy całą automatyzację wraz z jej zależnościami w przenośnym, odizolowanym kontenerze, gwarantując, że zadziała ona zawsze i wszędzie tak samo. Chcę pokazać, jak w praktyce wykorzystać to podejście do zarządzania całym ekosystemem IBM Power, aby raz na zawsze pożegnać problemy z zależnościami.

Podejście: Ansible Control Node

Wyobraź sobie serwer (maszynę wirtualną), który jest Twoim centrum dowodzenia automatyzacją. Instalujesz na nim Ansible, wszystkie potrzebne kolekcje (ansible-galaxy collection install...), biblioteki Pythona (pip install...) i inne narzędzia. To jest właśnie Ansible Control Node.

To podejście posiada generuje pewne problemy:

  • Chaotyczne zarządzanie zależnościami: Na współdzielonym serwerze każdy może doinstalować coś „tylko dla siebie”, często psując coś komuś innemu. Moduły Pythona instalowane są na przemian przez dnf i pip, raz globalnie dla roota, raz w katalogu domowym (--user), a do tego dochodzą różne wersje samego Pythona. To prowadzi do kompletnego bałaganu i trudnych do zdiagnozowania błędów.
  • Brak powtarzalności i syndrom „ale u mnie działało!”: Środowisko na Control Node żyje własnym życiem. Zwykła aktualizacja systemu (dnf update) potrafi zaktualizować Ansible lub kluczową bibliotekę, psując playbooki, które działały jeszcze wczoraj. Ponieważ serwer deweloperski, testowy i produkcyjny nigdy nie są identyczne, ten sam kod w jednym miejscu działa, a w innym już nie.
  • Koszmar utrzymaniowy: Kto zarządza tym serwerem? Co, jeśli aktualizacja systemu operacyjnego zepsuje kluczową zależność Pythona? Control Node staje się współdzielonym zasobem, którego nikt nie chce dotykać w obawie, że coś przestanie działać.

Podejście: Execution Environment (EE)

Execution Environment to kompletne, przenośne i odizolowane środowisko wykonawcze, spakowane w kontener. Zamiast instalować wszystko na jednym serwerze, definiujesz wszystkie zależności w pliku, budujesz z niego obraz kontenera i uruchamiasz swoje playbooki wewnątrz tego kontenera.

Pomyśl o tym tak. Ansible Control Node to jeden, wielki, wspólny warsztat, gdzie wszyscy rzucają swoje narzędzia na jedną kupę. Panuje bałagan, a narzędzia często do siebie nie pasują. Execution Environment to mała, wyspecjalizowana skrzynka z narzędziami. Do pracy z IBM Power bierzesz „skrzynkę IBM Power”, do automatyzacji sieci „skrzynkę sieciową”. Każda jest idealnie przygotowana, samowystarczalna i nie koliduje z innymi.

Dzięki Execution Environment automatyzacja staje się przenośne, spójne i w pełni odtwarzalne.

Własna „skrzynka z narzędziami” dla IBM Power

Dla środowiska IBM Power, taka „skrzynka” (kontener) będzie szczególnie istotna ponieważ mamy tutaj do czynienia z wielomak kolekcjami ansibla dedykowanymi dla każdej warstwy w platformie IBM Power. Nasz kontener bedzie zawierać wszystko, czego potrzebujesz do zarządzania HMC, VIOS czy partycjami AIX/IBM i:

  • Kolekcje Ansible: ibm.power_viosibm.power_hmc,ibm.power_aix, community.general itp.
  • Biblioteki Python: Wszystkie, których te kolekcje wymagają do komunikacji z docelowymi systemami.
  • Narzędzia systemowe: Może sshpass albo jakiś specyficzny klient, jeśli jest potrzebny.

Chociaż istnieją gotowe, publiczne obrazy EE nie zawierają one wszystkich kolekcji a przede wszystkim tych dla platformy IBM Power, budowanie własnego EE daje również pełną kontrolę, mniejszy rozmiar obrazu i większe bezpieczeństwo.

Proces budowy jest prosty i sprowadza się do trzech kroków.

Definiujesz potrzeby w pliku execution-environment.yml:

# execution-environment.yml
version: 3
dependencies:
    galaxy:
    collections:
        [ ... ]
        - ibm.power_vios
        - ibm.power_hmc
        [ ... ]
    python:
    - requests
    [ ... ]
YAML

Budujesz obraz kontenera za pomocą ansible-builder: Dobrą praktyką jest tagowanie obrazu zarówno konkretną wersją (1.0), jak i tagiem latest.

ansible-builder build \
    --tag my-company-registry/ibmpower-ee:1.0 \
    --tag my-company-registry/ibmpower-ee:latest
Bash

Wysyłasz obie wersje do firmowego repozytorium:

podman push my-company-registry/ibmpower-ee:1.0
podman push my-company-registry/ibmpower-ee:latest
Bash

Przy budowie EE mozna się wzorować np. na awx-ee

Scenariusze użycia

Teraz, gdy nasza dedykowana „skrzynka” jest gotowa w dwóch wariantach (:1.0 i :latest), zobaczmy, jak jej użyć.

  • :1.0 (tag wersji): Używaj w środowiskach produkcyjnych i wszędzie tam, gdzie liczy się stabilność i powtarzalność. Gwarantuje, że zadanie zawsze uruchomi się z tym samym, niezmiennym zestawem narzędzi.
  • :latest (tag pływający): Używaj w środowiskach deweloperskich i w pipeline’ach CI, które mają testować kod z najnowszą wersją narzędzi.

Sposób 1: Użycie w AWX / Ansible Automation Platform

To podstawowy sposób wykorzystania EE.

  1. Dodaj EE w AWX: W panelu administratora przejdź do Administration -> Execution Environments.
  2. Stwórz dwa wpisy:
    • Dla produkcji (stabilne):
      • Name: IBM Power EE 1.0
      • Image: my-company-registry/ibmpower-ee:1.0
      • Pull: Always pull container image before running
    • Dla deweloperów (najnowsze):
      • Name: IBM Power EE Latest
      • Image: my-company-registry/ibmpower-ee:latest
      • Pull: Always pull container image before running
  3. Podepnij EE do szablonu zadania: W ustawieniach Job Template, np. „Deploy VIOS Production Config”, w polu Execution Environment wybierz IBM Power EE 1.0. Dla zadań deweloperskich możesz wskazać IBM Power EE Latest.

Sposób 2: Integracja z GitLab CI (Automatyczne wdrożenia)

Zamiast instalować wszystko od zera w każdym pipeline, po prostu wskazujesz gotowy obraz EE.

# .gitlab-ci.yml
deploy_vios_production:
  stage: deploy
  # Dla wdrożeń na produkcję używamy konkretnej, zamrożonej wersji.
  image: 
    name: my-company-registry/ibmpower-ee:1.0

  script:
    - ansible-playbook create_vlan.yml -i inventory.ini --vault-password-file $VAULT_PASS_FILE
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

test_vios_playbook:
  stage: test
  # W testach możemy używać :latest, by sprawdzać kompatybilność z nowymi narzędziami.
  image: 
    name: my-company-registry/ibmpower-ee:latest

  script:
    - ansible-playbook create_vlan.yml --syntax-check
    - ansible-lint create_vlan.yml
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
YAML

Sposób 3: Praca z ansible-navigator

To nowoczesny sposób na pracę z Ansible lokalnie, który idealnie symuluje działanie w AWX w środowisku CLI.

W katalogu z projektem stwórz plik ansible-navigator.yml:

---
# ansible-navigator.yml
ansible-navigator:
  execution-environment:
    # Do codziennej pracy deweloperskiej :latest jest wygodny
    image: my-company-registry/ibmpower-ee:latest
    pull:
      policy: missing 
YAML

Teraz uruchomienie playbooka to po prostu:

ansible-navigator run create_vlan.yml -i inventory.ini
YAML

Jeśli chcesz przetestować coś na starszej wersji EE, możesz nadpisać ustawienie flagą:

ansible-navigator run create_vlan.yml --eei my-company-registry/ibmpower-ee:1.0
YAML

Sposób 4: Automatyzacja z ansible-runner (zaawansowane skrypty)

ansible-runner to narzędzie „pod maską”, którego używa m.in. AWX. Idealne do integracji Ansible z innymi skryptami. Wymaga specyficznej struktury katalogów.

power_project/
└── private_data_dir/
    ├── project/
    │   └── create_vlan.yml
    └── inventory/
        └── hosts
YAML

Skrypt w Bashu może wyglądać tak:

#!/bin/bash

# Domyślnie używamy stabilnej wersji, chyba że skrypt zostanie wywołany inaczej
EE_IMAGE_TAG=${1:-"1.0"}
EE_IMAGE="my-company-registry/ibmpower-ee:${EE_IMAGE_TAG}"
PRIVATE_DATA_DIR="./power_project/private_data_dir"

echo "Uruchamiam playbook create_vlan.yml używając obrazu: ${EE_IMAGE}"

ansible-runner run "${PRIVATE_DATA_DIR}" \
  -p create_vlan.yml \
  --inventory inventory/hosts \
  --process-isolation \
  --container-image "${EE_IMAGE}"

# Sprawdzenie wyniku...
LATEST_RUN_DIR=$(ls -td "${PRIVATE_DATA_DIR}/artifacts"/*/ | head -1)
if [ -f "${LATEST_RUN_DIR}/status" ] && [ "$(cat "${LATEST_RUN_DIR}/status")" == "successful" ]; then
    echo "Playbook zakończony sukcesem."
    exit 0
else
    echo "Błąd wykonania playbooka! Sprawdź logi w ${LATEST_RUN_DIR}"
    cat "${LATEST_RUN_DIR}/stdout"
    exit 1
fi
YAML

Możesz teraz uruchomić ten skrypt, opcjonalnie podając tag: ./run_playbook.sh latest.

Sposób 5: Czysty podman run (Pełna kontrola)

Świetne do szybkiego testowania i zrozumienia, jak to działa od kuchni. Uruchom to polecenie z katalogu, w którym znajdują się Twoje playbooki.

# Uruchomienie ze stabilną wersją do debugowania problemu produkcyjnego
podman run --rm -it \
  -v $(pwd):/runner/project:z \
  --workdir /runner/project \
  my-company-registry/ibmpower-ee:1.0 \
  ansible-playbook create_vlan.yml -i inventory.ini
YAML

Rozbijmy to polecenie na czynniki pierwsze:

  • podman run...: Uruchom kontener.
  • -v $(pwd):/runner/project:z: Zamontuj mój obecny katalog (pwd) wewnątrz kontenera, aby miał on dostęp do playbooka i inwentarza.
  • --workdir /runner/project: Ustaw katalog roboczy wewnątrz kontenera.
  • my-company-registry/ibmpower-ee:1.0: Użyj tej konkretnej „skrzynki z narzędziami”.
  • ansible-playbook...: A to jest komenda, która ma się wykonać w środku.

Podsumowując

Jak widać, Execution Environments to nie tylko nowa funkcja, ale zmiana sposobu myślenia. Koniec z zastanawianiem się, dlaczego playbook działa u Ciebie, a na produkcji już nie. Zamiast bałaganu na serwerze, dostajesz własną, przenośną skrzynkę z narzędziami, która działa tak samo wszędzie. Początkowy wysiłek w jej zbudowanie zwraca się błyskawicznie w postaci spokoju, porządku i automatyzacji, na której wreszcie można w pełni polegać.