Aller au contenu principal

Génerer des operateurs Kubernetes avec Ansible

· 14 minutes de lecture
Stéphane ROBERT
Consultant DevOps

Pour déployer une application au sein d'un cluster Kubernetes, on peut le faire de manière classique avec des fichiers de configuration YAML ou un gestionnaire de packages comme Helm. Il existe un troisième moyen qui est de créer un opérateur Kubernetes. Voyons dans un premier temps ce qu'est un opérateur Kubernetes.

Les opérateurs Kubernetes

Qu'est-ce qu'un opérateur Kubernetes

Un opérateur Kubernetes est un contrôleur personnalisé qui étend les fonctionnalités de l'API Kubernetes pour gérer des applications complexes. Il permet de déployer et de gérer une application Kubernetes de manière automatisée. L'opérateur peut automatiser des tâches telles que la sauvegarde des données, la récupération après défaillance et l'installation de nouvelles versions de l'application. L’utilisation d’un opérateur Kubernetes permet donc de réduire les interventions et donc les erreurs humaines.

Comment écrire un opérateur Kubernetes ?

Il existe de nombreuses méthodes pour écrire et déployer son propre un opérateur Kubernetes :

Qu'est l'Operator Framework

L’Operator Framework est un outil créé par Red Hat dans le cadre de l’Operator Framework. Avec ce Framework, on peut développer des opérateurs kubernetes, soit avec le langage Go, soit le gestionnaire de configuration Ansible ou encore le gestionnaire de packages Helm.

Ici, je ne vais utiliser Ansible pour créer notre premier opérateur.

Pourquoi utiliser Ansible pour écrire un opérateur Kubernetes ?

Au début, les opérateurs étaient écrits en Go, ce qui obligeait à connaître ce langage. L’opérateur Ansible a été créé pour en faciliter l'écriture. Autre point positif, cela permet aux utilisateurs d’intégrer des tâches de gestion hors cluster liées à votre application via la large collections de modules Ansible.

Création de notre premier Operateur Ansible

Installation des prérequis

Installation d'un cluster Kubernetes

Vous pouvez utiliser kind, k3s, minikube,... pour monter votre cluster mono-noeud. Personnellement j'utilise k3s:

curl -sfL https://get.k3s.io | sh -
sudo chmod 0644 /etc/rancher/k3s/k3s.yaml
k3s kubectl get node
NAME       STATUS   ROLES                  AGE   VERSION
internal   Ready    control-plane,master   9h    v1.26.3+k3s1

Installation de l'Operator Framework

La documentation de l'installation se trouve ici. Je vais tout de même détailler en français l'installation depuis les artefacts disponibles sur le projet.

export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac)
export OS=$(uname | awk '{print tolower($0)}')
export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.28.0
curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH}
gpg --keyserver keyserver.ubuntu.com --recv-keys 052996E2A20B5C7E
curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt
curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt.asc
gpg -u "Operator SDK (release) <cncf-operator-sdk@cncf.io>" --verify checksums.txt.asc

Vous devriez obtenir ce message :

gpg: les données signées sont supposées être dans « checksums.txt »
gpg: Signature faite le mer. 15 mars 2023 01:46:07 CET
gpg:                avec la clef RSA 8613DB87A5BA825EF3FD0EBE2A859D08BF9886DB
gpg: Bonne signature de « Operator SDK (release) <cncf-operator-sdk@cncf.io> » [inconnu]
gpg: Attention : cette clef n'est pas certifiée avec une signature de confiance.
gpg:          Rien n'indique que la signature appartient à son propriétaire.
Empreinte de clef principale : 3B2F 1481 D146 2380 80B3  46BB 0529 96E2 A20B 5C7E
     Empreinte de la sous-clef : 8613 DB87 A5BA 825E F3FD  0EBE 2A85 9D08 BF98 86DB

On vérifie que les checksums correspondent :

grep operator-sdk_${OS}_${ARCH} checksums.txt | sha256sum -c -

operator-sdk_linux_amd64: Réussi

On peut copier le binaire :

chmod +x operator-sdk_${OS}_${ARCH} && sudo mv operator-sdk_${OS}_${ARCH} /usr/local/bin/operator-sdk

On peut lancer la commande suivante que tout est bien installé :

operator-sdk version

operator-sdk version: "v1.28.0", commit: "484013d1865c35df2bc5dfea0ab6ea6b434adefa", kubernetes version: "1.26.0", go version: "go1.19.6", GOOS: "linux", GOARCH: "amd64"

Installation d'une registry Docker

Nous avons besoin d'une registry docker pour stocker les images.

docker run -d -p 5000:5000 --restart=always --name registry registry:2

Installation des librairies python pour molecule

Si vous souhaitez utiliser molecule pour mettre en place des tests, il est nécessaire d'installer dans votre environnement virtuel python les librairies suivantes :

pip install molecule kubernetes

Installation des outils

Installation de kustomize et kubectl

Nous aurons aussi besoin de certains outils que je vais installer avec asdf :

asdf plugin add kustomize
asdf install kustomize latest
asdf global kustomize latest

asdf plugin add kubectl
asdf install kubectl latest
asdf global kubectl latest

Création de l'opérateur

Maintenant que le SDK est installé passons à la création de notre opérateur.

mkdir first-ansible-operator
cd first-ansible-operator
operator-sdk init --domain example.me --plugins ansible

Il faut ensuite créer l'API :

operator-sdk create api --group cache --version v1alpha1 --kind FirstOperator --generate-role

Normalement, vous devriez obtenir toute une arborescence contenant ces répertoires et fichiers :

[0] .
├── [1] Makefile
├── [2] playbooks
├── [3] requirements.yml
├── [4] watches.yaml
├── [5] roles
│   └── [6] firstoperator
│       ├── [7] vars
│       │   └── [8] main.yml
│       ├── [9] meta
│       │   └── [10] main.yml
│       ├── [11] handlers
│       │   └── [12] main.yml
│       ├── [13] templates
│       ├── [14] tasks
│       │   └── [15] main.yml
│       ├── [16] README.md
│       ├── [17] defaults
│       │   └── [18] main.yml
│       └── [19] files
├── [20] molecule
│   ├── [21] kind
│   │   ├── [22] converge.yml
│   │   ├── [23] molecule.yml
│   │   ├── [24] create.yml
│   │   └── [25] destroy.yml
│   └── [26] default
│       ├── [27] kustomize.yml
│       ├── [28] prepare.yml
│       ├── [29] tasks
│       │   └── [30] firstoperator_test.yml
│       ├── [31] converge.yml
│       ├── [32] create.yml
│       ├── [33] verify.yml
│       ├── [34] destroy.yml
│       └── [35] molecule.yml
├── [36] config
│   ├── [37] rbac
│   │   ├── [38] firstoperator_viewer_role.yaml
│   │   ├── [39] role.yaml
│   │   ├── [40] auth_proxy_client_clusterrole.yaml
│   │   ├── [41] leader_election_role.yaml
│   │   ├── [42] auth_proxy_role_binding.yaml
│   │   ├── [43] auth_proxy_role.yaml
│   │   ├── [44] firstoperator_editor_role.yaml
│   │   ├── [45] leader_election_role_binding.yaml
│   │   ├── [46] service_account.yaml
│   │   ├── [47] role_binding.yaml
│   │   ├── [48] kustomization.yaml
│   │   └── [49] auth_proxy_service.yaml
│   ├── [50] scorecard
│   │   ├── [51] patches
│   │   │   ├── [52] basic.config.yaml
│   │   │   └── [53] olm.config.yaml
│   │   ├── [54] bases
│   │   │   └── [55] config.yaml
│   │   └── [56] kustomization.yaml
│   ├── [57] prometheus
│   │   ├── [58] monitor.yaml
│   │   └── [59] kustomization.yaml
│   ├── [60] crd
│   │   ├── [61] kustomization.yaml
│   │   └── [62] bases
│   │       └── [63] cache.example.me_firstoperators.yaml
│   ├── [64] samples
│   │   ├── [65] kustomization.yaml
│   │   └── [66] cache_v1alpha1_firstoperator.yaml
│   ├── [67] testing
│   │   ├── [68] kustomization.yaml
│   │   ├── [69] manager_image.yaml
│   │   ├── [70] pull_policy
│   │   │   ├── [71] Always.yaml
│   │   │   ├── [72] Never.yaml
│   │   │   └── [73] IfNotPresent.yaml
│   │   └── [74] debug_logs_patch.yaml
│   ├── [75] manager
│   │   ├── [76] kustomization.yaml
│   │   └── [77] manager.yaml
│   ├── [78] manifests
│   │   └── [79] kustomization.yaml
│   └── [80] default
│       ├── [81] kustomization.yaml
│       ├── [82] manager_auth_proxy_patch.yaml
│       └── [83] manager_config_patch.yaml
├── [84] Dockerfile
└── [85] PROJECT

Les fichiers et dossiers importants :

  • [1] Makefile : contient toutes les commandes pour gérer l'opérateur
  • [2] playbooks : un dossier vide par défaut dans lequel vous pouvez ajouter vos actions
  • [3] requirements.yml : les dépendances rôles et collections ansible-galaxy
  • [4] watches.yaml : Permet de définir les ressources que l'opérateur surveille.
  • [5] roles : C'est dans ce dossier que nous définir les ressources kubernetes qui doivent être créé par l'opérateur
  • [84] Dockerfile : Permet d'ajouter des dépendances python à l'image qui lance la création des ressources.

Ajout des ressources pilotées par l'opérateur

Pour cela, nous allons éditer le rôle Ansible. Nous allons déployer une simple déploiement avec une image nginx.

Ouvrez le fichier roles/firstoperator/tasks/main.yml :

---
- name: Create a Deployment with image hello-world
  kubernetes.core.k8s:
    definition:
      kind: Deployment
      apiVersion: apps/v1
      metadata:
        name: "{{ ansible_operator_meta.name }}-helloworld"
        namespace: "{{ ansible_operator_meta.namespace }}"
      spec:
        replicas: "{{ size }}"
        selector:
          matchLabels:
            app: helloworld
        template:
          metadata:
            labels:
              app: helloworld
          spec:
            containers:
              - name: helloworld
                image: "nginx"
- name: Create frontend service
  kubernetes.core.k8s:
    definition:
      kind: Service
      apiVersion: v1
      metadata:
        name: frontend-service
        namespace: '{{ ansible_operator_meta.namespace }}'
        labels:
          app: frontend
      spec:
        type: NodePort
        ports:
          - port: 80
            targetPort: 80
            nodePort: 30686
            protocol: TCP
        selector:
          app: frontend

ATTENTION : c'est bien un fichier de rôle Ansible utilisant le module kubernetes.core.k8s

D'ailleurs, vous remarquez que nous faisons appel à des variables Jinja.

{{ size }} que nous allons définir dans le fichier roles/firstoperator/defaults/main.yml qui pilote le nombre de pod(s) de notre déploiement.

---
size: 1

{{ ansible_operator_meta.name }}

Création de l'image docker

Pour éviter de devoir renseigner le nom de l'image chaque invocation de la commande make, éditons le fichier Makefile :

vi Makefile

À la ligne 50 remplacez la ligne commençant par IMG par :

IMG ?= localhost:5000/first-operator:v$(VERSION)

Nous allons construire l'image qui va servir à lancer les actions Ansible par l'opérateur. Nous allons l'installer dans la registry local :

make docker-build docker-push VERSION=0.0.1

Ce qui donne :

docker build -t localhost:5000/first-operator:v0.0.1 .
[+] Building 0.6s (11/11) FINISHED
 => [internal] load .dockerignore                                                                                      0.0s
 => => transferring context: 2B                                                                                        0.0s
 => [internal] load build definition from Dockerfile                                                                   0.0s
 => => transferring dockerfile: 351B                                                                                   0.0s
 => [internal] load metadata for quay.io/operator-framework/ansible-operator:v1.28.0                                   0.5s
 => [internal] load build context                                                                                      0.0s
 => => transferring context: 5.04kB                                                                                    0.0s
 => [1/6] FROM quay.io/operator-framework/ansible-operator:v1.28.0@sha256:e4356b6a35250901d436ad40f7defb3afb841d42cb1  0.0s
 => CACHED [2/6] COPY requirements.yml /opt/ansible/requirements.yml                                                   0.0s
 => CACHED [3/6] RUN ansible-galaxy collection install -r /opt/ansible/requirements.yml  && chmod -R ug+rwx /opt/ansi  0.0s
 => [4/6] COPY watches.yaml /opt/ansible/watches.yaml                                                                  0.0s
 => [5/6] COPY roles/ /opt/ansible/roles/                                                                              0.0s
 => [6/6] COPY playbooks/ /opt/ansible/playbooks/                                                                      0.0s
 => exporting to image                                                                                                 0.0s
 => => exporting layers                                                                                                0.0s
 => => writing image sha256:1079f6875f53a7cb4c6dfa8a6e33913806f5fe53315c84c7e0e1fc36eae75cca                           0.0s
 => => naming to localhost:5000/first-operator:v0.0.1                                                                  0.0s
docker push localhost:5000/first-operator:v0.0.1
The push refers to repository [localhost:5000/first-operator]
4c98d0d9ecab: Pushed
ec115a086a7b: Pushed
57b360c22e69: Pushed
b3caa9094c7b: Layer already exists
2e2156d26b91: Layer already exists
89b874d633f9: Layer already exists
5f70bf18a086: Layer already exists
5188f96e027c: Layer already exists
89cc1fe33e9a: Layer already exists
e28c0943f833: Layer already exists
6ce5a98a4fc8: Layer already exists
3570c420cda4: Layer already exists
bccb88911f57: Layer already exists
v0.0.1: digest: sha256:12c0db25a325bb5259feccc7553e79cadadd3a70da60ab4ffd188651fe04ce34 size: 3030

Déploiement de l'opérateur Ansible

Nous avons deux moyens de déployer notre opérateur dans notre instance kubernetes :

Nous utiliserons ici la seconde méthode pour le moment.

make deploy VERSION=0.0.1

Ici, nous déployons que l'opérateur qui ajoute juste la définition de notre ressource à l'API. Pour contrôler si l'opérateur est bien déployé, nous utiliserons les commandes kubectl habituelles :

kubectl get namespaces

NAME                            STATUS   AGE
default                         Active   11d
kube-system                     Active   11d
kube-public                     Active   11d
kube-node-lease                 Active   11d
firstoperator                   Active   7d
first-ansible-operator-system   Active   3d22h

Nous avons déployé notre opérateur dans le namespace first-ansible-operator-system. Verifions ce qui a été créé dans ce namespace :

kubectl -n first-ansible-operator-system get pod
NAME                                                         READY   STATUS    RESTARTS        AGE
first-ansible-operator-controller-manager-56bb9d55d6-vd6hs   2/2     Running   3 (3m59s ago)   3d22h

Pour vérifier les logs de l'opérateur (changez le nom de la ressource avec la vôtre) :

kubectl -n first-ansible-operator-system logs first-ansible-operator-controller-manager-56bb9d55d6-vd6hs manager
{"level":"info","ts":"2023-05-02T08:00:25Z","logger":"cmd","msg":"Version","Go Version":"go1.18.10","GOOS":"linux","GOARCH":"amd64","ansible-operator":"v1.28.0","commit":"484013d1865c35df2bc5dfea0ab6ea6b434adefa"}
{"level":"info","ts":"2023-05-02T08:00:25Z","logger":"cmd","msg":"Watch namespaces not configured by environment variable WATCH_NAMESPACE or file. Watching all namespaces.","Namespace":""}
I0502 08:00:27.097654       7 request.go:690] Waited for 1.049099946s due to client-side throttling, not priority and fairness, request: GET:https://10.43.0.1:443/apis/apiextensions.k8s.io/v1?timeout=32s
{"level":"info","ts":"2023-05-02T08:00:27Z","logger":"controller-runtime.metrics","msg":"Metrics server is starting to listen","addr":"127.0.0.1:8080"}
{"level":"info","ts":"2023-05-02T08:00:27Z","logger":"watches","msg":"Environment variable not set; using default value","envVar":"ANSIBLE_VERBOSITY_FIRSTOPERATOR_CACHE_EXAMPLE_ME","default":2}
{"level":"info","ts":"2023-05-02T08:00:27Z","logger":"cmd","msg":"Environment variable not set; using default value","Namespace":"","envVar":"ANSIBLE_DEBUG_LOGS","ANSIBLE_DEBUG_LOGS":false}
{"level":"info","ts":"2023-05-02T08:00:27Z","logger":"ansible-controller","msg":"Watching resource","Options.Group":"cache.example.me","Options.Version":"v1alpha1","Options.Kind":"Firstoperator"}
{"level":"info","ts":"2023-05-02T08:00:27Z","logger":"proxy","msg":"Starting to serve","Address":"127.0.0.1:8888"}
{"level":"info","ts":"2023-05-02T08:00:27Z","logger":"apiserver","msg":"Starting to serve metrics listener","Address":"localhost:5050"}
{"level":"info","ts":"2023-05-02T08:00:27Z","msg":"Starting server","path":"/metrics","kind":"metrics","addr":"127.0.0.1:8080"}
{"level":"info","ts":"2023-05-02T08:00:27Z","msg":"Starting server","kind":"health probe","addr":"[::]:6789"}
I0502 08:00:27.456406       7 leaderelection.go:248] attempting to acquire leader lease first-ansible-operator-system/first-ansible-operator...
I0502 08:00:44.125317       7 leaderelection.go:258] successfully acquired lease first-ansible-operator-system/first-ansible-operator
{"level":"info","ts":"2023-05-02T08:00:44Z","msg":"Starting EventSource","controller":"firstoperator-controller","source":"kind source: *unstructured.Unstructured"}
{"level":"info","ts":"2023-05-02T08:00:44Z","msg":"Starting Controller","controller":"firstoperator-controller"}
{"level":"info","ts":"2023-05-02T08:00:44Z","msg":"Starting workers","controller":"firstoperator-controller","worker count":9}

Notre Opérateur est correctement déployé. Passons à la création de notre première ressource.

Création de notre première ressource

Pour créer notre première ressource, c'est assez simple, car lors de la création de l'opérateur le SDK a créé un fichier de déclaration prêt à l'emploi. Ce fichier se trouve dans le dossier config/samples/ et se nomme cache_v1alpha1_firstoperator.yaml. Nous allons l'éditer pour spécifier le nombre de pod de notre ressource :

apiVersion: cache.example.me/v1alpha1
kind: Firstoperator
metadata:
  labels:
    app.kubernetes.io/name: firstoperator
    app.kubernetes.io/instance: firstoperator-sample
    app.kubernetes.io/part-of: first-ansible-operator
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: first-ansible-operator
  name: firstoperator-sample
  namespace: firstoperator
spec:
  size: 3

On ajoute simplement size avec la valeur de 3 à notre ressource.

Nous pouvons créer notre première ressource, mais avant cela créons un namespace dédié et changeons le context :

kubectl create namespace firstoperator
kubectl config set-context --current --namespace=firstoperator
kubectl get pod
No resources found in firstoperator namespace.

Dans une autre terminal lancez cette commande pour surveiller les logs de l'opérateur :

kubectl -n first-ansible-operator-system logs -f first-ansible-operator-controller-manager-56bb9d55d6-vd6hs manager

Créons notre ressource :

kubectl apply -f config/samples/cache_v1alpha1_firstoperator.yaml
firstoperator.cache.example.me/firstoperator-sample created

Dans l'autre terminal, vous devriez voir les logs de la création de la ressource :

{"level":"error","ts":"2023-05-02T08:25:18Z","msg":"Reconciler error","controller":"firstoperator-controller","object":{"name":"firstoperator-sample","namespace":"firstoperator"},"namespace":"firstoperator","name":"firstoperator-sample","reconcileID":"4b593968-f602-4d16-add3-1eec3b278820","error":"event runner on failed","stacktrace":"sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.14.5/pkg/internal/controller/controller.go:329\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.14.5/pkg/internal/controller/controller.go:274\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func2.2\n\t/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.14.5/pkg/internal/controller/controller.go:235"}
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Failed to retrieve requested object: b'{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"services \\\\\"frontend-service\\\\\" is forbidden: User \\\\\"system:serviceaccount:first-ansible-operator-system:first-ansible-operator-controller-manager\\\\\" cannot get resource \\\\\"services\\\\\" in API group \\\\\"\\\\\" in the namespace \\\\\"firstoperator\\\\\"\",\"reason\":\"Forbidden\",\"details\":{\"name\":\"frontend-service\",\"kind\":\"services\"},\"code\":403}\\n'", "reason": "Forbidden"}

Il y a une erreur dans notre déploiement ? Retirons notre ressource :

Que se passe-t-il ? Tout est indiqué dans les logs. Le service n'a pas été créé, car nous n'avons pas les droits ! Il faut ajouter les droits sur les services pour l'API Group "". Un petit tour dans le répertoire config/rbcpour éditer le fichier role.yaml pour y ajouter services à ce groupe :

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: manager-role
rules:
  ##
  ## Base operator rules
  ##
  - apiGroups:
      - ""
    resources:
      - secrets
      - pods
      - pods/exec
      - pods/log
      - services
    verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch

Redéployons notre Opérateur avec ces nouveaux droits !

make deploy VERSION=0.0.1
cd config/manager && /home/vagrant/.asdf/shims/kustomize edit set image controller=localhost:5000/first-operator:v0.0.1
/home/vagrant/.asdf/shims/kustomize build config/default | kubectl apply -f -
# Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically.
namespace/first-ansible-operator-system unchanged
customresourcedefinition.apiextensions.k8s.io/firstoperators.cache.example.me unchanged
serviceaccount/first-ansible-operator-controller-manager unchanged
role.rbac.authorization.k8s.io/first-ansible-operator-leader-election-role unchanged
clusterrole.rbac.authorization.k8s.io/first-ansible-operator-manager-role configured
clusterrole.rbac.authorization.k8s.io/first-ansible-operator-metrics-reader unchanged
clusterrole.rbac.authorization.k8s.io/first-ansible-operator-proxy-role unchanged
rolebinding.rbac.authorization.k8s.io/first-ansible-operator-leader-election-rolebinding unchanged
clusterrolebinding.rbac.authorization.k8s.io/first-ansible-operator-manager-rolebinding unchanged
clusterrolebinding.rbac.authorization.k8s.io/first-ansible-operator-proxy-rolebinding unchanged
service/first-ansible-operator-controller-manager-metrics-service unchanged

Vous remarquez que la ligne suivante indique bien un changement !

clusterrole.rbac.authorization.k8s.io/first-ansible-operator-manager-role configured

On vérifie que notre service est correctement créé :

kubectl get services
NAME               TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
frontend-service   NodePort   10.43.77.106   <none>        80:30686/TCP   27s

On vérifie que nous accédons bien à un des pods du déploiement :

curl localhost:30686

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Tout décommissionner

Nous avons fini de jouer avec notre Opérateur Ansible. Faisons le ménage !

Dans un premier détruisons notre application :

kubectl delete -f config/samples/cache_v1alpha1_firstoperator.yaml

firstoperator.cache.example.me "firstoperator-sample" deleted

Puis notre Opérateur :

make undeploy

/home/vagrant/.asdf/shims/kustomize build config/default | kubectl delete -f -
# Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically.
namespace "first-ansible-operator-system" deleted
customresourcedefinition.apiextensions.k8s.io "firstoperators.cache.example.me" deleted
serviceaccount "first-ansible-operator-controller-manager" deleted
role.rbac.authorization.k8s.io "first-ansible-operator-leader-election-role" deleted
clusterrole.rbac.authorization.k8s.io "first-ansible-operator-manager-role" deleted
clusterrole.rbac.authorization.k8s.io "first-ansible-operator-metrics-reader" deleted
clusterrole.rbac.authorization.k8s.io "first-ansible-operator-proxy-role" deleted
rolebinding.rbac.authorization.k8s.io "first-ansible-operator-leader-election-rolebinding" deleted
clusterrolebinding.rbac.authorization.k8s.io "first-ansible-operator-manager-rolebinding" deleted
clusterrolebinding.rbac.authorization.k8s.io "first-ansible-operator-proxy-rolebinding" deleted
service "first-ansible-operator-controller-manager-metrics-service" deleted
deployment.apps "first-ansible-operator-controller-manager" deleted

Plus loin

Après ces quelques jours où j'ai commencé à jouer avec l'Operator Framework version Ansible, je peux conclure que c'est au final plutôt simple. Le plus compliqué étant de lire et d'interpréter les logs retournées par Ansible. Je vais continuer à explorer cette techno pour essayer de provisionner des ressources externes et de gérer des backups. D'ailleurs maintenant que je comprends comment cela fonctionne, je suis allé faire un tour dans le code de l'opérateur AWX.

On peut y voir 3 watches :

---
# Use the 'create api' subcommand to add watches to this file.
- version: v1beta1
  group: awx.ansible.com
  kind: AWX
  playbook: playbooks/awx.yml
  snakeCaseParameters: False

- version: v1beta1
  group: awx.ansible.com
  kind: AWXBackup
  role: backup
  snakeCaseParameters: False
  finalizer:
    name: awx.ansible.com/finalizer
    role: backup
    vars:
      finalizer_run: true

- version: v1beta1
  group: awx.ansible.com
  kind: AWXRestore
  role: restore
  snakeCaseParameters: False

Il existe 2 rôles gérant les sauvegardes ! Par contre, cela fera l'objet d'un nouveau billet sur les watches, finalizers, ...