[PYTHON] Présentation d'Ansible

Ansible trébuche rapidement en essayant de faire quelque chose d'un peu différent de l'exemple de la documentation. Je soupçonne que ce mur Ansible est dû au fait que vous ne pouvez pas voir l'image entière. Au fur et à mesure que vous l'utiliserez, vous verrez progressivement l'image dans son ensemble, mais il est souvent nécessaire de la connaître plus tôt. Je vais le laisser comme mon propre mémo, comme la structure pour une vue d'ensemble de la situation dans son ensemble, mais j'espère que cela sera utile à d'autres personnes autant que possible.

  1. Notation de réglage Ansible
  2. Fichier de configuration ansible.cfg
  3. Inventaire
  4. Playbook
  5. Utilisez la structure de répertoires d'Ansible
  6. Différence entre l'importation et l'inclusion
  7. Bonus: faites de Raspberry Pi3 (Ubuntu Stretch 9) l'hôte de contrôle

Au minimum, si vous comprenez 1. la notation de configuration d'Ansible, 2. le fichier de configuration ansible.cfg, 3. Inventory et 4. Playbook, vous devriez pouvoir utiliser ansible. Je vais. (Il existe des conditions préalables telles que les paramètres SSH.)

Au fur et à mesure que vous l'utiliserez, vous pourrez gérer plusieurs tâches collectivement et les réutiliser plus souvent. La section 5 décrit comment utiliser ansible en utilisant la structure de répertoires.

Enfin, je décrirai comment l'utiliser avec Raspberry Pi3 en bonus.

Notation de réglage Ansible

Dans les paramètres Ansible, format YAML et format INI Vous pouvez utiliser E3% 82% A1% E3% 82% A4% E3% 83% AB) (notation INI étendue qui autorise «#» dans les commentaires). Bien que vous puissiez écrire de manière flexible en étant capable d'écrire les deux, ce sera déroutant lorsque vous l'utiliserez pour la première fois car il n'est pas uniforme.

C'est une bonne idée de garder à l'esprit les règles suivantes.

  1. * .cfg, fichier sans extension est au format INI
  2. * .yml et * .yaml sont au format YAML

Exemple de format INI

Il se compose d'un «nom de section» entre «[]» et d'un «paramètre» décrit par «=». Vous pouvez mettre des espaces, TAB, etc. avant et après =.

ini:./ansible.cfg


[defaults]
host_key_checking       = True

#Vous pouvez écrire des commentaires clairement
[privilege_escalation]
become_ask_pass         = True

;Vous pouvez écrire un commentaire avec un point-virgule
[ssh_connection]
scp_if_ssh              = False

Après =, sauf pour les booléens True / False et yes / no, il est traité comme une "chaîne de caractères" jusqu'à la fin de la ligne. Si vous le placez entre «» «etc.,« »« lui-même peut être interprété comme faisant partie de la chaîne.

Séparez les "listes" (tableaux) par des virgules (,).

Exemple de format YAML

L'énumération des «noms» séparés par «:» est appelée «scalaire».

Scalaire


name1:
name2:
:
nameN:

Si vous énumérez sans préfixer -, il devient" serial "(simple énumération," scalaire ").

Vous pouvez écrire la valeur après «:». Aussi appelé un type de dictionnaire, cela s'appelle un «mappage» en YAML.

cartographie


name1: aaaa
name2: bbbb
:
nameN: cccc

Si vous le préfixez avec -, il devient une liste (tableau). En YAML, cela s'appelle une "séquence".

séquence


- name1:
- name2:

- nameN:

L'indentation représente une hiérarchie, appelée "collection". Utilisez des espaces pour l'indentation. Veuillez noter que l'utilisation de TAB telle quelle entraînera une erreur. (Si vous utilisez vi / vim, le définir avec set expandtab remplacera TAB par des espaces)

Exemple-playbook-samle1.yml


- name: the 1st Example
  hosts: 172.17.0.2
  tasks:
    - name: Hello, World!
      debug:
    - name: Next debug
      debug: msg="Hello, Ansible!"

Dans cet exemple, name: the 1st Example, hosts: 172.17.0.2, tasks: sont au même niveau de paramètres scalaires (parallèles (séquentiels)), -name: Hello, ansible, -name: Next. La partie debug est la séquence (liste (tableau)). C'est un mappage, chacun avec une valeur. tâches est une collection.

Je vois souvent le format YAML avec «---» (trois tirets) au début. C'est parce que la structure de YAML est censée commencer un bloc de définition avec «---» et se terminer par «...» (trois points). Vous pouvez écrire plusieurs blocs dans un fichier avec «---», mais en général, ansible n'utilise pas une telle structure. Vous pouvez penser qu'il est prudent d'ajouter «---». La réécriture du playbook-samle1.yml ci-dessus entraînera ce qui suit.

playbook-samle1.yml


---
- name: the 1st Example
  hosts: 172.17.0.2
  tasks:
    - name: Hello, World!
      debug:
    - name: Next debug
      debug: msg="Hello, Ansible!"

Fichier de configuration ansible.cfg

Voir aussi: Paramètres de configuration Ansible - Documentation Ansible (https://docs.ansible.com/ansible/latest/reference_appendices/config.html) Puisque l'extension du fichier de configuration est .cfg, il est décrit au format INI. Les commandes liées à Ansible recherchent les fichiers de configuration dans l'ordre suivant, et le premier fichier de configuration trouvé est utilisé.

  1. Fichier spécifié par la variable d'environnement ʻANSIBLE_CONFIG`
  2. ʻansible.cfg (. / Ansible.cfg`) dans le répertoire courant
  3. Répertoire de base .ansible.cfg ( ~ / .ansible.cfg ou `$ HOME / .ansible.cfg)
  4. /etc/ansible/ansible.cfg

Exemple Ansible.cfg

ansible.cfg


[defaults]
inventory		= ./inventory
interpreter_python	= /usr/bin/python3
#deprecation_warnings	= False

[privilege_escalation]
become_ask_pass		= yes

[ssh_connection]
scp_if_ssh		= False

Inventaire

Voir: Comment créer votre inventaire - Documentation Ansible Afin d'exécuter la commande ansible et d'utiliser le playbook décrit plus loin, il est nécessaire de préparer un fichier appelé Inventory qui décrit l'hôte à exploiter. En un mot, c'est comme une collection de fichiers / etc / hosts.

Exemple d'inventaire

myhost1


172.17.0.2

Le plus petit fichier d'inventaire ne contient qu'une seule adresse IP (hôte).

myhost2


172.17.0.2
172.17.0.3

[group1]
172.17.0.2
172.17.0.3

[group2]
172.17.0.[3:7]

[my_all:children]
group1
group2

Playbook

Au lieu de la spécification du module ad hoc (= single-shot) et de l'opération de ʻansible -m ping host pattern`, spécifiez un fichier de configuration appelé playbook pour effectuer une série d'opérations. Le format du playbook est généralement le format YAML.

Exemple de Playbook

playbook-sample1.yml


- name: the 1st Example
  hosts: 172.17.0.2
  tasks:
#Les tâches sont répertoriées(séquence)Précisez avec.
#Afficher le message par défaut dans le débogage.
    - name: Hello, World
      debug:
#Afficher le message spécifié dans le débogage.
    - name: Next debug
      debug: msg="Hello, Ansible!"

Pour exécuter le playbook, vous devez spécifier un fichier d'inventaire.

myhosts1


172.17.0.2
$ ansible-playbook -i myhosts1 playbook-sample1.yml

PLAY [the 1st Example] *************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [172.17.0.2]

TASK [Hello, World] ****************************************************************************************************
ok: [172.17.0.2] => {
    "msg": "Hello world!"
}

TASK [Next debug] ******************************************************************************************************
ok: [172.17.0.2] => {
    "msg": "Hello, Ansible!"
}

PLAY RECAP *************************************************************************************************************
172.17.0.2                 : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Structure de répertoires Ansible

Voir: Roles - Ansible Documentation En utilisant la structure de répertoires suivante, il sera plus facile de spécifier des fichiers et des tâches.

./
├─ ansible.cfg  ……………………………… (1)Fichier de configuration. Variable d'environnement ANSIBLE_Dans CONFIG
│ Nom fixe sauf indication contraire.
├─ playbook.yml ……………………………… (2)Playbook Tout nom de fichier. Le format YAML est courant.
│
├─ inventory/ …………………………………… (3)Répertoire d'inventaire. Doit être spécifié,
│ │ N'importe quel nom. Spécifiez en option.
│    ├─ hosts …………………………………… (4)N'importe quel nom. Format INI sans extension,
│    ├─ hosts2.extension yml.Format YAML pour yml.
│    ├─ : 
│    └─ hostsN
├─ group_vars/ ………………………………… (5)Variables qui s'appliquent au "groupe d'hôtes cible" de la tâche spécifiée
│ │ Le répertoire à stocker. Nom fixe.
│    ├─ groupname1 ……………………… (6)Définissez le nom du "groupe d'hôtes cible" sur le nom du fichier. Format INI sans extension,
│    ├─ groupname2.S'il est au format yml YAML, l'extension.Faites-le yml.
│    ├─ : 
│    └─ groupnameN
├─ host_vars/ …………………………………… (7)Variables qui s'appliquent à "l'hôte cible" de la tâche spécifiée
│ │ Le répertoire à stocker. Nom fixe.
│    ├─ hostname1 ………………………… (8)Définissez le nom «hôte cible» sur le nom de fichier. Format INI sans extension,
│    ├─ hostname2.S'il est au format yml YAML, l'extension.Faites-le yml.
│    ├─ : 
│    └─ hostnameN
├─ files/ ……………………………………………… (9)Stockage de fichiers utilisé pour la copie et le transfert. Nom fixe.
│    ├─ file1 ……………………………………(10)Tout nom de fichier.
│    ├─ file1
│    ├─ :
│    └─ fileN
└─ roles/ ………………………………………………(11)Répertoire des paramètres pour l'utilisation des rôles dans les playbooks. Nom fixe.
    ├─ role1/ ……………………………………(12)Définissez le nom du "rôle cible" sur le nom du répertoire.
    ├─ role2/
    ├─ :
    └─ roleN/
         ├─ defaults …………………(13)Le répertoire qui stocke les paramètres de variable par défaut. Nom fixe.
         │   └── main.yml ……(14)Le fichier de paramétrage de variable chargé en premier. Nom fixe.
         │                       import_Comme les vars, il est chargé lorsque le playbook est analysé.
         ├─ vars ……………………………(15)Un répertoire qui stocke les paramètres de variable. Nom fixe.
│ │ Répertoire de base lors de la spécification d'un fichier avec un chemin relatif.
         │    ├─ varfile1 ……(16)Tout nom de fichier. Format INI sans extension,
         │    ├─ varfile2.S'il est au format yml YAML, l'extension.Faites-le yml.
         │    ├─ :
         │    └─ varfileN
         └─ tasks …………………………(17)Répertoire de stockage des tâches. Nom fixe.
             └── main.yml ……(18)Le premier fichier de configuration de tâche à exécuter. Nom fixe.
Si vous souhaitez modifier le traitement en fonction du système d'exploitation de l'hôte cible,
                                 main.importer depuis yml/Lire avec include.

Il existe d'autres rôles dans les répertoires tels que handlers /, templates / et meta /, mais pour le moment, si vous comprenez la structure de répertoires ci-dessus, il sera plus facile de comprendre les autres répertoires également. ..

Voir «Roles - Ansible Documentation» pour plus d'informations. Il existe également un exemple dans "Bonnes pratiques: mise en page de répertoire - Documentation Ansible".

Différence entre l'importation et l'inclusion

Voir: Inclure et importer - Documentation Ansible L'import * et l'inclusion * sont les mêmes pour la lecture des fichiers, mais ils sont lus à des moments différents.

  • All import* statements are pre-processed at the time playbooks are parsed.
  • All include* statements are processed as they are encountered during the execution of the playbook.

Il est particulièrement important de savoir quand traiter les variables (par exemple, le modèle {{samplevarname}}) en utilisant le modèle JINJA2 et quand les affecter aux variables.

Si vous utilisez import *, il est développé avant que la tâche ne soit exécutée, de sorte que le modèle intégré est remplacé par la valeur réelle et la tâche est exécutée une fois l'affectation à la variable terminée.

D'autre part, si vous utilisez include *, il sera développé lors de l'exécution de la tâche, donc quand il sera chargé et exécuté, le modèle sera remplacé par la valeur réelle et l'affectation sera effectuée.

Bonus: faites de Raspberry Pi3 (Ubuntu Stretch 9) l'hôte de contrôle

Ansible est utilisé dans l'environnement Python, mais si vous installez Ansibule basé sur le système d'exploitation (apt / apt-get install) sur Ubuntu (stretch 9) de Raspberry Pi3, la version 2.2 d'Ansible sera installée (écrite le 13 janvier 2020). À la date).

Les dernières fonctionnalités ne sont pas disponibles dans la v2.2, ce qui est un peu gênant, vous pouvez donc utiliser la dernière version d'Ansible (dernière v2.9 au moment de la rédaction) en installant (pip install) dans un environnement virtuel de Python. (La version de Python3 pour Raspberry Pi3 / Ubuntu est 3.5)

$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
NAME="Raspbian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
VERSION_CODENAME=stretch
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
$ python3 --version
Python 3.5.3

L'installation dans l'environnement virtuel Python est la suivante.

$ python3 -m venv ansible
$ source ansible/bin/activate
$ pip install -U pip
$ pip install ansible

Le * ansible * après python3 -m venv et le * ansible * spécifié dans la commande source sont les mêmes, et vous pouvez décider vous-même. Le ʻansiblespécifié danspip install` est le paquet à installer, alors exécutez-le tel quel sans le changer.

Utilisation de: point_up: alias

Si vous utilisez bash, il est pratique de définir les paramètres suivants dans ~ / .bashrc.

bash:~/.bashrc Ou ~/.bash_aliases Tel


alias ansibleenv='type deactivate > /dev/null 2>&1 && deactivate; cd ~/work/Ansible.d/; source ~/work/Python.d/envs/ansible/bin/activate'

Dans la partie de type disable> / dev / null 2> & 1 && deactivate, s'il a été activé dans un autre environnement, désactivez-le. Accédez à votre répertoire de travail avec cd ~ / work / Ansible.d. L'environnement d'ansible est activé par source ~ / work / Python.d / envs / ansible / bin / activate. Une fois défini, vous pouvez l'appeler avec ʻansibleenv`.

: point_up: Correction d'erreur Weakref.py

Sur Raspberry Pi, même si ansible lui-même est exécuté avec succès, l'erreur suivante peut se produire.

:
PLAY RECAP *************************************************************************************************************
172.17.0.2                 : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Exception ignored in: <function WeakValueDictionary.__init__.<locals>.remove at 0x75c7fdf8>
Traceback (most recent call last):
  File "/usr/lib/python3.5/weakref.py", line 117, in remove
TypeError: 'NoneType' object is not callable
Exception ignored in: <function WeakValueDictionary.__init__.<locals>.remove at 0x75c7fdf8>
Traceback (most recent call last):
  File "/usr/lib/python3.5/weakref.py", line 117, in remove
TypeError: 'NoneType' object is not callable
    :
    :
Exception ignored in: <function WeakValueDictionary.__init__.<locals>.remove at 0x75c7fdf8>
Traceback (most recent call last):
  File "/usr/lib/python3.5/weakref.py", line 117, in remove
TypeError: 'NoneType' object is not callable

Il s'agit d'une erreur causée par la variable non définie de / usr / lib / python3.5 / lowref.py``` (type "None"). La solution sous-jacente doit être considérée par l'appelant, mais peut être provisoirement évitée en appliquant le correctif suivant: (Bien que ce soit assez rugueux)

diff:weakref.py.patch


*** weakref.py.bak      2018-09-28 02:25:39.000000000 +0900
--- weakref.py  2020-01-03 18:44:49.190027705 +0900
***************
*** 114,120 ****
                  else:
                      # Atomic removal is necessary since this function
                      # can be called asynchronously by the GC
!                     _remove_dead_weakref(d, wr.key)
          self._remove = remove
          # A list of keys to be removed
          self._pending_removals = []
--- 114,121 ----
                  else:
                      # Atomic removal is necessary since this function
                      # can be called asynchronously by the GC
!                     if type(_remove_dead_weakref) is not type(None) and type(d) is not type(None) and type(wr) is not type(None):
!                         _remove_dead_weakref(d, wr.key)
          self._remove = remove
          # A list of keys to be removed
          self._pending_removals = []

Patcher:

$ sudo patch -c -b /usr/lib/python3.5/weakref.py weakref.py.patch

-c est une option de correction de type de contexte et -b est une option de création de sauvegarde.

Recommended Posts

Présentation d'Ansible
Présentation de Linux
Installation d'Ansible
Note d'Ansible
Présentation de Cloud Datalab
Présentation du service cloud natif