Ansible: configurazione iniziale di un server

Ansible: configurazione iniziale di un server

See the article in English

Con questo articolo vediamo come semplificare la configurazione iniziale di un nuovo server sia fisico che virtuale con l’utilizzo di Ansible.

Installazione ambiente per Ansible

Per poter proseguire è necessario avere un computer linux dov’è presente Ansible.

Per installare Ansible si può utilizzare il proprio pacchetto di distribuzione oppure utilizzare il comando pip e creare un virtualenv dove installare tutto all’ultima versione o alla versione desiderata senza modificare le librerie di sistema.

installazione prerequisiti

Prima installiamo, se non presente, python3 e pip:

  • su sistemi RedHat >=8: sudo dnf install -y python3 python3-pip
  • mentre su sistemi RedHat <8:  sudo yum install -y python3 python3-pip (necessita il reposity epel)
  • infine su sistemi Debian/Ubuntu: sudo install -y python3 python3-pip python3-venv

Ambiente virtuale venv per python

Ora da utente creiamo il nostro ambiente virtuale python:

cd $HOME && mkdir venv && python3 -m venv venv/ansible

Attiviamo il nostro ambiente virtuale python con:

source venv/ansible/bin/activate

A questo punto con questa shell abbiamo un nuovo ambiente python dove poter installare tutto quello che vogliamo senza interferire con quello di sistema.

Da ora in poi consideriamo di essere nel virtualenv oppure su un ambiente python dove poter installare librerie con pip.

Installazione Ansible, lint e molecule

Aggiorniamo all’ultima versione pip con:

pip install setuptools && pip install --upgrade pip

Installiamo ansible con:

pip install ansible

Possiamo testare il funzionamento con:

ansible -v

e controllare gli ansible_facts in localhost con:

ansible localhost -m setup

Per controllare la sintassi yaml e quella specifica di Ansible installiamo i parser:

pip install yamllint ansible-lint

Per testare le regole di Ansible in maniera automatica tramite Docker installiamo molecule:

pip install molecule docker molecule[docker]

Ruolo Ansible: configurazione iniziale

Passiamo quindi al progetto principale, ovvero la creazione di un ruolo Ansible per la configurazione iniziale.

cd $HOME && mkdir roles
cd roles
ansible-galaxy role init eniocarboni.test
cd eniocarboni.test
molecule init scenario -r eniocarboni.test -d docker

La prima cosa da fare è modificare i metadati nel file meta/main.yml aggiungendo o modificando dentro al tag galaxy_info:

galaxy_info:
  role_name: test
  namespace: eniocarboni
  author: Your Name
  company: Yours
  ...

Inoltre va modificato almeno la licenza e la compatibilità del ruolo con le varie distribuzioni:

license: GPL-3.0
platforms:
  - name: Ubuntu
    versions:
      - all

A questo punto possiamo già testare il nostro ruolo con molecule che automaticamente utilizzerà Docker con una sua immagine di default (quay.io/centos/centos:stream8):

molecule test

dato che abbiamo installato sia yamllint che ansible-lint configuriamoli per l’uso con molecule:

cat <<EOF >>molecule/default/molecule.yml
lint: |
  set -e
  yamllint .
  ansible-lint
EOF

cat <<EOF >.ansible-lint
---
exclude_paths:
  - molecule
EOF

Rilanciando il test vedremo che molecule usa anche yamllint ed ansible-lint:

molecule test

Naturalmente possiamo lanciare i comandi anche direttamente senza molecule:

yamllint .
ansible-lint

test su una vm reale

Per testare su un server fisico o virtuale abbiamo bisogno di avere l’accesso via ssh con utente che abbia accesso a root tramite sudo o a root direttamente.

Quindi quel che ci servirà sarà:

  • il nome del server o il suo ip: testserver;
  • utente per accedere: user;
  • il file di playbook: playbook.yml;
  • il file inventory: inventory_hosts

Quindi basta fare:

mkdir -p tests/mytest
echo "testserver" >tests/mytest/inventory_hosts
cat <<EOF >tests/mytest/playbook.yml
---
- hosts: all
  become: true
  roles:
    - eniocarboni.test
EOF

Per testare direttamente nel server testserver basta lanciare:

ansible-playbook -u root -i tests/mytest/inventory_hosts tests/mytest/playbook.yml

Task da effettuare

A questo punto dobbiamo aggiungere i task da fare sul server e li mettiamo nel file tasks/main.yml come ad esempio:

  • installazione nuovi pacchetti;
  • modifica del nome host;
  • modifica del fuso orario;
  • settaggio della lingua principale;

Vediamo brevemente come fare:

cat <<EOF >tasks/main.yml
---
- import_tasks: update_packages.yml
- import_tasks: hostname.yml
- import_tasks: update_timezone.yml
- import_tasks: update_locale.yml
EOF
for f in update_packages hostname update_timezone update_locale
do
  echo "---" >tasks/$f.yml
done

Completiamo quindi il primo file update_packages.yml con:

cat <<EOF >>tasks/update_packages.yml
- name: update apt cache
  ansible.builtin.apt:
    update_cache: yes
    cache_valid_time: 3600
  when: ansible_pkg_mgr == "apt"
- name: update yum cache
  ansible.builtin.yum:
    update_cache: yes
  when: ansible_pkg_mgr == "yum"
- name: update dnf cache
  ansible.builtin.dnf:
    update_cache: yes
  when: ansible_pkg_mgr == "dnf"
- name: Install new packages
  ansible.builtin.package: "name={{ item }} state=latest" # noqa package-latest
  with_items: "{{ packages | default([]) }}"
EOF

Basta quindi mettere nel file defaults/main.yml le variabili di default come ad esempio packages:

cat <<EOF >>defaults/main.yml
packages:
  - wget
  - openssh-server
EOF

Finalmente possiamo testare i primi task con molecule via docker o sul nostro server di test e verificare che tutto funzioni correttamente:

molecule test
INFO     default scenario test matrix: dependency, lint, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy
INFO     Performing prerun...
...
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > lint
WARNING  Loading custom .yamllint config file, this extends our internal yamllint config.
WARNING  Failed to discover lintable files using git: fatal: non è un repository Git (né lo è alcun genitore fino al punto di mount /)
Mi fermo al limite del filesystem (l'opzione GIT_DISCOVERY_ACROSS_FILESYSTEM non è impostata).
INFO     Running default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Running default > destroy
INFO     Sanity checks: 'docker'

PLAY [Destroy] *****************************************************************

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: [localhost]: Wait for instance(s) deletion to complete (300 retries left).
ok: [localhost] => (item=instance)

TASK [Delete docker networks(s)] ***********************************************

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     Running default > syntax

playbook: /home/enio/Progetti/ansible/eniocarboni.test/molecule/default/converge.yml
INFO     Running default > create
PLAY [Create] ******************************************************************

TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item=None) 
skipping: [localhost]

TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item={'image': 'quay.io/centos/centos:stream8', 'name': 'instance', 'pre_build_image': True})
...
...
TASK [eniocarboni.test : update apt cache] *************************************
skipping: [instance]

TASK [eniocarboni.test : update yum cache] *************************************
skipping: [instance]

TASK [eniocarboni.test : update dnf cache] *************************************
ok: [instance]

TASK [eniocarboni.test : Install new packages] *********************************
changed: [instance] => (item=wget)
changed: [instance] => (item=openssh-server)

PLAY RECAP *********************************************************************
instance                   : ok=3    changed=1    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

INFO     Running default > idempotence
...
...
PLAY RECAP *********************************************************************
instance                   : ok=3    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

INFO     Idempotence completed successfully.
INFO     Running default > side_effect
WARNING  Skipping, side effect playbook not configured.
INFO     Running default > verify
INFO     Running Ansible Verifier

PLAY [Verify] ******************************************************************

TASK [Example assertion] *******************************************************
ok: [instance] => {
    "changed": false,
    "msg": "All assertions passed"
}

PLAY RECAP *********************************************************************
instance                   : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Verifier completed successfully.
INFO     Running default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Running default > destroy

PLAY [Destroy] *****************************************************************

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: [localhost]: Wait for instance(s) deletion to complete (300 retries left).
changed: [localhost] => (item=instance)

TASK [Delete docker networks(s)] ***********************************************

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     Pruning extra files from scenario ephemeral directory
ansible-playbook -u root -i tests/mytest/inventory_hosts tests/mytest/playbook.yml

A questo punto dovremmo proseguire con tutti gli altri task che abbiamo lasciato vuoti ed aggiungerne eventualmente altri, operazione che non farò in questo articolo per non dilungarmi troppo.

Ruolo Ansible: eniocarboni.server_initial_setup

Per chi fosse interessato può utilizzare il mio ruolo presente su Ansible Galaxy eniocarboni.server_initial_setup installandolo con:

ansible-galaxy install eniocarboni.server_initial_setup

e controllando o clonando il codice su GitHub   dove si trova anche tutta la documentazione su come utilizzarlo.

Questo ruolo è testato nelle varie versioni di Ubuntu e sistemi RedHat o equivalenti.

I task che esegue in questo momento sono (e sono tutti configurabili):

  • aggiornamento della cache dei pacchetti;
  • aggiornamento dei pacchetti all’ultima versione;
  • installazione nuovi pacchetti;
  • pacchetto per aggiornamento automatico via cron in base alla distribuzione;
  • installazione di screen o tmux;
  • modifica dell’hostname;
  • timezone o fuso orario;
  • modifica dei locali e di quello principale (lingua del server);
  • aggiunta o cancellazione delle chiavi pubbliche ssh;
  • aggiunta parametri sysctl;
  • configurazione firewall (ufw su Debian/Ubuntu, Firewalld su sistemi RedHat o eventualmente iptables)

Riferimenti

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Q Captcha 7 + 2 =