Odroid-HC2 mit Ansible für das GlusterFS vorbereiten

Nachdem Ansible nun auf die Nodes zugreifen kann, folgt der nächste Schritt. Ich werde mich Stück für Stück an die notwendigen Bestandteile eines Playbooks an nähern. Ziel ist es, ein Playbook zu erhalten, welches mir die Nodes so Aufbaut, dass sie in das GlusterFS integriert werden können.

Zuerst schaue ich mir mal an, wie das von https://archlinuxarm.org/platforms/armv7/samsung/odroid-hc2 erzeugte Setup aussieht. Mich interessiert vor allem, wie das Arm Team die microSD Karte gemountet hat und wo diese und die eingebaute HDD im /dev Baum sitzt.

[ansible@alarm ~]$ cat /etc/fstab 
# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
[ansible@alarm ~]$ sudo cat /etc/fstab
# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
[ansible@alarm ~]$ 

Okay, kann man so machen.. seufz, damit hält man sich natürlich alle Freiheitsgrade offen, indem man die Medien gar nicht erst mountet.

Bin ich persönlich jetzt keine Freund davon etwas ungemountet zu booten, aber ich kann es nachvollziehen, dass das Team es so gemacht hat. Dadurch können die drei verschiedenen Arten von Mount-Points nach dem ersten Booten bedient werden. (/dev/sdX versus Label versus UUID). Ich selber nutze sehr gerne zum Mounten die Label, weil meiner Meinung nach dadurch in einem späteren Update sich verändernde Mount-Points a’la /dev/sda1 abgefangen werden und diese schwer handlebaren UUIDs umgangen werden können. Aber wie schon erwähnt, was für mich war ist, mag noch lange nicht für jedes Szenario gelten.

Na dann schau ich mir mal die Optionen zum Mounten im /dev/disk Baum genauer an.

[ansible@alarm ~]$ sudo tree /dev/disk/
/dev/disk/
|-- by-id
|   |-- ata-SAMSUNG_HD203WI_S1UYJ1KZ100183 -> ../../sda
|   |-- ata-SAMSUNG_HD203WI_S1UYJ1KZ100183-part1 -> ../../sda1
|   |-- mmc-SC16G_0xb48f4515 -> ../../mmcblk0
|   |-- mmc-SC16G_0xb48f4515-part1 -> ../../mmcblk0p1
|   |-- wwn-0x50024e9002b89270 -> ../../sda
|   `-- wwn-0x50024e9002b89270-part1 -> ../../sda1
|-- by-label
|   `-- ROOT -> ../../mmcblk0p1
<snip>

Am Ende steht mein gesetztes Label ROOT für die mmcblk0p1 Partition. Diese Partition möchte ich jetzt auch gerne fest in der /etc/fstab stehen haben, damit nach späteren Software-Updates nichts ins Schlingern gerät.

Ich baue mir das Zielplaybook aus einzelnen kleinen Playbook-Configlets zusammen, deshalb prüfe ich jetzt erstmal, ob das Mounten von einem / auf einem Node geht. Das Playbook-Configlets habe ich mir wie folgt ausgedacht.

[ansible@barney ~]$ cat label_root_mount.yml 
---
- name: All mount / by label ROOT
  hosts: glusterfs
  become: yes

  tasks:
   - name: generate LABEL=ROOT entry
     mount:
       path: /
       src: LABEL=ROOT
       fstype: ext4
       opts: defaults,noatime
       state: present

[ansible@barney ~]$ 

Damit ich das Playbook jetzt nicht gleich gegen alle Nodes lasse, habe ich mir die /etc/ansible/host aufgeteilt, so daß ich einzelne Nodes gezielt ansprechen kann. Die /etc/ansible/host Textdatei sieht wie folgt aus.

[root@barney ansible]# cat /etc/ansible/hosts
[glusterfs]
192.168.2.143
192.168.2.144
192.168.2.145
192.168.2.146
192.168.2.25

[g1]
192.168.2.143

[g2]
192.168.2.144

[g3]
192.168.2.145

[g4]
192.168.2.146

[g5]
192.168.2.25
[root@barney ansible]# 

Ich vermute, in größeren Installationen wird wohl eher mit dem DNS Namen der Nodes hantiert als mit der IPv4 Adresse, ist mir jetzt aber erstmal Wurst..

Okay, dann lassen wir mal das Playbook-Configlets gegen den Node g5 laufen und schauen uns an, wie das Ergebnis aussieht.

[ansible@barney ~]$ ansible-playbook label_root_mount.yml --limit g5

PLAY [All mount / by label ROOT] ***************************************************************************************************************************

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

TASK [generate LABEL=ROOT entrie] **************************************************************************************************************************
changed: [192.168.2.25]

PLAY RECAP *************************************************************************************************************************************************
192.168.2.25               : ok=2    changed=1    unreachable=0    failed=0   

[ansible@barney ~]$ 

Spannend war es jetzt für mich, da ich mir nicht ganz sicher war, was der Node denn nun wirklich als Ergebnis in der /etc/fstab stehen hat. Ich seh mal nach.

[ansible@alarm ~]$ cat /etc/fstab 
# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
LABEL=ROOT / ext4 defaults,noatime 0 0
[ansible@alarm ~]$ 

Sieht gut aus, allerdings gibt es noch ein Delta zwischen /etc/fstab und gelebter /etc/mtab. Dafür werde ich den Node jetzt mach rebooten und dann sollten die beiden symmetrisch sein.

[ansible@barney ~]$ ansible-playbook reboot.yml --limit g5

PLAY [All hosts reboot] ************************************************************************************************************************************

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

TASK [Unconditionally reboot the machine with all defaults] ************************************************************************************************
changed: [192.168.2.25]

PLAY RECAP *************************************************************************************************************************************************
192.168.2.25               : ok=2    changed=1    unreachable=0    failed=0   

[ansible@barney ~]$ 

Nach dem kleinen Klaps sieht es jetzt so aus, wie ich es haben wollte. Die microSD Karte ist über das Label gemountet.

[ansible@alarm ~]$ lsblk -Tf
NAME        FSTYPE LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda                                                                          
`-sda1      xfs          03df1da5-89d0-4fd3-8bf4-69cbbe8d87ce                
mmcblk0                                                                      
`-mmcblk0p1 ext4   ROOT  5ab9cbdc-0a5f-4fe8-8910-afdda9eafb81   12.4G    10% /

Nun wird es Zeit, die verbaute HDD der Nodes für die Nutzung im GlusterFS einzurichten. Dafür verwerfe ich das auf der HDD existierende Setup erst einmal weg.

Ich hab jetzt eine gute Stunde gebraucht, um festzustellen, dass auf meinen Nodes alle Befehle vom Modul parted nicht ausgeführt werden. Ich stell da mal eine steile Hypothese auf, das Modul parted braucht auf dem Nodes das Programm parted. Ich werde das also mal Installieren und gucken ob das Playbook dann sauber durch läuft.

Also schraub ich mir ein Playbook zum Ausrollen von parted.

[ansible@barney ~]$ cat parted.yml
---
- name: All hosts install parted
  hosts: glusterfs
  become: yes
  
  tasks:
    - name: install parted
      pacman:
        name: parted
        update_cache: yes
[ansible@barney ~]$ 

Und läuft es durch?

[ansible@barney ~]$ ansible-playbook parted.yml --limit g5

PLAY [All hosts install parted] ****************************************************************************************************************************

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

TASK [install parted] **************************************************************************************************************************************
changed: [192.168.2.25]

PLAY RECAP *************************************************************************************************************************************************
192.168.2.25               : ok=2    changed=1    unreachable=0    failed=0   
[ansible@barney ~]$

Okay, jetzt ist auf Node g5 also das Programm parted ausgerollt und jetzt lass ich nochmal das Playbook zum Löschen der Partition auf Node g5 los.

---
- name: All remove all partitions on sda
  hosts: glusterfs
  become: yes

  tasks:
   - parted:
       device: /dev/sda
       number: 1
       state: absent

Diese Partition stammt aus meinen Versuchen mit unterschiedlichen Softgware Defined Storages (Ceph/Hadoop/GlusterFs). Für mich stellt sich GlusterFS als am leichtesten handlebar dar, auch hier mag jeder zu seiner eigenen Sichtweisekommen auf Basis seines Bedarfs.

Nun gut, was macht denn nun das Playbok zum Löschen der Partion #1 auf SDA?

[ansible@barney ~]$ ansible-playbook remove_all_partitions_on_hdd.yml --limit g5

PLAY [All remove all partitions on sda] ********************************************************************************************************************

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

TASK [parted] **********************************************************************************************************************************************
changed: [192.168.2.25]

PLAY RECAP *************************************************************************************************************************************************
192.168.2.25               : ok=2    changed=1    unreachable=0    failed=0   

[ansible@barney ~]$ 

Jetzt noch flott eon prüfender Blick direkt ins Filesystem des Node g5.

[ansible@alarm ~]$ lsblk -Tf
NAME        FSTYPE LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda                                                                          
mmcblk0                                                                      
`-mmcblk0p1 ext4   ROOT  5ab9cbdc-0a5f-4fe8-8910-afdda9eafb81   12.4G    10% /
[ansible@alarm ~]$ 

Es hat funktioniert, die Partition sda1 ist gelöscht. Sicherlich geistern die Testdaten jetzt noch auf der HDD rum, aber was solls.

Als nächstes möchte ich jetzt eine Partition auf /dev/sda anlegen mit den Label=BRICK. Das Filesystem dieser BRICK Partition muss XFS sein. Das Playbook dafür habe ich mir wiefolgt vorgestellt.

[ansible@barney ~]$ cat make_sda1_partition.yml 
---
- name: All make one partition on sda1 with xfs
  hosts: glusterfs
  become: yes

  tasks:
   - name: Create sda1 partition
     parted:
       device: /dev/sda
       label: gpt
       number: 1
       state: present
       part_start: 0%
       part_end: 100%

   - name: Create a xfs filesystem on /dev/sda1
     filesystem:
       fstype: xfs
       dev: /dev/sda1
       opts: -i size=512

   - name: Label sda1 partition with LABEL=BRICK
     command: "xfs_admin -L BRICK /dev/sda1"
     become: true

[ansible@barney ~]$ 

Der Knackpunkt in diesem Ablauf ist, dass ich es auf Biegen und Brechen nicht hinbekommen habe mit den standard Ansible Modulen ein Label für die neue Partition zu setzen. Deshalb steht da im Playbook so ein hässliches Bash Command drin, aber nun ja. Dann lass ich mal mein erstes Playbook mit drei Tasks ausrollen. Mal sehen, ob das so geht, wie ich es mir vorstelle.

[ansible@barney ~]$ ansible-playbook make_sda1_partition.yml --limit g5

PLAY [All make one partition on sda1 with xfs] *************************************************************************************************************

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

TASK [Create sda1 partition] *******************************************************************************************************************************
changed: [192.168.2.25]

TASK [Label sda1 partition with LABEL=BRICK] ***************************************************************************************************************
changed: [192.168.2.25]

TASK [Create a xfs filesystem on /dev/sda1] ****************************************************************************************************************
ok: [192.168.2.25]

PLAY RECAP *************************************************************************************************************************************************
192.168.2.25               : ok=4    changed=2    unreachable=0    failed=0   

[ansible@barney ~]$

Ausgerollt ist es jedenfalls. Bei Filesystemveränderungen sehe ich lieber genau nach, bevor ich weiter mache.

[ansible@alarm ~]$ ls -l /dev/disk/by-label/
total 0
lrwxrwxrwx 1 root root 10 Mar 31 15:52 BRICK -> ../../sda1
lrwxrwxrwx 1 root root 15 Mar 31 09:56 ROOT -> ../../mmcblk0p1


[ansible@alarm ~]$ lsblk -Tf
NAME        FSTYPE LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda                                                                          
`-sda1      xfs    BRICK cdc27797-15eb-4e4d-b58e-3e6ad3315112                
mmcblk0                                                                      
`-mmcblk0p1 ext4   ROOT  5ab9cbdc-0a5f-4fe8-8910-afdda9eafb81   12.4G    10% /

[ansible@alarm ~]$ sudo xfs_db -c info /dev/sda1
meta-data=/dev/sda1              isize=512    agcount=4, agsize=122091705 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=488366820, imaxpct=5
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=238460, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

ansible@alarm ~]$ 

Das sieht doch nach einem gültigen Versuch aus. Es gibt eine Partition /dev/sda1 mit dem Label BRICK. Die orginale Anleitung zum GlusterFS sieht vor, dass die XFS Storage-Partitionen nach /export/sdX1 gemountet wird. Also lassen wir Ansible mal ein Verzeichnis /export erzeugen, worin danach /export/sda1 erzeugt wird. das Playbook dafür stelle ich mir wie folgt vor.

[ansible@barney ~]$ cat mkdir_export_mount_label_brick.yml 
---
- name: Generate /export/sdb1 and mount into fstab
  hosts: glusterfs
  become: yes

  tasks:
  - name: Creates directory and subdirectory
    file:
      path: /export/sda1
      state: directory

  - name: generate LABEL=BRICK entry
    mount:
      path: /export/sda1
      src: LABEL=BRICK
      fstype: xfs
      opts: defaults
      state: present

[ansible@barney ~]$ 

Wenn ich mir das Ergebnis des Playbooks ansehe, bin ich zufrieden. Nach einem Reboot sollte dann die Partition sauber gemountet sein.

[ansible@alarm ~]$ tree -dfugA /export/
/export
└── [root     root    ]  /export/sda1

1 directory

[ansible@alarm ~]$ cat /etc/fstab 
# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
LABEL=ROOT / ext4 defaults,noatime 0 0
LABEL=BRICK /export/sda1 xfs defaults 0 0

[ansible@alarm ~]$ 

Also steht als letzes für die Vorbereitung der GlusterFS installation noch ein Reboot an, dafür nehme ich das oben bereits beschriebene Playbook reboot.yml nochmal zur Hand und lasse es auf Node g5 los und sehe mir nachdem Reboot das Ergebnis auf dem Node g5 an.

[ansible@alarm ~]$ lsblk -Tf 
NAME        FSTYPE LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda                                                                          
`-sda1      xfs    BRICK cdc27797-15eb-4e4d-b58e-3e6ad3315112    1.8T     0% /export/sda1
mmcblk0                                                                      
`-mmcblk0p1 ext4   ROOT  5ab9cbdc-0a5f-4fe8-8910-afdda9eafb81   12.4G    10% /

[ansible@alarm ~]$ 

Das sieht genau so aus, wie ich es haben wollte. Damit sind die Vorbereitung des Dateisystems und der Partitonen abgeschlossen. Die einzelnen Code-Schnipsel baue ich jetzt noch in ein zusammenhängendes Playbook zusammen und lasse es dann über das gesammte Setup laufen.

Das finale Plabook lief fast zufriedenstellend durch. 😉

[ansible@barney ~]$ ansible-playbook preinstallation_glusterfs.yml

PLAY [Vorbereiten der Nodes vor der GlusterFS installation] ************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************
ok: [192.168.2.146]
ok: [192.168.2.144]
ok: [192.168.2.145]
ok: [192.168.2.143]
ok: [192.168.2.25]
ok: [192.168.2.137]

TASK [Installiere parted] **********************************************************************************************************************************
ok: [192.168.2.25]
changed: [192.168.2.145]
changed: [192.168.2.144]
changed: [192.168.2.143]
changed: [192.168.2.146]
ok: [192.168.2.137]

TASK [Installiere glusterfs] *******************************************************************************************************************************
changed: [192.168.2.25]
changed: [192.168.2.144]
changed: [192.168.2.145]
changed: [192.168.2.146]
changed: [192.168.2.143]
ok: [192.168.2.137]

TASK [Erzeuge einen FSTAB Eintrag für LABEL=ROOT] **********************************************************************************************************
changed: [192.168.2.145]
changed: [192.168.2.143]
changed: [192.168.2.144]
ok: [192.168.2.25]
changed: [192.168.2.146]
ok: [192.168.2.137]

TASK [Lösche existierende Partitionen SDA1 auf SDA] ********************************************************************************************************
fatal: [192.168.2.25]: FAILED! => {"changed": false, "err": "Warning: Partition /dev/sda1 is being used. Are you sure you want to continue?\n", "msg": "Error while running parted script: /usr/bin/parted -s -m -a optimal /dev/sda -- rm 1", "out": "", "rc": 1}
changed: [192.168.2.143]
changed: [192.168.2.144]
changed: [192.168.2.146]
changed: [192.168.2.145]
fatal: [192.168.2.137]: FAILED! => {"changed": false, "err": "Warning: Partition /dev/sda1 is being used. Are you sure you want to continue?\n", "msg": "Error while running parted script: /usr/bin/parted -s -m -a optimal /dev/sda -- rm 1", "out": "", "rc": 1}

TASK [Erzeuge eine SDA1 Partition] *************************************************************************************************************************
changed: [192.168.2.143]
changed: [192.168.2.144]
changed: [192.168.2.145]
changed: [192.168.2.146]

TASK [Formatiere SDA1 mit XFS] *****************************************************************************************************************************
changed: [192.168.2.143]
changed: [192.168.2.145]
changed: [192.168.2.144]
changed: [192.168.2.146]

TASK [Umlabeln der SDA1 mit LABEL=BRICK] *******************************************************************************************************************
changed: [192.168.2.145]
changed: [192.168.2.146]
changed: [192.168.2.144]
changed: [192.168.2.143]

TASK [Erzeuge Verzeichnis /export/sda1] ********************************************************************************************************************
changed: [192.168.2.143]
changed: [192.168.2.144]
changed: [192.168.2.146]
changed: [192.168.2.145]

TASK [Erzeuge einen FSTAB Eintrag für LABEL=BRICK] *********************************************************************************************************
changed: [192.168.2.143]
changed: [192.168.2.144]
changed: [192.168.2.145]
changed: [192.168.2.146]

TASK [Durchbooten um die FSTAB Einträge zu aktivieren] *****************************************************************************************************
changed: [192.168.2.144]
changed: [192.168.2.146]
changed: [192.168.2.143]
changed: [192.168.2.145]
        to retry, use: --limit @/home/ansible/preinstallation_glusterfs.retry

PLAY RECAP *************************************************************************************************************************************************
192.168.2.137              : ok=4    changed=0    unreachable=0    failed=1   
192.168.2.143              : ok=11   changed=10   unreachable=0    failed=0   
192.168.2.144              : ok=11   changed=10   unreachable=0    failed=0   
192.168.2.145              : ok=11   changed=10   unreachable=0    failed=0   
192.168.2.146              : ok=11   changed=10   unreachable=0    failed=0   
192.168.2.25               : ok=4    changed=1    unreachable=0    failed=1   

[ansible@barney ~]$ 

Schreibe einen Kommentar