top of page

Śledź nasze wpisy w social media

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
  • Zdjęcie autoraPiotr Kośka

AWX-operator - Instalacja i testowanie w docker desktop, kubernetes

Zaktualizowano: 29 paź 2023

Czym jest awx-operator

awx-operator to operator Kubernetes stworzony, aby ułatwić wdrażanie, konfigurację i zarządzanie instancjami AWX na klastrach Kubernetes. AWX jest otwartoźródłową wersją Ansible Tower, narzędziem zaprojektowanym do zarządzania i uruchamiania zadań w Ansible w skali korporacyjnej.


Główne funkcje awx-operator

  1. Automatyczne wdrażanie: Pozwala na łatwe wdrożenie AWX w klastrze Kubernetes za pomocą jednego polecenia.

  2. Konfiguracja: Operator umożliwia dostosowywanie różnych aspektów instancji AWX, takich jak ilość zasobów, konfiguracja baz danych czy dostęp do zewnętrznych systemów magazynowania.

  3. Automatyczne aktualizacje: Dzięki operatorowi, aktualizacja AWX może odbywać się płynnie, bez konieczności manualnej interwencji.

  4. Zarządzanie stanem: Operator dba o to, aby instancje AWX działały poprawnie i były w odpowiednim stanie. Monitoruję, czy wszystkie komponenty działają poprawnie i podejmuje odpowiednie działania w przypadku problemów.

Zastosowanie awx-operator

  1. Uproszczenie zarządzania: Dzięki awx-operator, administracja wieloma instancjami AWX w klastrze Kubernetes staje się prostsza.

  2. Integracja z chmurą: Możliwość uruchamiania AWX na platformach typu Kubernetes ułatwia integrację z popularnymi usługami chmurowymi.

  3. Skalowalność: Korzystanie z Kubernetes w połączeniu z awx-operator pozwala na łatwe skalowanie instancji AWX, zarówno w górę, jak i w dół, w zależności od aktualnych potrzeb.

AWX - czym jest

AWX to otwartoźródłowa wersja Ansible Tower. Jest to narzędzie webowe zaprojektowane do zarządzania i uruchamiania zadań w Ansible. Ansible to popularne narzędzie do automatyzacji, służące do konfiguracji systemów, wdrażania aplikacji oraz zarządzania orkiestracją. AWX stanowi "kontrolne centrum dowodzenia" dla Ansible, umożliwiające zarządzanie playbookami, zmiennymi, inwentarzami i dostępnymi hostami w centralny i uporządkowany sposób.


Kluczowe funkcje AWX

  1. Interfejs Użytkownika: AWX oferuje graficzny interfejs użytkownika, który umożliwia łatwe zarządzanie i monitorowanie zadań Ansible.

  2. Rest API: Oprócz interfejsu użytkownika, AWX udostępnia RESTful API, co ułatwia integrację z innymi narzędziami i skryptami.

  3. Planowanie Zadań: AWX pozwala na planowanie uruchamiania playbooków Ansible w określonych terminach lub cyklicznie.

  4. Zarządzanie Inwentarzem: Możesz definiować i grupować hosty, na których będą uruchamiane zadania, oraz synchronizować inwentarze z różnymi źródłami, takimi jak AWS, Google Cloud czy Azure.

  5. Role-Based Access Control (RBAC): AWX umożliwia definiowanie uprawnień na podstawie ról, dzięki czemu można precyzyjnie kontrolować, kto ma dostęp do określonych zasobów i jakie akcje może wykonywać.

  6. Zarządzanie Credentialem: Bezpieczne przechowywanie i zarządzanie danymi uwierzytelniającymi, które są używane podczas uruchamiania playbooków.

  7. Wizualizacje: AWX dostarcza wizualizacje w postaci diagramów i statystyk, umożliwiające szybki wgląd w status operacji oraz historię uruchomień.

  8. Integracja z systemami powiadomień: Możliwość wysyłania powiadomień na różne kanały, takie jak e-mail, Slack czy nawet webhooki, w odpowiedzi na różne zdarzenia w systemie.


Zastosowanie AWX

  1. Centralne zarządzanie konfiguracją: Zarządzaj konfiguracją różnych systemów i aplikacji z jednego centralnego miejsca.

  2. Automatyzacja zadań IT: Automatyzuj rutynowe zadania, takie jak wdrażanie oprogramowania, zarządzanie użytkownikami czy aktualizacje systemowe.

  3. Orkiestracja wielostanowiskowa: Koordynuj działania pomiędzy różnymi środowiskami i platformami.

  4. Integracja z innymi narzędziami DevOps: Dzięki REST API, AWX może być łatwo zintegrowany z narzędziami takimi jak Jenkins, GitLab czy Jira.

Konfiguracja AWX-operatora

Przystąpmy zatem do konfiguracji naszego awx-operatora. Na początek potrzeba nam klastra kubernetes. Możesz wykorzystać dowolny. Jeżeli nie masz klastra kubernetes skonfigurowanego możemy skorzystać z docker-desktop i włączyć funkcje kubernetes na platformie docker.


Docker desktop


Zatem pobieramy naszą platformę docker desktop instalujemy naszą aplikację i po jej uruchomieniu włączmy funkcje kubernetes - jak to zrobić przedstawiają obrazki poniżej.



Klikamy na trybik w górnej części okna docker desktop
Klikamy na trybik w górnej części okna docker desktop

Przechodzimy do ustawień aplikacji docker desktop, a potem w ustawieniach przechodzimy w sekcje kubernetes i włączamy nas engine k8s



Włączenie kubernetes w docker desktop
Włączenie kubernetes w docker desktop

Zaznaczamy funkcje Enable Kubernetes i restartujemy klaster po przez Apply & restart - kubernetes zaczyna się uruchamiać zajmie to kilkadziesiąt sekund.


Po uruchomieniu kubernetesa w docker sprawdzamy działanie naszego polecenia kubectl (jeżeli nie masz tego polecenia to zobacz jak go zainstalować z oficjalnej dokumentacji o instalacji kubectl)


Wydajemy polecenie kubectl version:


$ kubectl version
                                                                                                    
WARNING: This version information is deprecated and will be replaced with the output from kubectl version --short.  Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"1", Minor:"27", GitVersion:"v1.27.2", GitCommit:"7f6f68fdabc4df88cfea2dcf9a19b2b830f1e647", GitTreeState:"clean", BuildDate:"2023-05-17T14:20:07Z", GoVersion:"go1.20.4", Compiler:"gc", Platform:"linux/amd64"}
Kustomize Version: v5.0.1
Unable to connect to the server: dial tcp: lookup k3s1.koska.in on 192.168.64.1:53: no such host

I jeżeli tak ja ja masz kilka kontekstów konfiguracyjnych kubernetes to musimy zmienić kontekst pracy z naszym klastrem dla polecenia kubectl - robimy to za pomocą polecania:


kubectl config use-context docker-desktop

Weryfikacja wersji kubectl
Weryfikacja wersji kubectl

Na obrazku powyżej widać aktualna wersję uzywana umnie oraz kontekst na jaki mam ustawione polecenie kubectl - takie wyśietlenie dale shell zsh z nakładka oh my zsh

Oczywiście mozna sprawdzic to poleceniem kubectl config get-contexts


Na koniec sprawdźmy czy działa nasz klaster poleceniem kubectl get nodes -> i powinniśmy otrzymać coś takiego:


$ kubectl get nodes                                                       

NAME             STATUS   ROLES           AGE   VERSION
docker-desktop   Ready    control-plane   28m   v1.27.2

UWAGI: Nie musimy korzystać z docker-desktop i kubernetesa w nim. Możemy skorzystać z platformy minikube, w dokumentacji awx-operator znajdziemy instrukcje jak przygotować klaster minikube.


Plan naszej konfiguracji

Na początku musimy się zastanowić gdzie będziemy trzymać naszą bazę danych postgresql dla naszego AWX - mamy do wyboru w klastrze kubernetes (awx-operator stawia i robi to za nasz przy czystej instalacji) lub na osobnym serwerze - dedykowana instancja (nie zarządzana przez awx-operator).


W przypadku drugiej konfiguracji mamy to opisane w dokumentacji związanej z konfiguracja bazy danych


Ja w tym wpisie pójdę druga drogą, pierwsza po prostu pomija konfiguracja secretu dla bazy danych.


Przygotowanie pliku kustomization.yaml

Na początek musimy przygotować nasz plik kustomization.yaml (możemy bazować na tym dostępnym w instrukcji podstawowej instalacji) plik u mnie przedstawia się następująco:


apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - github.com/ansible/awx-operator/config/default?ref=2.7.0

images:
  - name: quay.io/ansible/awx-operator
    newTag: 2.7.0

namespace: default

Ten kod przedstawia plik `Kustomization`, który jest częścią narzędzia `kustomize` używanego do dostosowywania zasobów Kubernetes. Pozwala on na tworzenie wielowarstwowych konfiguracji na bazie istniejących zasobów, bez konieczności modyfikowania oryginalnych plików YAML.


Rozbijmy ten konkretny plik `Kustomization` na poszczególne sekcje:


  1. apiVersion i kind:

    1. - `apiVersion`: Określa wersję API, z którą jest zgodny ten plik. W tym przypadku używana jest wersja `v1beta1` związana z `kustomize.config.k8s.io`.

    2. - `kind`: Określa typ obiektu. W tym przypadku jest to `Kustomization`, co wskazuje, że jest to plik konfiguracyjny dla `kustomize`.

  2. resources:

    1. - W tej sekcji określono zasoby, które mają być uwzględnione w procesie dostosowywania.

    2. - W tym przypadku zasób jest pobierany z repozytorium GitHub (`github.com/ansible/awx-operator`). Szczególnie korzysta z konfiguracji znajdującej się w katalogu `config/default` w odniesieniu do tagu `ref=2.7.0`.

  3. images:

    1. - Ta sekcja pozwala na modyfikację obrazów używanych w zasobach. Możliwe jest podmienienie nazwy obrazu, tagu lub repozytorium.

    2. - W tym przypadku obraz `quay.io/ansible/awx-operator` jest modyfikowany tak, aby używać tagu `2.7.0`.

  4. namespace:

    1. - Określa przestrzeń nazw, w której mają zostać wdrożone zasoby. W tym przypadku jest to przestrzeń nazw `default`.


Możemy zatem wydać polecenie kubectl apply -k . które uruchomi nam nasza konfigurację:

$ kubectl apply -k .                                                                                                                                                    

Warning: resource namespaces/default is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
namespace/default configured
customresourcedefinition.apiextensions.k8s.io/awxbackups.awx.ansible.com created
customresourcedefinition.apiextensions.k8s.io/awxrestores.awx.ansible.com created
customresourcedefinition.apiextensions.k8s.io/awxs.awx.ansible.com created
serviceaccount/awx-operator-controller-manager created
role.rbac.authorization.k8s.io/awx-operator-awx-manager-role created
role.rbac.authorization.k8s.io/awx-operator-leader-election-role created
clusterrole.rbac.authorization.k8s.io/awx-operator-metrics-reader created
clusterrole.rbac.authorization.k8s.io/awx-operator-proxy-role created
rolebinding.rbac.authorization.k8s.io/awx-operator-awx-manager-rolebinding created
rolebinding.rbac.authorization.k8s.io/awx-operator-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/awx-operator-proxy-rolebinding created
configmap/awx-operator-awx-manager-config created
service/awx-operator-controller-manager-metrics-service created
deployment.apps/awx-operator-controller-manager created

  1. Ostrzeżenie:

    1. W wyniku pojawiło się ostrzeżenie dotyczące zasobu namespaces/default. Mówi ono o braku anotacji kubectl.kubernetes.io/last-applied-configuration, która jest wymagana przez kubectl apply. Ostrzeżenie sugeruje, że powinieneś używać polecenia kubectl apply tylko na zasobach utworzonych deklaratywnie przez

    2. kubectl create --save-config lub kubectl apply. Brakująca anotacja zostanie dodana automatycznie.

  2. Zasoby:

    1. namespace/default configured: Przestrzeń nazw default została skonfigurowana. Słowo kluczowe "configured" wskazuje, że zasób istniał wcześniej i został zmodyfikowany, a nie stworzony od nowa.

    2. customresourcedefinition.apiextensions.k8s.io/... created: Trzy Custom Resource Definitions (CRD) dla awxbackups, awxrestores i awxs zostały utworzone. CRD pozwala na dodanie własnych zasobów do API Kubernetes.

    3. serviceaccount/awx-operator-controller-manager created: Utworzono ServiceAccount o nazwie awx-operator-controller-manager.

    4. Role i ClusterRole (role.rbac.authorization.k8s.io/... i clusterrole.rbac.authorization.k8s.io/... created): Utworzono różne role i clusterrole, które definiują zestaw uprawnień na zasoby w klastrze.

    5. RoleBindings i ClusterRoleBindings (rolebinding.rbac.authorization.k8s.io/... i clusterrolebinding.rbac.authorization.k8s.io/... created): Utworzono rolebindings i clusterrolebindings, które przypisują określone role do użytkowników lub grup.

    6. configmap/awx-operator-awx-manager-config created: Utworzono ConfigMap, który przechowuje konfigurację dla managera AWX.

    7. service/awx-operator-controller-manager-metrics-service created: Utworzono usługę (Service) służącą do zbierania metryk z kontrolera awx-operator-controller-manager.

    8. deployment.apps/awx-operator-controller-manager created: Utworzono Deployment dla kontrolera awx-operator-controller-manager, który definiuje i kontroluje instancje aplikacji.

Między czasie możemy sprawdzić czy konfiguracja ta stworzyła i działają nasze pody, poleceniem kubectl get pods


$ kubectl get pods                                                                                                                                                      

NAME                                               READY   STATUS              RESTARTS   AGE
awx-operator-controller-manager-54fd9bc446-zl562   0/2     ContainerCreating   0          21s

Jak nasze pody dla awx będą ze statusem running wtedy możemy sprawdzić dodatkowo logi dla naszego deployment i zobaczyć czy wszystko z naszym deployment jest ok.


$ kubectl logs -f deployments/awx-operator-controller-manager -c awx-manager                                                                                            

{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"cmd","msg":"Version","Go Version":"go1.19.11","GOOS":"linux","GOARCH":"amd64","ansible-operator":"v1.31.0","commit":"e67da35ef4fff3e471a208904b2a142b27ae32b1"}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"cmd","msg":"Watching single namespace.","Namespace":"default"}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"controller-runtime.metrics","msg":"Metrics server is starting to listen","addr":"127.0.0.1:8080"}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"watches","msg":"Environment variable not set; using default value","envVar":"ANSIBLE_VERBOSITY_AWX_AWX_ANSIBLE_COM","default":2}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"watches","msg":"Environment variable not set; using default value","envVar":"ANSIBLE_VERBOSITY_AWXBACKUP_AWX_ANSIBLE_COM","default":2}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"watches","msg":"Environment variable not set; using default value","envVar":"ANSIBLE_VERBOSITY_AWXRESTORE_AWX_ANSIBLE_COM","default":2}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"ansible-controller","msg":"Watching resource","Options.Group":"awx.ansible.com","Options.Version":"v1beta1","Options.Kind":"AWX"}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"ansible-controller","msg":"Watching resource","Options.Group":"awx.ansible.com","Options.Version":"v1beta1","Options.Kind":"AWXBackup"}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"ansible-controller","msg":"Watching resource","Options.Group":"awx.ansible.com","Options.Version":"v1beta1","Options.Kind":"AWXRestore"}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"proxy","msg":"Starting to serve","Address":"127.0.0.1:8888"}
{"level":"info","ts":"2023-10-25T08:53:13Z","logger":"apiserver","msg":"Starting to serve metrics listener","Address":"localhost:5050"}
{"level":"info","ts":"2023-10-25T08:53:13Z","msg":"Starting server","path":"/metrics","kind":"metrics","addr":"127.0.0.1:8080"}

awx.yml

W tym samym katalogu gdzie stworzyliśmy nasz plik kustomization.yaml tworzymy nasz plik awx.yml zawierający konfiguracje naszego serwisu awx:


---
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
  name: awx
spec:
  service_type: NodePort
  service_labels: |
    environment: production
  hostname: ansible.koska.in
  postgres_configuration_secret: awx-postgres-configuration
  ingress_type: none
  ipv6_disabled: true

db.yml

Tworzymy nasz plik konfiguracyjny z konfiguracja polaczenia do naszej bazy danych


---
apiVersion: v1
kind: Secret
metadata:
  name: awx-postgres-configuration
  namespace: default
stringData:
  host: <IP>
  port: "<PORT>"
  database: <DBNAME>
  username: <USER>
  password: "<PASSWORD>"
  sslmode: disable
  type: unmanaged
type: Opaque

Nasza baza danych

W celu udawania zewnętrznego hosta z bazą danych postawie moja baze danych postgresql w kontenerze z wykorzystaniem docker-compose.yml:


services:

  # postgres server
  db:
    image: postgres:13.9 
    restart: always
    environment:
      POSTGRES_PASSWORD: example
    ports:
      - 5432:5432 

Uruchommy naszą bazę danych. W katalogu z plikiem docker-compose.yml wydajemy komende docker compose up -d


Przykladowy komunikat z polecnia docker-compose up -d dla  wskaznaego przykadu - sucessfull
Przykladowy komunikat z polecnia docker-compose up -d dla wskaznaego przykadu

Jak możemy zobaczyć wszystko się udało - nasz baza danych została postawiona i uruchomiona. Oczywiście w konfiguracji docker-compose brakuje pewnych parametrów związanych z zachowaniem danych. Jednak w ramach tego testu pozwoliłem sobie je pominąć - nie zależy mi na zachowaniu danych w tym akurat przypadku.


Pozostaje nam dodać naszą bazę danych z której będzie korzystał AWX, logujemy sie do kontenera z terminala lub przez docker desktop. W przypadku terminala będzie to polecenie:


$ docker compose exec -it "db" bash

Znajdziemy się teraz w kontenerze i wydajmy komendę w celu stworzenia bazy danych.


createdb -U postgres -h 127.0.0.1 awxdb

Mamy stworzoną bazę danych. Możemy pobrać pgadmin i sprawdzić działanie naszej bazy oraz czy dodatkowa baza została utworzona.


Podglad naszego serwera postgres sql w pgadmin i widok naszej stworzonej bazy danych awxdb
Podglad naszego serwera postgres sql w pgadmin i widok naszej stworzonej bazy danych awxdb

Mamy potwierdzone że serwer bazy danych działa i mamy stworzona bazę danych teraz powróćmy do naszego pliku db.yml i uzupełnijmy nasze brakujące dane.


Uzupełniamy db.yml

Nasz plik musimy uzupełnic o nastepujace dane: host: <IP> port: "<PORT>" database: <DBNAME> username: <USER> password: "<PASSWORD>"


Port znamy jest to 5432, database to awxdb, username i password wykorzystamy domyślne zdefiniowane w docker compose. Pozostaje nam zatem adres IP. Sprawdźmy zatem jak nasz klaster w przypadku konfiguracji docker desktop widzi sieci. Posłużymy się podem uruchomionym na naszym klastrze, uruchomimy go za pomoca naszego pliku konfiguracyjnego ubuntu-pod.yml:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-pod
  namespace: default
spec:
  containers:
  - name: ubuntu-container
    image: ubuntu:latest
    command:
    - sleep
    - "infinity"

Wydajemy polecenie:


$ kubectl apply -f ubuntu-pod.yml

A potem łączymy się do naszego poda


$ kubectl exec -n default -it ubuntu-pod -- /bin/bash

I wydajemy zestaw komend:


apt update

ping

apt install iputils-ping telnet

ping <ADDRESS_IP_WSL_HOST> or <IP_NODE_CLUSTER>


Adres IP_NODE_CLUSETR możemy zdobyć z polecania:


$ kubectl get nodes -o wide

NAME             STATUS   ROLES           AGE     VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE         KERNEL-VERSION                      CONTAINER-RUNTIME
docker-desktop   Ready    control-plane   3h24m   v1.27.2   172.31.255.3   <none>        Docker Desktop   5.15.90.1-microsoft-standard-WSL2   docker://24.0.6

Jak ktoś nie ufa ping można jeszcze uruchomić telnet (<ADDRESS_IP_WSL_HOST> or <IP_NODE_CLUSTER>) <PORT>


Zatem mamy wszystkie informacje. Możemy uzupełnić nasz db.yml


---
apiVersion: v1
kind: Secret
metadata:
  name: awx-postgres-configuration
  namespace: default
stringData:
  host: 192.168.79.146
  port: "5432"
  database: awxdb
  username: postgres
  password: "example"
  sslmode: disable
  type: unmanaged
type: Opaque

Dodajemy sekrety

Do naszej pierwotnej konfiguracji kustomization.yaml dodajemy dodatkowa linijkę z naszym plikiem db.yml

...
resources:
  - github.com/ansible/awx-operator/config/default?ref=2.7.0
  - db.yml
...

Zmiany zapisujemy i uruchamiamy nasze polecenie kubectl apply -k .



...
secret/awx-postgres-configuration created
...

kubectl poinformuje nas o tym że sekret został dodany / stworzony.

Teraz dodajemy nasz awx.yml do kustomization.yaml

...
resources:
  - github.com/ansible/awx-operator/config/default?ref=2.7.0
  - db.yml
  - awx.yml
...

Zmiany zapisujemy i uruchamiamy nasze polecenie kubectl apply -k .


Po wydaniu polecenia możemy od razu wskoczyć w logi naszego awx-menagera


$ kubectl logs -f deployments/awx-operator-controller-manager -c awx-manager

Warto podczas działania uruchamiania naszych podów i konfiguracji potrzeć czy jakie dane przechodzą do naszego postgres.

Panel pgadmin z statystykami w celu weryfikacji procesy deploymentu awx
Panel pgadmin z statystykami w celu weryfikacji procesy deploymentu awx

Z poziomu kubectl możemy sprawdzić nasze pody czy mają odpowiedni status:

kubectl get pods -l "app.kubernetes.io/managed-by=awx-operator" 

Oraz na jakim porcie działa nasza aplikacja:

kubectl get svc -l "app.kubernetes.io/managed-by=awx-operator" 


AWX login page
AWX login page

Hasło do naszego panelu możemy pobrać z polecenia:


kubectl get secret awx-admin-password -o jsonpath="{.data.password}" | base64 --decode ; echo

AWX dashboard page
AWX dashboard page

Mamy nasz panel i możemy się zalogować - oczywiscie to tylko testowa konfiguracja ale na jej bazie możemy już planować nasze wdrożenia.


A w tym artykule to już wszystko. Zapraszam do kolejnych wpisów.

268 wyświetleń0 komentarzy

Ostatnie posty

Zobacz wszystkie

Comments


Śledź nasze wpisy w social media

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube

Poznaj terraform jedno z najepszych narzedzi do zarządzania infrastrukturą w kodzie (IaC) - w kursie tym przeprowadzam Cię przez proces instalacji i konfiguracji tego narzędzia.

bottom of page