Archives de catégorie : Ansible

Ansible – Comment créer un user et une base mysql ?

Cela fait quelques temps que je n’ai pas posté d’article ansible. La chaîne youtube prend pas mal de temps mais j’aime beaucoup le blog. Le mode écrit est tout de même bien sympa.

Mon orchestrateur préféré est une vraie mine d’or pour ce qui est de gérer les petites actions du quotidien et c’est aussi le cas en matière de base de données. De nombreuses actions sont natives sur ansible (moyennant d’avoir installé le module python qui va bien pour pouvoir le faire).

Si vous souhaitez la version vidéo de cette article, la voici :

Sinon pour la version écrite. Commençons par définir quelques variables dans notre rôle mysql.

Commençons par définir quelques variables dans notre répertoire defaults de notre rôle mysql.

mysql_packages:
  - mysql-server
  - python-mysqldb
mysql_db: "wordpress"
mysql_user: "user1"
mysql_password: "password"

On y retrouve la liste des paquets à installer à savoir mysql-server et python-mysqldb. C’est ce dernier qui permet à ansible d’interagir avec le moteur mysql.

Ensuite éditons notre fichier main.yml dans le répertoire tasks.

- name: "[MYSQL] - update cache"
  apt:
    update_cache: yes

- name: "[MYSQL] - install"
  apt:
    name: "{{ mysql_packages }}"
    state: latest

- name: "[MYSQL] - start mysql"
  service:
    name: "mysqld"
    state: started
    enabled: yes

Jusque là rien de neuf si ce n’est que la dernière version de ansible nous demande de ne plus utiliser le with_items. En effet, nous pouvons désormais passer directement un tableau. On installe les paquets et active le démarrage de mysql au lancement de notre machine.

Ensuite rentrons dans l’administration mysql.

- name: "[MYSQL] - create database"
  mysql_db:
    name: "{{ mysql_db}}"
  become: yes

Là on vient de créer la base de données dont le nom a été défini dans nos variables par défauts (et donc que l’on peut écraser facilement par les variables d’inventory).

- name: "[MYSQL] - create user"
  mysql_user:
    name: "{{ mysql_user }}"
    password: "{{ mysql_password }}"
    priv: "*.*:ALL"
    host: "127.0.0.1"
  become: yes

Là on vient de créer un user et de lui donner tous les droits sur les bases de notre moteur (nous aurions pu limiter tout ceci bien sûr).

Voici donc pour la découverte du module mysql de ansible. Mais sachez qu’il existe la même chose pour :

  • influxdb
  • mongodb
  • postgres
  • proxysql

En savoir plus sur la documentation officielle de ansible à ce sujet.

Ansible – installer un serveur LAMP automatiquement

Hello la team ! j’espère que vous allez bien. A priori, c’est kool vous êtes nombreux à revenir sur le blog vu les statistiques.

La chaîne youtube marche bien aussi et là encore c’est grâce à vous.

Aujourd’hui, je vous propose de revenir sur ansible avec une vidéo qui vous fait découvrir assez simplement comment installer un serveur LAMP de manière orchestrée. Cela est assez simple et tient sur quelques lignes.

Voici la vidéo :

N’oubliez pas que vous pouvez vous abonner à la chaine ou aussi mettre des petits pouces bleus pour m’encourager.

Qu’est-ce que l’on fait dans cette vidéo ?

1- Création du squelette d’un rôle ansible

A la racine, c’est à dire là on l’on trouve notre playbook et notre fichier d’inventory, on créé un répertoire rôles. Comme son nom l’indique c’est ici que nous stockerons les rôles développés ou récupérés de Galaxy. Pour créer la structure d’un rôle lançons :

ansible-galaxy init wordpress

Il ne nous reste plus qu’à éditer nos fichiers et en particulier le fichier mai.yml situé dans le répertoire tasks. C’est la clef d’entrée dans notre rôle.

2- Edition de main.yml dans tasks

La première chose à faire c’est de commencer par mettre à jour le cache de apt. C’est la moindre des choses avant d’installer des paquets.

- name: "[WORDPRESS] - update cache"
  apt:
    update_cache: yes
  become: yes

Le become à yes permet de réaliser une élévation de privilèges comme pour faire un sudo. Et nous utilisons le module apt.

- name: "[WORDPRESS] - install LAMP"
  apt:
   name: "{{ item }}"
   state: latest
  become: yes
  with_items: 
    - apache2
    - mysql-server
    - php7.0-common
    - php7.0-mysql
    - libapache2-mod-php7.0
    - python-mysqldb
    - wget

Vous pouvez le voir nous allons plus loin qu’un simple LAMP. Cela nous permettra d’aller plus loin par la suite dans notre installation de notre wordpress.

Puis lançons le démarrage de nos services :

- name: "[WORDPRESS] - start apache2 mysql"
  service:
    name: "{{ item }}"
    state: started
    enabled: yes
  become: yes
  with_items:
    - apache2
    - mysqld

Ici nous avons utilisé le module service qui nous permet d’intervenir sur systemd.

Vous pouvez aller plus loin en consultant les articles et vidéos spécifiques à ansible sur cette page.

Ansible – les différents niveaux de variables

Ansible est un orchestrateur simple d’utilisation dès lors que l’on en retient les concepts de base. Parmi ces concepts, la hiérarchie des variables fait partie des essentiels.

Je vous propose d’y revenir en vidéo.

[youtube https://www.youtube.com/watch?v=_8Az2egUKwY&w=700&h=500]

D’ailleurs n’hésitez pas à vous abonner à la chaine xavki.

Au total, Ansible possède plus de 20 manières pour définir des variables. On peut les classer par ordre hiérarchique en fonction de s’imposer les unes aux autres. Je ne reviendrais pas sur l’ensemble des 20 variables mais sur les plus courantes. Néanmoins voici la liste de ces variables ordonnée hierarchiquement :

ansible-v2-and-beyond-ansible-nyc-meetup-19-638

Les principales qui me semblent importantes à retenir sont :

  • 1. extra vars : passable à partir de la command line
  • 2. task vars : variable de tâche (dans le playbook)
  • 3. block vars : la variable de block
  • 4. role vars : dans le répertoire /vars d’un rôle
  • 5. set_facts : définie dans les set_facts
  • 6. playbook vars : dans le fichier playbook
  • 7. host_vars : précisée dans les fichiers individuels des machines de l’inventaire
  • 8. inventory vars : dans l’inventaire (par exemple hosts.yml)
  • 9. group_vars : dans les fichiers de groupes de l’inventaire
  • 10. role defaults vars : la variable par défaut

Un rôle bien rédigé doit être très largement paramétrable : OS, paquets, version, user, passwords… Ainsi un bon rôle possède souvent un fichiers de variables par défaut (répertoire defaults du rôle) très fourni. Cela vous permet de personnaliser très largement l’application de ce rôle.

En outre, un bon rôle doit aussi avoir l’intégratilité de ses variables définies dans son README, en tout cas au moins toutes les variables par défaut. Elles doivent alors être documentées sur la manière de les définir (liste, string, booléens…).

Par ailleurs, vous pouvez utiliser le module debug pour afficher le contenu des variables à n’importe quel moment de votre playbook.

- name: "affichage contenu de var1"
  debug:
    msg: "Voici le contenur de var1 => {{ var1 }}"

Il faut aussi savoir que ansible n’aime pas traiter les variables vides.

Enfin ansible possède des variables particulières propres à son fonctionnement, on parle de facts (version OS, etc…). Celles-ci sont utilisables à tout moment. Pour les connaître utilisez le module setup :

 ansible all -m setup

Vous pouvez également créer vos propres facts.

Ansible – prise en main de checksum, set_facts, register et block

Ansible c’est un peu le fil rouge du moment. Certains l’ont bien vu avec le lancement de la chaine youtube xavki. L’idée c’est de vous montrer comment j’ai appris à utiliser et développer avec ansible.

La vidéo ci-dessous présente ce que nous allons découvrir dans l’article.

[youtube https://www.youtube.com/watch?v=YqKAXnmAetY&w=700&h=300]

L’objectif du jour, c’est de charger un fichier avec l’aide d’ansible, de le modifier et surtout faire en sorte qu’une fois ces opérations réalisées nous gérions la réentrance (ou idempotence). C’est à dire que si nous relançons aussitôt le playbook ansible aucun opération ne soit réalisée.

Or sans vérification du contenu du fichier, le fichier est systématiquement rechargé. Pourquoi ?

Tout simplement car ansible va contrôler l’état du fichier présent sur la cible avec celui présent sur la source. Et malheureusement ansible ne sait pas prendre en compte les diverses opérations qu’il aura réalisé sur le fichier après son chargement. Donc il est systématiquement différent du fichier source.

Comment vérifier l’état du fichier ? de cette manière peut être (si vous avez mieux je suis preneur.

---
- name: "[XAVKI]"
  hosts: all
  vars:
    - check5: "2789ebeb61ab3b1985e9f6df9256d8a1" 
  tasks:

      - name: "[XAVKI] - check md5"
        stat:
          path: /tmp/xavki.txt
          get_checksum: yes
          checksum_algorithm: md5
        register: sum5

      - set_fact:
          data: "0"
        when: sum5.stat.checksum is not defined

      - set_fact:
          data: "{{ sum5.stat.checksum }}"
        when: sum5.stat.checksum is defined

      - name: "[XAVKI] - Bloc"
        block:
        - name: "[XAVKI] - copie du fichier" 
          copy:
            src: ./monfichier.txt
            dest: /tmp/xavki.txt

        - name: "[XAVKI] - add line"
          lineinfile:
            path: /tmp/xavki.txt
            line: "ajout d'une ligne" 

        when: data != check5

Voici le cheminement :

  • tout d’abord on calcul et on place dans une variable le md5 du fichier dans l’état final souhaité (check5 en l’occurence), c’est notre référence
  • à l’aide du module stat on place avec register la valeur du fichier déjà présent dans une variable (sum5)
  • nous devons traiter alors 2 cas de figures : la variable est définie car le fichier existe ou il n’existe pas et la variable n’est pas définie
  • si la variable existe on attribue à la variable data la valeur du sum5 sinon on lui donne la valeur « 0 »
  • enfin on encapsule dans un bloc avec le module block les actions de chargement de fichier et de modification si data ne vaut pas la valeur finale souhaitée (avec when)

[Ansible] : comment installer et configurer logrotate ? et trouver un rôle adapté

Aujourd’hui, après l’installation ntp (client et serveur), je vous propose l’installation et la configuration de logrotate. Il s’agit donc d’une action de niveau plutôt débutant à réaliser avec ansible. En effet, logrotate est un service facile à mettre en place (souvent déjà installé et bien pris en compte par d’autres services) et surtout car ansible-galaxy regorge de rôles dans ce domaine.

La plus grosse difficulté réside dans le choix du rôle en essayant de trouver celui qui corrrespond le plus à notre besoin. Dans notre cas, on cherche un rôle qui installe logrotate si celui-ci n’est pas déjà installé et qu’il permettent de réaliser la conf par défaut de logrotate et au cas par cas pour différents services que l’on souhaite ajouter.

ansible_logrotate

Avant de commencer, je vous rappelle que j’utilise un réseau de conteneurs docker pour mettre en place mes tests de rôles ansible. Pour en savoir plus c’est ici et c’est super simple.

1. Logrotate

C’est un service basique dans les différents OS linux de base. Logrotate est souvent déjà installé comme c’est le cas sur Debian et sur Redhat.

Sa configuration par défaut se situe dans /etc/logrotate.conf et se résume souvent à :

weekly
su root syslog
rotate 4
create
dateext

# packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own wtmp, or btmp -- we'll rotate them here
/var/log/wtmp {
    missingok
    monthly
    create 0664 root utmp
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0660 root utmp
    rotate 1
}

Que dire ?

  • weekly : la fréquence de rotation (daily, mais aussi d’autres formats peuvent être utilisés)
  • su root syslog : avec quel user et quel groupe est réalisé l’archivage (important pour les permissions par la suite)
  • rotate 4 : nombre de fichiers de logs conservés
  • create : création d’un nouveau fichier de log après la rotation

De très nombreuses options sont possibles. Elles sont consultables sur la page man de logrotate : mail, action réalisée après rotation, compression…

Par ailleurs, il faut savoir que les services les plus répandus sur Linux ajoutent leur propre configuration dans /etc/logrotate.d/ (apache2, nginx, varnish, postgres…). Le travail est donc généralement simplifié,  ce qui permet de ne pas trop s’inquiéter si vous cherchez un rôle ansible.

2. Le rôle ansible logrotate

Nsou avons vu à peu près ce que nous souhaitions  trouver comme rôle. Après en avoir feuilleté une petite dizaine, j’ai retenu celui-ci : arillso.logrotate

Il réalise ce que j’ai listé ci-dessus (configuration par défaut et ajout possible). Pour toucher à la configuration par défaut il suffit simplement de compléter la variable logrotate_options avec un tableau du type : [ ‘weekly’, ‘su root syslog’, ‘rotate 4’, ‘create’ ].

Sa struture est la suivante :

└─ $ ▶ tree
.
├── defaults
│   └── main.yml
├── handlers
│   └── main.yml
├── LICENSE
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
│   ├── application.j2
│   └── logrotate.conf.j2
└── vars
    ├── CentOS.yml
    ├── Debian.yml
    └── defaults.yml

Il s’appuie aussi sur deux fichiers jinja2 un pour la configuration par défaut et un autre pour gérer des configurations par application.

Ainsi pour spécifier une conf particulière pour une machine notre inventory ressemblerait à ceci :

all:
  hosts:
    172.17.0.2:
      logrotate_options: [ 'daily', '', 'rotate 4', 'create' ]
    172.17.0.3:
    172.17.0.4:
    172.17.0.5:

Ainsi on a part défaut : [‘weekly’, ‘su root syslog’, ‘rotate 4’, ‘create’]
et sinon autre chose comme pour la 172.17.0.2.

Mes tests se déroulent sur 4 machines comme pour le test du rôle ntp : 2 debian et 2 redhat (centos).

Mon inventory est celui indiqué ci-dessus et mon playbook contient simplement :

---
- name: Lancement roles
  hosts: all
  remote_user: oki
  become: yes

  roles:
  - arillso.logrotate

Lançons tout ceci :

└─ $ ▶ ansible-playbook -i hosts.yml --user=oki playbook-logrotate.yml 

PLAY [Lancement roles] **************************************************************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************************************************************
ok: [172.17.0.2]
ok: [172.17.0.3]
ok: [172.17.0.4]
ok: [172.17.0.5]

TASK [arillso.logrotate : add OS specific variables] ********************************************************************************************************************************************
ok: [172.17.0.2] => (item=/home/oki/autoform_ansible/roles/arillso.logrotate/vars/Debian.yml)
ok: [172.17.0.3] => (item=/home/oki/autoform_ansible/roles/arillso.logrotate/vars/Debian.yml)
ok: [172.17.0.4] => (item=/home/oki/autoform_ansible/roles/arillso.logrotate/vars/CentOS.yml)
ok: [172.17.0.5] => (item=/home/oki/autoform_ansible/roles/arillso.logrotate/vars/CentOS.yml)

TASK [arillso.logrotate : install logrotate] ****************************************************************************************************************************************************
ok: [172.17.0.5]
ok: [172.17.0.4]
ok: [172.17.0.3]
ok: [172.17.0.2]

TASK [arillso.logrotate : Create logrotate configuration file] **********************************************************************************************************************************
ok: [172.17.0.2]
ok: [172.17.0.4]
ok: [172.17.0.5]
ok: [172.17.0.3]

TASK [arillso.logrotate : Create logrotate application configuration files] *********************************************************************************************************************

PLAY RECAP **************************************************************************************************************************************************************************************
172.17.0.2                 : ok=0    changed=4   unreachable=0    failed=0   
172.17.0.3                 : ok=0    changed=4    unreachable=0    failed=0   
172.17.0.4                 : ok=0    changed=4    unreachable=0    failed=0   
172.17.0.5                 : ok=0    changed=4    unreachable=0    failed=0   

Une fos de plus Ansible nous propose un jolie récapitulatif. On voit que le playbook est passé sur toutes les machines. On voit également qu’il a bien utilisé la conf debian et la conf redhat quand cela était nécessaire.

Bref que du bonheur.

Et sur la machine ayant une conf spécifique ?

root@69a5076d127d:~# cat /etc/logrotate.conf 
# Ansible managed

# see "man logrotate" for details
weekly

rotate 4
create

Bingo pas de souci. Et vous quel est votre expérience avec ce genre de rôle sur ansible.

[Ansible] : lister les variables de rôles non documentées dans le README.md

Les rôles de ansible sont plus ou moins faciles à utiliser. Un des principaux facteurs limitants, c’est la documentation du README. Du coup j’ai créé un petit script pour lister les variables de vos rôles et ensuite vérifier si ces variables sont bien documentées dans le README.md (si vous avez d’autres idées n’hésitez pas).

#!/usr/bin/python3


# coding: utf8



import re
import os

def list_variables (pattern, dir):
    
  variables=[]
    
  r = re.compile(pattern)
    
  for parent, dnames, fnames in os.walk(dir):
 
       for fname in fnames:

            filename = os.path.join(parent, fname)

            if os.path.isfile(filename):

                with open(filename,encoding="latin-1") as f:

                    for line in f:

                        if r.search(line):

                          reg=r"pattern"

                          for item in re.findall(r''+pattern+'',line):

                            if item not in variables:

                              variables.append(item)

  return variables



# lister les roles

def list_roles (dir):

        roles=[]

        regexp = re.compile(r'.*\/roles\/[a-z0-1_-]+$')

        for dirname, dirnames, filenames in os.walk('.'):

                for subdirname in dirnames:

                        rep=os.path.join(dirname, subdirname)

                        if regexp.search(rep):

                                roles.append(rep)

        return roles



# avec la fonction grep on liste toutes les variables contenant un _


for role in list_roles("."):

    r = re.compile('[.]?roles/(.*)')

    match = r.search(role)

    print("")

    print("#################################################################")

    print("         Analyse du role : "+ match.group(1))

    print("#################################################################")
    compteur=0

    list_var=list_variables("\{\{\s?([a-z]+[_]+[a-z_]+)\s?\}\}",role)

    for variable in list_var:

        compteur+=1

        with open(roles+"/README.md",encoding="latin-1") as f:

            concaten=""

            for line in f:

                concaten+=line

            if not re.search(variable,concaten):

                print("Variable à éditer :"+variable)

    print(" = "+str(compteur)+" variable(s) analysé(es)")

Explications :

  •  une fonction qui liste les variables ansible :
    • on parcourt les directories (à l’aide du module OS de python)
    • et avec une regex on applique un pattern pour retrouver ce qui ressemble à une variable ({{ variable }}
    • enfin on met tout cela dans un tableau bien propre
  • une fonction qui liste les rôles :
    • idem on parcourt les directories et on cherche les répertoires contenus dans « roles »
    • à l’aide d’une regex on nettoie le nom du rôle
  • Pour finir on orchestre tout cela :
    • on boucle sur la liste des variables
    • on ouvre le README.md que l’on place dans une variable simple(on concatène les lignes)
    • et on y cherche la variable
    • si elle n’est pas dedans on affiche qu’elle est à éditer
    • et pour finir on affiche à la fin de chaque rôle le nombre de variables analysées.

Si vous voyez d’autres scripts de ce genre qui pourrait être utiles indiquez le en commentaire j’y jeterez un coup d’oeil.

[Ansible] : comment installer un client et un serveur ntp ?

Cet article fait suite à mon fil rouge sur ansible. L’idée c’est de vous relater quelques moments de mon autoformation dans ce domaine. Pour moi c’est aussi le moment de me pencher différement sur ce que je fais et de constituer mon bloc-note.

Avant de commencer, je ne vais pas revenir dessus dans le détail mais j’utilise un script sympa (enfin je trouve). Il permet de me créer un ensemble de conteneurs façon VM (debian et redhat depuis la dernière évolution). Ainsi j’ai une plateforme de développement et je peux simuler des lancements de playbook sur un parc de machines. Pour en savoir plus rendez-vous sur cet article qui présente le script et les grandes lignes.

Donc j’ai lancé deux fois le script et je possède pour l’exemple 4 machines (2 debian stretch et 2 centos7).

Et voilà. Maintenant comment je peux faire pour avoir 1 serveur ntp et 3 serveurs clients ? L’idée c’est de faire en sorte qu’un seul serveur soit exposé et soit utilisé pour contacter les ntp externes.

ansible-ntp

Ainsi on veut avoir le schéma :

ntp_externes >> ntp_serveur >> ntp_clients

1. Les principes des clients et du serveur (sans ansible)

Là encore on va aller à l’essentiel de la configuration. Vous trouverez facilement des articles clairs et courts comme celui-ci qui vous donnera ce qu’il faut pour installer un ntp.

D’un côté, sur le serveur ntp est installé ntp. Il doit au niveau de sa conf taper vers les serveurs externes et surtout accepter les requêtes des autres serveurs. Pour cela il faut supprimer simplement dans /etc/ntp.conf la ligne :

restrict default nomodify notrap nopeer noquery

Et ajouter la localisation ntp :

ntp_area: 'fr'

De l’autre côté pour les serveurs clients, il faut juste modifier les serveurs vers lesquels on fait la synchro dans /etc/ntp.conf. Les serveurs par défaut deviennent par exemple :

server 172.17.0.2 ibusrt

Pour vérifier le bon fonctionnement, il suffira de faire un ntpq -p et voir où les machines vont se synchroniser.

2. NTP avec ansible c’est facile

Bien sûr que c’est facile car ntp est un utilitaire de base des serveurs web ou autres. Ansible Galaxy vous propose donc de très bon rôles. Et j’aurais tendance à dire comme d’habitude c’est geerlingguy qui va vous le proposer avec geerlingguy.ntp.

Alors pour le mettre en place dans votre répertoire de rôles il suffit de faire :

ansible-galaxy install -p roles geerlingguy.ntp

et dedans on a ceci mais on ne va toucher à rien :

.
├── defaults
│   └── main.yml
├── handlers
│   └── main.yml
├── LICENSE
├── meta
│   └── main.yml
├── README.md
├── tasks
│   ├── clock-rhel-6.yml
│   └── main.yml
├── templates
│   ├── clock.j2
│   └── ntp.conf.j2
├── tests
│   ├── README.md
│   └── test.yml
└── vars
├── Archlinux.yml
├── Debian.yml
├── FreeBSD.yml
├── RedHat.yml
└── Suse.yml

Nous avons donc un rôle ntp qui ne demande qu’à tourner. Pour cela mettons à jour notre liste de hosts.yml de notre inventory :

all:
  children:
    ntp-client:
      hosts:
        172.17.0.3:
        172.17.0.4:
        172.17.0.5:
    ntp-server:
      hosts:
        172.17.0.2:

Vous voyez que j’ai entré les ip de mes conteneurs docker. Elles sont classées en 2 groupes ntp-server et ntp-client.

Maintenant je vais créer 2 group_vars (deux répertoires avec un fichier yaml chacun) :

.
├── group_vars
│   ├── ntp-client
│   │   └── ntp-client.yml
│   └── ntp-server
│       └── ntp-server.yml

Puis je complète les fichiers de la manière suivante (en prenant en compte ce que nous avons abordé dans le paragraphe 1.).

ntp-client.yml

ntp_manage_config: True
ntp_servers:
- "172.17.0.2 ibusrt"

ntp-server.yml

ntp_manage_config: True
ntp_restrict:
- "127.0.0.1" 
- "::1" 
- "-4 default kod notrap nomodify nopeer noquery" 
- "-6 default kod notrap nomodify nopeer noquery"

Et là c’est terrible car je vous dis « nous avons fait le plus dur » ! Car maintenant on lance le playbook :

ansible-playbook -i hosts.yml --user=oki playbook-ntp.yml

Et la bingo

PLAY RECAP ************************************************************************************
172.17.0.2 : ok=7 changed=0 unreachable=0 failed=0 
172.17.0.3 : ok=8 changed=0 unreachable=0 failed=0 
172.17.0.4 : ok=8 changed=0 unreachable=0 failed=0 
172.17.0.5 : ok=8 changed=0 unreachable=0 failed=0

Comme vous le voyez moi je n’ai pas de changement car j’ai fait tourner le playbook deux fois.

Maintenant rendez vous sur le serveur ntp :

[root@7dcab8fb52ed ~]# ntpq -p
remote refid st t when poll reach delay offset jitter
================================================================
dev.rudloff.pro 209.176.15.122 3 u 53 64 1 35.024 -29.279 8.299
clients0.arcani 131.188.3.223 2 u 53 64 1 41.120 -23.491 9.220
myminers.net 10.21.137.1 2 u 53 64 1 28.079 -27.255 13.304
*master.servme.f 213.251.128.249 2 u 53 64 1 22.207 -30.641 11.5

et sur le client :

[root@6c6c89bc23ac ~]# ntpq -p
remote refid st t when poll reach delay offset jitter
================================================
172.17.0.2 178.33.111.48 3 u 1 64 1 0.079 0.018 0.000

Nos avons donc bien installé un serveur ntp qui se met à jour sur des serveurs externes et des clients ntp qui se mettent à jour sur notre serveur maitre.

Si cet article vous a plus partagez-le et n’hésitez pas à vous abonner pour ne pas manquer les prochains articles.

[Ansible] : commençons simplement : copie de fichiers, modification/écriture avec copy et lineinfile

Précédemment, je vous avais fait part de ma volonté de me lancer dans ansible et de vous partager cette expérience d’apprentissage.

Un précédent article vous présentait un script qui me permet de mettre en place un « centre serveur de poche » à partir de conteneurs (attention ce ne sont que des conteneurs pas de VM donc pas des serveurs… pas la peine de lancer des discussions à ce sujet). Bref, l’idée de cet article était de vous expliquer mon script pour mettre en place une infrastructure légère permettant de me faire la main sur ansible.

Et le bilan c’est que ça marche très bien et que c’est bien plus léger que tout ce qui est à partir de VM. C’est extrèmement pratique pour bosser sur son portable car on peut faire et réinitialiser les serveurs très vites.

Maintenant, il faut se former.

Le fichier inventory, la liste des serveurs

L’inventory est le fichier contenant la liste de référence de vos machines. Dans mon cas j’ai lancé deux conteneurs (machine) 172.17.0.2 et172.17.0.3. En avoir plusieurs c’est vraiment bien pour créer des variations au niveau des hosts et ainsi approfondir le fonctionnement de ansible.

Mon fichier se nomme hosts (comme souvent sur ansible) :

└─ $ ▶ cat hosts
[web]
172.17.0.2
172.17.0.3

J’ai choisi le format init et non le yaml car je suis tombé avec un bug en lien avec python 3.5 (ansible ne lisait pas le yaml de l’inventory).

Pour tester votre inventory, vous pouvez lancer :

ansible -i hosts all --list-hosts

Ensuite, vous pouvez tester une commande linux sur votre parc, par exemple « uptime » :

00:07:33 - oki @ doki ~/autoform_ansible 
└─ $ ▶ ansible -i hosts all -u oki -m shell -a "uptime"
172.17.0.3 | SUCCESS | rc=0 >>
22:07:35 up 1:26, 1 user, load average: 1.00, 0.75, 0.66

172.17.0.2 | SUCCESS | rc=0 >>
22:07:35 up 1:26, 1 user, load average: 1.00, 0.75, 0.66

L’arborescence

Extrèmement importante cette arborescence dans un outil d’orchestration comme ansible. En effet, cela peut vite tourner au boxon tellement vous aller générer de fichiers.

De base si on ne rentre pas dans les roles :

.
├── group_vars
│   └── web
├── hosts
├── host_vars
│   ├── 172.17.0.2
│   └── 172.17.0.3
├── playbook-manip.yml

  • group_vars : contient les variables des groupes (regroupement de serveur) par exemple « web » dans mon cas
  • hosts : c’ets l’inventory de nos machines classées par groupe
  • host_vars : contient les variables des machines (pour spécifier à la machine une variable)
  • playbook.yml : les actions à réaliser

Les deux éléments centraux sont donc : la liste des machines et les actions à réaliser dessus.

Le playbook

On l’a dit le playbook contient les actions à réaliser (et par qui et sur qui). L’entête sert principalement à définir par qui et sur qui de cette manière :

---
- name: Lancement des actions
  hosts: web
  remote_user: oki
  become: yes
  tasks:
  • hosts : pour dire sur quelles machines ou quel groupe on travaille (en l’occurence web dans mon exemple)
  • remote_user : qui va exécuter les actions
  • become : permet d’élever les privilèges si nécessaire pour faire les actions
  • tasks : indique la liste des actions à venir

Le « – name: » est extrèment important. Il permet sera défini de nombreuse fois tout au long de notre code et permet au lancement du playbook de savoir où nous en sommes. C’est donc indispensable pour débugger.

La première action que nous allons réaliser c’est de copier un fichier présent au même niveau que notre playbook (c’est moche je sais mais c’est simple avant tout).

 - name: Transfert de monfichier.txt
   copy:
     src: ./monfichier.txt
     dest: /tmp/monfichier.txt

Nous définissons donc le nom de l’action que nous allons lancer par « – name: ». Puis utilisons le module copy de ansible. Pour copier/coller un fichier il prend deux éléments :

  • src: le fichier source
  • dest: le fichier de destination

Dans une deuxième action nous allons modifier le contenu de mon fichier qui ne contient que « bonjour Xavier » pour le faire contenir « Remplacement salut Xavier ». Et pour cela nous allons utiliser le module lineinfile :

 - name: Modification de monfichier.txt
   lineinfile:
     path: /tmp/monfichier.txt
     regexp: "^bonjour(.*)"
     line: 'Remplacement salut'
     backrefs: yes

Dans cette utilisation de lineinfile je transmets les éléments :

  • path : la localisation de mon fichier à modifier
  • regexp : un élément permettant de retrouver la ligne et capturer un motif (dans mon cas je capture « Xavier » par exemple
  • line : la nouvelle ligne contenant mon texte et « \1 » c’est à dire le motif capturé
  • backrefs : pour utiliser la capture à partir du backslash

Mon playbook au final contient ceci (attention l’indentation doit être stricte, c’est un yaml) :

---
- name: Lancement des actions
  hosts: all
  remote_user: oki
  become: yes
  tasks:

    - name: Transfert de monfichier.txt
      copy:
        src: ./monfichier.txt
        dest: /tmp/monfichier.txt

    - name: Modification de monfichier.txt
      lineinfile:
        path: /tmp/monfichier.txt
        regexp: "^bonjour(.*)"
        line: 'Remplacement salut'
        backrefs: yes

Pour lancer votre playbook sur votre inventory passez :

ansible-playbook -i hosts --user=oki -D playbook-fichier.yml

Et en sortie le résultat du log ansible donne :

PLAY [Lancement des actions] ********************************************************************************************************************************************************************

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

TASK [Transfert de monfichier.txt] **************************************************************************************************************************************************************
--- before: /tmp/monfichier.txt
+++ after: /home/oki/autoform_ansible/monfichier.txt
@@ -12,4 +12,4 @@
###############################################################


-Remplacement salut Xavier
+bonjour Xavier

changed: [172.17.0.3]
--- before: /tmp/monfichier.txt
+++ after: /home/oki/autoform_ansible/monfichier.txt
@@ -12,4 +12,4 @@
###############################################################


-Remplacement salut Xavier
+bonjour Xavier

changed: [172.17.0.2]

TASK [Modification de monfichier.txt] ******************************************
--- before: /tmp/monfichier.txt (content)
+++ after: /tmp/monfichier.txt (content)
@@ -12,4 +12,4 @@
###############################################################


-bonjour Xavier
+Remplacement salut Xavier

changed: [172.17.0.3]
--- before: /tmp/monfichier.txt (content)
+++ after: /tmp/monfichier.txt (content)
@@ -12,4 +12,4 @@
###############################################################


-bonjour Xavier
+Remplacement salut Xavier

changed: [172.17.0.2]

PLAY RECAP ***************************************************
172.17.0.2 : ok=3 changed=2 unreachable=0 failed=0 
172.17.0.3 : ok=3 changed=2 unreachable=0 failed=0

[Ansible] : le samedi c’est debug de mon erreur avec include_tasks

Pour une fois je publie un article le samedi. Ne vous inquiétez pas, pas de spam. D’ailleurs si ce n’est déjà fait vous pouvez vous inscrire pour recevoir les articles du blog et ne pas manquer les prochains.

J’aimerai revenir sur ma mésaventure ansible de la semaine.

En fait, je suis toujours en train de monter en compétences sur ansible. Hier je testé un rôle tout simple de ntp (dont la source est le très bon geerlingguy).

Donc j’importe mon rôle :

ansible-galaxy install -p roles geerlingguy.ntp

Et là paff ça marche pas.

The error appears to have been in '/home/oki/autoform_ansible/roles/geerlingguy.ntp/tasks/main.yml': line 16, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

Pourtant l’auteur de la source est ultra fiable et les dernières mises à jour datent de 22 jours. Là j’ai un gros doute.

Donc mon premier réflexe (le mauvais), je recherche sur internet à partir du message d’erreur. Je vois donc que l’on parle de la version 2.4 et je ne suis qu’en 2.3. Bon ben je décide de monter de version.

Me voici en 2.4 et là je tombe sur une autre erreur : mauvaise reconnaissance de l’inventory.

 [WARNING]: * Failed to parse /home/oki/autoform_ansible/hosts with constructed plugin:
Unable to parse /home/oki/autoform_ansible/hosts: Syntax Error while loading YAML.

Pas de bol. Donc je recherche et là je tombe sur quelqu’un qui explique qu’un patch est passé pour régler le pb en 2.4.1. Ce que je fais je monte de version.

Ah au fait pour monter de version facilement :

sudo pip install ansible==2.4.1

et la bingo tout marche comme il faut.

Mais le  bon réflexe c’est déjà de voir la doc ansible de include_tasks. J’aurais vu que cette fonctionnalité est incrémentée à partir de la 2.4. Bon pour l’autre problème c’est autre chose.

[Docker][Ansible] : comment se créer un mini datacenter de test sans VM ? (parc de conteneurs)

Datacenter, le terme est bien prétencieux car il ne s’agit ni de machines physiques, ni de vm mais de simples conteneurs docker. L’idée est très simple et je sais que certains d’entre vous ont besoin de ce genre de script : comment créer facilement, à la volée, une série de conteneurs identiques pour reproduire des actions à la manière d’un centre serveur (orchestration, scheduler…).

Attention, ce qui est fait dans ce script et l’image utilisée (que j’ai adapté pour l’occasion) ne prennent pas en compte la sécurité nécessaire pour faire de la production. L’idée est de créer ce mini pool de conteneurs et de le supprimer une fois les manipulations réalisées. En moins de 5 minutes vous avez autant de machine que vous voulez sous la main et dans le même réseau.

Le besoin ? faire des tests sur un parc de « machines »

Pourquoi moins sécurisé que d’autres ? Par exemple, je permets de faire du ssh sur le user root depuis l’extérieur du conteneur. Je mets en place un mot de passe unique pour root et le user. Tout cela pour faire comme si il s’agissait d’une vm ou une machine physique donc de ne plus passer par un « docker exec » pour accéder à root.

Pourquoi faire ? des tests. Dans mon cas, je vais m’en servir pour me faire la main sur Ansible et runner des playbooks sur tout le parc ou sur une partie.

L’intérêt comme je l’ai déjà dit :

  • pouvoir casser et repartir avec des machines vierges en 2 minutes
  • pouvoir en lancer une bonne dizaine (voir plusieurs) sur mon pc
  • avoir un réseau facilement opérationnel
  • switcher d’OS ou d’image à volonté
  • cela reste léger car il n’y a pas de noyau embarqué

Dans le détail du conteneur

De base, j’utilise une image que j’ai créé et mis à disposition sur mon compte dockerhub (priximmo/debian-sshd). Il s’agit d’une image debian officielle à laquelle j’ai ajouté un openssh-server et dont j’ai permis la connexion en ssh sur le user root. C’est ce point qui aura été le plus difficile car je ne voyais pas pourquoi je ne pouvais pas passer root sur les conteneurs docker. Il suffit d’ouvrir /etc/ssh/sshd_config et de passer la clause PermitRootLogin à « yes ».

Le mot de passe root est aussi configuré mais je vous invite à le modifier à l’aide d’une commande docker (en lançant chgpasswd). Mais comme le but est de ne pas garder les conteneurs en fonction hors des phases de test c’est moins grave.

Le script ? c’est du shell et il est dispo sur le github

Quatre options :

  • –proxy : utilisation perso mais à vous de l’adapter vous pouvez avec prévoir d’ajouter votre proxy dans http-proxy.conf
  • –create : par défaut il créé 2 conteneurs mais vous pouvez en mettre autant que vous souhaitez
  • — drop : pour nettoyer les conteneurs créés
  • –infos : donne les ips,users des conteneurs

Dans le create, vous pouvez voir que l’on créé un user du même nom que votre utilisateur courant et on pousse votre clé publique dans le conteneur. On installe aussi python-minimal et sudo, nécessaires pour faire du ansible dans mon cas. Et à la fin de la création j’utilise docker inspect pour récupérer les ip des conteneurs pour donner un petit récapitulatif.

#!/bin/bash

###############################################################
#  TITRE: parc de conteneurs
#
#  AUTEUR:   Xavier
#  VERSION: 1.1
#  CREATION:  17/09/2018
#  MODIFIE: 
#
#  DESCRIPTION: 
#   mot de passe obtenu par :
#          perl -e 'print crypt("password", "salt"),"\n"'
###############################################################

USERNAME=$(id -nu)

if [ "$1" == "--proxy" ];then
	
	if [ -f /etc/systemd/system/docker.service.d/http-proxy.conf ];then
		sudo rm -f /etc/systemd/system/docker.service.d/http-proxy.conf
		sudo service docker restart
	fi 

fi


if [ "$1" == "--create" ];then
	
	nbserv=$2
	[ "$nbserv" == "" ] && nbserv=2
	
	# rapatriement de l'image si elle n'exsiste pas
	echo "Installation de l'image "
	docker pull priximmo/stretch-systemd-ssh:v3.1

	# création des conteneurs
	echo "Création : ${nbserv} conteneurs..."

	# détermination de l'id mini
  id_first=$(docker ps -a --format "{{ .Names }}" |grep "oki-vmparc" | sed s/".*-vmparc"//g  | sort -nr | head -1)
	id_min=$(($id_first+1))

	#détermination de l'id max
	id_max=$(($nbserv + $id_min - 1))

	for i in $( seq $id_min $id_max );do
		echo ""
		echo "=> conteneur ${USERNAME}-vmparc${i}"
    docker run -tid -v /sys/fs/cgroup:/sys/fs/cgroup:ro --name ${USERNAME}-vmparc${i} priximmo/stretch-systemd-ssh:v3.1
		echo "    => création de l'utilisateur ${USERNAME}"
		docker exec -ti ${USERNAME}-vmparc${i} /bin/bash -c "useradd -m -p sa3tHJ3/KuYvI ${USERNAME}"
		echo "Installation de votre clé publique ${HOME}/.ssh/id_rsa.pub"
		docker exec -ti ${USERNAME}-vmparc${i} /bin/bash -c "mkdir  ${HOME}/.ssh && chmod 700 ${HOME}/.ssh && chown ${USERNAME}:${USERNAME} $HOME/.ssh"
		docker cp ${HOME}/.ssh/id_rsa.pub ${USERNAME}-vmparc${i}:${HOME}/.ssh/authorized_keys
		docker exec -ti ${USERNAME}-vmparc${i} /bin/bash -c "chmod 600 ${HOME}/.ssh/authorized_keys && chown ${USERNAME}:${USERNAME} ${HOME}/.ssh/authorized_keys"
		docker exec -ti ${USERNAME}-vmparc${i} /bin/bash -c "echo '${USERNAME}   ALL=(ALL) NOPASSWD: ALL'>>/etc/sudoers"
		docker exec -ti ${USERNAME}-vmparc${i} /bin/bash -c "service ssh start"
	done
	echo ""
	echo "Liste des ip  attribuées :"
	for i in $( seq $id_min $id_max );do

	infos_conteneur=$(docker inspect -f '   => {{.Name}} - {{.NetworkSettings.IPAddress }}' ${USERNAME}-vmparc${i})
	echo "${infos_conteneur} - Utilisteur : ${USERNAME} / mdp:password"
	
	done

fi

if [ "$1" == "--drop" ];then

	for i in $(docker ps -a --format "{{ .Names }}" |grep "${USERNAME}-vmparc" );do
		echo "     --Arrêt de ${i}..."
		docker stop $i
		echo "     --Suppression de ${i}..."
		docker rm $i
		done

fi

if [ "$1" == "--infos" ]; then

	for i in $(docker ps -a --format "{{ .Names }}" |grep "vmparc" );do
		infos_conteneur=$(docker inspect -f '   => {{.Name}} - {{.NetworkSettings.IPAddress }}' ${i})
		echo "${infos_conteneur} - Utilisteur : ${USERNAME} / mdp:password"
	done

fi

if [ "$1" == "--start" ];then
	
	sudo /etc/init.d/docker start

	
        for i in $(docker ps -a --format "{{ .Names }}" |grep "vmparc" );do
                echo "     --Démarrage de ${i}..."
                docker start $i
                #echo "     --Démarrage de sshd sur ${i}"
                #docker exec -ti ${i} /bin/bash -c "sudo service ssh start"
        done
echo ""
echo "#### Récap des infos ####"
echo ""


	for i in $(docker ps -a --format "{{ .Names }}" |grep "${USERNAME}-vmparc" );do
                infos_conteneur=$(docker inspect -f '   => {{.Name}} - {{.NetworkSettings.IPAddress }}' ${i})
                echo "${infos_conteneur} - Utilisteur : ${USERNAME} / mdp:password"
        done


fi

[Ansible] : Récupérer un rôle de Galaxy

Petit à petit je me met à Ansible et ça commence à devenir sympa. Et pour bien avancer et pas réinventer les choses, je vous recommande de vous rendre sur le site Galaxy. Il héberge les rôles partagés par la communauté.

person sky silhouette night

Photo by Snapwire on Pexels.com

Bien sûr il y a à boire et à manger. Il faut faire le tri pour trouver une chaussure à votre pied. Trouver le bon OS, voir le nombre de téléchargement etc… Mais ça vaut le coup car il y a vraiment beaucoup de rôles disponibles.

Mais comment récupérer un rôle de galaxy ?

Dans un premier temps on aurait tendance à faire avec la commande :

ansible-galaxy install -p roles username.role_name

L’option « p » permet d’indiquer le chemin où déposer le rôle.

Mais que se passe-til si vous devez retélécharger le rôle quelques moi splutard et que vous n’avez pas conservé votre ligne de commande ? plus rien

Donc le mieux, c’est de stocker ça dans un fichier pour relancer en tant que de besoin. Ne serait-ce que pour faire un upgrade.

Et là la commande idéale c’est :

ansible-galaxy install -v -p roles -r requirements.yml

L’option « r » pointe vers le fichier qui contient l’auteur et le nom du rôle sous cette forme:

- src: geerlingguy.postgresql
  name: postgres_server

Et voilà le tour est joué.

PS : n’oubliez pas d’exporter vos variables de proxy si vous êtes derrière un proxy.

[Ansible] : Find lister des fichiers et réaliser une action dessus

Ansible est nouveau pour moi donc vous devriez trouver dans les prochains jours pas mal de tips pour réaliser de petites actions avec ansible.

Aujourd’hui je cherche à lister les fichier d’un répertoire et à réaliser dessus une action. Dans mon cas je vais créer des liens symboliques pour faire en sorte que les binaires oracle soient directement accessible via /usr/bin (dans le path des users). On aurait aussi pu supprimer des fichiers ou autres.

tasks:
  - name: Liste les binaires oracle
    find:
      paths: /usr/lib/oracle/12.2/client64/bin/
    register: result
  - name: Création des liens symboliques
    file:
      src: "{{ item.path }}" 
      dest: /usr/bin/{{ item.path | basename }}
      state: link
    with_items: "{{ result.files }}" 

On met donc la liste des fichiers dans la variable « result ». Il s’agit d’un tableau. Si vous voulez aller plus loin vous pouvez vous référer à la doc sur le module find pour utiliser d’autres éléments du tableau.

Ensuite, on parcourt chaque file avec le with_items. On utilise alors item.path pour récupérer le chemin en dur. Pour la destination on lui applique la commande basename pour récupérer uniquement le nom de fichier.

Au passage j’ai découvert un blog ansible sympa… mais peut être un peu court.