Información general

Build workflow GitHub contributors GitHub stars

Aquest llibre conté el recull de pràctiques ha realitzar a l'assignatura d'Administració i Manteniment de Sistemes i Aplicacions (AMSA). Aquestes pràctiques estan enfocades a l'administració de sistemes GNU/Linux, en concret, amb la distribucions AlmaLinux i Debian.

  • AlmaLinux és una distribució de GNU/Linux basada en Red Hat Enterprise Linux (RHEL) i CentOS utilizarem la versió 9.4.

  • Debian és una distribució de GNU/Linux utilitzarem la versió 12.5.0.

Continguts

  1. Instal·lació i Configuració de Màquines Virtuals.
  2. Scripting.
  3. Arrancada del Sistema.
  4. Sistema de Fitxers.
  5. RAID.
  6. Servidors.

Utilització

Es tracten de laboratoris pràctics resolts que us permet experimentar amb els continguts teòrics presentats a les sessions de teoria. Moltes comandes i configuracions es troben amagades inicialment per tal que pugueu intentar resoldre els exercicis per vosaltres mateixos. Si us trobeu amb problemes o voleu comprovar la vostra solució, podeu consultar la solució clicant al botó en forma d'ull 👁️.

Adicionalment, es demanara l'entrega d'informes per a cada laboratori. Aquests informes han d'intentar donar resposta a les preguntes plantejades en el context de cada laboratori.

Instal·lació d'una màquina virtual

Per a realitzar tots els laboratoris d'aquest curs, necessitareu una màquina virtual amb un sistema operatiu basat en Linux. En aquest curs us proposo utilitzar, dos distribucions molt populars per a servidors en entorns de producció.

  1. Debian 12: Debian és una distribució de Linux molt popular i estable. És una de les distribucions més antigues i utilitzades en servidors. Debian és conegut per la seva estabilitat, seguretat i facilitat d'ús. És una excel·lent opció per a servidors web, servidors de correu electrònic, servidors de bases de dades i altres aplicacions de servidor. Concretament, utilitzarem la versió 12.5.0.

  2. AlmaLinux 9: AlmaLinux és una distribució de Linux basada en Red Hat Enterprise Linux (RHEL). És una distribució de Linux empresarial que ofereix suport a llarg termini i actualitzacions de seguretat. Es una de les alternativa open-source de RHEL. Concretament, utilitzarem la versió 9.4.

Software de virtualització

En aquest curs, us recomano utilitzar VMWare com a software de virtualització. VMWare és un dels software de virtualització més populars i utilitzats en entorns de producció. A més, VMWare ofereix una versió gratuïta per a ús personal i educatiu:

A més, VMWare funciona en les principals arquitectures de processador com x86 i ARM. Durant el curs, els exemple i el suport es basaran en l'ús de VMWare. Resta a la vostra elecció utilitzar un altre software de virtualització com VirtualBox, KVM, UTM o d'altres.

Tasques

  1. Instal·la un màquina virtual amb Debian 12.5.0 en mode text
  2. Informació bàsica sobre hostname i hostnamectl
  3. Informació bàsica sobre resolució de noms
  4. Informació bàsica sobre com connectar-se a una màquina virtual amb SSH i transferència de fitxers

Activitats

  • Documenta el procés d'instal·lació de la màquina virtual amb AlmaLinux 9.4 amb una interfície gràfica.
  • Descriu les diferències entre el procés d'instal·lació de les dues distribucions.
  • Investiga com es pot crear un clon d'una màquina virtual amb VMware i documenta el procés. Comenta els avantatges i inconvenients de clonar una màquina virtual.

Rúbriques d'avaluació

Realització de les tasques: 100%

Criteris d'avaluacióExcel·lent (5)Notable(3-4)Acceptable(1-2)No Acceptable (0)
ContingutEl contingut és molt complet i detallat. S'han cobert tots els aspectes de la tasca.El contingut és complet i detallat. S'han cobert la majoria dels aspectes de la tasca.El contingut és incomplet o poc detallat. Falten alguns aspectes de la tasca.El contingut és molt incomplet o inexistent.
EstilL'estil és molt adequat i professional. S'ha utilitzat un llenguatge tècnic precís.L'estil és adequat i professional. S'ha utilitzat un llenguatge tècnic precís.L'estil és poc adequat o professional. Hi ha errors en el llenguatge tècnic.L'estil és molt poc adequat o professional. Hi ha molts errors en el llenguatge tècnic.
Precisió i exactitudLa informació és precisa i exacta. No hi ha errors.La informació és precisa i exacta. Hi ha pocs errors.La informació és imprecisa o inexacta. Hi ha errors.La informació és molt imprecisa o inexacta. Hi ha molts errors.
OrganitzacióLa informació està ben organitzada i estructurada. És fàcil de seguir.La informació està organitzada i estructurada. És fàcil de seguir.La informació està poc organitzada o estructurada. És difícil de seguir.La informació està molt poc organitzada o estructurada. És molt difícil de seguir.
JustificacióS'han justificat les respostes amb arguments vàlids i exemples pràctics.S'han justificat les respostes amb arguments vàlids.S'han justificat les respostes amb arguments poc vàlids.No s'han justificat les respostes.
ExpansióS'han ampliat les respostes amb informació addicional rellevant.S'han ampliat les respostes amb informació addicional.S'han ampliat les respostes amb informació poc rellevant.No s'han ampliat les respostes.
Suport gràfic o audiovisualS'han utilitzat recursos gràfics o audiovisuals per aclarir la informació.S'han utilitzat recursos gràfics o audiovisuals.S'han utilitzat pocs recursos gràfics o audiovisuals.No s'han utilitzat recursos gràfics o audiovisuals.

Instal·lació del sistema operatiu Debian 12

En aquest laboratori, instal·larem el sistema operatiu Debian 12 en una màquina virtual i descriurem els components principals del sistema operatiu. Aquesta instal·lació és la base per a tots els laboratoris que realitzarem en aquest curs. En alguns, us demanaré que modifiqueu alguns paràmetres de configuració per adaptar-los a les necessitats del laboratori.

Configuració de la màquina virtual amb VMWare

  1. Selecciona l’opció Create a New Virtual Machine a VMWare Workstation Player o VMWare Fusion.
  2. Selecciona Install from disc or image. Install from disc or image
  3. Selecciona la imatge ISO de Debian 12. Select ISO
  4. Configura els recursos de la màquina virtual. Configuració

Instal·lació del sistema operatiu

  1. Un cop iniciada la màquina virtual, podeu seleccionar la opció Install o bé Graphical install. Install Debian

    En aquest tutoriral, seleccionarem la opció Graphical install per a una instal·lació més amigable. La principal diferència entre les dues opcions és l'entorn gràfic.

  2. Selecciona l'idioma d'instal·lació. Select Language

    Podeu seleccionar l'idioma que vulgueu per a la instal·lació. En aquest cas, seleccionarem l'idioma Català.

  3. Selecciona la ubicació geogràfica. Select Location

    En aquest cas, seleccionarem la ubicació Espanya.

  4. Selecciona la disposició del teclat. Select Keyboard Layout

    En aquest cas, seleccionarem la disposició de teclat Català. Això ens asegurarà un mapeig correcte del teclat.

  5. Espereu que el sistema carregui els components necessaris. Loading Components

  6. Configura la xarxa.

    • El primer pas és configurar el nom d'amfitrió o hostname. Aquest nom permet identificar de forma única el vostre sistema. Podeu deixar el nom per defecte o canviar-lo al vostre gust.

    Hostname

    En aquest cas, hem canviat el nom d'amfitrió a lab00-debian.

    🚀 Consell:

    Els administradors de sistemes acostumen a administrar múltiples servidors i dispositius. Per tant, és important identificar cada dispositiu amb un nom únic per facilitar la gestió i la comunicació entre ells. Per tant, us recomano que utilitzeu un nom d'amfitrió significatiu per identificar-lo fàcilment.

    Us recomano un cop instal·lat el sistema que doneu una ullada a l'apartat Hostname per obtenir més informació sobre com gestionar el nom d'amfitrió.

    • El segon pas és configurar el domini de la xarxa. Aquest pas el podeu deixar en blanc si no teniu un domini específic. O bé, podem utilitzar .local com a domini local per identicar que el servidor pertany a la xarxa local.

    Domain

    💡 Nota:

    En un domini empresarial, normalment s'utilitza el nom de domini de l'empresa. Imagina que aquesta màquina virtual és el servidor d'una base de dades mysql de l'empresa acme.com. En aquest cas, el domini seria acme.com. I el nom d'amfitrió podria ser mysql01.acme.com.

  7. Configura l'usuari administrador.

    User

    En aquest punt, heu de tenir en compte que si no poseu cap contrasenya, es crearà l'usuari normal amb permisos de sudo i això us permetra executar comandes amb privilegis d'administrador.

    Si poseu una contrasenya, aquesta serà la contrasenya de l'usuari root i no es crearà un usuari normal amb permisos de sudo. I tampoc s'instal·larà el paquet sudo.

    ⚠️ Compte

    Com utilitzarem les màquines virtuals com a laboratoris de pràctiques, no cal que poseu una contrasenya molt segura. Podeu utilitzar una com a 1234. Però, recordeu que en un entorn real, la seguretat és molt important i cal utilitzar contrasenyes segures.

  8. Configura un usuari normal.

    • Nom complet: Podeu posar el vostre nom complet o el que vulgueu.

    Normal User

    • Nom d'usuari: Podeu posar el vostre nom d'usuari o el que vulgueu.

    Normal User

    • Contrasenya: El mateix que per l'usuari root.

    Normal User

  9. Configura la zona horària.

    Timezone

    En aquest cas, seleccionarem la zona horària de Madrid.

  10. Configura el disc dur.

    • Particionament: Durant el curs apendreu a realitzar particionament manual i, també discutirem sobre LV (Logical Volumes) i LVM (Logical Volume Manager). Però, per a una instal·lació senzilla, de moment, seleccionarem la primera opció (Guiat - utilitzar tot el disc).

    Partitioning

    • Selecciona el disc on instal·lar el sistema. En el meu cas, només tinc un disc virtual amb l'etiqueta /dev/nvme0n1. L'etiqueta indica el tipus de disc (NVMe) i el número de disc (1). Es possible tenir altres etiquetes com /dev/sda per discos SATA o /dev/vda per discos virtuals.

    Partitioning

    • Particions: Durant el curs apendreu les avantatges i com gestionar sistemes amb particions separades. Però, de moment, seleccionarem la primera opció (Totes les dades en una sola partició).

    Partitioning

    • Confirmeu els canvis. En aquest punt, el sistema crearà les particions necessàries:
      • La primera partició serà la partició /boot on es guardaran els fitxers de boot.
      • La segona partició serà la partició / on es guardaran els fitxers del sistema.
      • La tercera partició serà la partició de swap on es guardaran les dades de la memòria virtual.

    Partitioning

    👁️ Observació:

    En aquest punt es poden fer moltes personalitzacions com ara:

    • Configurar un sistema RAID.
    • Configurar un sistema LVM.
    • Configurar un sistema de xifrat. Tots aquests temes els veurem més endavant en el curs.
    • Escriu els canvis al disc.

    Write Changes

  11. Espera que s'instal·li el sistema.

    Install

  12. Configura el gestor de paquets.

    • Analitzar els discos de la instal·lació. Aquest pas permet seleccionar els discos on es troben els paquets d'instal·lació. Normalment, aquest pas no cal modificar-lo.

    Package Manager

    • Configura el gestor de paquets. En aquest cas, seleccionarem el servidor de paquets més proper a la nostra ubicació.

      • Filtrar els servidors de paquets per ubicació. Package Manager

      • Seleccionar el servidor de paquets. Package Manager

      👀 Nota:

      A vegades, els servidors de paquets poden estar saturats o no funcionar correctament. En aquest cas, podeu seleccionar un servidor alternatiu o provar més tard.

    • Configura el proxy. Si esteu darrere d'un proxy, podeu configurar-lo en aquest pas.

      Package Manager

      ℹ️ Què és un proxy?

      Un proxy és un servidor intermediari entre el vostre sistema i Internet. Aquest servidor pot ser utilitzat per controlar l'accés a Internet, per protegir la vostra privacitat o per accelerar la connexió a Internet. Les peticions de connexió a Internet es fan a través del servidor proxy, que actua com a intermediari i reenvia les peticions al servidor de destinació. Per exemple, en una empresa, el proxy pot ser utilitzat per controlar l'accés a Internet dels empleats i protegir la xarxa interna de possibles amenaces.

  13. Espera que s'instal·lin els paquets.

    Install

  14. Configura el paquet popularity-contest.

    • Aquest paquet permet enviar informació anònima sobre els paquets instal·lats al servidor de Debian per millorar la selecció de paquets i la qualitat dels paquets. Podeu seleccionar si voleu participar en aquest programa o no.

    Popularity Contest

  15. Selecció de programari. En aquest punt podeu seleccionar si voleu un servidor en mode text o amb interfície gràfica. També us permet seleccionar si voleu instal·lar els serveis web i ssh al servidor i finalment si voleu les utilitats estàndard del sistema. Aquestes opcions les anirem modifciant en funció dels laboratoris que realitzarem. Per defecte, seleccionarem el servidor en mode text, el servei SSH activat i les utilitats estàndard del sistema.

    Software Selection

    ℹ️ Què és un servidor en mode text?

    Un servidor en mode text és un servidor que no té una interfície gràfica. Això significa que tota la interacció amb el servidor es fa a través de la línia de comandes. Aquest tipus de servidor és molt comú en entorns de producció, ja que consumeix menys recursos i és més segur que un servidor amb interfície gràfica.


    ℹ️ Què és el servei SSH?

    El servei SSH (Secure Shell) és un protocol de xifratament que permet connectar-se de forma segura a un servidor remot. Aquest servei és molt utilitzat per administrar servidors a distància, ja que permet accedir al servidor de forma segura i xifratada.

  16. Espera que s'instal·li el programari.

    Install

  17. Instal·lació acabada. Un cop finalitzada la instal·lació, el sistema es reiniciarà i podreu accedir al GRUB per seleccionar el sistema operatiu. Finish

  18. El GRUB us permet accedir al sistema operatiu. En aquest cas, seleccionarem Debian GNU/Linux. La resta d'opcions les veurem més endavant en el curs.

    GRUB

    ℹ️ Què és el GRUB?

    Com veurem al capítol de Booting, el GRUB és un gestor d'arrencada que permet seleccionar el sistema operatiu que volem iniciar. Aquest gestor és molt útil en sistemes amb múltiples sistemes operatius o múltiples versions del mateix sistema operatiu.

  19. Inicieu sessió amb l'usuari i la contrasenya que heu configurat durant la instal·lació.

    Login

  20. Tanqueu la sessió amb la comanda exit.

  21. Inicieu sessió amb l'usuari root i la contrasenya que heu configurat durant la instal·lació.

    Login

Hostname

Els administradors de sistemes acostumen a administrar múltiples servidors i dispositius. Per tant, és important identificar cada dispositiu amb un nom únic per facilitar la gestió i la comunicació entre ells. El nom d'un dispositiu s'anomena nom d'amfitrió o hostname. Per a gestionar el nom d'amfitrió d'un sistema Linux, utilitzarem la comanda hostnamectl.

Comprovar el nom d'amfitrió actual

Per comprovar el nom d'amfitrió actual del vostre sistema, podeu utilitzar la comanda hostnamectl:

hostnamectl

Aquesta comanda us mostrarà informació sobre el vostre sistema, incloent el nom d'amfitrió actual.

Nom d'amfitrió

A part del nom d'amfitrió, també podeu veure informació com la versió del sistema operatiu, el kernel, la data i l'hora actuals, etc.

Modificar el nom d'amfitrió

Per canviar el nom d'amfitrió del vostre sistema, podeu utilitzar la comanda hostnamectl amb l'opció set-hostname. Per exemple, si voleu canviar el nom d'amfitrió a nou-nom, executeu la següent comanda:

hostnamectl set-hostname nou-nom

Aquesta comanda canviarà el nom d'amfitrió del vostre sistema a nou-nom. Si voleu comprovar que el canvi s'ha aplicat correctament, torneu a executar la comanda hostnamectl. Per aplicar el canvi, sortiu de la sessió actual exit i torneu a iniciar sessió.

Canviar el nom d'amfitrió

🔗 Recordatori:

Cal tenir en compte que aquesta comanda requereix permisos d'administrador. Per tant, és possible que hàgiu de precedir la comanda amb sudo o executar-la com a usuari root.

Nom en xarxa

Hi ha dos maneres d'identificar un servidor o dispositiu connectat en una xarxa, o bé utilitzant la direcció IP del dispositiu o bé utilitzant el seu nom d'amfitrió. Per poder resoldre el nom d'amfitrió correctament, cal configurar-lo correctament en el sistema o disposar d'un servidor DNS que pugui resoldre el nom d'amfitrió en una adreça IP.

Network Address Translation (NAT)

Per defecte, VMWare utilitza una xarxa NAT per connectar les màquines virtuals. Per fer-ho, VMWare crea una xarxa privada a la qual es connecten les màquines virtuals i utilitza la xarxa de l'amfitrió per connectar-se a Internet. Això permet a les màquines virtuals connectar-se a Internet a través de l'amfitrió sense necessitat de configurar una xarxa addicional. Ara bé, això també significa que les màquines virtuals utilitzen una adreça IP privada que no és accessible des de l'exterior. Tot i això, aquesta configuració la podeu canviar si cal. Però, pels nostres laboratoris, aquesta configuració és suficient.

ℹ️ Què és NAT?

La xarxa NAT (Network Address Translation) és una tècnica que permet a diversos dispositius connectar-se a Internet utilitzant una única adreça IP pública. Aquesta tècnica és àmpliament utilitzada per a xarxes domèstiques i petites empreses per permetre a diversos dispositius connectar-se a Internet sense necessitat de disposar d'una adreça IP pública per a cada dispositiu.

Ús de la direcció IP

La direcció IP és una forma única d'identificar un dispositiu en una xarxa. Cada dispositiu connectat a una xarxa ha d'estar configurat amb una adreça IP única per poder comunicar-se amb altres dispositius. Les adreces IP poden ser dinàmiques (assignades per un servidor DHCP) o estàtiques (configurades manualment).

Quan es crea una màquina virtual utilitzant el programari VMWare per defecte, la màquina virtual obté una adreça IP a través del servidor DHCP de VMWare. Aquesta adreça IP es pot utilitzar per accedir a la màquina virtual des de l'amfitrió o altres dispositius de la xarxa.

Per obtenir aquesta informació podeu consultar la interficie gràfica de VMWare o bé utilitzar la comanda ip addr en la terminal de la màquina virtual.

  • Interfície gràfica de VMWare:

    Interfície gràfica de VMWare

  • Comanda ip addr:

    ip addr
    

    Aquesta comanda us mostrarà la informació de la interfície de xarxa de la màquina virtual, incloent la seva adreça IP.

    Comanda ip addr

Podeu testar la connectivitat de la màquina virtual amb l'amfitrió o altres dispositius de la xarxa utilitzant la comanda ping. Per exemple, per provar la connectivitat amb l'amfitrió, podeu utilitzar la següent comanda:

ping -c 4 <adreça IP de l'amfitrió>

Prova de connectivitat

Ús del nom d'amfitrió

El nom d'amfitrió és una forma més fàcil de recordar i identificar un dispositiu en una xarxa. En lloc d'utilitzar una adreça IP, podeu utilitzar un nom d'amfitrió per connectar-vos a un dispositiu. Per exemple, en lloc de connectar-vos a 172.16.10.199, podeu connectar a lab0-amsa.

Per fer-ho, cal modificar la configuració del vostre ordinador local perquè pugui resoldre el nom d'amfitrió correctament. Això es pot fer afegint una entrada al fitxer /etc/hosts amb el nom d'amfitrió i la seva adreça IP. Per exemple afegint la següent línia al fitxer /etc/hosts:

# /etc/hosts
172.16.10.199 lab0-amsa
  • Windows: C:\Windows\System32\drivers\etc\hosts
  • Linux: /etc/hosts
  • macOS: /etc/hosts

Un cop afegida aquesta entrada, podeu provar la connectivitat amb la màquina virtual utilitzant el nom d'amfitrió:

ping -c 4 lab0-amsa

Prova de connectivitat amb el nom d'amfitrió

Una forma alternativa de resoldre el nom d'amfitrió és utilitzar un servidor DNS. Un servidor DNS és un servidor que tradueix els noms d'amfitrió en adreces IP i viceversa. Aquest és el cas de la majoria de xarxes corporatives i d'Internet, on es fa servir un servidor DNS per resoldre els noms de domini.

Connexió SSH i SFTP

En els nostres laboratoris, utilitzarem màquines virtuals per simular els nostres servidors. Per tant, sempre tindreu accés físic a les màquines virtuals a través de la interfície gràfica de VMWare. No obstant això, en un entorn de producció, no sempre tindreu accés físic als servidors o no us resultarà pràctic anar físicament a cada servidor per gestionar-los. Per tant, és important tenir una forma de connectar-vos als servidors de forma remota per poder gestionar-los de manera eficient.

ℹ️ Què és SSH?

SSH (Secure Shell) és un protocol de xarxa que permet als usuaris connectar-se a un dispositiu remot de forma segura. SSH utilitza una connexió xifrada per autenticar els usuaris i protegir les dades que es transmeten entre els dispositius. Això fa que SSH sigui una eina molt útil per connectar-se a servidors remots de forma segura.


ℹ️ Què és SFTP?

SFTP (SSH File Transfer Protocol) és un protocol de transferència de fitxers que permet als usuaris transferir fitxers de forma segura entre dos dispositius. SFTP utilitza SSH per autenticar els usuaris i xifrar les dades que es transmeten entre els dispositius. Això fa que SFTP sigui una eina molt útil per transferir fitxers de forma segura entre servidors remots.


ℹ️ Què és secure copy (SCP)?

SCP (Secure Copy) és una eina que permet als usuaris copiar fitxers de forma segura entre dos dispositius utilitzant SSH. SCP utilitza SSH per autenticar els usuaris i xifrar les dades que es transmeten entre els dispositius.

Connexió SSH entre la vostra màquina i la màquina virtual

Per connectar-vos a una màquina virtual utilitzant SSH, necessitareu l'adreça IP de la màquina virtual o bé el hostname de la màquina virtual. A més, necessitareu un client SSH instal·lat al vostre sistema local. A continuació, us mostrem com connectar-vos a una màquina virtual utilitzant SSH:

  • Mac/Linux:

    ssh <usuari>@<adreça IP o hostname>
    

Exemple de connexió SSH

On: <usuari> és el nom d'usuari amb el qual voleu connectar-vos a la màquina virtual i <adreça IP o hostname> és l'adreça IP o el hostname de la màquina virtual a la qual voleu connectar-vos.

Un cop connectats, podreu interactuar amb la màquina virtual com si estiguéssiu connectats físicament a la màquina. Per sortir de la sessió SSH, executeu la comanda exit.

  • Windows: Obrir una sessió de PowerShell i executar la comanda anterior. També podeu utilitzar un client SSH com PuTTY.

ℹ️ Què és el fingerprint que es mostra quan connecteu per primera vegada a un servidor SSH?

El fingerprint és una empremta digital única que identifica un servidor SSH. Quan connecteu per primera vegada a un servidor SSH, el vostre client SSH us mostrarà el fingerprint del servidor perquè pugueu verificar que esteu connectant-vos al servidor correcte. Això us protegeix contra atacs de suplantació de servidor.


😵‍💫 Troubleshooting:

Si una IP d'una màquina virtual a la qual havíeu accedit prèviament es reassigna a una altra màquina virtual i intenteu accedir a la màquina virtual original, el client SSH mostrarà un missatge d'advertència. Això succeeix perquè el fingerprint del servidor ha canviat. Quan connecteu per primera vegada a un servidor SSH, el vostre client SSH emmagatzema aquest fingerprint en el fitxer ~/.ssh/known_hosts per a futures referències.

Si el fingerprint del servidor canvia (per exemple, perquè l'adreça IP s'ha reassignat a una altra màquina virtual), el client SSH detectarà aquesta discrepància i mostrarà un missatge d'advertència per protegir-vos contra possibles atacs de suplantació de servidor. Aquest missatge us informa que el servidor al qual esteu intentant connectar-vos no coincideix amb el fingerprint emmagatzemat.

Per resoldre aquest problema i poder connectar-vos al servidor, podeu eliminar l'entrada del servidor del fitxer ~/.ssh/known_hosts. Això permetrà al client SSH acceptar el nou fingerprint i establir la connexió sense mostrar l'advertència.

Per resoldre aquest problema, simplement elimineu l'entrada del servidor del fitxer ~/.ssh/known_hosts i torneu a intentar connectar-vos al servidor. En el sistema operatiu Windows, el fitxer known_hosts es troba a la carpeta C:\Users\<usuari>\.ssh\known_hosts.

Transferència de fitxers amb SFTP

Per transferir fitxers entre la vostra màquina local i la màquina virtual utilitzant SFTP, necessitareu l'adreça IP de la màquina virtual o bé el hostname de la màquina virtual. A més, necessitareu un client SFTP instal·lat al vostre sistema local. A continuació, us mostrem com transferir fitxers entre la vostra màquina local i la màquina virtual utilitzant SFTP:

  • Mac/Linux:

    sftp <usuari>@<adreça IP o hostname>:<ruta>
    

    On:

    • <ruta> és la ruta al directori de la màquina virtual on voleu transferir els fitxers.
    • Els fitxers es transferiran al directori actual de la vostra màquina local.

    Un cop connectats, podeu utilitzar les comandes put i get per transferir fitxers entre la vostra màquina local i la màquina virtual. Si voleu transferir un directori sencer, podeu utilitzar la comanda put -r o get -r. Per acabar la sessió SFTP, executeu la comanda exit.

  • Windows: Obrir una sessió de PowerShell i executar la comanda anterior. També podeu utilitzar un client SFTP com WinSCP.

Si voleu fer servir SCP en lloc de SFTP, podeu utilitzar la comanda scp en lloc de sftp. La sintaxi de la comanda scp és similar a la de la comanda cp de Linux. Per exemple, per copiar un fitxer de la vostra màquina local a la màquina virtual, executeu la següent comanda:

scp <fitxer> <usuari>@<adreça IP o hostname>:<ruta>

on:

  • <fitxer> és el fitxer que voleu copiar.
  • <ruta> és la ruta al directori de la màquina virtual on voleu copiar el fitxer.
  • El fitxer es copiarà al directori especificat de la màquina virtual.
  • Si voleu copiar un directori sencer, podeu utilitzar l'opció -r.

Exemple pràctic de transferència de fitxers

  1. Crear un fitxer fitxer.txt a la vostra màquina local.

    echo "Aquest és un fitxer de prova" > fitxer.txt
    
  2. Copia el fitxer fitxer.txt a la màquina virtual a la ruta /home/usuari.

    • Amb scp:
    scp fitxer.txt jordi@172.16.10.199:/home/jordi
    
    • Amb sftp:
    sftp jordi@172.16.10.199:/home/jordi
    put fitxer.txt
    
  3. Edita el fitxer fitxer.txt a la màquina virtual.

    echo "Aquest és un fitxer de prova editat" > fitxer.txt
    
  4. Copia el fitxer fitxer.txt de la màquina virtual a la vostra màquina local.

    sftp jordi@172.16.10.199:/home/jordi
    get fitxer.txt
    

Scripting

En aquest laboratori es realitzaran tasques de scripting amb Bash i Awk. Aquests llenguatges són molt utilitzats en l'administració de sistemes GNU/Linux per automatitzar tasques repetitives.

Objectius

  • Repassar els conceptes bàsics de Bash estudiats al curs de Sistemes Operatius.
  • Aprendre a utilitzar Awk per processar fitxers de text.
  • Conèixer les diferències entre Bash i Awk.
  • Combina Bash i Awk per a realitzar tasques més complexes.

Continguts

  1. Bash
  2. Awk

Activitat

Heu d’incorporar al repositori cinc exemples diferents, ordenats de menor a major complexitat. Cada exemple ha de ser únic i ha d’incloure una explicació detallada del que fa el codi, així com versions tant en bash com en AWK. Si l’exemple que tenies pensat ja ha estat implementat per un company, hauràs de buscar-ne un de nou. Per tant, és recomanable que revisis els exemples que ja han publicat els teus companys abans de publicar els teus propis exemples.

Rúbriques d'avaluació

Presentació d'un Pull Request amb els scripts realitzats: 100%

En aquest laboratori s'avaluarà la capacitat de l'estudiant per a generar nous scripts en Bash i Awk. Aquest scripts hauran de ser funcionals i correctes, així com també hauran de ser ben documentats.

Criteris d'avaluacióExcel·lent (5)Notable(3-4)Acceptable(1-2)No Acceptable (0)
ContingutEl contingut és molt complet i detallat. S'han cobert tots els aspectes de la tasca.El contingut és complet i detallat. S'han cobert la majoria dels aspectes de la tasca.El contingut és incomplet o poc detallat. Falten alguns aspectes de la tasca.El contingut és molt incomplet o inexistent.
OperacionalsEls scripts generats són funcionals i correctes. No hi ha errors.Els scripts generats són funcionals i correctes. Hi ha pocs errors.Els scripts generats són funcionals i correctes. Hi ha errors.Els scripts generats no són funcionals o correctes.
CreatiusEls scripts generats són originals i no s'han copiat de cap font.Els scripts generats són originals i no s'han copiat de cap font.Els scripts generats són originals i no s'han copiat de cap font.Els scripts generats són còpia d'altres scripts.
DocumentacióEls scripts estan ben documentats i s'ha explicat el seu funcionament.Els scripts estan ben documentats i s'ha explicat el seu funcionament.Els scripts estan documentats. Falta explicar el seu funcionament.Els scripts no estan documentats.
PresentacióEls scripts s'han lliurat en un format adequat i s'han seguit les indicacions del professor.Els scripts s'han lliurat en un format adequat i s'han seguit les indicacions del professor.Els scripts s'han lliurat en un format adequat. Falten algunes indicacions del professor.Els scripts no s'han lliurat en un format adequat.
DidàcticsEls scripts són fàcils de seguir i entenent per a qualsevol persona.Els scripts són fàcils de seguir i entenent per a qualsevol persona.Els scripts són fàcils de seguir i entenent per a qualsevol persona.Els scripts són difícils de seguir i entenent.
OptimitzacióEls scripts són eficients i no es poden millorar.Els scripts són eficients i no es poden millorar.Els scripts són eficients i es poden millorar.Els scripts no són eficients.

Bash

En aquest laboratori repassarem els conceptes bàsics de Bash, el llenguatge de programació de scripts més utilitzat en sistemes GNU/Linux. Aquest laboratori està enfocat en repassar els conceptes bàsics que vau estudiar en l'assignatura de Sistemes Operatius.

Contextualització

En aquest laboratori crearem una aplicació per gestionar una llista de pokemons. Aquesta aplicació haurà de permetre afegir, llistar, eliminar i buscar pokemons. A més a més, haureu de fer servir un fitxer per emmagatzemar la informació dels pokemons.

Preparació

  • Entorn de treball: Màquina virtual amb una distribució GNU/Linux instal·lada pot ser Debian o AlmaLinux.

Objectius

  • Repassar els conceptes bàsics de Bash.

Tasques

  1. Creeu un esquelet pel vostre script Bash.

    #!/bin/bash
    
    # Constants
    
    # Functions
    
    # Main
    
    return 0
    
  2. Implementeu una constant POKEDEX_FILE amb el nom del fitxer on emmagatzemareu la informació dels pokemons.

    POKEDEX_FILE="pokedex.txt"
    
  3. Implementeu un menu amb la sintaxi case que permeti executar les següents comandes: help, list, search, delete i new.

    case $1 in
        help)
            pokedex_help
            ;;
        list)
            pokedex_list
            ;;
        search)
            pokedex_search $2
            ;;
        delete)
            pokedex_delete $2
            ;;
        new)
            pokedex_new $2 $3 $4 $5 $6 $7
            ;;
        *)
            echo "Comanda no trobada."
            pokedex_help
            ;;
    esac
    
  4. Implementeu la funció pokedex_help que mostri per pantalla les instruccions d'ús del script.

    function pokedex_help() {
        echo "Ús: ./pokedex.sh <comanda> <arguments>"
        echo "Comandes:"
        echo "  list: Llistar pokemons"
        echo "  search <name>: Buscar pokemon"
        echo "  delete <name>: Eliminar pokemon"
        echo "  new <name> <type> <hp> <attack> <defense> <speed>: Afegir pokemon"
    }
    
  5. Implementeu la funció pokedex_list que llegeixi el fitxer POKEDEX_FILE i mostri per pantalla la llista de pokemons.

    • Podeu fer servir la comanda cat per llegir el fitxer POKEDEX_FILE.
    function pokedex_list() {
        cat $POKEDEX_FILE
    }
    
    • Assegureu-vos que existeix el fitxer POKEDEX_FILE.
    if [[ ! -f $POKEDEX_FILE ]]; then
        echo "El fitxer $POKEDEX_FILE no existeix."
        return 1
    fi
    
  6. Implementeu la funció pokedex_search <name> que llegeixi el fitxer POKEDEX_FILE i mostri per pantalla la informació del pokemon amb nom <name>.

    • Podeu fer servir la comanda grep per buscar el pokemon amb nom <name>.
    function pokedex_search() {
        grep $1 $POKEDEX_FILE
    }
    
    • Assegureu-vos que la funció pokedex_search rep un argument.
    if [[ -z $1 ]]; then
        echo "Has d'indicar el nom del pokemon."
        echo "Ús: ./pokedex.sh search <name>"
        return 1
    fi
    
  7. Implementeu la funció pokedex_delete <name> que elimini el pokemon amb nom <name> del fitxer POKEDEX_FILE.

    • Podeu fer servir la comanda sed per eliminar el pokemon amb nom <name>.
    function pokedex_delete() {
        sed -i "/$1/d" $POKEDEX_FILE
    }
    
    • Assegureu-vos que la funció pokedex_delete rep un argument.
    if [[ -z $1 ]]; then
        echo "Has d'indicar el nom del pokemon."
        echo "Ús: ./pokedex.sh delete <name>"
        return 1
    fi
    
  8. Implementeu la funció pokedex_new <name> <type> <hp> <attack> <defense> <speed> que permet afegir un nou pokemon a la pokedex.

    • Podeu fer servir la comanda echo per afegir el nou pokemon al fitxer POKEDEX_FILE.
    function pokedex_new() {
        echo "$1 $2 $3 $4 $5 $6" >> $POKEDEX_FILE
    }
    
    • Assegureu-vos que la funció pokedex_new rep tots els arguments necessaris.
    if [[ -z $1 || -z $2 || -z $3 || -z $4 || -z $5 || -z $6 ]]; then
        echo "Has d'indicar el nom, tipus, hp, attack, defense i speed del pokemon."
        echo "Ús: ./pokedex.sh new <name> <type> <hp> <attack> <defense> <speed>"
        return 1
    fi
    

Introducció al llenguatge AWK

Objectius

  • Entendre la sintaxi bàsica d'AWK.
  • Aprendre a utilitzar AWK per processar fitxers de text.
  • Entendre les diferències entre AWK i BASH.

Prerequisits

  • Una màquina virtual amb sistema operatiu Linux, preferiblement AlmaLinux 9.4. Es recomana accedir a la màquina virtual mitjançant SSH.

Què és AWK?

AWK és un llenguatge de programació potent i versàtil, dissenyat específicament per a l’anàlisi de patrons i el processament de text. La seva funció principal és processar fitxers de text de manera eficient, permetent la transformació de dades, la generació d’informes i la filtració de dades.

Pràcticament tots els sistemes Unix disposen d’una implementació d’AWK. Això inclou sistemes operatius com GNU/Linux, macOS, BSD, Solaris, AIX, HP-UX, entre d’altres. Per consultar el manual d’AWK, pots utilitzar la comanda man awk. Per consultar la versió d’AWK instal·lada al teu sistema, pots utilitzar la comanda awk -W version.

AWK es caracteritza per ser compacte, ràpid i senzill, amb un llenguatge d’entrada net i comprensible que recorda al llenguatge de programació C. Disposa de construccions de programació robustes que inclouen if/else, while, do/while, entre d’altres. L’eina AWK processa una llista de fitxers com a arguments. En cas de no proporcionar fitxers, AWK llegeix de l’entrada estàndard, permetent així la seva combinació amb pipes per a operacions més complexes.

Utilització de l'eina AWK

Pots trobar tota la informació sobre el funcionament de l’eina AWK a la pàgina de manual. Per exemple, per obtenir informació sobre la comanda awk, pots utilitzar la comanda man awk. Aquesta comanda et proporcionarà tota la informació necessària per utilitzar l’eina AWK.

  • Pots utilitzar l’eina amb el codi escrit directament acció-awk a la línia de comandes o combinada en un script:

    awk [-F] '{acció-awk}' [ fitxer1 ... fitxerN ]
    
  • També pots utilitzar l’eina amb tota la sintaxi awk guardada en un fitxer script-awk des de la línia de comandes o combinada amb altres scripts:

    awk [-F] -f script-awk [ fitxer1 ... fitxerN ]
    

En aquests exemples, [-F] és una opció que permet especificar el caràcter delimitador de camps, {acció-awk} és el codi AWK que vols executar, i [ fitxer1 ... fitxerN ] són els fitxers d’entrada que AWK processarà. Si no s’especifica cap fitxer, AWK llegirà de l’entrada estàndard.

Fitxer de Dades d'Exemple per utilitzar en aquest Laboratori

En aquest laboratori, farem servir un fitxer de dades específic com a conjunt de dades d’exemple. Aquest fitxer representa una pokedex i es pot obtenir amb la següent comanda:

curl -O https://gist.githubusercontent.com/armgilles/194bcff35001e7eb53a2a8b441e8b2c6/raw/92200bc0a673d5ce2110aaad4544ed6c4010f687/pokemon.csv

Aquest fitxer conté 801 línies (800 pokemons + 1 capçalera) i 13 columnes. Les columnes són les següents:

  • #: Número de pokémon
  • Name: Nom del pokémon
  • Type 1: Tipus 1 del pokémon
  • Type 2: Tipus 2 del pokémon
  • Total: Total de punts de tots els atributs
  • HP: Punts de vida
  • Attack: Atac
  • Defense: Defensa
  • Sp. Atk: Atac especial
  • Sp. Def: Defensa especial
  • Speed: Velocitat
  • Generation: Generació
  • Legendary: Llegendari (0: No, 1: Sí)

Per comprovar aquestes dades, podem fer servir les següents comandes:

  • Utilitzeu la comanda wc per comptar el nombre de línies del fitxer:

    wc -l pokemon.csv
    
  • Utilitzeu la comanda head per mostrar les primeres 10 línies del fitxer:

    head pokemon.csv
    
  • Utilitzeu les comandes wc i head per comptar el nombre de columnes del fitxer. Recordeu que les columnes estan separades per comes:

    head -1 pokemon.csv | tr ',' '\n' | wc -l
    

Awk - Bàsic

Estrucutra Bàsica d'AWK

El llenguatge AWK s'organitza amb duples de la forma patró { acció }. El patró pot ser una expressió regular o una condició lògica. L’acció és el que es vol realitzar amb les línies que compleixen el patró. Per tant, AWK processa els fitxers línia per línia. Per cada línia del fitxer, AWK avalua el patró. Si el patró és cert, executa l’acció. Si el patró és fals, passa a la següent línia.

Per exemple, si volem imprimir totes les línies d'un fitxer (acció) que contenten una expressió regular definida a regex (patró), podem fer servir la següent sintaxi:

awk '/regex/ { print }' fitxer

Observeu que utilitzem el caràcter / per indicar que el patró és una expressió regular.

A més, AWK ens permet utilitzar una estructura de control BEGIN i END. La clàusula BEGIN s'executa abans de processar qualsevol línia i la clàusula END s'executa després de processar totes les línies. Aquestes clausules són opcionals i no són necessàries en tots els casos.

BEGIN { acció }
patró { acció }
END { acció }

Per exemple, si volem indicar que estem començant a processar un fitxer, podem fer servir la clàusula BEGIN. I si volem indicar que hem acabat de processar el fitxer, podem fer servir la clàusula END. A continuació, teniu un exemple de com utilitzar les clàusules BEGIN i END:

awk '
    BEGIN { print "Començant a processar el fitxer..." } 
    /regex/ { print }
    END { print "Finalitzant el processament del fitxer..." }
' fitxer

Aprenent a utilitzar AWK amb Exemples

Sintaxis Bàsica

En aquesta secció veurem com podem utiltizar AWK per substituir algunes comandes bàsiques de bash com cat, grep, cut.

cat

La comanda cat ens permet mostrar el contingut d'un fitxer. Per exemple, per mostrar el contingut del fitxer pokemon.csv:

cat pokemon.csv

Podem fer servir AWK per fer el mateix. Per exemple, per mostrar el contingut del fitxer pokemon.csv:

awk '{print}' pokemon.csv

on {print} és l'acció que volem realitzar. En aquest cas, volem imprimir totes les línies del fitxer. Això és equivalent a la comanda cat.

AWK també ens permet acompanyar l'acció amb variables. Per exemple, la variable $0 conté tota la línia. Per tant, podem utilitzar la variable $0 per imprimir totes les línies del fitxer:

awk '{print $0}' pokemon.csv

Nota: AWK processa els fitxers línia per línia. Per cada línia del fitxer, AWK avalua l'acció. Es a dir, amb la comanda awk '{print $0}' pokemon.csv estem indicant que per cada línia del fitxer, imprimeixi la línia sencera. Per tant, aquesta comanda és equivalent a la comanda cat.

Podeu comparar les sortides de les comandes cat i awk per assegurar-vos que són les mateixes utilitzant la comanda diff:

diff <(cat pokemon.csv) <(awk '{print $0}' pokemon.csv)

grep

La comanda grep ens permet cercar patrons en un fitxer. Per exemple, per mostrar totes les línies que contenen la paraula "Char" al fitxer pokemon.csv:

grep Char pokemon.csv

Podem fer servir AWK per fer el mateix. Per exemple, per mostrar totes les línies que contenen la paraula "Char" al fitxer pokemon.csv:

awk '/Char/ {print}' pokemon.csv

on /Char/ és el patró que volem cercar. Per tant, tenim un patró de cerca i una acció a realitzar. En aquest cas, estem cercant linia per linia la paraula "Char" i si la trobem, imprimim tota la línia. Això és equivalent a la comanda grep.

Una confusió comuna es pensar que l'expressió /Char/ indica que la línia comença per "Char". Això no és cert. L'expressió /Char/ indica que la línia conté la paraula "Char". Per exemple, podem buscar totes les línies del fitxer pokemon.csv que contenen el patró "ois":

awk '/ois/ {print}' pokemon.csv

En la sortida, veureu que tant les paraules "poison" del tipus de pokémon com els diferents noms de pokémon que contenen la paraula "ois" són mostrats.

1,Bulbasaur,Grass,Poison,318,45,49,49,65,65,45,1,False
9,Blastoise,Water,-,530,79,83,100,85,105,78,1,False
...
71,Victreebel,Grass,Poison,490,80,105,65,100,70,70,1,False
...
691,Dragalge,Poison,Dragon,494,65,75,90,97,123,44,6,False

Conteu quantes línies compleixen aquest patró, combinant AWK amb la comanda wc:

awk '/ois/ {print}' pokemon.csv | wc -l

En aquest cas, hi ha 64 entrades que satisfan aquest patró.

cut

La comanda cut ens permet extreure columnes d'un fitxer. Per exemple, per mostrar només la primera columna del fitxer pokemon.csv:

cut -d, -f1 pokemon.csv

on -d, indica que el separador de camps és la coma i -f1 indica que volem la primera columna. Podem fer servir AWK per fer el mateix. Per exemple, per mostrar només la primera columna del fitxer pokemon.csv:

awk -F, '{print $1}' pokemon.csv

on -F, indica que el separador de camps és la coma i {print $1} indica que volem la primera columna. Això és equivalent a la comanda cut.

Cada item separat pel separador de camps es denomina camp. Per exemple, en el fitxer pokemon.csv, cada columna separada per una coma és un camp. Per defecte, el separador de camps és l'espai en blanc. Per tant, si no especifiquem el separador de camps, AWK utilitzarà l'espai en blanc com a separador de camps.

Si intentem imprimir la tercera columna sense especificar el separador de camps, la sortida no serà correcta:

awk '{print $3}' pokemon.csv

Això és degut a que el separador de camps per defecte és l'espai en blanc i no la coma. Ara bé, si modifiquem el separador de camps a l'espai en blanc, enlloc de la coma, podem obtenir la sortida correcta:

sed 's/,/ /g' pokemon.csv | awk '{print $3}'

En aquest cas, estem substituint totes les comes per espais en blanc i després utilitzant AWK per imprimir la tercera columna.

Verificacions lògiques

Es pot utilitzar com a patró una expressió composta amb operadors i retornar true o false.

OperadorSignificat
<Menor
>Major
<=Menor o igual
>=Major o igual
==Igualtat
!=Desigualtat
~Correspondència amb expressió regular
!~No correspondència amb expressió regular
!Negació
&&AND
||OR
()Agrupació

Per utilizar aquestes expressions, podem fer servir la següent sintaxi:

awk 'patró { acció }' fitxer

on el patró és una expressió composta amb operadors lògics i l'acció és el que es vol fer amb les línies que compleixen el patró. Per exemple:

  • Mostrar tots els pokemons que tenen més de 100 punts d'atac (valor de la columna 7):

    awk -F, '$7 > 100 {print}' pokemon.csv
    
  • Mostrar tots els pokemons que tenen més de 100 punts d'atac (valor de la columna 7) i són de la primera generació (valor de la columna 12):

    awk -F, '$7 > 100 && $12 == 1 {print}' pokemon.csv
    
  • Mostrar tots els pokemons que tenen més de 100 punts d'atac (valor de la columna 7) o són de la primera generació (valor de la columna 12):

    awk -F, '$7 > 100 || $12 == 1 {print}' pokemon.csv
    
  • Mostrar tots els pokemons que són Mega pokemons (contenen la paraula "Mega" a la columna 2):

    awk -F, '$2 ~ /Mega/ {print}' pokemon.csv
    
  • Mostra tots els pokemons que no són Mega pokemons (no contenen la paraula "Mega" a la columna 2):

    awk -F, '$2 !~ /Mega/ {print}' pokemon.csv
    

Exercicis Bàsics

Aquests exercicis estan resolts en bash i en AWK. Podeu provar-los en el vostre sistema per entendre com funcionen. Intenta resoldre primer els exercicis en bash i després en AWK. Un cop pensada la solució, podeu comparar-la amb la solució proporcionada.

  1. Implementeu una comanda que permeti filtrar tots els pokemon de tipus foc (Foc) i imprimir únicament per stdout el nom i els seus tipus (columnes 2, 3 i 4).

    • En bash podem fer servir la comanda grep per filtrar les línies que contenen la paraula "Fire" i la comanda cut per extreure les columnes 2, 3 i 4:
    grep Fire pokemon.csv | cut -d, -f2,3,4
    
    • En AWK:
    awk -F, '/Fire/ {print $2,$3,$4}' pokemon.csv
    
  2. Implementeu una comanda que permeti imprimir totes les línies que continguin una 'b' o una 'B' seguida de "ut". Mostra només el nom del pokémon (columna 2).

    • En AWk podem fer servir l'expressió regular [bB]ut:
    awk -F, '/[bB]ut/ {print $2}' pokemon.csv
    
    • En bash podem fer servir la comanda grep amb l'argument -i per ignorar la diferència entre majúscules i minúscules:
    grep -i "but" pokemon.csv | cut -d, -f2
    
  3. Implementeu una comanda que permeti imprimir totes les línies que comencin per un "K" majúscula. Mostra només el nom del pokémon (columna 2).

    • En bash podem fer servir la comanda grep amb el meta caràcter ^ per indicar que la línia comença per "K" majúscula:
    grep "^K" pokemon.csv | cut -d, -f2
    
    • En AWK:
    awk -F, '$2 ~ /^K/ {print $2}' pokemon.csv
    

    !Compte: Per defecte, les expressions regulars actuen sobre tota la línia $0. Si voleu aplicar l'expressió regular a una columna determinada, necessiteu l'operador (~). Si intenteu aplicar: awk -F,'/^K/ {print $2}' pokemon.csv no funcionarà ja que l'inici ^ de $0 serà un enter.

  4. Imprimiu tots els pokemons que siguin del tipus foc o lluita. Imprimiu el nom, tipus 1 i tipus 2. Podeu fer servir l'operador | per crear l'expressió regular.

    • En AWK podem fer servir l'operador | per combinar dos patrons:
    awk -F, '/Fire|Fighting/ {print $2,$3,$4}' pokemon.csv
    
    • En bash, podeu fer servir l'argument -E per utilitzar expressions regulars exteses amb la comanda grep:
    grep -E "Fire|Fighting" pokemon.csv | cut -d, -f2,3,4
    
  5. Imprimiu tots els pokemons que siguin del tipus foc i lluita. Imprimiu el nom, tipus 1 i tipus 2. Podeu fer servir l'operador && per crear l'expressió regular.

    • En AWK podem fer servir l'operador && per combinar dos patrons:
    awk -F, '/Fire/ && /Fighting/ {print $2,$3,$4}' pokemon.csv
    
    • En bash, podeu fer servir l'argument -E per utilitzar expressions regulars exteses amb la comanda grep:
    grep -E "Fire.*Fighting|Fighting.*Fire" pokemon.csv | cut -d, -f2,3,4
    

    En aquest cas no podem fer servir l'operador && ja que grep no permet aquesta funcionalitat. Per tant, hem de fer servir l'operador | per combinar els dos patrons. A més, hem de fer servir l'expressió regular **Fire.Fighting|Fighting.Fire per indicar que volem les línies que contenen "Fire" seguit de "Fighting" o "Fighting" seguit de "Fire".

  6. Imprimiu el nom de tots els pokemons de la primera generació que siguin llegendaris. Per fer-ho utilitzeu les columnes 12 i 13. La columna 12 indica la generació amb valors númerics (1,2,3,...) i la columna 13 indica si un pokémon és llegendari o no (0: No, 1: Sí).

    • En AWK podem fer servir l'operador && per combinar dos patrons:
    awk -F, '$12 == 1 && $13 == "True" {print $2}' pokemon.csv
    
    • En bash, podem fer servir la comanda grep per filtrar les línies que contenen la primera generació i són llegendaris i la comanda cut per extreure la columna 2:
    grep "1,True" pokemon.csv | cut -d, -f2
    

    Aquesta solució no és la més òptima, ja que es podria donar el cas que altres columnes continguessin la paraula "1,True". Per solucionar-ho podem fer un script més complex que comprovi que la columna 12 conté el valor 1 i la columna 13 conté la paraula "True".

    #!/bin/bash
    while IFS=, read -r col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13; do
    if [[ "$col12" == "1" ]] && [[ "$col13" == "True" ]]; then
        echo "$col2"
    fi
    done < pokemon.csv
    

Awk - Intermedi

Variables en AWK

El llenguatge de programació AWK ens permet definir variables i utilitzar-les en les nostres accions. Les variables en AWK són dinàmiques i no necessiten ser declarades abans d'utilitzar-les. Això significa que podem utilitzar una variable sense haver-la declarat prèviament.

Per exemple, si volem comptar el nombre de línies que hi ha al fitxer pokemon.csv, podem fer servir una variable per a emmagatzemar el nombre de línies. A continuació, mostrem un exemple de com comptar el nombre de línies del fitxer pokemon.csv:

awk 'BEGIN { n=0 } { ++n } END{ print n }' pokemon.csv

On n és la variable que utilitzem per emmagatzemar el nombre de línies. Per començar, inicialitzem la variable n a 0 amb la clàusula {BEGIN}. Aquesta clausula és opcional, ja que les variables en AWK són dinàmiques i no necessiten ser declarades prèviament. Després, incrementem la variable n per a cada línia amb la clàusula {++n}. Finalment, utilitzem la clàusula {END} per imprimir el valor de la variable n després de processar totes les línies.

Operacions Aritmètiques

OperadorAritatSignigicat
+BinariSuma
-BinariResta
*BinariMultiplicació
/BinariDivisió
%BinariMòdul
^BinariExponent
++UnariIncrement 1 unitat
--UnariDecrement 1 unitat
+=Binarix = x+y
-=Binarix = x-y
*=Binarix=x*y
/=Binarix=x/y
%=Binarix=x%y
^=Binarix=x^y

Implementeu un script que comprovi que el Total (columna 5) és la suma de tots els atributs (columnes 6,7,8,9,10 i 11). La sortida ha de ser semblant a:

Charmander->Total=309==309
Charmeleon->Total=405==405
Charizard->Total=534==534
  • En AWK:

    awk -F, '{ print $2"->Total="$5"=="($6+$7+$8+$9+$10+$11)}' pokemon.csv
    
  • En bash:

    #!/bin/bash
    while IFS=, read -r col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13; do
    if [[ "$col5" == "$((col6+col7+col8+col9+col10+col11))" ]]; then
        echo "$col2->Total=$col5==$((col6+col7+col8+col9+col10+col11))"
    fi
    done < pokemon.csv
    

Variables Internes

AWK té variables internes que són molt útils per a la manipulació de dades. Aquestes variables són:

VariableContingut
$0Conté tot el registre actual
NFConté el valor del camp (columna) actual.
$1,$2...,$1 conté el valor del primer camp i així fins l'últim camp. noteu que $NF serà substituït al final pel valor de l'últim camp.
NRÍndex del registre actual. Per tant, quan es processa la primera línia aquesta variable té el valor 1 i quan acaba conté el nombre de línies processades.
FNRÍndex del fitxer actual que estem processant.
FILENAMENom del fitxer que estem processant.

Per exemple:

  • Utilitzeu la variable NR per simplificar la comanda per comptar el nombre de línies del fitxer pokemon.csv:

    awk 'END{ print NR }' pokemon.csv
    
  • Traduïu la capçalera del fitxer pokemon.csv al catala. La capçalera és la següent: # Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed Generation Legendary. La traducció és la següent: # Nom Tipus 1 Tipus 2 Total HP Atac Defensa Atac Especial Defensa Especial Velocitat Generació Llegendari. I després imprimiu la resta de línies del fitxer.

    awk 'NR==1 { $1="#"; $2="Nom"; $3="Tipus 1"; $4="Tipus 2"; $5="Total"; $6="HP"; $7="Atac"; $8="Defensa"; $9="Atac Especial"; $10="Defensa Especial"; $11="Velocitat"; $12="Generació"; $13="Llegendari"; print $0 } NR>1 {print}' pokemon.csv
    
  • Implementeu una comanda que permeti detectar entrades incorrectes a la pokedex. Un entrada incorrecta és aquella que no té 13 valors per línia. En cas de detectar una entrada incorrecta, la eliminarem de la sortida i comptarem el nombre de línies eliminades per mostrar-ho al final.

    awk 'NF != 13 { n++ } NF == 13 { print } END{ print "There are ", n, "incorrect entries." }' pokemon.csv
    

Condicionals

Les sentències condicionals s'utilitzen en qualsevol llenguatge de programació per executar qualsevol sentència basada en una condició particular. Es basa en avaluar el valor true o false en les declaracions if-else i if-elseif. AWK admet tot tipus de sentències condicionals com altres llenguatges de programació.

Implementeu una comanda que us indiqui quins pokemons de tipus foc són ordinaris o llegendaris. Busquem una sortida semblant a:

Charmander is a common pokemon.
Charizard is a legendary pokemon.
 ...

La condició per ser un pokémon llegendari és que la columna 13 sigui True.

awk -F, '/Fire/ { if ($13 == "True") { print $2, "is a legendary pokemon." } else { print $2, "is a common pokemon." } }' pokemon.csv

Es pot simplificar la comanda anterior amb l'ús de l'operador ternari ?::

awk -F, '/Fire/ { print $2, "is a", ($13 == "True" ? "legendary" : "common"), "pokemon." }' pokemon.csv

Formatant la sortida

AWK ens permet també utilitzar una funció semblant al printf de C. Permet imprimir la cadena amb diferents formats: printf("cadena",expr1,,expr2,...)

%20sEs mostraran 20 caràcters de la cadena alineats a la dreta per defecte.
%-20sEs mostraran 20 caràcters de la cadena alineats a l'esquerra per defecte.
%3dEs mostrarà un enter de 3 posicions alineat a la dreta
%03dEs mostrarà un enter de 3 posicions completat amb un 0 a l'esquerra i tot alineat a la dreta
%-3dEs mostrarà un enter de 3 posicions alineat a la esquerra.
&+3dIdem amb signe i alineat a la dreta
%10.2fEs mostrarà un nombre amb coma flotant amb 10 posicions, 2 de les quals seràn decimals.

Per exemple:

 awk -F, \
' BEGIN{ 
    max=0  
    min=100  
}  
{  
    if ($3 =="Fire") {  
        n++  
        attack+=$7
        
        if ($7 > max){  
            pmax=$2  
            max=$7  
        }  
        if ($7 < min){  
            pmin=$2
            min=$7  
        }  
    }  
}  
END{ printf("Avg(Attack):%4.2f \nWeakest:%s \nStrongest:%s\n",attack/n,pmin,pmax)
}' pokemon.csv 

Exercicis Intermedis

  • Implementeu un script que compti tots els pokemons que tenim a la pokedex i que tingui la sortida següent:

    Counting pokemons...
    There are 800 pokemons.
    

    Recordeu que la primera línia és la capçalera i no la volem comptar.

    • En bash:

      !/bin/bash
      echo "Counting pokemons..." 
      n=`wc -l pokemon.csv` 
      n=`expr $n - 1`
      echo "There are $n pokemons."
      
    • En AWK:

      awk 'BEGIN { print "Counting pokemons..." } { ++n } END{ print "There are ", n-1, "pokemons." }' pokemon.csv
      
  • Implementeu un comptador per saber tots els pokemons de tipus foc de la primera generació descartant els Mega pokemons i que tingui la sortida següent:

    Counting pokemons...
    There are 12 fire type pokemons in the first generation without Mega evolutions.
    
    • Per fer-ho en bash, podeu combinar les comandes grep, cut, wc i expr. Nota, l'argyment -v de grep exclou les línies que contenen el patró i la generació s'indica a la columna 12 amb el valor 1:

      !/bin/bash
      echo "Counting pokemons..."
      n=`grep Fire pokemon.csv | grep -v "Mega" | cut -d, -f12 | grep 1 | wc -l`
      n=`expr $n - 1`
      echo "There are $n pokemons in the first generation without Mega evolutions."
      
      • Per fer-ho en AWK, teniu el negador ! per negar el patró:
      awk -F, 'BEGIN { print "Counting pokemons..." } /Fire/ && !/Mega/ && $12 == 1 { ++n } END{ print "There are ", n, "fire type pokemons in the first generation without Mega evolutions." }' pokemon.csv
      

      En aquest exemple, hem utilitzat l'operador lògic && per combinar dos patrons. Això significa que la línia ha de contenir el patró Fire i no ha de contenir el patró Mega. Això ens permet filtrar els Mega pokemons del nostre comptador. A més, hem utilitzat l'operador ! per negar el patró Mega. Això significa que la línia no ha de contenir el patró Mega. Finalment, hem utilitzat la clàusula {END} per imprimir el resultat final.

  • Indiqueu a quina línia es troba cada pokémon del tipus foc. Volem imprimir la línia i el nom del pokémon. La sortida ha de ser semblant a:

    Line:  6    Charmander
    Line:  7    Charmeleon
    Line:  8    Charizard
    Line:  9    CharizardMega Charizard X
    Line:  10   CharizardMega Charizard Y
    ...
    Line:  737  Litleo
    Line:  738  Pyroar
    Line:  801  Volcanion
    

    on el format de cada línia és Line: n\tNom del pokémon.

    • En AWK podem fer servir la variable NR per obtenir el número de línia actual. A més a més, podeu formatar la sortida amb print cadena,variable,cadena,variable,...:

      awk -F, '/Fire/ {print "Line: ", NR, "\t" $2}' pokemon.csv
      
    • En bash:

      #!/bin/bash
      while IFS=, read -r col1 col2 col3 rest; do
      ((line_number++))
      # Check if the line contains the word "Fire"
      if [[ "$col2" == *"Fire"*  || "$col3" == *"Fire"* ]]; then
          echo "Line: $line_number    $col2"
      fi
      done < pokemon.csv
      
  • Implementeu un script que permeti comptar el nombre de pokemons de tipus foc i drac. La sortida ha de ser semblant a:

    Fire:64
    Dragon:50
    Others:689
    
    • En AWK:

      awk -F, 'BEGIN{ fire=0; dragon=0; others=0 } /Fire/ { fire++ } /Dragon/ { dragon++ } !/Fire|Dragon/ { others++ } END{ print "Fire:" fire "\nDragon:" dragon "\nOthers:" others }' pokemon.csv
      
    • En bash:

      #!/bin/bash
      fire=0
      dragon=0
      others=0
      
      while IFS=, read -r col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13; do
       if [[ "$col3" == *"Fire"*  || "$col4" == *"Fire"* ]]; then
           ((fire++))
       fi
      
       if [[ "$col3" == *"Dragon"*  || "$col4" == *"Dragon"* ]]; then
           ((dragon++))
       fi
       
       if [[ "$col3" != *"Fire"*  && "$col4" != *"Fire"* && "$col3" != *"Dragon"*  && "$col4" != *"Dragon"* ]]; then
           ((others++))
       fi
      done < pokemon.csv
      
      echo "Fire:$fire"
      echo "Dragon:$dragon"
      echo "Others:$others"
      
  • Imprimiu la pokedex amb una nova columna que indiqui la mitjana aritmètica dels atributs de cada pokémon. La sortida ha de ser semblant a:

    #,Name,Type 1,Type 2,Total,HP,Attack,Defense,Sp. Atk,Sp. Def,Speed,Generation,Legendary,Avg
    1,Bulbasaur,Grass,Poison,318,45,49,49,65,65,45,1,False,53
    2,Ivysaur,Grass,Poison,405,60,62,63,80,80,60,1,False,67.5
    3,Venusaur,Grass,Poison,525,80,82,83,100,100,80,1,False,87.5
    
    • En AWK:

      awk -F, '{ if (NR==1) print $0",Avg"; else print $0","($6+$7+$8+$9+$10+$11)/6 }' pokemon.csv
      
    • En bash:

      #!/bin/bash
      while IFS=, read -r col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13; do
      if [[ "$col1" == "#" ]]; then
          echo "$col1,$col2,$col3,$col4,$col5,$col6,$col7,$col8,$col9,$col10,$col11,$col12,$col13,Avg"
      else
          avg=$((($col6+$col7+$col8+$col9+$col10+$col11)/6))
          echo "$col1,$col2,$col3,$col4,$col5,$col6,$col7,$col8,$col9,$col10,$col11,$col12,$col13,$avg"
      fi
      done < pokemon.csv
      

      Nota: Bash de forma nativa no permet operacions aritmètiques amb nombres decimals. Per fer-ho, cal utilitzar una eina com bc. En aquest cas, podeu adaptar el codi per utilitzar bc quan calculeu la mitjana i fer servir printf per formatar la sortida amb el nombre de decimals que vulgueu.

  • Cerca el pokémon més fort i més feble tenint en compte el valor de la columna 7 dels pokemons de tipus foc de la primera generació.

    • En AWK, assumiu que el valors de la columna 7 van de 0 a 100:

      awk -F, 'BEGIN{ max=0; min=100 } /Fire/ && $12 == 1 { if ($7 > max) { max=$7; pmax=$2 } if ($7 < min) { min=$7; pmin=$2 } } END{ print "Weakest: "pmin "\nStrongest: "pmax }' pokemon.csv
      
    • En bash:

      #!/bin/bash
      max=0
      min=100
      while IFS=, read -r col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13; do
      if [[ "$col3" == *"Fire"* ]] && [[ "$col12" == "1" ]]; then
          if [[ "$col7" -gt "$max" ]]; then
          max=$col7
          pmax=$col2
          fi
          if [[ "$col7" -lt "$min" ]]; then
          min=$col7
          pmin=$col2
          fi
      fi
      done < pokemon.csv
      echo "Weakest: $pmin"
      echo "Strongest: $pmax"
      

Awk - Avançat

Variables definides quan executem AWK

VariableValor per defecteSignificat
RS/n (Salt de línia)Valor que fem servir per separar els registres (entrada)
FSEspais o tabulacionsValor que fem servir per separar els camps en l'entrada.
OFSespaiValor que fem servir per separar el camps en la sortida.
ORS/n (Salt de línia)Valor que fem servir per separar els registres (sortida).
ARGV-Taula inicialitzada amb els arguments de la línia de comandes (opcions i nom del script awk s'exclouen).
ARGC-Nombre d'arguments.
ENVIRONVariables entornTaula amb les variables entorn exportades per la shell.

Per exemple:

  • Transformeu el fitxer pokemon.csv en un fitxer amb els camps separats per tabulacions:

    awk -F, 'BEGIN{OFS="\t"} {print $0}' pokemon_tab.csv
    
  • Per fer servir el fitxer pokemon_tab.csv podem utilitzar els mateixos scripts que hem fet servir amb el fitxer pokemon.csv. Però indicant que el separador de camps és un tabulador. Per exemple, per comptar el nombre de pokemons lluitadors:

    awk -F"\t" '/Fighting/ {print $2}' pokemon_tab.csv
    
  • Si volem fer servir una variable entorn per indicar el tipus de pokemons que volem comptar, podem fer-ho així:

    awk -F"\t" -v type=$TYPE '{ if ($3 == type) { print $2 } }' pokemon_tab.csv
    

    on $TYPE és una variable entorn que conté el tipus de pokemons que volem comptar.

Bucles

El llenguatge AWK també ens permet fer bucles accepta les següents estructures:

  • for (expr1;expr2;expr3) { acció }: Aquest bucle executa la primera expressió, després avalua la segona expressió i si és certa executa l'acció. Després executa la tercera expressió i torna a avaluar la segona expressió. Això es repeteix fins que la segona expressió sigui falsa.

Per exemple, transformeu el fitxer pokemon.csv en un fitxer amb els camps separats per ; utilitzant un bucle for:

awk -F, \
'BEGIN{OFS=";";}
{  
for (i=1;i<=NF;i++)  
    printf("%s%s",$i,(i==NF)?"\n":OFS)
}' pokemon.csv
  • while (condició) { acció }: Aquest bucle executa l'acció mentre la condició sigui certa.

Per exemple, substituïu els camps del tipus de pokemon per un camps tipus compost per els dos tipus de pokemon separats per un / dels primers 10 pokemons:

awk -F, \
'BEGIN{OFS=",";}
{
while (NR>1 && NR <= 11) {
    print $1, $2, $3 "/" $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
    getline
}
}' pokemon.csv

La comanda getline ens permet llegir la següent línia de l'entrada. Això ens permet llegir la següent línia dins del bucle while. Si no fem servir la comanda getline, el bucle while es quedaria en un bucle infinit ja que la condició NR <= 11 sempre seria certa.

  • do { acció } while (condició): Aquest bucle executa l'acció una vegada i després avalua la condició. Si la condició és certa, torna a executar l'acció.

Per exemple, utilitzeu el bucle do per comptar el nombre de pokemons de tipus foc:

awk -F, \
'BEGIN{print "Counting pokemons..."; n=0}  
{
do {  
    if ($3 == "Fire" || $4 == "Fire")  
        n++  
} while (getline)  
}  
END{print "There are ", n, "fire type pokemons."}' pokemon.csv

Instruccions de control:

  • break: Finalitza el bucle actual.
  • continue: Salta a la següent iteració del bucle.
  • next: Salta a la següent línia de l'entrada.

Per exemple:

  • Cerqueu la primera entrada que compleixi les següents condicions: el tipus de pokemon és "Fire" i la seva velocitat és més gran que 100:

    awk -F, 'BEGIN {found = 0} { if (found == 0) { for (i=1; i<=NF; i++) { if ($i == "Fire" && $7 > 100) { print "El primer Pokémon de tipus Fire amb velocitat superior a 100 és: " $2; found = 1; break } } } }' pokemon.csv
    

    Observació: break finalitza el bucle actual que recorre els camps de la línia. Per tant, ens permet deixar de buscar en una línia quan ja hem trobat el que volem.

  • Cerqueu totes les entrades que compleixen les següents condicions: el tipus de pokemon és "Fire" i la seva velocitat és més gran que 100:

    awk -F, '{ for (i=1; i<=NF; i++) { if ($i == "Fire" && $7 > 100) { print $2 } } }' pokemon.csv
    

    o bé

    awk -F, '{ for (i=1; i<=NF; i++) { if ($i == "Fire" && $7 > 100) { print $2; break } } }' pokemon.csv
    

    Observació: break ens permet que quan trobem un pokemon que compleix les condicions, no cal seguir buscant en la mateixa línia i podem passar a la següent. En aquest cas, next seria equivalent a break.

  • Cerqueu tots els pokemons que són voladors i de foc assumint que les columnes poden estar en qualsevol ordre i que cada entrada pot estar ordenada de forma diferent:

    awk -F, '{ for (i=1; i<=NF; i++) { if ($i == "Fire") { for (j=1; j<=NF; j++) { if ($j == "Flying") { print $2; next } } } } }' pokemon.csv
    

    Observació: next ens permet que quan trobem un pokemon que compleix les condicions, no cal seguir buscant en la mateixa línia i podem passar a la següent.

    Observació: break ens donaria el mateix resultat en aquest cas. Però next és més eficient perquè no cal seguir recorrent els camps de la línia. La comanda break seguiria recorrent els camps al bucle de la variable i.

Arrays

AWK també ens permet fer servir arrays. Per exemple, podem fer servir un array per comptar el nombre de pokemons de cada tipus:

awk -F, '
{
    if (NR > 1) {
        type1 = $3
        type2 = $4
        types[type1]++
        if (type2 != "") {
            types[type2]++
        }
    }
}
END {
    for (type in types) {
        print type, types[type]
    }
}' pokemon.csv

Els arrays en AWK són associatius, és a dir, no cal indicar la posició de l'element en l'array. Per exemple, si volem comptar el nombre de pokemons de cada tipus per generació:

gawk -F, '
{
    if (NR > 1) {
        type1 = $3
        type2 = $4
        gen = $12
        types[type1][gen]++
        if (type2 != "") {
            types[type2][gen]++
        }
    }
}
END {
    for (type in types) {
        printf "%s\n", type
        for (gen in types[type]) {
            printf "  Gen %d: %d\n", gen, types[type][gen]
        }
    }
}' pokemon.csv

Nota: En aquest exemple, hem fet servir un array bidimensional. El llenguatge awk no permet declarar arrays multidimensionals, per poder fer-lo servir necessitem la extensió gawk. Per instal·lar-la, podeu fer servir la comanda apt install gawk o dnf install gawk.

Per fer-ho en AWK, podem utiltizar una clau combinada amb el tipus i la generació i la funció split per separar les dues claus:

awk -F, '
{
    if (NR > 1) {
        type1 = $3
        type2 = $4
        gen = $12
        types[type1 " " gen]++
        if (type2 != "") {
            types[type2 " " gen]++
        }
    }
}
END {
    for (typegen in types) {
        split(typegen, temp, " ")
        type = temp[1]
        gen = temp[2]
        printf "%s %d: %d\n", type, gen, types[typegen]
    }
}' pokemon.csv | sort -k2 -n

Exercicis Avançats AWK

  1. Implementeu un script que mostri la pokedex en ordre invers. Però mantenint la primera línia com a capçalera.

    awk -F, '
    {
        if (NR == 1) {
            print $0
        } else {
            lines[NR] = $0
        }
    }
    END {
        for (i = NR; i > 1; i--) {
            print lines[i]
        }
    }' pokemon.csv
    
  2. Implementeu un script que simuli la comanda sort -t, -k5 -n pokemon.csv. Aquesta comanda ordena el fitxer pokemon.csv pel camp Total de forma numèrica. Podeu fer servir la funció asort per ordenar els pokemons. Aquesta funció ordena un array i retorna el nombre d'elements de l'array ordenat. Per exemple:

    asort(array, sorted, "@val_num_asc")
    

    ordena l'array array de forma numèrica ascendent i guarda el resultat a l'array sorted.

    A més, podeu fer servir la funció split que ens permet dividir una cadena de text en un array. Per exemple:

    split("a,b,c,d", array, ",")
    

    divideix la cadena de text "a,b,c,d" en l'array array amb els valors "a", "b", "c" i "d".

    awk -F, '
    {
        if (NR == 1) {
            print $0
        } else {
            lines[NR] = $0
            totals[NR] = $5 " " NR
        }
    }
    END {
        n = asort(totals, sorted, "@val_num_asc")
        for (i = 1; i <= n; i++) {
            split(sorted[i], temp, " ")
            line = temp[2]
            print lines[line]
        }
    }' pokemon.csv
    
  3. Implementeu un script que mostri una taula resum amb els pokemons de cada tipus a cada generació. Un exemple de la sortida esperada:

    TipusGen 1Gen 2Gen 3Gen 4Gen 5Gen 6
    Normal24151818198
    Dragon42158129
    Ground14111612122
    Electric99512123
    Poison3645872
    Steel261212125
    Bug14121411183
    Grass151018172015
    Fire141196168
    Dark18137166
    Ice557894
    Fighting94910174
    Water35183115189
    Ghost4189915
    Flying23191416218
    Rock128127109
    Fairy5882314
    Psychic18102810168

    Notes:

    1. Els tipus de pokemons es troben a la columna 3 i 4 i la generació a la columna 12.
    2. Utilitzeu printf per formatar la sortida.
    • En AWK:
    awk -F, '
    BEGIN {
        print "| Tipus      | Gen 1 | Gen 2 | Gen 3 | Gen 4 | Gen 5 | Gen 6 |"
        print "|------------|-------|-------|-------|-------|-------|-------|"
    }
    {
        if (NR > 1) {
            type1 = $3
            type2 = $4
            gen = $12
            types[type1][gen]++
            if (type2 != "") {
                types[type2][gen]++
            }
        } 
    }
    END {
        for (type in types) {
            printf "| %-10s |", type
            for (gen = 1; gen <= 6; gen++) {
                printf " %-5s |", types[type][gen] ? types[type][gen] : 0
            }
            print ""
        }
    }' pokemon.csv
    
  4. Implementeu un parser que transformi el fitxer pokemon.csv en un fitxer pokemon.json. Aquest fitxer ha de ser formatat de forma correcta. Podeu assumir que coneixeu els headers del fitxer i la tipologia de les seves dades. Per exemple, la primera línia del fitxer pokemon.csv ha de ser transformada en:

    {
        "Name": "Bulbasaur",
        "Type 1": "Grass",
        "Type 2": "Poison",
        "Total": 318,
        "HP": 45,
        "Attack": 49,
        "Defense": 49,
        "Sp. Atk": 65,
        "Sp. Def": 65,
        "Speed": 45,
        "Generation": 1,
        "Legendary": false
    }
    
    • Una solució simple en AWK:
    awk -F, '
    BEGIN {
        print "["
    }
    {
        if (NR > 1) {
            printf "  {\n"
            printf "    \"Name\": \"%s\",\n", $2
            printf "    \"Type 1\": \"%s\",\n", $3
            printf "    \"Type 2\": \"%s\",\n", $4
            printf "    \"Total\": %d,\n", $5
            printf "    \"HP\": %d,\n", $6
            printf "    \"Attack\": %d,\n", $7
            printf "    \"Defense\": %d,\n", $8
            printf "    \"Sp. Atk\": %d,\n", $9
            printf "    \"Sp. Def\": %d,\n", $10
            printf "    \"Speed\": %d,\n", $11
            printf "    \"Generation\": %d,\n", $12
            printf "    \"Legendary\": %s\n", $13
            printf "  }%s\n", (NR == 800) ? "" : ","
        }
    }
    END {
        print "]"
    }' pokemon.csv > pokemon.json
    
    • Una solució més complexa en AWK:
    awk -F, '
    BEGIN {
       print "["
    }
    {
        if(NR == 1) {
            for (i = 2; i <= NF; i++) {
                headers[i] = $i
            }
        }
        else {
            if(NR != 2) {
                print "  },"
            }
            printf "  {\n"
            for (i = 2; i <= NF; i++) {
                if ($i ~ /^[0-9]+$/) {
                    printf "    \"%s\": %d,\n", headers[i], $i
                } else {
                    printf "    \"%s\": \"%s\",\n", headers[i], $i
                }
            }
        }
    }
    END {
        print "  }\n]"
    }' pokemon.csv > pokemon.json
    
  5. Implementeu un script que permeti simular un combat entre dos pokémons. Els pokémons es passen com a variables d'entorn i han d'utilitzar el nom del pokémon a la pokedex. La lògica del combat és comparar els valors de velocitat per saber qui ataca primer. El pokémon que ataca primer és el que té més velocitat. Si els dos pokémons tenen la mateixa velocitat, el primer pokémon que s'ha passat com a variable d'entorn ataca primer. El combat es fa de forma alternada fins que un dels dos pokémons es queda sense punts de vida. El dany es mesura com (Atac - Defensa) multiplicat per un valor aleatori entre 0 i 1. Aquest es resta a la vida del pokémon oponent. La sortida ha de ser semblant a:

    Charizard attacks first!
    Charizard attacks Charmander with 50 damage!
    Charmander has 20 HP left.
    Charmander attacks Charizard with 30 damage!
    Charizard has 70 HP left.
    Charizard attacks Charmander with 40 damage!
    Charmander has -10 HP left.
    Charmander fainted!
    
    • Una possible solució combinar AWK i bash:
    #!/bin/bash
    
    # Get the pokemons from the command line arguments
    pokemon1=$1
    pokemon2=$2
    
    # Function to get stats of a pokemon
    get_stats() {
        awk -F, -v pokemon="$1" '$2 == pokemon { print $6, $7, $8, $9, $10, $11 }' pokemon.csv
    }
    
    # Get the stats of the pokemons
    stats1=$(get_stats $pokemon1)
    stats2=$(get_stats $pokemon2)
    
    # Extract the stats
    read hp1 attack1 defense1 spatk1 spdef1 speed1 <<< $stats1
    read hp2 attack2 defense2 spatk2 spdef2 speed2 <<< $stats2
    
    # Check who attacks first
    if [ $speed1 -gt $speed2 ]; then
        attacker=$pokemon1
        hp=$hp2
        defender=$pokemon2
        attack=$attack1
        defense=$defense2
    else
        attacker=$pokemon2
        defender=$pokemon1
        hp=$hp1
        attack=$attack2
        defense=$defense1
    fi
    
    echo "$attacker attacks first!"
    
    # Start the battle
    while true; do
        damage=$((($attack - $defense) * $RANDOM / 32767))
        damage=${damage#-}
        hp=$(($hp - $damage))
        echo "$attacker attacks $defender with $damage damage!"
        if [ $hp -le 0 ]; then
            echo "$defender has 0 HP left."
            echo "$defender fainted!"
            break
        else
            echo "$defender has $hp HP left."
        fi
    
         # Swap the attacker and defender
        tmp=$attacker
        attacker=$defender
        defender=$tmp
        tmp=$hp
        hp=$hp2
        hp2=$tmp
        tmp=$attack
        attack=$attack2
        attack2=$tmp
        tmp=$defense
        defense=$defense2
        defense2=$tmp
    done
    

Repositori d'exercicis

Aquesta secció conté els exercicis realitzats pels estudiants de l'assignatura d'Administració i Manteniment de Sistemes i Aplicacions (AMSA).

Exercicis

Bàsics

Intermedis

Avançats

Arrancada del sistema

Quan arranquem un ordinador, tenen lloc una sèrie de processos que permeten que el sistema operatiu es carregui i es posi en marxa. Aquests processos són els que es coneixen com a arrancada del sistema. En un sistema linux, la seqüència d'arrancada es pot dividir en les següents fases:

  1. Càrrega del BIOS o UEFI. Quan encenem l'ordinador, el primer programa que s'executa està emmagatzemat en una memòria no volàtil (NVRAM). Aquest programa pot ser el BIOS (Basic Input/Output System) en sistemes més antics o l'UEFI (Unified Extensible Firmware Interface) en sistemes més moderns. Aquest firmware és el responsable de gestionar les funcions bàsiques del sistema abans de carregar el sistema operatiu.

  2. Test de l'ordinador. El BIOS o l'UEFI realitza un test de l'ordinador per assegurar-se que tots els components funcionen correctament. Aquest test s'anomena POST (Power-On Self Test). Si el test falla, l'ordinador emet una sèrie de senyals acústics o visuals per indicar quin component ha fallat.

  3. Selecció del dispositiu d'arrancada. El BIOS o l'UEFI permet triar quin dispositiu volem utilitzar per a carregar el sistema operatiu. Aquest dispositiu pot ser el disc dur, un dispositiu USB, un CD-ROM, etc..

  4. Identificació de la partició d'arrancada. El BIOS o UEFI localitza la partició d'arrencada del dispositiu seleccionat. En sistemes amb BIOS, es fa servir el Master Boot Record (MBR), mentre que en sistemes amb UEFI es fa servir la taula de particions GUID (GPT) per identificar la partició correcta (normalment, anomenada EFI). Aquesta partició conté el gestor d'arrencada i altres fitxers necessaris per continuar el procés d'arrencada.

  5. Càrrega del gestor d'arrancada. El BIOS o UEFI carrega el gestor d'arrencada. El gestor d'arrancada és un petit programa que permet triar quin sistema operatiu volem carregar. Els gestors d'arrencada més comuns en sistemes Linux són GRUB (Grand Unified Bootloader) o LILO (Linux Loader). Aquests gestors d'arrancada mostren una llista amb els sistemes operatius disponibles i permeten triar-ne un.

  6. Càrrega del kernel. En aquesta fase, el gestor d'arrancada descomprimeix el codi del nucli i el carrega a la memòria.

  7. Càrrega del sistema de fitxers inicial. El nucli carrega un sistema de fitxers inicial (initramfs o initrd) que conté els mòduls i els programes necessaris per muntar el sistema de fitxers real del sistema operatiu.

  8. Sistema d'inicialització. És el primer procés que s'executa en un sistema operatiu en l'espai usuari. En el cas de GNU/Linux, el sistema d'inicialització més comú és el systemd. Una altre gestor d'arrancada, més vell però molt utilitzat és el SysVInit (Init).

  9. Execució dels targets o runlevels. El sistema d'inicialització carrega els diferents targets o runlevels, que defineixen l'estat del sistema en un moment determinat. Aquests runlevels poden ser diferents nivells d'arrencada, com arrencada en mode gràfic o mode de recuperació. Cada runlevel pot tenir diferents serveis i daemons activats o desactivats.

  10. Execució dels scripts d'arrancada. El sistema d'inicialització executa els scripts d'arrancada definits per a cada runlevel. Aquests scripts són responsables de configurar els serveis i daemons del sistema, com ara la xarxa, els dispositius de maquinari, els sistemes de fitxers, entre altres.

  11. Inici de la Sessió d'Usuari. Finalment, el sistema està preparat per a l'usuari. Si el sistema està configurat per a un entorn gràfic, es carrega el gestor de finestres o l'entorn d'escriptori. En sistemes sense entorn gràfic, es presenta una línia de comandes. En aquest punt, l'usuari pot iniciar sessió i començar a utilitzar el sistema.

  12. Execució dels scripts d'inici de sessió. Un cop iniciada la sessió, s'executen els scripts d'inici de sessió de l'usuari. Aquests scripts poden configurar variables d'entorn, carregar programes o configurar preferències de l'usuari. Això permet personalitzar l'experiència de l'usuari i preparar l'entorn de treball.

Etapes de l'arrancada en un sistema linux

En aquest laboratori veurem totes aquestes fases en una màquina virtual i modificarem els paràmetres per veure com afecten als sistemes.

Objectius

  • Entendre com funciona el procés d'arrancada del sistema.
  • Conèixer els diferents components implicats en l'arrancada del sistema.
  • Apendre a gestionar i optimitzar el procés d'arrancada.

Continguts

  1. UEFI i dispositius d'arrancada
  2. GRUB
  3. initramfs
  4. Inici del sistema i Dimonis de gestió de serveis

Activitats

Realització de les tasques: 50%

S'ha de mostrar en un document amb format lliure les evidències de la realització de les tasques. Aquest document es pot incloure al informe tècnic o es pot lliurar com a document adjunt. En aquest document heu de mostrar les dificultats trobades i com les heu resolt. Us recomano que feu servir eines de captura de pantalla per a mostrar les evidències. Per exemple, podeu incloure una secció anomenada Troubleshooting on mostreu les dificultats trobades i com les heu resolt.

Informe tècnic: 50%

El informe tècnic ha de contenir respostes a les preguntes plantejades a continuació:

  1. Investigació d'una unitat del sistema

    • Elegeix una unitat del sistema, com ara ssh.service, i investiga la seva funció i configuració.
    • Utilitza les comandes systemctl status i systemctl cat per obtenir més informació sobre la unitat.
    • Inclou a l'informe els resultats de la teva investigació:
      • Descripció de la unitat.
      • Documentació associada.
      • Dependències i condicions.
      • Tipus de servei i comandaments d'inici i parada.
      • Temps d'execució i estat actual.
  2. Comparació entre arrencada amb i sense interfície gràfica

    • Instal·la la interfície gràfica utilitzant la comanda tasksel i selecciona l'opció Debian desktop environment.
    • Compara el temps d'arrencada del sistema amb i sense interfície gràfica utilitzant la comanda systemd-analyze.
    • Inclou al informe de la diferència entre arrencar el sistema amb una interfície gràfica i sense interfície gràfica, incloent:
      • Temps d'arrencada del kernel i l'espai d'usuari.
      • Unitats crítiques i temps d'arrencada.
      • Avantatges i desavantatges de cada configuració
  3. Dissenyeu un escenari real on un script d'arrancada podria ser útil

    • Pensa en un escenari real on un script d'arrancada podria ser útil per configurar l'entorn de l'usuari.
    • Crea un script d'arrancada que realitzi una tasca específica en aquest escenari.
    • Configura el script d'arrancada perquè s'executi automàticament quan un usuari inicia una sessió de terminal.
    • Inclou a l'informe amb els detalls de l'escenari i el script d'arrancada, incloent:
      • Descripció de l'escenari i la tasca a realitzar.
      • Contingut del script d'arrancada.
      • Configuració del script d'arrancada per a l'usuari.

Rúbriques d'avaluació

Criteris d'avaluacióExcel·lent (5)Notable(3-4)Acceptable(1-2)No Acceptable (0)
ContingutEl contingut és molt complet i detallat. S'han cobert tots els aspectes de la tasca.El contingut és complet i detallat. S'han cobert la majoria dels aspectes de la tasca.El contingut és incomplet o poc detallat. Falten alguns aspectes de la tasca.El contingut és molt incomplet o inexistent.
Precisió i exactitudLa informació és precisa i exacta. No hi ha errors.La informació és precisa i exacta. Hi ha pocs errors.La informació és imprecisa o inexacta. Hi ha errors.La informació és molt imprecisa o inexacta. Hi ha molts errors.
OrganitzacióLa informació està ben organitzada i estructurada. És fàcil de seguir.La informació està organitzada i estructurada. És fàcil de seguir.La informació està poc organitzada o estructurada. És difícil de seguir.La informació està molt poc organitzada o estructurada. És molt difícil de seguir.
Diagrames i il·lustracionsS'han utilitzat diagrames i il·lustracions de collita pròpia per aclarir la informació. Són molt útils.S'han utilitzat diagrames i il·lustracions de collita pròpia per aclarir la informació. Són útils.S'han utilitzat pocs diagrames o il·lustracions de collita pròpia. Són poc útils.No s'han utilitzat diagrames o il·lustracions de collita pròpia.
PlagiNo hi ha evidències de plagi. Tota la informació és original.Hi ha poques evidències de plagi. La majoria de la informació és original.Hi ha evidències de plagi. Alguna informació no és original.Hi ha moltes evidències de plagi. Poca informació és original.
BibliografiaS'ha inclòs una bibliografia completa i detallada.S'ha inclòs una bibliografia completa.S'ha inclòs una bibliografia incompleta.No s'ha inclòs una bibliografia.
EstilL'estil és molt adequat i professional. S'ha utilitzat un llenguatge tècnic precís.L'estil és adequat i professional. S'ha utilitzat un llenguatge tècnic precís.L'estil és poc adequat o professional. Hi ha errors en el llenguatge tècnic.L'estil és molt poc adequat o professional. Hi ha molts errors en el llenguatge tècnic.

UEFI i dispositius d'arrancada

El Unified Extensible Firmware Interface (UEFI) és un estàndard de firmware dissenyat per reemplaçar els dissenys antics anomenats BIOS. Els principals problemes de les BIOS eren la falta d'estandardització.

ℹ️ UEFI o EFI?

La UEFI i la EFI són pràcticament el mateix. La EFI va ser el primer estàndard, però amb el temps va evolucionar cap a la UEFI actual.

En aquest laboratori, analitzarem el funcionament de la UEFI i com podem utilitzar-la.

Objectius

  • Conèixer el funcionament de la UEFI.
  • Impacte de la UEFI en l'arrancada del sistema.
  • Apendre les funcions bàsiques de la consola UEFI.
  • Configurar la UEFI per a diferents finalitats.

Preparació

  1. Inicieu una màquina virtual amb el sistema operatiu AlmaLinux anomenada VM1. Podeu utilitzar la configuració per defecte.

  2. Inicieu una altra màquina virtual amb el sistema operatiu Debian anomenada VM2. Podeu utilitzar també la configuració per defecte.

  3. Afegiu a la màquina virtual VM1 el disc virtual de la màquina virtual VM2 o viceversa. Per fer-ho amb VMWare:

    • Apagueu la màquina virtual.
    • Aneu a la configuració de la màquina virtual.
    • Aneu a Add.
    • Selecciona Hard Disk.
    • Selecciona Use an existing disk.
    • Selecciona el disc virtual de la màquina virtual que vulgueu afegir.
    • Inicieu la màquina virtual.

    Un cop iniciada la màquina virtual, no hauríeu de detectar cap canvi. No obstant això, si inicieu sessió a la màquina virtual, podreu veure el disc afegit utilitzant la comanda lsblk.

    [root@localhost ~]# lsblk
    NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    sr0                 11:0    1  1.7G  0 rom
    nvme0n1            259:0    0   20G  0 disk
    ├─nvme0n1p1        259:1    0  600M  0 part /boot/efi
    ├─nvme0n1p2        259:2    0    1G  0 part /boot
    └─nvme0n1p3        259:3    0 18.4G  0 part
    ├─almalinux-root 253:0    0 16.4G  0 lvm  /
    └─almalinux-swap 253:1    0    2G  0 lvm  [SWAP]
    nvme0n2            259:4    0   20G  0 disk
    ├─nvme0n2p1        259:5    0  512M  0 part
    ├─nvme0n2p2        259:6    0 18.5G  0 part
    └─nvme0n2p3        259:7    0  976M  0 part
    

    On nvme0n2 és el disc afegit que conté la instal·lació de Debian i nvme0n1 és el disc original que conté la instal·lació d'AlmaLinux.

Tasques

  1. Inciant la consola UEFI
  2. Observant els Dispositius Disponibles
  3. Navegant per la Consola UEFI
  4. Arrancant des d'una Partició EFI
  5. Automatitzant l'Arrancada
  6. Creant una Entrada d’Arrancada Personalitzada

Inciant la consola UEFI

Per accedir a la consola UEFI, seguiu aquests passos:

  1. Inicieu la màquina virtual VM1.

  2. Premeu la tecla ``ESC`durant l'arrencada de la màquina virtual per accedir a Boot Manager.

    Boot Manager

  3. Seleccioneu EFI Internal Shell per accedir a la consola UEFI.

    EFI Internal Shell

La consola UEFI és una interfície de text que permet interactuar amb el firmware de la màquina. El primer que necessiteu saber es com interactuar amb la consola. Per això, podeu utilitzar la comanda help per obtenir una llista de comandes disponibles.

Observant els Dispositius Disponibles

Un dels usos més comuns de la consola UEFI és la selecció del dispositiu d'arrancada. Per veure quins dispositius estan disponibles, podeu utilitzar la comanda map.

Shell> map

Aquesta comanda us mostrarà una llista de tots els dispositius disponibles i les seves adreces. Això us permetrà identificar quin dispositiu voleu utilitzar per a l’arrancada. En el nostre cas, us retornarà una llista similar a aquesta:

  • FS0: Alias(s):CD0B0A0;;BLK1: PciRoot(OxO)/Pci(0x11,0x0)/Pci(0x3,0x0)/Sata(0x1,0x0,0x0)/CDROM(0x0)

  • FS1: Alias(s):HD1b;;BLK3: PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(1,GPT,61942D3C-DD95-47F4-8C57-C22009E9C7BA,0x800,0x12C000)

  • FS2: Alias(s):HD2b;;BLK7: PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x2,00-00-00-00-00-00-00-00)/HD(1,GPT,8DD9095B-5B0C-45A3-A026-33DE34ED23B5,0x800,0x10000)

  • BLK0: Alias(s): PciRoot(0x0)/Pci(0x11,0x0)/Pci(0x3,0x0)/Sata(0x1,0x0,0x0)

  • BLK2: Alias(s): PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)

  • BLK6: Alias(s): PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x2,00-00-00-00-00-00-00-00)

  • BLK4: Alias(s): PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(2,GPT, 7D330E0D-0E09-440C-A79D-9239BD9F11C0,0x12C800,0x200000)

  • BLK5: Alias(s): PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00)/HD(3,GPT, 94B55114-4795-4748-AD0E-BB068D437691,0x32C800,0x24D3000)

  • BLK8: Alias(s): PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x2,00-00-00-00-00-00-00-00)/HD(2,GPT, 760F1F2F-BA6F-479C-8D4D-8FA31D9226F6,0x100800,0x251700)

  • BLK9: Alias(s): PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x2,00-00-00-00-00-00-00-00)/HD(3,GPT, CD375C90-A2BA-4507-9263-55BE97B26672,0x2617800,0x1E8000)

En aquest cas, tenim 3 sistemes de fitxers (FS0, FS1, FS2) i diversos dispositius de bloc (BLK0, BLK2, BLK6, BLK4, BLK5, BLK8, BLK9).

Els sistemes de fitxers representen dispositius que contenen un sistema de fitxers que la UEFI pot llegir. Això inclou dispositius com discos durs, SSDs, i CD-ROMs. Per exemple, FS0 representa un CD-ROM, mentre que FS1 i FS2 representen discos durs.

Els dispositius de bloc representen dispositius de baix nivell que no necessàriament tenen un sistema de fitxers que la UEFI pot llegir. Això inclou dispositius com discos durs, SSDs, i CD-ROMs, així com particions individuals dins d’aquests dispositius.

En els sistemes EFI, hi ha una partició especial anomenada Partició de Sistema EFI (ESP) que conté els fitxers d’arrancada del sistema operatiu. Aquesta partició es pot identificar pel seu tipus de sistema de fitxers EFI. Normalment utilitza un sistema de fitxers basat en FAT32. En aquest cas, els sistemes de fitxers FS1 i FS2 són les particions ESP dels discos durs NVMe1 i NVMe2 respectivament. A més, podem veure que els dos discos durs NVMe1 i NVMe2 tenen una taula de particions GPT i que la primera partició correspon a la partició ESP. Es pot veure el seu UUID, l’adreça d’inici i l’adreça final de la partició.

👁️ Observació

Les particions EFI sempre acostumen ser la primera partició de la taula de particions GPT. Això es deu a que UEFI sempre busca la partició EFI per carregar el gestor d’arrancada.

Els dispositius de bloc representen els discos durs i les seves particions. En aquest cas, tenim dos discos durs NVMe1 i NVMe2 amb les seves particions. Fixeu-vos que podem identificar el disc NVMe1 o NVMe2 amb BLK2 o BLK6 respectivament. A més, podem veure les particions del disc NVMe1 amb BLK4 i BLK5 i les particions del disc NVMe2 amb BLK8 i BLK9. En totes les entrades es pot veure el UUID de la taula de particions GPT, l’adreça d’inici i l’adreça final de la partició.

👁️ Observació

La etiqueta NVMe indica que el disc és un disc NVMe. Si el disc fos un disc SATA, la etiqueta seria SATA. En funció del hardware de la màquina virtual, els discos poden tenir diferents etiquetes.

Navegant per la Consola UEFI

Un cop identificats els dispositius disponibles, podeu utilitzar la consola UEFI per navegar per ells. Per exemple, per accedir a la partició ESP del disc NVMe1, podeu utilitzar la següent comanda:

Shell> fs1:

Això canviarà el directori de treball actual a la partició ESP del disc NVMe1. Si ara voleu accedir a fs2, podeu utilitzar la comanda fs2:.

Shell> fs2:

⚠️ Compte La consola UEFI acostuma a tenir un keymap diferent al vostre. Els caràcters poden no ser els mateixos que els que veieu a la pantalla. Per exemple, la tecla : pot ser ñ o la tecla / pot ser -. Si teniu problemes amb les tecles podeu consultar el keymap de VMWare a la documentació oficial.

Un cop hàgiu accedit a una partició, podeu utilitzar la comanda ls per veure el contingut de la partició.

FS1:\> ls

La comanda ls us mostrarà una llista dels fitxers i directoris del directori actual. En aquest cas, veureu els fitxers i directoris del directori arrel de la partició ESP.

Finalment, podeu utilitzar la comanda cd per canviar de directori.

FS1:\> cd EFI
FS1:\EFI> ls
FS1:\EFI> cd ..

Arrancant des d'una Partició EFI

Per arrancar la màquina virtual VM1 amb el disc NVMe2 seleccionat com a dispositiu d'arrancada (això carregarà el sistema operatiu Debian), seguiu aquests passos:

  1. Navegueu a la partició ESP del disc NVMe2.

    Shell> fs2:
    
  2. Navegueu al directori EFI i seleccioneu el directori del sistema operatiu Debian.

    FS2:\> cd EFI
    FS2:\EFI> cd debian
    
  3. Llisteu el contingut del directori per veure els fitxers d'arrancada.

    En aquest directori, podeu observar diferents fitxers que acaben amb .efi. Aquests fitxers són els fitxers d'arrancada del sistema operatiu Debian. El nom ens indica el tipus de firmware que utilitzen. Per exemple, grubaa64.efi és el fitxer d'arrancada del gestor d'arrancada GRUB per a sistemes de 64 bits.

    ℹ️ Quina és la diferència entre shimx64.efi, grubx64.efi, fbx64, mmx64?

    Les principals diferències entre aquests fitxers són el tipus de firmware que utilitzen i la seva funció. El fitxer shimx64.efi és un fitxer d'arrancada segur que permet carregar altres fitxers d'arrancada segurs. El fitxer grubx64.efi és el fitxer d'arrancada del gestor d'arrancada GRUB. Els fitxers fbx64.efi i mmx64.efi no són específics de cap sistema operatiu, sinó que són part del firmware UEFI i proporcionen funcionalitats addicionals.

  4. Seleccioneu el fitxer d'arrancada del grub per a arrancar el sistema operatiu Debian.

    FS2:\EFI\debian> grubaa64.efi
    

Això carregarà el gestor d'arrancada GRUB i us permetrà seleccionar el sistema operatiu Debian per a l'arrancada.

Automatitzant l'Arrancada

👁️ Observació:

Aquest procediment és una mica tedios i ens pot resultar poc eficient si hem d'arrencar el sistema operatiu Debian sovint.

Per automatitzar l'arrancada del sistema operatiu Debian, podeu utilitzar la comanda boot de la consola UEFI. Aquesta comanda us permetrà carregar un fitxer d'arrancada directament sense haver de navegar per la partició ESP.

boot fs2:\EFI\debian\grubaa64.efi

Tot i que aquesta comanda pot ser útil, encara requereix accedir manualment a la consola UEFI i introduir la comanda. Per tant, ara veurem com crear una entrada d'arrancada personalitzada a la taula d'arrancada de la UEFI semblant a la ja existent per a l'arrancada d'AlmaLinux anomenda AlmaLinux.

Creant una Entrada d’Arrancada Personalitzada

La UEFI manté una taula d’arrancada que conté una llista d’entrades d’arrancada. Cada entrada correspon a un sistema operatiu o aplicació que pot ser arrancada per la UEFI. Per exemple, si tenim instal·lats els sistemes operatius AlmaLinux i Debian en la mateixa màquina, cada un tindrà la seva pròpia entrada d’arrancada a la taula d’arrancada de la UEFI.

Per crear una nova entrada d’arrancada per al sistema operatiu Debian, podem utilitzar la comanda bcfg de la consola UEFI. Aquesta comanda proporciona una interfície per gestionar la taula d’arrancada de la UEFI.

  1. Reinicieu la màquina virtual i accediu a la consola UEFI.

  2. Utilitzeu la comanda bcfg boot add per crear una nova entrada d’arrancada. Per exemple, per afegir una nova entrada amb el nom Debian i el fitxer BOOTAA64.EFI de la partició FS2, utilitzeu la següent comanda:

    bcfg boot add 6 fs2:\EFI\debian\grubaa64.efi Debian
    

    En aquesta comanda, 6 és el número de la nova entrada a la UEFI. Aquest número ha de ser únic i no pot ser repetit. Si ja tenim una entrada amb el número 3, haurem de canviar el número per un altre número que no estigui en ús. Per saber quins números estan en ús, podem utilitzar la comanda bcfg boot dump.

  3. Un cop creada la nova entrada d’arrancada, podem voler canviar la seva posició a la llista d’arrancada. Per exemple, si volem que la nova entrada sigui la segona opció d’arrancada, podem utilitzar la comanda:

    bcfg boot mv 6 1
    

    En aquesta comanda, 6 és el número de l’entrada que volem moure, i 1 és la nova posició de l’entrada a la llista d’arrancada.

    ✏️ Nota:

    Els items es numeren de 0 a n-1, on n és el nombre d'entrades.

  4. Ara tenim la entrada AlmaLinux i Debian a la UEFI. Podem sortir de la consola UEFI i reiniciar la màquina virtual. Ara, quan accedim a la consola UEFI, veurem dues opcions: AlmaLinux i Debian.

EFI Internal Shell

Amb aquesta configuració, podem seleccionar quin sistema operatiu volem arrancar directament des del menú d’arrancada de la UEFI, sense haver d’accedir a la consola UEFI.

GRUB

El GRUB (Grand Unified Bootloader) és un gestor d'arrancada que s'utilitza en la majoria de les distribucions de GNU/Linux. El UEFI és l'encarregat de carregar el GRUB, En aquest laboratori veurem com funciona el GRUB i com podem configurar-lo per a arrancar amb diferents sistemes operatius.

👁️ Observació:

GRUB no és l'únic gestor d'arrancada que es pot utilitzar en un sistema GNU/Linux. Però és el més comú i el que s'utilitza per defecte en la majoria de les distribucions. Altres gestors d'arrancada com el LILO (Linux Loader) o rEFInd també són compatibles amb GNU/Linux.

Preparació

  1. Entorn de treball: Màquina virtual amb una distribució GNU/Linux instal·lada pot ser Debian o AlmaLinux. La màquina virtual pot tenir una configuració per defecte. Característiques de la màquina virtual:

    • Disc dur virtual de 20 GB.
    • 1 CPU.
    • 1 GB de memòria RAM.

    Configuració de la màquina virtual

    A més, inicialitzeu com a mínim un usuari root amb contrasenya (pot ser 1234).

    Estat inicial de la màquina virtual

✏️ Nota:

En el meu cas he utilitzat una màquina virtual amb la imatge de Debian 12 proporcionada al inici de curs al campus virtual.

Tasques

  1. Modificació de les opcions del GRUB
  2. Accés no autoritzat a través del GRUB
  3. Dual Boot
  4. Anàlisi del procediment
  5. Actualitzant el GRUB

Modificació de les opcions del GRUB

Com heu pogut observar, la instal·lació del sistema operatiu Debian 12 ha configurat el GRUB de forma predeterminada.

GRUB de Debian 12

En aquesta pantalla, podeu observar 3 entrades:

  1. Debian GNU/Linux. Aquesta és l'entrada per defecte que carrega el sistema operatiu Debian 12.

  2. Advanced options for Debian GNU/Linux. Aquesta entrada permet seleccionar una versió específica del kernel per a carregar.

    Opcions avançades del GRUB

    En el nostre cas, podem seleccionar entre la versió 6.1.0-23 i la 6.1.0-18 ambdues amb les opcions recovery mode.

    ℹ️ Què és el mode de recuperació?

    El mode de recuperació és un mode d'arrancada que carrega el sistema amb un conjunt de paràmetres mínims. Això permet accedir al sistema en un estat més bàsic i realitzar tasques de manteniment o recuperació del sistema.

  3. UEFI Firmware Settings. Aquesta entrada permet accedir a la configuració de la UEFI.

Modificació de les opcions del GRUB (temporal)

Seleccioneu l'entrada Debian GNU/Linux i premeu la tecla e per a editar les opcions de l'arrencada de forma temporal, és a dir, aquestes opcions només es mantindran durant l'arrencada actual del sistema.

Configuració de l'entrada debian del GRUB

En aquesta pantalla, podeu observar les opcions de l'arrencada del sistema. Si analitzem la informació tenim:

  1. Carreguem els mòduls del kernel:

    ℹ️ Per què carreguem aquests mòduls?

    Els mòduls del kernel són programes que s'executen en l'espai del nucli del sistema operatiu. Aquests mòduls permeten al sistema operatiu interactuar amb el maquinari de l'ordinador. En aquest cas, carreguem els mòduls necessaris per a interactuar amb el disc dur i el sistema de fitxers.

    • load_video: Aquest mòdul s’encarrega de la inicialització del subsistema de vídeo. És necessari per a la correcta visualització de la interfície gràfica durant l’arrancada.
    • insmod gzio: Aquest mòdul permet al kernel llegir fitxers comprimits en format gzip. És útil per a carregar imatges del kernel o del sistema d’inicialització que estiguin comprimits.
    • insmod part_gpt: Aquest mòdul permet al kernel llegir particions de disc que utilitzen la taula de particions GUID (GPT). GPT és un estàndard modern per a la disposició de la taula de particions en un disc dur.
    • insmod ext2: Aquest mòdul permet al kernel llegir i escriure en sistemes de fitxers ext2. Ext2 és un sistema de fitxers comú en Linux, encara que ara s’utilitza menys en favor de ext3 i ext4.
  2. Indiquem el dispositiu on es troba el sistema operatiu:

    • search --no-floppy --fs-uuid --set=root xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    on xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx és l'identificador únic del dispositiu on es troba el sistema operatiu.

  3. Carreguem el kernel del sistema operatiu;

    • linux /boot/vmlinuz-6.1.0.23-arm64 root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ro quiet

    on les opcions són:

    • ro: indica que el sistema s'ha de muntar en mode de només lectura.
    • quiet: indica que el sistema s'ha de carregar sense mostrar missatges.
  4. Finalment, carreguem el sistema d'inicialització:

    • initrd /boot/initrd.img-6.1.0.23-arm64

    ℹ️ Què és el sistema d'inicialització?

    El sistema d'inicialització és el primer procés que s'executa en un sistema operatiu. En el cas de GNU/Linux, el sistema d'inicialització més comú és el systemd. Aquest sistema d'inicialització s'encarrega de carregar els serveis i els daemons del sistema operatiu.

Modifiquem les opcions de l'arrencada per mostrar els missatges del sistema durant l'arrencada. Per a fer-ho, eliminem l'opció quiet de la línia linux i premem la tecla ctrl+x o F10 per a iniciar el sistema amb les opcions modificades.

Modificació de les opcions de l'arrencada del GRUB

Ara, el sistema mostrarà els missatges durant l'arrencada.

Modificació de les opcions del GRUB (permanent)

Aquestes opcions només es mantindran durant l'arrencada actual del sistema. Per a fer que aquestes opcions es mantinguin de forma permanent, haurem de modificar el fitxer de configuració del GRUB. Aquest fitxer normalment es troba a /etc/default/grub.

  1. Accedeix al sistema amb l'usuari root.

  2. Fes una còpia de seguretat del fitxer de configuració del GRUB.

    cp /etc/default/grub /etc/default/grub.bak
    
  3. Edita el fitxer de configuració del GRUB amb un editor de text com vi.

    vi /etc/default/grub
    

    Observareu un fitxer similar al: Edició del fitxer de configuració del GRUB

  4. Busca la línia que comença amb GRUB_CMDLINE_LINUX_DEFAULT i modifica-la per a afegir les opcions que vulguis. Per exemple, per a mostrar els missatges del sistema durant l'arrencada, elimina l'opció quiet.

    💡 Nota:

    Les opcions del GRUB es separen per espais. Per a afegir una nova opció, simplement afegeix-la a la llista separada per un espai.


    🔍 Pregunta: Quines altres opcions podries afegir al fitxer de configuració del GRUB?

    Algunes opcions comunes que es poden afegir al fitxer de configuració del GRUB són:

    • GRUB_TIMEOUT: temps d'espera per a seleccionar una entrada del GRUB.
    • GRUB_DISABLE_OS_PROBER: per defecte, en debian es troba activada. Per tant, no detectarà altres sistemes operatius instal·lat en el sistema.
  5. Desa els canvis i surt de l'editor de text.

  6. Un cop hagis modificat el fitxer de configuració del GRUB, hauràs de regenerar el fitxer de configuració del GRUB amb la comanda següent:

    update-grub
    

    Aquesta comanda regenerarà el fitxer de configuració del GRUB amb les opcions que has definit. Aquest fitxer es troba a /boot/grub/grub.cfg. Pots veure el contingut d'aquest fitxer amb la comanda següent:

    less /boot/grub/grub.cfg
    

    ⚠️ Compte:

    No modifiquis manualment el fitxer /boot/grub/grub.cfg. Aquest fitxer es genera automàticament amb la comanda update-grub i qualsevol modificació manual es sobreescriurà en la propera generació del fitxer.

  7. Reinicia el sistema per a aplicar els canvis.

    reboot
    

Un cop reiniciat el sistema, el GRUB carregarà el sistema amb les opcions que has definit. Ara, el sistema mostrarà els missatges durant totes les arrencades.

Accés no autoritzat a través del GRUB

Assumeix que teniu un servidor instal·lat amb un carregar de sistema GRUB. Un atacant ha conseguit accés físic al vostre servidor i vol modificar la contrasenya de l'usuari root per a poder accedir al sistema amb privilegis d'administrador. Per a fer-ho, l'atacant ha reiniciat el sistema i ha accedit al carregador de sistema GRUB. A continuació assumirem el rol i veurem com podem accedir al sistema operatiu i modificar la contrasenya de l'usuari root a través del carregador de sistema GRUB.

  1. Reinicia el sistema i accedeix al carregador de sistema GRUB.

  2. Selecciona el sistema operatiu que vols arrancar i prem la tecla e per a editar les opcions de l'arrencada.

    Configuració de la entrada debian del GRUB

  3. Busca la línia que comença amb linux i acaba amb ro i afegeix-hi la següent opció: init=/bin/bash.

    Modificació de la línia linux del GRUB

    ✏️ Nota:

    La opció ro indica que el sistema s'ha de muntar en mode de només lectura. Això significa que no es poden modificar els fitxers del sistema. Afegint la opció init=/bin/bash, indiquem al sistema que ha d'iniciar el procés d'inicialització amb /bin/bash en lloc del sistema d'inicialització habitual. Això ens permetrà accedir al sistema amb un intèrpret de comandes bash sense haver d'iniciar el sistema completament.

  4. Prem la tecla Ctrl + X per a iniciar el sistema amb les opcions modificades.

  5. Un cop iniciat el sistema, hauries d'accedir a una consola bash.

    Consola bash iniciada des del GRUB

  6. Un cop aquí, montarem el sistema de fitxers en mode de lectura i escriptura amb la comanda següent:

    mount -o remount,rw /
    
  7. Ara que el sistema esta muntat, accedirem al sistema amb una chroot per a poder modificar la contrasenya de l'usuari root. Per a fer-ho, executa la comanda següent:

    chroot /
    

    ℹ️ Què és una chroot?

    Una chroot és un entorn aïllat que permet executar programes en un directori arrel diferent del directori arrel del sistema. Això ens permet accedir al sistema com si estiguéssim dins del directori arrel del sistema, però sense haver d'iniciar el sistema completament. Això és útil per a realitzar tasques de manteniment o recuperació del sistema sense haver d'iniciar el sistema completament.

  8. Un cop dins de la chroot, modifica la contrasenya de l'usuari root amb la comanda passwd:

    passwd
    
  9. Introdueix la nova contrasenya de l'usuari root i confirma-la.

  10. Un cop modificada la contrasenya, surt de la chroot amb la comanda exit:

    exit
    
  11. Reinicia el sistema amb la comanda reboot:

    reboot
    
  12. Un cop reiniciat el sistema, accedeix amb l'usuari root i la nova contrasenya que has definit.

🔍 Pregunta: Com podriam protegir els nostres servidors d'aquestes situacions?

  • La principal manera de protegir els servidors d'aquest tipus d'atacs és assegurar-se que només les persones autoritzades poden accedir físicament al servidor.
  • Configurar el GRUB perquè requereixi una contrasenya per a poder editar les opcions de l'arrencada és una bona pràctica. Això dificulta l'accés no autoritzat al sistema a través del GRUB.

👁️ Observació:

Malgrat l'ús d'una contrasenya per a protegir el GRUB, aquesta tècnica no és infal·lible. Un atacant amb accés físic pot montar un usb bootable i iniciar el sistema amb aquest dispositiu. Un cop iniciat el sistema, l'atacant podria montar el sistema de fitxers i modificar la contrasenya de l'usuari root. Ara bé, es podria configurar el BIOS o UEFI per a desactivar l'arrencada des de dispositius externs com els USBs. Això dificultaria l'accés no autoritzat al sistema a través d'aquesta tècnica.


🤔 Reflexió: En les dues situacions, si el disc dur està xifrat, l'atacant no podrà utilitzar aquestes tècniques per a accedir al sistema.

Dual Boot

En aquesta tasca, configurarem el GRUB per a poder arrancar amb dos sistemes operatius diferents. Per a fer-ho, utilitzarem la màquina virtual on ja tenim instal·lat un sistema operatiu GNU/Linux. A continuació, instal·larem un segon sistema operatiu i configurarem el GRUB per a poder arrancar amb els dos sistemes operatius.

  1. Muntatge de la iso a la màquina virtual. A continuació es mostra el procediment per VMWare, adapatar-lo al vostre hypervisor.

    1. Accedeix a la màquina virtual on tens instal·lat un sistema operatiu GNU/Linux.
    2. Selecciona la màquina virtual i apaga-la.
    3. Prem el boto en forma d'eina 🔧 per a obrir la configuració de la màquina virtual. Configuració de la màquina virtual
    4. A la pestanya CD/DVD (SATA), selecciona la opció Use ISO image file i selecciona la imatge ISO del sistema operatiu que vols instal·lar. Configuració de la imatge ISO
    5. Prem la tecla OK per a tancar la finestra de configuració de la màquina virtual.
  2. Arrancada de la màquina virtual amb la iso.

    1. Inicia la màquina virtual.
    2. Accedeix a la configuració UEFI.
    3. Selecciona el CD-ROM com a dispositiu d'arrancada. Selecció del dispositiu d'arrancada
    4. Accedeix al GRUB amb la imatge ISO del sistema operatiu que vols instal·lar. En aquest cas, Almalinux 9.4. Selecció del sistema operatiu
  3. Instal·lació del sistema operatiu.

    1. Segueix els passos d'instal·lació del sistema operatiu.

      • Selecciona Destino de la instalación i prem Personalitzada.
      • En aquest punt, el nostre disc virtual de 20 GB, té 4 particions ocupant tot l'espai. Particions del disc dur
      • Per poder instal·lar el nou sistema operatiu haurem de reimensionar la partició (/) per alliberar espai per a la nova partició, en el nostre cas podem alliberar 10 GB. La partició (/) es redueix de 18,54 GB a 8,54 GB. Simplement heu de modificar el valor númeric com mostro a la imatge. Reducció de la partició
      • Seleccioneu Partición estándar i premeu Pulse aqui para crearlas automáticamente. Creació de les particions
    2. Assigna una contrasenya a l'usuari root i finalitza la instal·lació.

  4. Test de l'arrancada del sistema.

    1. Reinicia la màquina virtual.
    2. Accedeix al GRUB i comprova que pots seleccionar el sistema operatiu que vols arrancar. Selecció del sistema operatiu
    3. Selecciona el sistema operatiu que has instal·lat i comprova que pots iniciar-lo correctament.

Anàlisi del procediment

El GRUB és un gestor d’arrancada que es configura automàticament durant la instal·lació d’un sistema operatiu. Quan instal·les un nou sistema operatiu, l’instal·lador detecta altres sistemes operatius presents en el mateix disc dur i crea entrades per a cada sistema operatiu en el fitxer de configuració del GRUB. Aquestes entrades permeten seleccionar quin sistema operatiu volem carregar durant l’arrancada del sistema.

A més, durant la instal·lació d’un nou sistema operatiu, es crea una nova entrada a la UEFI per a poder iniciar aquest nou sistema operatiu. Aquesta entrada s’ha creat amb la informació del nou GRUB, de manera que aquest conté les entrades dels dos sistemes operatius.

UEFI amb les entrades dels dos sistemes operatius

Si accediu a l’entrada inicial de la UEFI (debian), veureu que el GRUB únicament conté el sistema operatiu que teníem instal·lat inicialment. En canvi, si accediu a l’entrada nova de la UEFI (almalinux), veureu que el GRUB conté els dos sistemes operatius.

👁️ Observació:

Quan instal·les un sistema operatiu Windows després d’un sistema operatiu GNU/Linux, el GRUB es sobreescriu pel carregador d’arrancada de Windows. Això significa que no podràs accedir al sistema operatiu GNU/Linux des del GRUB. Per poder accedir al sistema operatiu GNU/Linux, hauràs de restaurar el GRUB. Aquesta restauració es pot realitzar mitjançant una unitat d’arrancada en viu (live boot) i utilitzant eines com ara boot-repair.

Si compareu el grub de debian amb el d'almalinux, veure que estan organitzats de manera diferent. Això és degut a que cada distribució GNU/Linux té la seva pròpia configuració del GRUB. A més, cada distribució GNU/Linux pot utilitzar diferents versions del GRUB, amb diferents opcions i configuracions.

Actualitzant el GRUB

Actualitzant el GRUB de debian per a mostrar l'entrada d'almalinux

  1. Accedeix a la màquina virtual on tens instal·lat el teu Debian.

  2. Accedeix a la consola del sistema operatiu.

  3. Edita el fitxer de configuració del GRUB de debian amb un editor de text com vi.

    vi /etc/default/grub
    
  4. Descomenta la línia GRUB_DISABLE_OS_PROBER i assigna-li el valor false.

    GRUB_DISABLE_OS_PROBER=false
    
  5. Desa els canvis i tanca l’editor de text.

  6. Actualitza el fitxer de configuració del GRUB amb la comanda següent:

    update-grub
    
  7. Reinicia el sistema amb la comanda següent:

    reboot
    
  8. Accedeix al GRUB de debian a través de la UEFI i comprova que ara pots seleccionar l’entrada d’almalinux.

    Selecció de l'entrada d'almalinux

🤔 Reflexió: Quin GRUB és millor?

Indiferent. Cada distribució GNU/Linux configura el GRUB de manera diferent per a adaptar-lo a les seves necessitats i requeriments. Això significa que cada distribució GNU/Linux pot tenir una configuració del GRUB diferent, amb diferents opcions i configuracions. La millor configuració del GRUB és aquella que millor s’adapta a les necessitats del teu sistema.

initramfs

La initramfs (intial RAM filesystem) és un sistema de fitxers temporal que es munta a la arrel del sistema de fitxers (rootfs) durant el procés d'arrencada del sistema. La initramfs s'utilitza per realitzar tasques d'inicialització del sistema abans que el sistema de fitxers arrel real estigui disponible. Per exemple, la initramfs pot ser utilitzada per carregar mòduls del nucli, muntar dispositius de bloc, o realitzar tasques de configuració de xarxa.

Quin és el funcionament de la initramfs?

La initramfs és un arxiu comprimit que conté un sistema de fitxers mínim necessari per inicialitzar el sistema. Aquest arxiu es descomprimeix a la memòria RAM durant l'arrencada i s'utilitza com el sistema de fitxers arrel temporal. La initramfs inclou scripts i binaris essencials que permeten al sistema realitzar tasques crítiques abans que el sistema de fitxers arrel real estigui disponible.

Hi ha diverses situacions en les quals un administrador de sistemes podria necessitar modificar la initramfs:

  • Inclusió de mòduls del nucli addicionals: Si el sistema requereix mòduls del nucli que no estan inclosos en la initramfs per defecte, com controladors de xarxa, controladors d'emmagatzematge, o sistemes de fitxers específics (per exemple, Btrfs o ZFS), serà necessari modificar la initramfs per incloure aquests mòduls.

  • Configuració de dispositius d'emmagatzematge complexos: Si el sistema utilitza configuracions d'emmagatzematge complexes, com RAID o LVM, pot ser necessari incloure scripts i binaris addicionals en la initramfs per assegurar que aquests dispositius siguin correctament inicialitzats i muntats.

  • Configuració de xarxa: En alguns casos, pot ser necessari incloure scripts de configuració de xarxa en la initramfs per assegurar que el sistema tingui accés a la xarxa durant el procés d'arrencada. Això pot ser útil en entorns on la xarxa és essencial per l'arrencada del sistema.

  • Solucionar problemes d'arrencada: Si el sistema experimenta problemes d'arrencada, modificar la initramfs pot ser una solució per incloure scripts de diagnòstic o correccions temporals que permetin al sistema arrencar correctament.

En aquest laboratori, explorarem com podem examinar i modificar la initramfs en un sistema Linux basat en Debian. Per a més informació sobre la initramfs, podeu consultar la documentació oficial de Debian a Debian Wiki - Initramfs.

Objectius

  • Entendre què és la initramfs i com funciona.
  • Aprendre a examinar el contingut de la initramfs.
  • Aprendre a modificar la initramfs per incloure mòduls del nucli addicionals.

Preparació

  1. Entorn de treball: Màquina virtual amb una distribució GNU/Linux instal·lada pot ser Debian o AlmaLinux. La màquina virtual pot tenir una configuració per defecte. Característiques de la màquina virtual:

    • Disc dur virtual de 20 GB.
    • 1 CPU.
    • 1 GB de memòria RAM.

    Configuració de la màquina virtual

    A més, inicialitzeu com a mínim un usuari root amb contrasenya (pot ser 1234).

    Estat inicial de la màquina virtual

En el meu cas he utilitzat una màquina virtual amb la imatge de Debian 12 proporcionada al inici de curs al campus virtual.

Tasques

  1. Examinar el contingut de la initramfs
  2. Carregar un mòdul del nucli addicional a la initramfs
  3. Personalitzar la initramfs

Examinant la initramfs

  1. Inicia la màquina virtual: Inicia la màquina virtual i inicia sessió amb l'usuari root.

  2. Examina el contingut de la initramfs: Utilitza la comanda lsinitramfs per examinar el contingut de la initramfs. Aquesta comanda mostrarà el contingut de la initramfs i els scripts i binaris que s'executen durant el procés d'arrencada.

    lsinitramfs /boot/initrd.img-$(uname -r)
    

    Examinar el contingut de la initramfs

    En la figura anterior, he limitat la sortida amb la comanda head per mostrar només les 10 primeres línies de la sortida. La sortida completa mostrarà tot el contingut de la initramfs.

    Si analitzeu la sortida completa al vostre servidor, podreu veure que la initramfs conté diversos scripts i binaris que s'utilitzen durant el procés d'arrencada. Aquests scripts i binaris són responsables de realitzar tasques com muntar dispositius de bloc, carregar mòduls del nucli, i configurar la xarxa.

    💡 Nota: La sortida de la comanda lsinitramfs pot ser molt extensa, ja que la initramfs conté molts scripts i binaris necessaris per l'arrencada del sistema. Si voleu veure la sortida completa, podeu redirigir-la a un fitxer o utilitzar la comanda less per navegar-hi.

  3. Cerca si el modul ext4 està present a la initramfs:

    lsinitramfs /boot/initrd.img-$(uname -r) | grep ext4
    

    En aquest cas, hauria de veure que el mòdul ext4 està present a la initramfs. Aquest mòdul és necessari per muntar sistemes de fitxers ext4 durant el procés d'arrencada.

    Cerca del mòdul ext4 a la initramfs

Carregant un mòdul addicional

  1. Carrega el mòdul del nucli: En aquest pas, carregarem un mòdul del nucli addicional a la initramfs actual. En aquest cas, carregarem el mòdul nls_utf8, que és un mòdul de suport per a la codificació de caràcters UTF-8. El primer pas és comprovar si el mòdul ja està carregat:

    lsmod | grep nls_utf8
    

    Si la comanda no retorna cap sortida, significa que el mòdul nls_utf8 no està carregat actualment al sistema.

  2. Comprovar si el modul esta carregat a la initramfs: Abans de carregar el mòdul a la initramfs, comprovem si ja està present:

    lsinitramfs /boot/initrd.img-$(uname -r) | grep nls_utf8
    

    Si la comanda no retorna cap sortida, significa que el mòdul nls_utf8 no està present a la initramfs actual.

  3. Cerca la ubicació del mòdul del nucli: Utilitza la comanda modinfo per cercar la ubicació del mòdul nls_utf8.

    modinfo nls_utf8
    

    Aquesta comanda mostrarà informació detallada sobre el mòdul nls_utf8, incloent la ubicació del fitxer del mòdul. En aquest cas, el fitxer del mòdul es troba a /lib/modules/$(uname -r)/kernel/fs/nls/nls_utf8.ko.

  4. Carrega el mòdul a la initramfs: Utilitza la comanda echo per afegir el mòdul nls_utf8 a la llista de mòduls que s'inclouran a la initramfs durant el procés de generació.

    echo nls_utf8 >> /etc/initramfs-tools/modules
    
  5. Regenera la initramfs: Utilitza la comanda update-initramfs per regenerar la initramfs amb el mòdul nls_utf8 inclòs.

    update-initramfs -u
    

    Aquesta comanda regenerarà la initramfs amb el mòdul nls_utf8 inclòs. Si tot ha anat bé, no hauria de veure cap error durant el procés de generació.

  6. Reinicia el sistema: Reinicia el sistema per aplicar els canvis.

    reboot
    
  7. Comprova si el mòdul s'ha carregat: Després de reiniciar el sistema, comprova si el mòdul nls_utf8 s'ha carregat correctament.

    lsmod | grep nls_utf8
    lsinitramfs /boot/initrd.img-$(uname -r) | grep nls_utf8
    

    Si la comanda lsmod retorna el mòdul nls_utf8, significa que el mòdul s'ha carregat correctament al sistema. Si la comanda lsinitramfs retorna el mòdul nls_utf8, significa que el mòdul s'ha inclòs correctament a la initramfs.

Personalitzar la initramfs

En aquesta secció, personalitzarem la initramfs afegint un missatge personalitzat que es mostrarà durant el procés d'inici. Això ens permetrà veure com podem modificar la initramfs per incloure scripts i binaris addicionals que es poden executar durant l'arrencada del sistema.

Nota:

Realitzeu les accions següents com a superusuari su -.

  1. Crea un nou directori per construir la initramfs personalitzada:

    mkdir /tmp/initramfs
    cd /tmp/initramfs
    

    Això crea un espai de treball temporal on es construirà la nova imatge de la initramfs.

  2. Extreu la imatge actual de la initramfs:

    unmkinitramfs /boot/initrd.img-$(uname -r) .
    

    ℹ️ Nota:

    unmkinitramfs és una eina que permet descomprimir la imatge de la initramfs a un directori de treball. Això permet modificar els fitxers continguts en la initramfs.


    Compte!: Es possible que al descomprimir la imatge us generi dos carpetes main i stable. En aquest cas, heu de treballar amb la carpeta main. Cerqueu dins de main la carpeta scripts i dins d'aquesta la carpeta init-top. Aquesta és la carpeta on s'executen els scripts durant l'arrencada de la initramfs.

  3. Crea un nou fitxer de script amb un missatge personalitzat:

    echo 'echo "Hola, Initramfs!"' > scripts/init-top/custom_message.sh
    # Afegeix una pausa per veure el missatge
    echo '/usr/bin/sleep 10' >> scripts/init-top/custom_message.sh
    # Atorga permisos d'execució al script
    chmod +x scripts/init-top/custom_message.sh
    
  4. Actualitza el manifest de la initramfs:

    # Nota: order no existeix, és ORDER amb majúscules 
    echo 'scripts/init-top/custom_message.sh' >> scripts/init-top/ORDER
    

    Això afegeix el nou script al manifest de la initramfs, assegurant-se que s'executi durant el procés d'inici.

  5. Crea una nova imatge de la initramfs amb el script personalitzat:

    Realitzeu una de les següents opcions:

    • Nova imatge de la initramfs (nom acaba en custom):
    find . | cpio -o -H newc | gzip > /boot/initrd.img-$(uname -r)-custom
    
    • Sobreescriure la imatge original:
    find . | cpio -o -H newc | gzip > /boot/initrd.img-$(uname -r)
    

    ℹ️ Nota:

    Aquest pas utilitza cpio per empaquetar tots els fitxers del directori de treball en un sol arxiu, i gzip per comprimir-lo. La nova imatge es guarda a /boot amb un nom personalitzat. Si voleu sobreescriure la imatge original, podeu utilitzar el nom initrd.img-$(uname -r). Si feu anar custom, al grub també cal indicar-ho.

  6. Actualitza la configuració de GRUB per utilitzar la nova imatge de la initramfs:

    Com editarem la initramfs de forma temporal, no actualitzarem la configuració de GRUB de forma permanent. Per tant, no ens calen aquests passos.

    update-initramfs -u -k $(uname -r)
    update-grub
    

    ℹ️ Nota:

    Per fer l'experiment no actualizarem el grub de forma permanent. Simplement, editarem la configuració de GRUB durant l'arrencada per utilitzar la nova imatge de la initramfs.

  7. Reinicia el sistema: Reinicia el sistema per aplicar els canvis.

    reboot
    
  8. GRUB: A l'arrencada, accedeix a la configuració de GRUB i modifica la línia de comandament per utilitzar la nova imatge de la initramfs. Recorda prement la tecla e per editar la configuració de GRUB.

    # Elimina les opcions `quiet` i `splash` per veure el missatge personalitzat
    # Afegeix custom al final de la línia de comandament de la initramfs
    initrd /boot/initrd.img-$(uname -r)-custom
    

    GRUB Personalitzat

  9. Comprova el missatge personalitzat durant l'arrencada: Després de reiniciar el sistema, observa el missatge personalitzat que s'ha afegit a la initramfs durant el procés d'inici.

    Missatge Personalitzat

Activitat opcional

  • Quin seria el procediment si volem modificar de forma permanent la initramfs de la primera entrada de GRUB? Documenteu el procediment. Aquesta activitat comptarà únicament a la primera persona que faci un PR amb la resposta correcta. No compte a HandsOn, això es part de la millora dels continguts (un dels punts extres de la nota final).

Inici del sistema i Dimonis de gestió de serveis

Un cop el kernel ha estat carregat i ha completat el seu procés d’inicialització, crea un conjunt de processos espontanis en l’espai d’usuari. El primer d'aquests processos és el procés init, que és el pare de tots els altres processos en el sistema. El procés init és responsable de la inicialització del sistema i de la gestió de la resta de serveis. Tradicionalment, el procés init era conegut com a SysVinit, però amb el temps han sorgit alternatives com systemd.

🧐 El canvi de SysVinit a Systemd...

En moltes distribucions Linux es va fer per millorar l’eficiència i la gestió dels serveis del sistema. SysVinit utilitza scripts seqüencials per iniciar serveis, cosa que pot ser lenta i menys flexible. En canvi, Systemd permet una arrencada paral·lela, reduint significativament el temps d’inici del sistema. A més, Systemd ofereix una gestió més avançada dels processos amb funcionalitats com els cgroups, que permeten controlar els recursos utilitzats per cada servei. Ara bé, aquest canvi també ha generat controvèrsia, ja que molts usuaris prefereixen el sistema més senzill i transparent de SysVinit.

En aquest laboratori, explorarem el procés d'arrencada del sistema amb systemd i com crear i gestionar serveis amb aquesta eina. També veurem com utilitzar journalctl per analitzar els registres del sistema i com personalitzar el procés d'arrencada amb scripts i serveis personalitzats.

Objectius

  • Comprendre el procés d'arrencada del sistema amb systemd.
  • Crear i gestionar serveis amb systemd.
  • Utilitzar journalctl per analitzar els registres del sistema.
  • Personalitzar el procés d'arrencada amb scripts i serveis personalitzats.

Preparació de l'entorn

Per a aquest laboratori, necessitarem un sistema Linux amb systemd instal·lat. Aquest laboratori es pot realitzar en qualsevol distribució Linux moderna que utilitzi systemd com a gestor d'inicialització. En aquest laboratori, utilitzarem una màquina virtual amb Debian 12. A més, assegureu-vos de no instal·lar la interfície gràfica, i seleccionar el servidor SSH durant la instal·lació.

Tasques

  1. Analitzar el procés d'arrencada amb systemd
  2. Crear i gestionar serveis amb systemd
  3. Execució de serveis programats amb systemd
  4. Anàlisi de registres del sistema amb journalctl
  5. Afegir informació d'inici al sistema

Analitzant el procés d'arrancada

La comanda systemd ens permet gestionar els serveis del sistema i controlar el procés d'arrencada. Podeu comprovar les seves possibilitats amb la comanda man systemd. Una de les funcionalitats més útils de systemd és la capacitat de generar informació detallada sobre el procés d'arrencada del sistema.

El primer pas per analitzar el procés d'arrencada amb systemd és utilitzar la comanda systemd-analyze per obtenir informació sobre el temps que ha trigat el sistema a arrencar. Aquesta comanda mostrarà informació sobre el temps que ha trigat el sistema a arrencar, incloent el temps que ha trigat el kernel i l'espai d'usuari.

Startup finished in 899ms (kernel) + 2.074s (userspace) = 2.973s
graphical.target reached after 2.068s in userspace.
KernelEspai d'usuariTotal
899ms2.074s2.973s

En aquest cas, els primers 899ms s'utilitzen per carregar les funcions del kernel com ara els controladors de dispositius i el sistema de fitxers. Els següents 2.074s s'utilitzen per carregar l'espai d'usuari, com ara els serveis i els processos del sistema. En total, el sistema ha trigat 2.973s a arrencar.

Ara que tenim aquesta informació, podem utilitzar la comanda systemd-analyze blame per obtenir informació detallada sobre el temps que ha trigat cada unitat a carregar durant el procés d'arrencada. Aquesta opció ens llistarà les unitats ordenades per temps d'arrencada, de major a menor.

TempsUnitat
1.876ssystemd-random-seed.service
784msdbus.service
782mse2scrub_reap.service
778mssystemd-logind.service
......
4mssystemd-update-utmp-runlevel.service

Amb aquesta informació, podem identificar les unitats que poden estar retardant el procés d'arrencada i optimitzar-les si cal. Per obtenir més informació sobre una unitat específica, podeu utilitzar la comanda systemctl status seguida del nom de la unitat. Per exemple, si volem informació sobre la unitat systemd-random-seed.service, podem executar:

systemctl status systemd-random-seed.service

systemctl status

Aquesta informació ens mostrarà:

  1. L'estat actual de la unitat (inactiu, actiu, desactivat, error o recarregant).
  2. La linia Loaded ens indica la ruta al fitxer on es desa la configuració de la unitat. En aquest cas, /lib/systemd/system/systemd-random-seed.service. A més ens indica static que vol dir que la unitat no es pot desactivar. Altres unitats ens poden indicar error, masked, not-found, enable o disabled
  3. La entrada al manual de la unitat, si n'hi ha.
  4. Finalment, ens mostra informació sobre el procés: PID, estat del procés i temps que ha estat en execució (això en el exemple) també pot mostrar la memòria, el cgroup, o el nombre de tasques associades.

Si volem saber exactament què fa aquest servei, podem consultar el manual amb la comanda man systemd-random-seed.service.

Entrada del manual de systemd-random-seed.service

En el manual d'aquesta comanda us explicarà de forma detallada què aquest servei carrega una llavor aleatòria al espai del nucli quan arranca i la desa quan s'apaga. Aquesta llavor es guarda a /var/lib/systemd/random-seed. Per defecte, no s’assigna entropia quan s’escriu la llavor al nucli, però això es pot canviar amb $SYSTEMD_RANDOM_SEED_CREDIT. El servei s’executa després de muntar el sistema de fitxers /var/, per la qual cosa és recomanable utilitzar un carregador d’arrencada que passi una llavor inicial al nucli, com systemd-boot.

👁️ Observació:

Amb aquesta informació podem identificar quina és la funció de cada servei i decidir si pel nostre sistema és necessari o no. En aquest cas, el servei systemd-random-seed.service és necessari per a la generació de nombres aleatoris, per tant, no és recomanable desactivar-lo.

Si volem informació sobre la unitat systemd-random-seed.service, podem utilitzar la comanda systemctl cat systemd-random-seed.service per veure la configuració de la unitat.

# /lib/systemd/system/systemd-random-seed.service
#  SPDX-License-Identifier: LGPL-2.1-or-later
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Load/Save Random Seed
Documentation=man:systemd-random-seed.service(8) man:random(4)
DefaultDependencies=no
RequiresMountsFor=/var/lib/systemd/random-seed
Conflicts=shutdown.target
After=systemd-remount-fs.service
Before=first-boot-complete.target shutdown.target
Wants=first-boot-complete.target
ConditionVirtualization=!container
ConditionPathExists=!/etc/initrd-release

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/lib/systemd/systemd-random-seed load
ExecStop=/lib/systemd/systemd-random-seed save

# This service waits until the kernel's entropy pool is initialized, and may be
# used as ordering barrier for service that require an initialized entropy
# pool. Since initialization can take a while on entropy-starved systems, let's
# increase the timeout substantially here.
TimeoutSec=10min

Aquesta informació ens mostra la configuració de la unitat, incloent la descripció, la documentació, les dependències, les condicions, el tipus de servei, els comandaments d'inici i parada, i altres opcions de configuració. El servei té una dependència de muntatge per a /var/lib/systemd/random-seed, i s'executa després de systemd-remount-fs.service i abans de first-boot-complete.target i shutdown.target. A més, ens indica que és un servei de tipus oneshot, que s'executa una sola vegada i roman actiu després de la sortida. Els comandaments d'inici i parada són /lib/systemd/systemd-random-seed load i /lib/systemd/systemd-random-seed save, respectivament.

💡 Nota::

Si ovserveu el paramètre TimeoutSec=10min aquesta unitat pot trigar fins a 10 minuts a carregar. Si el sistema està en un entorn amb poca entropia, aquesta unitat pot trigar més temps a carregar.

Per exemple, editarem la unitat systemd-random-seed.service per activar la entropia al sistema.Per editar la unitat podeu utilitzar qualsevol editor de text ( i.e vi) o bé la comanda systemctl edit systemd-random-seed.service que obrirà un editor de text per afegir la línia. Un cop obert l'editor heu d'afegir la lína a la secció [Service] i desar el fitxer. Recordeu que per fer aquesta acció necessitareu permisos d'administrador. Per tant, su - per canviar a l'usuari root i després fer la comanda.

Environment=SYSTEMD_RANDOM_SEED_CREDIT=4096

Compte! Si feu anar el systemctl edit aquest crearà un fitxer de configuració a /etc/systemd/system/systemd-random-seed.service.d/override.conf que sobreescriurà la configuració de la unitat original. Per afegir la configuració còpieu la configuració original i afegiu la línia Environment=SYSTEMD_RANDOM_SEED_CREDIT=4096 a la secció [Service].

Estem assignant un crèdit de 4096 a la llavor aleatòria. Això augmentarà la quantitat d'entropia que es passa al nucli quan s'escriu la llavor. Un crèdit més alt pot augmentar la seguretat del sistema, però també pot augmentar el temps d'arrencada en sistemes amb poca entropia.

Un cop hàgim fet els canvis, guardarem el fitxer i sortirem de l'editor. Després, podem fer un reboot per aplicar els canvis. Quan el sistema s'hagi reiniciat, podem tornar a utilitzar la comanda systemd-analyze per comprovar si els canvis han tingut algun impacte en el temps d'arrencada del sistema.

InicialDesprés de canviar la entropiaDiferència
2.973s3.008s+0.035s

En el meu cas, el temps d'arrencada ha augmentat lleugerament després de fer aquest canvi. Això és normal, ja que hem augmentat la quantitat d'entropia que es passa al nucli.

Una altra opció interesant que ens ofereix systemd és la comanda systemd-analyze critical-chain. Aquesta comanda ens permet veure la cadena crítica de les unitats de temps del sistema. Això ens mostra quines unitats són les més crítiques per al temps d'arrencada del sistema. Per analizar la sortida, heu de mirar el temps després del caràcter @ per veure quant temps ha trigat la unitat a activar-se o iniciar-se, i el temps després del caràcter + per veure quant temps ha trigat la unitat a iniciar-se. A més, aquesta comanda només mostra el temps que les unitats han passat a l'estat activant-se, i no cobreix les unitats que mai han passat per l'estat activant-se (com les unitats de dispositius que passen directament de inactiu a actiu). Tot i això, és una eina útil per identificar les unitats que poden estar retardant el procés d'arrencada.

graphical.target @2.076s
└─multi-user.target @2.075s
  └─ssh.service @1.497s +578ms
    └─network.target @1.494s
      └─networking.service @1.225s +268ms
        └─apparmor.service @1.158s +63ms
          └─local-fs.target @1.158s
            └─run-credentials-systemd\x2dtmpfiles\x2dsetup.service.mount @1.171s
              └─local-fs-pre.target @242ms
                └─systemd-tmpfiles-setup-dev.service @224ms +17ms
                  └─systemd-sysusers.service @192ms +20ms
                    └─systemd-remount-fs.service @131ms +54ms
                      └─systemd-journald.socket @114ms
                        └─-.mount @86ms
                          └─-.slice @86ms

En aquest cas, podem veure que la unitat ssh.service és la més crítica per al temps d'arrencada del sistema, ja que ha trigat 578ms a iniciar-se. A més, podem veure les dependències de totes les unitats que s'han carregat durant el procés d'arrencada. Començant pel graphical.target i seguint per les unitats multi-user.target, aquestes dos unitats ens asseguren que el sistema ha arrencat en mode gràfic i multiusuari. A partir d'aquest moment es carreguen la resta de serveis.

Un altra opció interessant és utilitzar la comanda systemd-analyze plot per generar un gràfic del procés d'arrencada del sistema. Aquesta comanda generarà un fitxer SVG amb el gràfic del procés d'arrencada, que podeu visualitzar amb un navegador web o un visor d'imatges.

  • Si volem analitzar tots les unitats:

    systemd-analyze plot > boot_system.svg
    
  • Si volem analitzar les unitats de la instancia de l'usuari:

    systemd-analyze --user plot > boot_user.svg
    
  • Si volem les unitats de l'arrencada del sistema:

    systemd-analyze --system plot > boot_system.svg
    

⚠️ Compte: Com puc visualtizar una imatge SVG en un debian sense interfície gràfica?

Per visualitzar una imatge SVG en un sistema sense interfície gràfica, podeu descarregar el fitxer SVG a la vostra màquina local i visualitzar-lo amb un visor d'imatges o un navegador web. Per exemple, podeu utilitzar la comanda scp per descarregar el fitxer SVG a la vostra màquina local:

scp user@remote:/path/to/boot.svg /path/to/local/boot.svg

⚠️ Compte: Debian no permet conexions remotes com a root per defecte. Abans de fer-ho, com debian per defecte no permet l'execució de scp com a root, caldrà fer-ho com a usuari normal i després copiar el fitxer a la carpeta desitjada.

mv boot.svg /tmp 
chown user:user /tmp/boot.svg  

Gràfic d'arrencada

Per a més informació sobre les opcions de la comanda systemd-analyze, podeu consultar el manual amb la comanda man systemd-analyze.

Per acabar, podem comentar que així com systemctl status unitat ens mostra la informació d'una unitat. També podem consultar la informació de totes les unitats amb:

  • systemctl status: Mostra informació sobre l'estat actual del sistema o d'una unitat específica acompanyada de les dades més recents del registre del diari.

systemctl status

  • systemctl list-units: Mostra una llista de totes les unitats carregades al sistema, incloent les unitats actives, inactives i fallades.

systemctl list-units

Totes aquestes comandes són molt complexes i tenen moltes opcions, per tant us recomano que consulteu el manual de cada comanda per obtenir més informació sobre com utilitzar-les i quines opcions podeu elegir.

Creant i Gestionant serveis

En aquesta secció, crearem un servei systemd per realitzar una còpia de seguretat del sistema a l'arrencada. Aquest servei s'executarà automàticament quan el sistema s'arrenqui i realitzarà una còpia de seguretat del sistema a una ubicació específica. Aquest servei pot ser interessant en situacions on l'ús pot comportar la pèrdua de dades o la corrupció del sistema.

  1. Crea un script de còpia de seguretat: Crea un script de còpia de seguretat a /usr/local/bin/backup.sh amb el següent contingut:

    #!/bin/bash
    
    # Còpia de seguretat del sistema
    tar -czf /backup/system_backup_$(date +%Y%m%d).tar.gz /etc /var
    

    Aquest script realitzarà una còpia de seguretat dels directoris /etc i /var a la ubicació /backup amb el nom system_backup_YYYYMMDD.tar.gz, on YYYYMMDD és la data actual.

  2. Crea un fitxer de servei systemd: Crea un fitxer de servei systemd a /etc/systemd/system/backup.service amb el següent contingut:

    [Unit]
    Description=System Backup Service
    After=network.target
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/backup.sh
    
    [Install]
    WantedBy=multi-user.target
    

    Aquest fitxer de servei defineix un servei backup que s'executarà un cop s'hagi carregat el sistema de fitxers. El servei executarà l'script de còpia de seguretat backup.sh al directori /usr/local/bin. El servei s'instal·larà a la unitat multi-user.target, de manera que s'executarà quan el sistema hagi carregat tots els serveis necessaris.

  3. Inicia el servei: Inicia el servei backup amb la comanda systemctl start backup.

    systemctl start backup
    
  4. Comprova l'estat del servei: Comprova l'estat del servei backup amb la comanda systemctl status backup.

    systemctl status backup
    
  5. Habilita el servei: Habilita el servei backup perquè s'executi a l'arrencada amb la comanda systemctl enable backup.

    systemctl enable backup
    
  6. Reinicia el sistema: Reinicia el sistema per aplicar els canvis.

    reboot
    
  7. Comprova si el servei s'ha executat: Després de reiniciar el sistema, comprova si el servei backup s'ha executat correctament.

    ls /backup
    

Ara el sistema arranca de forma més lenta ja que s'executa el servei de còpia de seguretat. Podeu utilitzat les comandes systemd-analyze i systemd-analyze blame per comparar els temps d'arrencada abans i després de la creació del servei.

En el meu cas, el temps d'arrencada ha augmentat lleugerament després de crear el servei de còpia de seguretat:

InicialDesprés de crear el serveiDiferència
2.973s10.380s+7.407s

👁️ Observació:

Noteu que l'augment es produeix en l'espai d'usuari, ja que el servei de còpia de seguretat s'executa després de carregar les funcions del kernel. Això és normal, ja que el servei de còpia de seguretat pot trigar una estona a completar-se, especialment si els directoris /etc i /var són grans.

Serveis programats

Un altra funcionalitat interessant de systemd és la possibilitat de programar la execució de serveis amb systemd.timer. Aquesta funcionalitat permet programar la execució de serveis en un moment concret o de forma periòdica. Això pot ser útil per realitzar tasques de manteniment automàticament, com ara còpies de seguretat, actualitzacions de sistema, etc.

Anem a veure com podem programar l'actualització del sistema amb un servei apt-update i un temporitzador apt-update.timer cada dia a les 00:00.

  1. Crea un fitxer de servei apt-update.service: Crea un fitxer de servei apt-update.service a /etc/systemd/system/apt-update.service amb el següent contingut:

    [Unit]
    Description=Update the package list
    
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/apt update
    

    Aquest fitxer de servei executa la comanda apt update per actualitzar la llista de paquets del sistema.

  2. Crea un fitxer de temporitzador apt-update.timer: Crea un fitxer de temporitzador apt-update.timer a /etc/systemd/system/apt-update.timer amb el següent contingut:

    [Unit]
    Description=Run apt-update daily at 00:00
    
    [Timer]
    OnCalendar=daily
    
    [Install]
    WantedBy=timers.target
    

    Aquest fitxer de temporitzador programa l'execució del servei apt-update.service cada dia a les 00:00.

  3. Inicia el temporitzador: Inicia el temporitzador apt-update.timer amb la comanda systemctl start apt-update.timer.

    systemctl start apt-update.timer
    
  4. Habilita el temporitzador: Habilita el temporitzador apt-update.timer perquè s'executi a l'arrencada amb la comanda systemctl enable apt-update.timer.

    systemctl enable apt-update.timer
    

    💡 Nota:

    Podeu utilitzar systemctl enable --now unitat per iniciar i habilitar una unitat al mateix temps.

  5. Comprova l'estat del temporitzador: Comprova l'estat del temporitzador apt-update.timer amb la comanda systemctl status apt-update.timer.

Una vegada configurat el temporitzador, el sistema executarà el servei apt-update.service cada dia a les 00:00 per actualitzar la llista de paquets del sistema.

systemctl status apt-update.timer

Anàlisi de logs

Un altre eina útil que ens ofereix systemd és journalctl, que ens permet analitzar els registres del sistema. Aquesta eina ens permet veure els registres del sistema en temps real, buscar registres específics, filtrar registres per unitat, i molt més.

Crearem un servei amb bash i awk que monitoritzi l'estat del sistema i registri la informació en un fitxer de registre. A continuació, utilitzarem journalctl per analitzar els registres del sistema i buscar la informació del servei.

  1. Crea un script de monitoratge:

    #!/bin/bash
    
    # Monitor the system state
    echo "Date: $(date)" 
    echo "Load: $(uptime | awk '{print $10}')" 
    echo "Memory: $(free -m | awk 'NR==2{print $3}')" 
    echo "Disk: $(df -h / | awk 'NR==2{print $5}')" 
    echo "Processes: $(ps aux | wc -l)" 
    
  2. Crea un fitxer de servei system-monitor.service: En aquest cas, crearem un fitxer de servei system-monitor.service a /etc/systemd/system/system-monitor.service amb el següent contingut:

    [Unit]
    Description=System Monitor Service
    
    [Service]
    Type=simple
    ExecStart=/usr/local/bin/system-monitor.sh
    
    [Install]
    WantedBy=multi-user.target
    
  3. Inicia el servei: Inicia el servei system-monitor amb la comanda systemctl start system-monitor.

    systemctl start system-monitor
    
  4. Comprova l'estat del servei: Comprova l'estat del servei system-monitor amb la comanda systemctl status system-monitor.

    systemctl status system-monitor
    

    systemctl status system-monitor

    Ups! Sembla que hi ha un error en el servei. Podem veure que el servei ha fallat a l'iniciar-se. La mateixa comanda ens indica la causa de l'error: Permission denied. Això significa que el script no té permisos d'execució. Per solucionar aquest problema, podem canviar els permisos del script perquè sigui executable amb la comanda chmod +x /usr/local/bin/system-monitor.sh.

    systemctl restart system-monitor
    

    systemctl status system-monitor

  5. Un altra forma d'accedir a la informació del servei és utilitzar la comanda journalctl amb l'opció -u seguida del nom de la unitat. Per exemple, per veure els registres del servei system-monitor, podem utilitzar la comanda:

    journalctl -u system-monitor
    

    Aquesta comanda ens mostrarà tots els registres associats amb el servei system-monitor, incloent els missatges de registre, les entrades de diari i altres informacions rellevants.

    👁️ Observació:

    Tot i que journalctl sembla que ens mostra la mateixa informació que systemctl status, journalctl ens permet accedir a tots els registres del sistema, no només als registres de les unitats. Això ens permet analitzar els registres del sistema de forma més detallada i buscar informació específica. A més, no sempre podem veure tota la informació d'una unitat amb systemctl status, ja que aquesta comanda només ens mostra les dades més recents del registre del diari.

💡 Nota:

journalctl és una eina molt potent que ens permet analitzar els registres del sistema de forma detallada. Podeu utilitzar opcions com -f per veure els registres en temps real, -n per limitar el nombre de línies mostrades, -r per mostrar els registres en ordre invers, -p per filtrar els registres per prioritat, i moltes altres opcions. Podeu consultar el manual de journalctl amb la comanda man journalctl per obtenir més informació sobre com utilitzar aquesta eina. Durant les vostres sessions administrant el sistema, journalctl serà una eina molt útil per analitzar els registres del sistema i poder identificar problemes o errors.

Afegint informació d'inici

Els scripts d'arrancada en sistemes Unix i Linux són fitxers que s'executen automàticament quan un usuari inicia una sessió de terminal. Aquests scripts configuren l'entorn de l'usuari, definint variables d'entorn, carregant funcions i configuracions personalitzades, i executant comandes específiques.

Breument, tal com vam veure al curs de sistemes operatius, els scripts d'arrancada més comuns en sistemes Unix i Linux són:

  • /etc/profile: Script d'arrancada global per a tots els usuaris del sistema.
  • /etc/profile.d/: Directori que conté scripts d'arrancada addicionals.
  • ~/.bash_profile: Script d'arrancada específic de l'usuari per a la shell bash.
  • ~/.bash_login: Un altre script d'arrancada específic de l'usuari per a la shell bash.
  • ~/.profile: Script d'arrancada específic de l'usuari per a la shell sh i altres shells compatibles.
  • ~/.bashrc: Script d'arrancada específic de l'usuari per a la shell bash.
  • /root/.profile: Script d'arrancada específic de l'usuari root per a la shell sh i altres shells compatibles.

Aquests scripts s'executen en un ordre específic quan un usuari inicia una sessió de terminal. A continuació, veurem una descripció de cada script d'arrancada i el seu ús, així com l'ordre d'execució dels scripts d'arrancada. Per veure l'ordre d'execució dels scripts d'arrancada, podeu consultar el manual de bash amb la comanda man bash i buscar la secció INVOCATION.

Anem a veure com podem mostrar informació sobre el servidor després de l'arrencada i el login de l'usuari. Aquesta informació pot ser útil per als administradors de sistemes per mostrar informació rellevant sobre el sistema, com ara la càrrega del sistema, l'ús de la CPU, la memòria disponible, la addresa IP i el nombre d'usuaris connectats.

  1. Crea un script d'informació del sistema: Crea un script d'informació del sistema a /usr/local/bin/system-info.sh amb el següent contingut:

    #!/bin/bash
    
    # Informació del sistema
    echo "System Information"
    echo "------------------"
    echo "Hostname: $(hostname)"
    echo "IP Address: $(hostname -I | awk '{print $1}')"
    echo "Uptime: $(uptime | awk '{print $3 " " $4}')"
    echo "Load Average: $(uptime | awk '{print $10 " " $11 " " $12}')"
    echo "Memory Usage: $(free -h | grep Mem | awk '{print $3 "/" $2}')"
    echo "Disk Usage: $(df -h / | grep /dev | awk '{print $3 "/" $2}')"
    echo "Users: $(who | wc -l)"
    

    Aquest script mostra informació rellevant sobre el sistema, com ara el nom de l'amfitrió, la addresa IP, el temps d'activitat, la càrrega del sistema, l'ús de la memòria, l'ús del disc i el nombre d'usuaris connectats.

  2. Atorga permisos d'execució al script:

    chmod +x /usr/local/bin/system-info.sh
    
  3. Crea un script d'informació del sistema: Crea un script d'informació del sistema a /etc/profile.d/system-info.sh amb el següent contingut:

    # Informació del sistema
    /usr/local/bin/system-info.sh
    

    Si posem l'script a /etc/profile.d/ aquest s'executarà automàticament quan un usuari inicia una sessió de terminal. Això permet mostrar informació rellevant sobre el sistema després de l'arrencada i el login de l'usuari.

  4. Atorga permisos d'execució al script:

    chmod +x /etc/profile.d/system-info.sh
    
  5. Reinicia el sistema: Reinicia el sistema per aplicar els canvis.

    reboot
    

Un cop el sistema s'hagi reiniciat, podeu iniciar una sessió de terminal i veure la informació del sistema després de l'arrencada i el login de l'usuari. Aquesta informació us pot ajudar a monitoritzar l'estat del sistema i identificar problemes o errors.

  • Inici de sessió amb un usuari normal:

    Informació del sistema

  • Inici de sessió com a usuari root:

    Informació del sistema

Si únicament voleu mostrar la informació del sistema quan s'inicia la sessió de l'usuari root, podeu afegir el script system-info.sh al fitxer /root/.profile en lloc de /etc/profile.d/system-info.sh. Això farà que la informació del sistema es mostri només quan s'inicia la sessió de l'usuari root.

ℹ️ Diferencia entre .bashrc i .bash_profile?

El fitxer .bashrc s'executa cada vegada que s'inicia una sessió de terminal, mentre que el fitxer .bash_profile s'executa només quan s'inicia una sessió de terminal interactiva. Això significa que el fitxer .bashrc s'executarà cada vegada que s'obri una nova finestra de terminal, mentre que el fitxer .bash_profile s'executarà només quan s'inicia una sessió de terminal interactiva. Per tant, si voleu mostrar la informació del sistema només quan s'inicia la sessió de l'usuari, podeu afegir el script al fitxer .bash_profile en lloc de .bashrc.

Sistema de Fitxers

En aquest laboratori apendrem a gestionar els sistemes de fitxers tradicionals en un servidor Linux; com ext4, i xfs. A més, aprendrem a realitzar tasques comunes com la creació de particions, el muntatge de sistemes de fitxers, la comprovació de la integritat dels fitxers, la realització de còpies de seguretat i la recuperació de dades en cas de corrupció. També analitzarem sistemes de fitxers temporals i un sistema de fitxers avançat com ZFS.

Objectius

Els objectius d'aquest laboratori són:

  • Comprendre els conceptes bàsics dels sistemes de fitxers.
  • Crear i gestionar particions en un servidor Linux.
  • Muntar i desmuntar sistemes de fitxers.
  • Comprovar la integritat dels fitxers en un sistema de fitxers.

Tasques

  1. Muntatge d'un disc extern per fer un backup
  2. Migració de dades a altres particions
  3. Simulació d'una corrupció a la partició /home i recuperació
  4. Sistemes de fitxers temporals
  5. Explorant un sistema de fitxers avançat: zfs

Muntatge d'un disc extern per fer un backup

En aquest laboratori simularem que volem muntar un disc dur extern en el nostre servidor per a realitzar còpies de seguretat de les nostres dades. Crearem una partició en el disc dur i la formatejarem amb el sistema de fitxers ext4.

  1. Connecta el disc dur extern a la màquina virtual.

  2. Utilitza la comanda lsblk per a identificar el disc dur extern.

    Utilitza la comanda lsblk per a identificar el disc dur extern

    👁️ Observació:

    En aquest cas, el disc dur extern s'identifica com a /dev/nvme0n2. La etiqueta nvme indica que el disc dur és un disc dur SSD NVMe. Aquesta etiqueta pot variar en funció del tipus de disc dur que tingueu connectat com ara sda per a disc dur SATA o vda per a disc dur virtual.

  3. Utilitza la comanda fdisk per a crear una nova partició en el disc dur extern.

    fdisk /dev/nvme0n2
    

    Utilitza la comanda fdisk per a crear una nova partició en el disc dur extern

    La comanda ens mostrarà un missatge d'avís indicant que no hi ha cap taula de particions en el disc dur. Això és normal ja que el disc dur és nou i no té cap partició creada.

  4. Crearem una nova taula de particions en el disc dur extern. Aquesta taula serà de tipus msdos.

    Command (m for help): o
    

    Crearem una nova taula de particions en el disc dur extern

    💫 Recordatori:

    Hi ha dos tipus de taula de particions: msdos i gpt. La taula msdos és més antiga i té limitacions en el nombre de particions que es poden crear. La taula gpt és més nova i permet crear més particions. Per tant, és recomanable utilitzar la taula gpt a no se que esteu treballant en un servidor antic.


    👁️ Observació:

    Com únicament volem fer una sola partició, la elecció de la taula de particions no afectarà en aquest cas.

  5. Crearem una nova partició primària en el disc dur extern.

    Command (m for help): n
    Select (default p):
    Partition number (1-4): 1
    First sector (2048-20971519, default 2048):
    Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-20971519, default 20971519):
    

    En aquest cas, crearem una partició primària que ocuparà tot el disc dur. Per tant, acceptarem els valors per defecte. Podeu veure el procés a la següent imatge.

    Crearem una nova partició primària en el disc dur extern

    Per a finalitzar la creació de la partició, premeu la tecla w per a guardar els canvis.

    Guarda els canvis realitzats a la taula de particions

  6. Comprova que la partició s'ha creat correctament.

    lsblk
    

    Comprova que la partició s'ha creat correctament

    Com podeu veure, la partició s'ha creat correctament i s'identifica com a /dev/nvme0n2p1.

  7. Formateja la partició amb el sistema de fitxers ext4.

    mkfs.ext4 /dev/nvme0n2p1
    

    Formateja la partició amb el sistema de fitxers ext4

    👁️ Observació:

    La sortida de la comanda ens mostra el nombre d'inodes, blocs i tamany de blocs del sistema de fitxers creat i també l'identificador UUID del sistema de fitxers. Aquest identificador és únic per a cada sistema de fitxers i ens permet identificar-lo de forma unívoca.

    Podeu utilitzar la comanda blkid per a veure l'identificador UUID del sistema de fitxers en qualsevol moment.

    blkid /dev/nvme0n2p1
    

    Identificador UUID del sistema de fitxers

    També podeu utilitzar la comanda tune2fs per a canviar l'etiqueta del sistema de fitxers.

    tune2fs -L "Backup" /dev/nvme0n2p1
    

    Per a comprovar que l'etiqueta s'ha canviat correctament, podeu utilitzar la comanda lsblk.

    lsblk -o LABEL,UUID,FSTYPE,SIZE,MOUNTPOINT
    

    Sortida de la comanda lsblk amb l'etiqueta del sistema de fitxers

    💡 Nota:

    L'etiqueta del sistema de fitxers ens permet identificar-lo de forma més fàcil i intuïtiva. A més, ens permet identificar el contingut del sistema de fitxers sense haver de muntar-lo.


    👁️ Observació:

    La comanda lsblk té moltes opcions per a mostrar informació dels discs i les particions. Podeu consultar la documentació de la comanda per a veure totes les opcions disponibles (lsblk -h). L'argument -o ens permet seleccionar les columnes que volem mostrar. En aquest cas, hem seleccionat les columnes LABEL, UUID, FSTYPE, SIZE i MOUNTPOINT.

  8. Monta la partició en un directori del sistema de fitxers.

    mount /dev/nvme0n2p1 /mnt
    
  9. Comprova que la partició s'ha muntat correctament o podeu fer amb lsblk o df.

    df -h
    

    Comprova que la partició s'ha muntat correctament

    En el meu cas, he utilitzat la comanda df per a comprovar que la partició s'ha muntat correctament. L'argument -h ens permet mostrar les dades en un format llegible per a humans.

  10. Còpiem totes les dades del directori /home a la nova partició.

    cp -r /home/* /mnt
    
  11. Comparem les dades del directori /home amb les dades de la partició.

    diff -r /home /mnt
    

    Comparem les dades del directori /home amb les dades de la partició

    👁️ Observació:

    En aquest cas, la comanda diff ens mostrarà un missatge indicant que no hi ha cap diferència entre els dos directoris. Ara bé, en el meu cas es mostra el directori lost+found que únicament es troba al disc dur secundari (és a dir a mnt). Aquest directori és creat pel sistema de fitxers ext4 i s'utilitza per a emmagatzemar els inodes dels fitxers que no estan associats a cap directori. Per tant, la seva presència és normal i com no hi ha cap altra diferència, podem assegurar que la còpia s'ha realitzat correctament.

  12. Desmunta la partició per a poder treure el disc dur extern.

    umount /mnt
    

    Desmunta la partició

Migració de directoris a particions diferents

En aquest laboratori assumirem que volem reorganitzar els directoris del nostre sistema de fitxers per a millorar el rendiment i la seguretat del sistema. Crearem 3 noves particions en el disc dur i migrarem els directoris /var, /tmp i /opt en aquestes noves particions.

  1. Utilitzarem el mateix disc dur que en l'escenari anterior.

    Com que ja tenim dades el que farem serà destruir totes les dades per a començar de nou. Per fer-ho, una forma senzilla és sobreescriure les dades amb zeros. Podem sobreescriure els 10GB del disc dur amb zeros amb la comanda dd.

    dd if=/dev/zero of=/dev/nvme0n2 bs=1M count=10000
    

    💡 Nota:

    La comanda dd ens permet copiar dades d'un lloc a un altre. En aquest cas, estem copiant zeros (/dev/zero) al disc dur (/dev/nvme0n2) amb un tamany de 1MB (bs=1M) i tantes vegades com indiquem (count=10000). Això sobreescriurà les dades del disc dur amb zeros i eliminarà totes les dades existents.

  2. Utilitzarem la comanda fdisk per a crear tres noves particions en el disc dur.

    • La primera partició serà per a /var amb el sistema de fitxers ext4, etiqueta var mida 4GB.
    • La segona partició serà per a /tmp amb el sistema de fitxers xfs, sense etiqueta i mida 2GB.
    • La tercera partició serà per a /opt amb el sistema de fitxers ext4, etiqueta opt mida 3GB.
    1. Crearem les noves particions en el disc dur. Podeu utilzar una pipeline per a automatitzar la creació de les particions.

      echo -e "n\np\n\n\n+4G\nn\np\n\n\n+2G\nn\np\n\n\n+3G\nw" | fdisk /dev/nvme0n2
      

      Crearem les noves particions en el disc dur

    2. Formateja les particions amb els sistemes de fitxers corresponents i assigna les etiquetes.

      mkfs.ext4 /dev/nvme0n2p1
      tune2fs -L "var" /dev/nvme0n2p1
      mkfs.xfs /dev/nvme0n2p2
      mkfs.ext4 /dev/nvme0n2p3
      tune2fs -L "opt" /dev/nvme0n2p3
      

      💡 Nota:

      El sistema de fitxers xfs no esta instal·lat per defecte a debian, per tant, haurem d'instal·lar-lo abans de poder utilitzar-lo (apt install xfsprogs).

  3. Monta les particions en directoris del sistema de fitxers. Montarem les particions a /mnt per a poder migrar els directoris.

    mkdir /mnt/var
    mount /dev/nvme0n2p1 /mnt/var
    mkdir /mnt/opt
    mount /dev/nvme0n2p3 /mnt/opt
    

    Monta les particions en directoris del sistema de fitxers

    💡 Nota: Com que la partició /tmp és temporal, no la muntarem ja que no necessitem migrar cap dada.

  4. Migrarem els directoris /var, /tmp i /opt a les noves particions. Per fer-ho podem utilitzar la comanda cp o rsync. En aquest cas utilitzarem rsync per a poder mostrar el progrés de la còpia. Normalment, la eina rsync no ve instal·lada per defecte en la majoria de distribucions, per tant, haurem d'instal·lar-la abans de poder utilitzar-la (apt install rsync).

    rsync -av /var /mnt
    cp -ax /opt /mnt
    

    🚀 Suggeriment:

    Us recomano utilitzar la comanda rsync per a migrar els directoris ja que ens permet mostrar el progrés de la còpia i també ens permet reprendre la còpia en cas que es talli la connexió o hi hagi un error. A més, també ens permet excloure directoris o fitxers que no volem migrar i ens permet fer còpies incrementals. Podeu consultar la documentació de la comanda per a veure totes les opcions disponibles (man rsync).

  5. Comprovem que les dades s'han migrat correctament.

    diff -r /var /mnt/var
    diff -r /opt /mnt/opt
    
  6. Montarem les particions en els directoris corresponents del sistema de fitxers.

    umount /mnt/var
    mount /dev/nvme0n2p1 /var
    umount /mnt/opt
    mount /dev/nvme0n2p3 /opt
    mount /dev/nvme0n2p2 /tmp
    

    Ara ja teniu els directoris /var, /tmp i /opt muntats en les noves particions. Podem fer servir la comanda df per a comprovar que les particions s'han muntat correctament.

    Comprova que les particions s'han muntat correctament

  7. Ara reinicieu el sistema:

    reboot
    

    💡 Nota:

    Un cop reinicieu el sistema, els directoris /var, /tmp i /opt no estaran muntats en les noves particions. Podeu comprovar-ho amb la comanda df. Això és normal ja que hem muntat les particions manualment i no hem el fitxer /etc/fstab per a que es muntin automàticament en l'arrencada del sistema.

  8. Modifica el fitxer /etc/fstab per a que les particions es muntin automàticament en l'arrencada del sistema.

    echo "/dev/nvme0n2p1 /var ext4 defaults 0 0" >> /etc/fstab
    echo "/dev/nvme0n2p2 /tmp xfs defaults 0 0" >> /etc/fstab
    echo "/dev/nvme0n2p3 /opt ext4 defaults 0 0" >> /etc/fstab
    

    💡 Nota:

    El fitxer /etc/fstab conté la informació de les particions que es muntaran automàticament en l'arrencada del sistema. Cada línia del fitxer conté la informació d'una partició. Els camps de cada línia són: dispositiu, punt de muntatge, sistema de fitxers, opcions, freqüència de comprovació i ordre de comprovació. Podeu consultar la documentació del fitxer per a més informació (man fstab).

  9. Comprova que les particions es muntin automàticament en l'arrencada del sistema.

    reboot
    

    Un cop reinicieu el sistema, les particions /var, /tmp i /opt s'hauran muntat automàticament en els directoris corresponents. Podeu comprovar-ho amb la comanda df.

En aquest punt podriam optimitzar la configuració particions per a millorar el rendiment del sistema.

  1. Utiltizarem els UUIDs en lloc dels dispositius per a muntar les particions. Això ens permetrà identificar les particions de forma unívoca i evitar problemes en cas que els dispositius canviïn d'identificador. Per fer-ho podem utilitzar la comanda sed per actualitzar el fitxer /etc/fstab.

    sed -i "s|/dev/nvme0n2p1|UUID=$(blkid -s UUID -o value /dev/nvme0n2p1)|" /etc/fstab
    sed -i "s|/dev/nvme0n2p2|UUID=$(blkid -s UUID -o value /dev/nvme0n2p2)|" /etc/fstab
    sed -i "s|/dev/nvme0n2p3|UUID=$(blkid -s UUID -o value /dev/nvme0n2p3)|" /etc/fstab
    

    🔍 Pregunta: En quins casos poden canviar els dispositius o tenir duplicats?

    Els dispositius poden canviar d'identificador en cas que es connectin més dispositius al sistema o es canvii l'ordre de connexió dels dispositius. Això pot provocar que les particions es muntin en llocs diferents dels esperats. Per a evitar aquest problema, és recomanable utilitzar els UUIDs en lloc dels dispositius per a muntar les particions.

  2. Utilitzarem opcions més específiques per protegir la partició /tmp per a evitar que s’executin programes des de la partició. Utilitzant les opcions nodev, nosuid, i noexec:

    • Edita el fitxer /etc/fstab i afegeix les opcions nodev, nosuid, i noexec a la partició /tmp.

      ℹ️ Què fan les opcions nodev, nosuid, i noexec?

      La opció nodev evita que es puguin executar dispositius en la partició. La opció nosuid evita que es puguin executar programes amb permisos de superusuari en la partició. La opció noexec evita que es puguin executar fitxers binaris des de la partició.

    • Comprova les opcions després d'editar el fitxer /etc/fstab.

      mount | grep /tmp
      

      Comprova les opcions de muntatge de la partició /tmp

    • Per aplicar les opcions de muntatge a la partició /tmp, farem un reboot del sistema.

      Comprova les opcions de muntatge de la partició /tmp

    • Testem les opcions de muntatge de la partició /tmp:

      1. Prova d'executar un programa des de la partició /tmp com a usuari no privilegiat.

        echo "echo 'Hello, World'" > /tmp/hello.sh
        chmod +x /tmp/hello.sh
        /tmp/hello.sh
        bash /tmp/hello.sh
        

        Prova d'executar un programa des de la partició /tmp

      2. Prova de fer el mateix com a usuari privilegiat.

        su -
        /tmp/hello.sh
        bash /tmp/hello.sh
        

        Prova d'executar un programa des de la partició /tmp

        👁️ Observació:

        Observeu que la opció noexec impedeix la execució dels binaris però no ens protegeix contra l'execució de scripts de bash.

      3. Prova d'accedir a un dispositiu creat a /tmp:

        • Inicialitza un dispositiu a /tmp utilitzant la comanda mknod.

          mknod /tmp/dispositiu c 1 3
          

          ⚠️ Compte:

          La comanda mknod única i exclusivament la poden fer els usuaris amb permisos de superusuari. Per tant, feu servir la comanda su per a canviar a l'usuari root abans de fer servir la comanda mknod.

        • Per accedir al dispositiu, utilitza la comanda cat.

          cat /tmp/dispositiu
          

          Prova d'accedir a un dispositiu creat a /tmp

        👁️ Observació:

        Fixeu-vos que quan intento accedir a un dispositiu al directori actual, no hi ha cap problema. Però quan intento accedir al dispositiu creat a /tmp, rebre un missatge d'error indicant que no es pot accedir al dispositiu. Això és degut a la opció nodev que impedeix l'accés a dispositius en la partició.

      4. Per veure, les implicacions de la opció nosuid, podem realitzar el següent experiment:

        Per fer-ho, crearem un executable amb c que ens indicarà l'identificador de l'usuari real i l'identificador de l'usuari efectiu. On l'usuari real és l'usuari que ha iniciat la sessió i l'usuari efectiu és l'usuari que executa el programa. Si un programa té el bit suid activat, l'usuari efectiu serà l'usuari propietari del programa i no l'usuari que l'ha executat.

        #include <stdio.h>
        #include <sys/types.h>
        #include <unistd.h>
        
        int main() {
            printf("Effective user ID: %d\n", geteuid());
            printf("Real user ID: %d\n", getuid());
            return 0;
        }
        

        Compilem el programa amb la comanda gcc.

        gcc -o /tmp/suid /tmp/suid.c
        

        💡 Nota:

        El paquet gcc no ve instal·lat per defecte en una instal·lació mínima de Debian, per tant, haurem d'instal·lar-lo abans de poder utilitzar-lo (apt install build-essential).

        • Desactiva la opció nosuid i també la opció noexec per a la partició /tmp. Per fer-ho, utilitza l'usuari root per a editar el fitxer /etc/fstab.

        • Remunta la partició /tmp.

        • Prova d'executar el programa com a usuari no privilegiat.

          /tmp/suid
          
        • Activa la opció nosuid i torna a provar d'executar el programa.

          /tmp/suid
          

        La següent imatge representa la seqüència de comandes per a provar la opció nosuid:

        Seqüència de comandes

        👁️ Observació:

        Fixeu-vos que quan la opció nosuid està activada, no es pot executar el programa amb permisos de superusuari. Això és important per a evitar que els usuaris no privilegiats puguin executar programes amb permisos de superusuari. Aquesta opció pot permetre escalar privilegis i comprometre la seguretat del sistema.

🔍 Pregunta: Per què és important tenir els directoris /var, /tmp i /opt en particions diferents?

La raó principal per a tenir els directoris /var, /tmp i /opt en particions diferents és per a millorar el rendiment i la seguretat del sistema. El directori /var conté dades variables com ara logs, bases de dades, correu electrònic, etc. Si aquest directori es queda sense espai, el sistema podria fallar. El mateix raonament s'aplica al directori /tmp i /opt. Per això, és important tenir-los en particions separades per a evitar que el sistema falli. A més, tenir els directoris /var, /tmp i /opt en particions separades també millora la seguretat del sistema ja que si una partició falla, les altres particions seguiran funcionant.

Anem a fer una simulació de com respon el sistema en cas de no tenir els directoris /var, /tmp i /opt en particions separades. Per a això, simularem que el directori /opt es va omplint fins a ocupar tot l'espai disponible en la partició principal del sistema.

  1. Desmuntem la partició /opt per a poder continuar amb l'exercici.

    umount /opt
    
  2. Creeu un fitxer de 20GB al directori /opt:

    dd if=/dev/urandom of=/opt/fitxer bs=1M count=20480
    
  3. Comprova l'estat del sistema.

    df -h
    

    Comprova l'estat del sistema

  4. Intenta instal·lar un paquet amb apt i comprova que el sistema falla.

    apt install htop
    

    Intenta instal·lar un paquet amb apt i comprova que el sistema falla

    Com podeu veure, el sistema fallarà ja que no té espai suficient per a instal·lar el paquet. Això és un problema greu ja que el sistema no podrà funcionar correctament fins que no alliberem espai en la partició principal.

  5. Elimina el fitxer que has creat per a poder continuar amb la resta de l'exercici.

    rm /opt/fitxer
    
  6. Munteu la partició /opt i torneu a crear el fitxer per a omplir el directori.

    mount /dev/nvme0n2p3 /opt
    dd if=/dev/urandom of=/opt/fitxer bs=1M count=20480
    

    Munteu la partició /opt i torneu a crear el fitxer per a omplir el directori

  7. Ara únicament teniu la partició /opt plena; però el sistema pot continuar fent tasques:

    apt install htop
    

    El sistema pot continuar fent tasques

Simulant una corrupció a /home

En aquest escenari simularem que hem patit una corrupció a la partició /home i quines eines podem utiltzar per intentar recuperar les dades.

Preparació de l'escenari

El primer pas que farem serà migrar el directori /home a una partició diferent per a poder simular la corrupció. A continuació, simularem la corrupció i finalment recuperarem les dades.

  1. Crearem una nova partició en el disc dur extern. Recorda que ja tenim 3 particions creades en aquest disc dur, per tant, la nova partició serà la quarta. Aquesta partició la farem de 600M de mida i la formatejarem amb el sistema de fitxers xfs.

    echo -e "n\np\n4\n\n+600M\nw" | fdisk /dev/nvme0n2
    mkfs.xfs /dev/nvme0n2p4
    
  2. Crearem un directori on muntarem la nova partició.

    mkdir /mnt/home
    
  3. Muntarem la nova partició en el directori /mnt/home.

    mount /dev/nvme0n2p4 /mnt/home
    
  4. Copiarem totes les dades del directori /home a la nova partició.

    rsync -a /home/ /mnt/
    
  5. Desmontarem la partició.

    umount /mnt/home
    
  6. Modificarem el fitxer /etc/fstab per a que la partició es munti automàticament en l'arrencada del sistema.

    echo "/dev/nvme0n2p4 /home xfs defaults,nodev 0 0" >> /etc/fstab
    
  7. Comprovarem que la partició es munta automàticament en l'arrencada del sistema.

    reboot
    

Simulant la corrupció

Un cop hem migrat el directori /home a una partició diferent, si tot ha anat bé, hauriau de tenir el següent resultat:

home_migrat

Ara podem crear fitxers i directoris al directori /home del vostre usuari normal, en el meu cas jordi.

mkdir codi
mkdir dades
touch dades/pokemon.csv
touch codi/main.c
touch codi/Makefile
touch codi/README.md
touch .vim

home_migrat_fitxers

Per a simular una corrupció editarem alguns valors de la partició /home amb un editor hexadecimal.

  1. Desmuntem la partició /home.

    umount /home
    

    Compte!: Si esteu connectats per SSH, no podreu desmuntar la partició /home ja que el vostre usuari està utilitzant aquesta partició. En la primera sessió. Per tant, haure de fer-ho a la consola de la màquina virtual.

    home_desmuntat

  2. Obrirem la partició /home amb un editor hexadecimal. Podeu instal·lar l'editor hexadecimal hexedit amb la comanda apt install hexedit.

    hexedit /dev/nvme0n2p4 
    
  3. Modifiqueu bits a l'atzar i deseu els canvis. Per fer-ho escriviu damunt dels valors hexadecimals altres valors. Un cop fet guardeu amb Ctrl + X i Y.

    home_corrupte_hexedit

    Fixeu-vos en els primers valors resaltats en negreta són els que he modificat.

  4. Ara intentarem muntar la partició /home per a comprovar que ha estat corrompuda.

    mount /home
    

    Si la partició /home s'ha corromput, hauríeu de veure un missatge d'error com aquest:

    home_corrupte

  5. Els diferents sistemes de fitxers tenen eines per a comprovar la integritat dels fitxers. Per exemple, el sistema de fitxers xfs té l'eina xfs_ncheck que permet comprovar la integritat dels fitxers.

    xfs_ncheck /dev/nvme0n2p4
    
  6. Per a reparar la partició /home utilitzarem l'eina xfs_repair.

    xfs_repair /dev/nvme0n2p4
    
  7. Un cop reparada la partició /home, la muntarem de nou.

    mount /home
    
  8. Comprovarem que la partició /home s'ha muntat correctament i conté els fitxers que havíem creat.

    ls /home
    

Sistemes de fitxers temporals

En aquest laboratori, compararem el rendiment dels sistemes de fitxers ext4, xfs i tmpfs en un entorn de còmput científic. Els sistemes de fitxers temporals, com tmpfs, poden millorar significativament el rendiment d’operacions d’entrada/sortida intensives.

Context

Assumeix l'administració d'un servidor de còmput científic que necessita realitzar moltes operacions d'entrada/sortida. En aquest escenari, el rendiment del sistema de fitxers pot ser crític per a l'eficiència del sistema. En aquest laboratori volem corrobarar la següent hipòtesi: els sistemes de fitxers temporals, com tmpfs, poden millorar significativament el rendiment d'operacions d'entrada/sortida intensives per aquest tipus de càrregues de treball.

Objectius

  • Comprendre el rendiment dels sistemes de fitxers ext4, xfs i tmpfs.
  • Comparar el rendiment dels sistemes de fitxers ext4, xfs i tmpfs en un entorn de còmput científic.
  • Optimitzar el rendiment del sistema de fitxers utilitzant un sistema de fitxers temporal.

Preparació de l'entorn

  1. Creeu un nova màquina virtual amb Debian 12. Podeu utiltizar una configuració per defecte amb 2GB de RAM i 20GB d'espai en el disc principal. En cas, de tenir problemes de RAM durant l'execució de l'experiment, podeu augmentar la RAM a 4GB. Aquests problemes poden causar que el kernel mati el procés per falta de memòria (OOM Killer).
  2. Creeu un disc secundari de 20GB per crear els sistemes de fitxers ext4, xfs i tmpfs.
  3. Particioneu el disc secundari amb 3 particions: ext4, xfs i tmpfs cada una amb 5GB d'espai.
  4. Munteu les particions a les rutes /mnt/ext4, /mnt/xfs i /mnt/tmpfs respectivament.

Per crear el sistema de fitxers temporal tmpfs, podeu utilitzar la comanda següent:

mount -t tmpfs -o size=5G tmpfs /mnt/tmpfs

Per veure el sistema de fitxers muntat, podeu utilitzar la comanda següent:

df -h

Preparació de l'experiment

Per simular el nostre experiment, crearem un script de Python que generi un fitxer gran i realitzi moltes operacions d'escriptura aleatòria. Aquest script pot ser executat en un servidor de còmput per provar el rendiment del sistema de fitxers. Com a parametres d'entrada podem especificar la ruta del fitxer, la mida del fitxer, el nombre d'operacions d'escriptura aleatòria i la mida del bloc d'escriptura.

import os
import random
import time
import argparse

def create_large_file(file_path, size_in_mb):
    with open(file_path, 'wb') as f:
        f.write(os.urandom(size_in_mb * 1024 * 1024))

def random_write(file_path, num_operations, block_size):
    with open(file_path, 'r+b') as f:
        for _ in range(num_operations):
            offset = random.randint(0, os.path.getsize(file_path) - block_size)
            f.seek(offset)
            f.write(os.urandom(block_size))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Simulació de càlcul intensiu d'entrada/sortida")
    parser.add_argument('--file_path', type=str, default="/mnt/tmpfs/large_file.bin", help="Camí del fitxer a crear")
    parser.add_argument('--log_file', type=str, default="/mnt/tmpfs/experiment_log.txt", help="Camí del fitxer de registre")
    parser.add_argument('--size_in_mb', type=int, default=1024, help="Mida del fitxer en MB")
    parser.add_argument('--num_operations', type=int, default=10000, help="Nombre d'operacions d'escriptura aleatòria")
    parser.add_argument('--block_size', type=int, default=4096, help="Mida del bloc en bytes")

    args = parser.parse_args()

    start_time = time.time()
    create_large_file(args.file_path, args.size_in_mb)
    random_write(args.file_path, args.num_operations, args.block_size)
    end_time = time.time()

    total_time = end_time - start_time
    log_message = f"Experiment completat en {total_time} segons"

    print(log_message)

Execució de l'experiment

Un cop analitzat el codi, podem executar l'experiment per comparar el rendiment dels sistemes de fitxers ext4, xfs i tmpfs.

  1. Executem l'experiment amb el sistema de fitxers ext4:

    python3 simulate_io_intensive.py --file_path /mnt/ext4/large_file.bin --size_in_mb 1024 --num_operations 10000 --block_size 4096
    
  2. Executem l'experiment amb el sistema de fitxers xfs:

    python3 simulate_io_intensive.py --file_path /mnt/xfs/large_file.bin --size_in_mb 1024 --num_operations 10000 --block_size 4096
    
  3. Executem l'experiment amb el sistema de fitxers tmpfs:

    python3 simulate_io_intensive.py --file_path /mnt/tmpfs/large_file.bin --size_in_mb 1024 --num_operations 10000 --block_size 4096
    

Ara realitzarem l'experiment 10 vegades per obtenir una mitjana del temps d'execució per a cada sistema de fitxers.

  • Sistema de fitxers: ext4
for i in {1..10}
do
    python3 simulate_io_intensive.py --file_path /mnt/ext4/large_file.bin --size_in_mb 1024 --num_operations 10000 --block_size 4096
done
Temps d'execució (s)Iteració
3.041
2.582
2.623
3.284
2.685
2.986
2.667
3.348
2.799
2.8310
Mitjana2.88
  • Sistema de fitxers: xfs
for i in {1..10}
do
    python3 simulate_io_intensive.py --file_path /mnt/xfs/large_file.bin --size_in_mb 1024 --num_operations 10000 --block_size 4096
done
Temps d'execució (s)Iteració
2.341
2.422
2.413
2.414
2.405
2.396
2.417
2.448
2.499
2.4610
Mitjana2.42
  • Sistema de fitxers: tmpfs
for i in {1..10}
do
    python3 simulate_io_intensive.py --file_path /mnt/tmpfs/large_file.bin --size_in_mb 1024 --num_operations 10000 --block_size 4096
done
Temps d'execució (s)Iteració
2.331
2.292
2.283
2.294
2.325
2.326
2.307
2.338
2.319
2.2910
Mitjana2.31

Observeu com el sistema de fitxers tmpfs té un rendiment significativament millor que els sistemes de fitxers ext4 i xfs en aquest escenari. Això es deu al fet que tmpfs emmagatzema les dades a la memòria RAM en lloc de l'emmagatzematge en disc, el que permet un accés més ràpid a les dades. Ara bé, cal tenir en compte que les dades emmagatzemades a tmpfs es perden quan el sistema es reinicia.

Explorant d'un sistema de fitxers avançat: zfs

En aquesta secció, explorarem el sistema de fitxers ZFS (Zettabyte File System). ZFS és un sistema de fitxers avançat que ofereix moltes característiques interessants com ara la integritat de les dades, la compressió, la deduplicació, la replicació, la instantània, la clonació, etc. Per fer-ho utilitzarem la màquina virtual amb Almalinux 9.4.

  1. Instal·la el repositori EPEL:

    dnf install epel-release -y
     ```
    
    
  2. Afegeix el repositori ZFS:

    dnf install https://zfsonlinux.org/epel/zfs-release-2-3$(rpm --eval "%{dist}").noarch.rpm -y
    
  3. Instal·lació dels paquets necessaris:

    dnf install kernel-devel
    
  4. Actualitzar el sistema:

    dnf update -y
    
  5. Segons la documentació, veure Getting Started: Per defecte, el paquet zfs-release està configurat per instal·lar paquets de tipus DKMS perquè funcionin amb una àmplia gamma de kernels. Per poder instal·lar els mòduls kABI-tracking, cal canviar el repositori predeterminat de zfs a zfs-kmod.

    dnf config-manager --disable zfs
    dnf config-manager --enable zfs-kmod
    dnf install zfs
    
  6. Reinicieu la màquina virtual:

    reboot
    
  7. Carregeu el modul zfs al kernel de linux:

    modprobe zfs
    

Creació d'un pool ZFS

Una pool ZFS és un conjunt de dispositius de blocs que es poden utilitzar per emmagatzemar dades. Aquesta pool pot estar formada per un o més dispositius de blocs. Aquests dispositius poden ser discos durs, SSD, dispositius de xarxa, etc. Aquesta pool es pot utilitzar per crear conjunts de dades i sistemes de fitxers ZFS. Utiltizarem el disc /etc/vdb per crear la pool.

  1. Creació de la pool:

    zpool create -f zfspool /dev/vdb
    
  2. Comprovació de la pool:

    zpool status
    
    pool: zfspool
    state: ONLINE
    scan: none requested
    config:
    
    NAME        STATE     READ WRITE CKSUM
    zfspool     ONLINE       0     0     0
      vdb       ONLINE       0     0     0
    
    errors: No known data errors
    
  3. Creació d'un sistema de fitxers que anomenarem (dades):

    zfs create zfspool/dades
    
  4. Comprovació del conjunt de dades:

    zfs list
    
    NAME            USED  AVAIL     REFER  MOUNTPOINT
    zfspool         135K   352M     25.5K  /zfspool
    zfspool/dades    24K   352M       24K  /zfspool/dades
    

    NOTA: Ara mateix tenim muntats dos sistemes de fitxers: zfspool i zfspool/dades. Per defecte, els sistemes de fitxers ZFS es muntaran a /zfspool i /zfspool/dades. Però, podem canviar aquest comportament i muntar els sistemes de fitxers a un altre directori.

  5. Anem a canviar el punt de muntatge de zfspool/dades a /mnt/dades:

    mkdir /mnt/dades
    
    zfs set mountpoint=/mnt/dades zfspool/dades
    
    zfs list
    
    NAME            USED  AVAIL     REFER  MOUNTPOINT
    zfspool         135K   352M     25.5K  /zfspool
    zfspool/dades    24K   352M       24K  /mnt/dades
    
  6. Ara crearem uns quants fitxers i directoris a /mnt/data:

    mkdir /mnt/dades/sergi
    mkdir /mnt/dades/adria
    touch /mnt/dades/sergi/a.txt
    touch /mnt/dades/sergi/a.c
    mkdir /mnt/dades/adria/config
    touch /mnt/dades/adria/config/.vim
    
  7. ZFS ens permet crear snapshots (instantànies) dels nostres sistemes de fitxers. Aquestes instantànies són còpies de seguretat dels nostres sistemes de fitxers en un moment determinat. Aquestes instantànies es poden utilitzar per restaurar els nostres sistemes de fitxers en cas de fallada o error. Crearem una instantània del nostre sistema de fitxers zfspool/dades:

    zfs snapshot zfspool/dades@snap1
    
  8. Ara eliminarem el directori /mnt/dades/adria/config:

    rm -rf /mnt/dades/adria/config
    
  9. Podem utilitzar la comanda zfs rollback per restaurar el nostre sistema de fitxers a l'estat de l'instantània:

    zfs rollback zfspool/dades@snap1
    
  10. Comprovem que el directori /mnt/dades/adria/config ha estat restaurat:

    ls -la /mnt/dades/adria/config
    
    total 2
    drwxr-xr-x. 2 root root 3 Oct  3 10:01 .
    drwxr-xr-x. 3 root root 3 Oct  3 10:01 ..
    -rw-r--r--. 1 root root 0 Oct  3 10:01 .vim
    
  11. Podem utilitzar la comanda zfs clone per crear un clon del nostre sistema de fitxers zfspool/dades:

    zfs clone zfspool/dades@snap1 zfspool/dades/clone1
    

    OBSERVACIÓ 1: Els clons en ZFS permeten realitzar migracions de dades eficients i segures. Abans d'efectuar canvis en el sistema de producció o transferir dades a un nou sistema, es pot crear un clon de les dades existents per provar la migració sense afectar les dades originals

    OBSERVACIÓ 2: Quan es requereix realitzar operacions de processament, anàlisi o transformació de dades, els clons permeten fer-ho sense modificar o posar en perill les dades originals.

    zfs list
    
    NAME                   USED  AVAIL     REFER  MOUNTPOINT
    zfspool                217K   352M       24K  /zfspool
    zfspool/dades           43K   352M       29K  /mnt/dades
    zfspool/dades/clone1     0B   352M       29K  /mnt/dades/clone1
    
  12. Per eliminar un clon, utilitzarem la comanda zfs destroy:

    zfs destroy zfspool/dades/clone1
    
  13. Per eliminar una instantània, utilitzarem la comanda zfs destroy:

    zfs destroy zfspool/dades@snap1
    
  14. Per eliminar un sistema de fitxers, utilitzarem la comanda zfs destroy:

    zfs destroy zfspool/dades
    

    NOTA: Si enlloc d'eliminar volem únicament desmuntar, utilitzarem la comanda zfs umount. Per exemple: zfs umount zfspool/dades.

  15. Per eliminar una pool, utilitzarem la comanda zpool destroy:

    zpool destroy zfspool
    

Raids

En aquest laboratori aprendrem a configurar i gestionar sistemes RAID en un servidor Linux. Aquesta tecnologia ens permetrà augmentar la disponibilitat i la tolerància a fallades dels nostres sistemes.

Objectius

  • Comprendre els conceptes bàsics de RAID.
  • Configurar diferents nivells de RAID.
  • Comparar el rendiment de diferents nivells de RAID.

Comandes bàsiques

  • mdadm: Utilitzada per gestionar dispositius RAID.
  • lsblk: Mostra informació sobre els dispositius de bloc.
  • fio: Eina de benchmarking per provar el rendiment dels dispositius de bloc.
  • mount: Utilitzada per muntar sistemes de fitxers.
  • mkfs: Utilitzada per crear sistemes de fitxers.

Continguts

  1. Rendiment.
  2. Simulant fallades.
  3. Migració.

Comparant el rendiment de diferents nivells de RAIDs

En aquest laboratori, compararem el rendiment de diferents nivells de RAID utilitzant l'eina de benchmark fio. En concret, compararem el rendiment del RAID 0 i del RAID 1 en operacions d'escriptura i de lectura. Aquesta anàlisi ens permetrà comprendre les diferències de rendiment entre els dos tipus de RAID i determinar quin tipus de RAID és més adequat per a les nostres necessitats.

Configuració de l'entorn

En aquest laboratori utiltizarem una màquina virtual amb Debian 12 i 4 discos secundaris de 5GB cadascun. Aquests discos secundaris es configuraran en dos nivells de RAID diferents: RAID0 i RAID1.

📝 Nota

Si no voleu utilitzar 4 discs podeu utiltizar 2 disc amb diferents particions per a crear les RAID. El més important és que la RAID0 i la RAID1 tinguin el mateix nombre de discs, capacitat i tipus per poder fer una comparació justa.

Creació de les raids

  1. Creació de raid0:

    mdadm --create --verbose /dev/md0 --level=0 --raid-devices=2 /dev/nvme0n2 /dev/nvme0n3
    
  2. Creació del sistema de fitxers:

    mkfs.ext4 /dev/md0
    
  3. Muntatge del sistema de fitxers:

    mkdir /mnt/md0
    mount /dev/md0 /mnt/md0
    
  4. Creació de raid1:

    mdadm --create --verbose /dev/md1 --level=1 --raid-devices=2 /dev/nvme0n4 /dev/nvme0n5
    
  5. Creació del sistema de fitxers:

    mkfs.ext4 /dev/md1
    
  6. Muntatge del sistema de fitxers:

    mkdir /mnt/md1
    mount /dev/md1 /mnt/md1
    

Instal·lant l'eina de benchmark fio

La eina fio ens permetrà realitzar diferents experriments per tal de comparar diferents operacions d'entrada/sortida amb diferents configuracions de blocs.

apt install fio -y

Proves de rendiment

  1. Test de rendiment del RAID0 en oepracions d'escriptura:

    fio --name=write-raid1 --ioengine=libaio --iodepth=32 --rw=write \
    --bs=4k --size=500M --numjobs=4 --runtime=120 --time_based \
    --ramp_time=15 --group_reporting --filename=/dev/raid1 \
    --output-format=json --output=/tmp/write-raid1.json
    
  2. Test de rendiment del RAID0 en operacions de lectura:

    fio --name=read-raid0 --ioengine=libaio --iodepth=32 --rw=read \
    --bs=4k --size=500M --numjobs=4 --runtime=120 --time_based \
    --ramp_time=15 --group_reporting --filename=/dev/raid0 \
    --output-format=json --output=/tmp/read-raid0.json
    
  3. Test de rendiment del RAID1 en operacions d'escriptura:

    fio --name=write-raid1 --ioengine=libaio --iodepth=32 --rw=write \
    --bs=4k --size=500M --numjobs=4 --runtime=120 --time_based \
    --ramp_time=15 --group_reporting --filename=/dev/raid1 \
    --output-format=json --output=/tmp/write-raid1.json
    
  4. Test de rendiment del RAID1 en operacions de lectura:

    fio --name=read-raid1 --ioengine=libaio --iodepth=32 --rw=read \
    --bs=4k --size=500M --numjobs=4 --runtime=120 --time_based \
    --ramp_time=15 --group_reporting --filename=/dev/raid1 \
    --output-format=json --output=/tmp/read-raid1.json
    

Anàlisi de resultats

Per analitzar els resultats obtinguts, ens centrarem en els següents paràmetres:

  • Bandwidth: La velocitat de transferència de dades en bytes per segon.
  • IOPS: El nombre d’operacions d’entrada/sortida per segon.
  • Latència: El temps que triga el sistema a respondre a una petició d’entrada/sortida.
  • Total IO: El nombre total d’operacions d’entrada/sortida.
Op.RAIDBandwidth (GB/s)IOPSLatència(µs)Total IO (GB)
W010.582.65e+0648.22317.6
W17.931.98e+0664.40238.0
R018.764.69e+0627.16562.98
R118.824.71e+0627.08564.6

La taula mostra un resum dels resultats obtinguts de les proves de rendiment del RAID 0 i del RAID 1. Aquests resultats corroboren les diferències de rendiment entre els dos tipus de RAID. En primer lloc, si ens centrem en el Bandwidth, podem observar un rendiment similar en les operacions de lectura amb unes velocitats de 18.76GB/s i 18.82GB/s respectivament. En canvi, el RAID 0 té un rendiment superior en les operacions d'escriptura amb una velocitat de 10.59GB/s, mentre que el RAID 1 té una velocitat de 7.93GB/s. Això es deu al fet que en el RAID 0 les dades es distribueixen entre els dos discs, mentre que en el RAID 1 les dades s'han de copiar en tots dos discs. En segon lloc, si analitzem les variables de Latency i IOPS observem un rendiment similar en les operacions de lectura, amb una latència de 27.16µs i 27.08µs respectivament. En canvi, en les operacions d'escriptura, el RAID 0 té una latència de 48.22µs i 64.40µs en el RAID 1. Finalment, en termes de Total IO, el RAID 0 té un rendiment superior amb 317.69GB en les operacions d'escriptura, mentre que el RAID 1 té un rendiment de 238.01GB.

🚀 Conclusió:

Aquesta anàlisi demostra que el RAID 0 ofereix un rendiment superior en termes de velocitat d'escriptura, mentre que el RAID 1 proporciona una major seguretat de les dades a costa d'una velocitat d'escriptura més lenta. Per tant, la selecció del tipus de RAID depèn de les necessitats específiques de l'usuari, prioritzant la velocitat o la seguretat de les dades.

Tolerància a fallades

Preparació de l'entorn

En aquest laboratori podeu utilitzar la mateixa màquina virtual que en el laboratori anterior. Ens centrarem en la tolerància a fallades dels sistemes RAID0 i RAID1.

Simulant una fallada en un disc del RAID1

  1. Crearem dades en el sistema de fitxers del RAID1.

    fallocate -l 100M /mnt/md1/testfile
    
  2. Simularem una fallada en un dels discos del RAID1. Utilitzant l'argument --set-faulty de mdadm podem simular una fallada en un dels discos.

    mdadm --manage /dev/md1 --set-faulty /dev/nvme0n4
    
  3. Comproveu l'estat del RAID1 amb la comanda mdadm --detail /dev/md1.

    📝 Nota

    Alternativament, podeu utilitzar la comanda cat /proc/mdstat per comprovar l'estat dels vostres dispositius RAID.

  4. Comproveu integritat de les dades:

    ls -la /mnt/md1
    

    Si tot ha anat bé, les dades haurien de ser accessibles.

Simulant una fallada en un disc del RAID0

  1. Crearem dades en el sistema de fitxers del RAID0.

    fallocate -l 100M /mnt/md0/testfile
    
  2. Utilitzarem la comanda hexdump per escriure dades aleatòries al disc i corrompre'l.

    hexdump -C /dev/nvme0n2 | head -n 10
    
  3. Desmuntarem el sistema de fitxers i el muntarem de nou.

    umount /mnt/md0
    mount /dev/md0 /mnt/md0
    
  4. El sistema us hauria de mostrar un error semblant a aquest:

    mount: /mnt/md0: can't read superblock on /dev/md0.
       dmesg(1) may have more information after failed mount system call.
    

    En aquest cas, el sistema no pot muntar el sistema de fitxers ja que el disc ha estat corromput.

Migració d'un servidor tradicional a un servidor amb RAID

En aquest laboratori aprendrem a migrar un servidor tradicional a un servidor amb RAID.

Notes

📝 Nota 1

Es possible que observeu un missatge com el següent quan realitzeu el laboratori: mount: (hint) your fstab has been modified, but systemd still uses the old version; use 'systemctl daemon-reload' to reload. Podeu ignorar aquest missatge ja que no afecta el funcionament del laboratori. O si voleu podeu executar la comanda systemctl daemon-reload per assegurar-vos que el sistema ha recarregat la configuració.

Preparació de l'entorn

Assumirem una màquina virtual amb AlmaLinux on tenim un disc dur principal de 20GB particionat de la següent manera:

  • /boot de 600MB amb el sistema de fitxers xfs.
  • /boot/efi de 1024MB amb el sistema de fitxers vfat.
  • swap de 2GB.
  • / de 16GB amb el sistema de fitxers xfs.

Estat inicial lsblk

Instal·leu els paquet següents que necessitarem per aquest laboratori:

  1. mdadm: Utilitzada per gestionar dispositius RAID.

    dnf install mdadm -y
    
  2. rsync: Utilitzada per copiar el contingut de les particions.

    dnf install rsync -y
    

Disseny de la nova arquitectura

Utiltizarem 2 discs secundaris de 20GB cadascun per crear la següent arquitectura:

  • RAID 1 amb /boot i /boot/efi.
  • RAID 1 amb swap.
  • RAID 1 amb /.

Preparació dels discs

  1. Creació de la taula de particions i de les particions als discs secundaris.

    • /boot/efi:

      echo -e "g\nn\np\n\n\n+600M\nt\n29\nw" | fdisk /dev/nvme0n2
      echo -e "g\nn\np\n\n\n+600M\nt\n29\nw" | fdisk /dev/nvme0n3
      
    • boot:

      echo -e "n\np\n\n\n+1024M\nt\n2\n29\nw" | fdisk /dev/nvme0n2
      echo -e "n\np\n\n\n+1024M\nt\n2\n29\nw" | fdisk /dev/nvme0n3
      
    • swap:

      echo -e "n\np\n\n\n+2G\nt\n3\n29\nw" | fdisk /dev/nvme0n2
      echo -e "n\np\n\n\n+2G\nt\n3\n29\nw" | fdisk /dev/nvme0n3
      
    • /:

      echo -e "n\np\n\n\n+16G\nt\n4\n29\nw" | fdisk /dev/nvme0n2
      echo -e "n\np\n\n\n+16G\nt\n4\n29\nw" | fdisk /dev/nvme0n3
      
  2. Comproveu que les particions s'han creat correctament amb lsblk.

    Estat de les particions lsblk

RAID 1 amb /boot/efi

  1. Creació del RAID 1 amb /boot/efi.

    mdadm --create --verbose /dev/md0 --level=1 --raid-devices=2 \
    --metadata=1.0 /dev/nvme0n2p1 /dev/nvme0n3p1
    
  2. Creació del sistema de fitxers fat32.

    mkfs.vfat /dev/md0
    
  3. Crear un punt de muntatge temporal i muntar el sistema de fitxers.

    mkdir /tmp/raid1
    mount /dev/md0 /tmp/raid1
    
  4. Copiar el contingut de /boot/efi al RAID 1.

    rsync -avx /boot/efi/ /tmp/raid1
    
  5. Desmuntar la RAID:

    umount /tmp/raid1
    
  6. Seleccionar el UUID del RAID 1:

    EFI_RAID_UUID=$(blkid -s UUID -o value /dev/md0)
    
  7. Actualitzar /etc/fstab amb el nou UUID.

    CURRENT_BOOT_UUID=$(blkid -s UUID -o value /dev/nvme0n1p1)
    sed -i "s|UUID=$CURRENT_BOOT_UUID|UUID=$EFI_RAID_UUID |" /etc/fstab
    

RAID 1 amb boot

Repetiu els passos anteriors per crear el RAID 1 anomenta (/dev/md1) amb /boot. Utiltizant les particions /dev/nvme0n2p2 i /dev/nvme0n3p2.

  1. Creació del RAID 1 amb /boot.

    mdadm --create --verbose /dev/md1 --level=1 --raid-devices=2 \
    --metadata=1.0 /dev/nvme0n2p2 /dev/nvme0n3p2
    
  2. Creació del sistema de fitxers xfs.

    mkfs.xfs /dev/md1
    
  3. Crear un punt de muntatge temporal i muntar el sistema de fitxers.

    mkdir /tmp/raid2
    mount /dev/md1 /tmp/raid2
    
  4. Copiar el contingut de /boot al RAID 1.

    rsync -avx /boot/ /tmp/raid2
    
  5. Desmuntar la RAID:

    umount /tmp/raid2
    
  6. Seleccionar el UUID del RAID 1:

    BOOT_RAID_UUID=$(blkid -s UUID -o value /dev/md1)
    
  7. Actualitzar /etc/fstab amb el nou UUID.

    CURRENT_BOOT_UUID=$(blkid -s UUID -o value /dev/nvme0n1p2)
    sed -i "s|UUID=$CURRENT_BOOT_UUID|UUID=$BOOT_RAID_UUID |" /etc/fstab
    

RAID 1 amb swap

  1. Creació del RAID 1 amb swap.

    mdadm --create --verbose /dev/md2 --level=1 --raid-devices=2 \
    /dev/nvme0n2p3 /dev/nvme0n3p3
    
  2. Creació del sistema de fitxers swap.

    mkswap /dev/md2
    
  3. Activar el sistema de fitxers swap.

    swapon /dev/md2
    
  4. Actualitzar /etc/fstab amb el nou UUID.

    CURRENT_SWAP_UUID=$(blkid -s UUID -o value /dev/nvme0n1p3)
    SWAP_RAID_UUID=$(blkid -s UUID -o value /dev/md2)
    sed -i "s|UUID=$CURRENT_SWAP_UUID|UUID=$SWAP_RAID_UUID |" /etc/fstab
    
  5. Compproveu que la partició swap s'ha activat correctament.

    swapon --show
    

RAID 1 amb /

  1. Creació del RAID 1 amb /.

    mdadm --create --verbose /dev/md3 --level=1 --raid-devices=2 \
    /dev/nvme0n2p4 /dev/nvme0n3p4
    
  2. Creació del sistema de fitxers xfs.

    mkfs.xfs /dev/md3
    
  3. Crear un punt de muntatge temporal i muntar el sistema de fitxers.

    mkdir /tmp/raid3
    mount /dev/md3 /tmp/raid3
    
  4. Noms de dispositius RAID persistents.

    mkdir -p /etc/mdadm
    mdadm --detail --scan > /etc/mdadm/mdadm.conf
    
  5. Seleccionar el UUID del RAID 1:

    ROOT_RAID_UUID=$(blkid -s UUID -o value /dev/md3)
    
  6. Actualitzar /etc/fstab amb el nou UUID.

    CURRENT_ROOT_UUID=$(blkid -s UUID -o value /dev/nvme0n1p4)
    sed -i "s|UUID=$CURRENT_ROOT_UUID|UUID=$ROOT_RAID_UUID |" /etc/fstab
    
  7. Copiar el contingut de / al RAID 1.

    cp -ax / /tmp/raid3
    

Configuració del GRUB

  1. Actualitzar la configuració del GRUB.

    vi /etc/default/grub
    

    Teniu dos opcions per configurar el GRUB, com els noms dels dispositius no canviaran, ja que els hem fet persistent, podeu utilitzar el nom del dispositiu /dev/mdX o el UUID del RAID.

    GRUB_CMDLINE_LINUX="root=/dev/md3 rd.auto ..."
    GRUB_ENABLE_BLSCFG=false
    GRUB_CMDLINE_LINUX_DEFAULT=""
    

    o bé utilitzant el UUID del RAID.

    GRUB_CMDLINE_LINUX="root=UUID=<UUID> rd.auto ..."
    GRUB_ENABLE_BLSCFG=false
    GRUB_CMDLINE_LINUX_DEFAULT=""
    # on <UUID> és el UUID del RAID 1 amb /.
    # rd.auto: Per carregar automàticament els mòduls RAID.
    # GRUB_ENABLE_BLSCFG=false: Per desactivar el suport de BLS.
    # GRUB_CMDLINE_LINUX_DEFAULT="": Per desactivar les opcions per defecte.
    
  2. Copiar el GRUB al nou disc.

    cp /etc/default/grub /tmp/raid3/etc/default/grub
    
  3. Instal·lar el GRUB a cada disc secundari.

    efibootmgr --create --disk /dev/nvme0n2 --part 1 --label "almalinux-mirror-01" --loader "\EFI\almalinux\grubaa64.efi"
    efibootmgr --create --disk /dev/nvme0n3 --part 1 --label "almalinux-mirror-02" --loader "\EFI\almalinux\grubaa64.efi"
    
  4. Actualitzar la configuració del GRUB.

    grub2-mkconfig -o /boot/efi/EFI/almalinux/grub.cfg
    
  5. Actualitzarem la initramfs per incloure els mòduls RAID.

    dracut -f
    
  6. Reiniciar el sistema.

    reboot
    

Nota: Aquesta configuració no és del tot correcta, i veureu que el raid de la partició del sistema / no es munta i es segueix utilitzant la partició original. Tot i això, si en el grub indiquem root=/dev/md3 i rd.auto, el sistema arrenca correctament. Per tant, deures investigar com fer que el sistema munti el raid de la partició / correctament.

Desplegant un servidor web: Wordpress

En aquest laboratori, desplegarem un servidor web senzill amb WordPress, una de les plataformes de gestió de continguts (CMS) més populars del món. WordPress permet crear i gestionar llocs web de manera intuïtiva i eficient, i és ideal per a projectes com blocs, botigues en línia, portals de notícies, i molt més.

Per a aquest desplegament, utilitzarem una arquitectura monolítica, una solució senzilla on tots els components del lloc web es troben en una sola màquina virtual. Aquesta configuració és adequada per a llocs web petits o amb poc trànsit, ja que ofereix una implementació ràpida i fàcil de gestionar. No obstant això, a mesura que el lloc web creixi o augmenti el trànsit, caldrà considerar opcions més complexes, com ara l'escalabilitat horitzontal o vertical.

Esquema de la implementació monolítica

Si consulteu la web oficial de Wordpress, veureu que la versió actual és la 6.6.2. I els seus requeriments per la instal·lació són els següents:

  • PHP: Versió 7.4 o superior.
  • MySQL o MariaDB: MySQL versió 5.7 o superior o MariaDB versió 10.3 o superior.
  • Apache o Nginx: Versió 2.4 o superior per a Apache o versió 1.26 o superior per a Nginx.
  • HTTPS: Recomanat per a la seguretat del lloc web.

Per tant, haurem de preparar un servidor que compleixi aquests requeriments abans de procedir a la instal·lació de Wordpress.

Requisits

  • Màquina virtual amb sistema operatiu AlmaLinux.

Objectius

  • Desplegar un servidor web senzill amb Wordpress.
  • Configurar un servidor web amb Apache.
  • Configurar una base de dades amb MariaDB.
  • Configurar un servidor PHP amb PHP.
  • Instal·lar i configurar Wordpress.
  • Provar el lloc web de Wordpress.

Desplegant un servidor web: Wordpress

En aquest laboratori, desplegarem un servidor web senzill amb WordPress, una de les plataformes de gestió de continguts (CMS) més populars del món. WordPress permet crear i gestionar llocs web de manera intuïtiva i eficient, i és ideal per a projectes com blocs, botigues en línia, portals de notícies, i molt més.

Per a aquest desplegament, utilitzarem una arquitectura monolítica, una solució senzilla on tots els components del lloc web es troben en una sola màquina virtual. Aquesta configuració és adequada per a llocs web petits o amb poc trànsit, ja que ofereix una implementació ràpida i fàcil de gestionar. No obstant això, a mesura que el lloc web creixi o augmenti el trànsit, caldrà considerar opcions més complexes, com ara l'escalabilitat horitzontal o vertical.

Esquema de la implementació monolítica

Si consulteu la web oficial de Wordpress, veureu que la versió actual és la 6.6.2. I els seus requeriments per la instal·lació són els següents:

  • PHP: Versió 7.4 o superior.
  • MySQL o MariaDB: MySQL versió 5.7 o superior o MariaDB versió 10.3 o superior.
  • Apache o Nginx: Versió 2.4 o superior per a Apache o versió 1.26 o superior per a Nginx.
  • HTTPS: Recomanat per a la seguretat del lloc web.

Per tant, haurem de preparar un servidor que compleixi aquests requeriments abans de procedir a la instal·lació de Wordpress.

Requisits

  • Màquina virtual amb sistema operatiu AlmaLinux.

Objectius

  • Desplegar un servidor web senzill amb Wordpress.
  • Configurar un servidor web amb Apache.
  • Configurar una base de dades amb MariaDB.
  • Configurar un servidor PHP amb PHP.
  • Instal·lar i configurar Wordpress.
  • Provar el lloc web de Wordpress.

Preparant el servidor

Un cop creada la màquina virtual, el primer pas és actualitzar el sistema operatiu amb la comanda següent per assegurar-nos que disposem de les últimes actualitzacions de seguretat.

💡 Nota

Mantenir el sistema operatiu actualitzat és una responsabilitat fonamental de qualsevol administrador de sistemes, ja que garanteix l'estabilitat i la seguretat del servidor. Per això, és recomanable començar qualsevol configuració executant una actualització completa del sistema.

dnf -y update

Aquesta comanda actualitza tots els paquets del sistema utilitzant el gestor de paquets DNF. L'opció -y respon automàticament sí a totes les preguntes de confirmació, permetent que l'actualització es realitzi sense intervenció manual.

A més, si preferiu utilitzar un editor de text diferent de vi, podeu instal·lar alternatives com vim, emacs o nano amb les comandes següents:

dnf install vim -y
dnf install nano -y
dnf install emacs -y

Es recomanable tenir un script amb el resum de les comandes que s'han d'executar per preparar el servidor. Així, si cal crear un nou servidor o repetir la configuració en un altre moment, es pot utilitzar aquest script per automatitzar el procés.

#!/bin/bash

# Actualitzar el sistema
dnf -y update

# Instal·lar editors de text
dnf install vim -y

Instal·lant i configurant Apache

El primer pas per desplegar un servidor web amb WordPress és instal·lar i configurar un servidor web. Necessitem la versió 2.4 o superior d'Apache per a la nostra instal·lació.

  1. Comprovem si el paquet httpd està disponible:

    dnf search httpd
    

    La sortida hauria de mostrar el paquet httpd i les seves dependències.

    Last metadata expiration check: 0:00:00 ago on Tue 15 Feb 2022 09:00:00 PM UTC.
    ============== Name Exactly Matched: httpd ==============
    httpd.x86_64 : Apache HTTP Server
    

    Si el paquet esta disponible, primer revisarem la informació del paquet amb la comanda dnf info httpd.

    Installed Packages
    Name         : httpd
    Version      : 2.4.57
    Release      : 11.el9_4.1
    Architecture : aarch64
    Size         : 155 k
    Source       : httpd-2.4.57-11.el9_4.1.src.rpm
    Repository   : @System
    From repo    : appstream
    Summary      : Apache HTTP Server
    URL          : https://httpd.apache.org/
    License      : ASL 2.0
    Description  : The Apache HTTP Server is a powerful, efficient, and extensible
                : web server.
    

    Un cop ens assegurem que el paquet està disponible amb la versió correcta, procedirem a la instal·lació.

  2. Instal·lem el dimoni httpd:

    dnf install httpd -y
    
  3. Comprovem l'estat del servei amb systemctl:

    systemctl status httpd
    
  4. Visualitzem els fitxers de configuració del servei httpd:

    less /usr/lib/systemd/system/httpd.service
    
    [Unit]
    Description=The Apache HTTP Server
    Wants=httpd-init.service
    After=network.target remote-fs.target nss-lookup.target httpd-init.service
    Documentation=man:httpd.service(8)
    
    [Service]
    Type=notify
    Environment=LANG=C
    
    ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
    ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
    # Send SIGWINCH for graceful stop
    KillSignal=SIGWINCH
    KillMode=mixed
    PrivateTmp=true
    OOMPolicy=continue
    
    [Install]
    WantedBy=multi-user.target
    

    Aquest fitxer de configuració conté instruccions com:

    • ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND: Defineix la comanda que s'utilitza per iniciar el servei. El mode foreground permet veure la sortida al terminal, útil per a la depuració.
    • ExecReload=/usr/sbin/httpd $OPTIONS -k graceful: Permet recarregar la configuració del servidor sense interrompre les connexions actives, garantint que els canvis es puguin aplicar de manera controlada.
    • KillSignal=SIGWINCH: El senyal que s'envia per aturar el servei, assegurant una parada segura.
    • PrivateTmp=true: Millora la seguretat creant un sistema de fitxers temporal privat per al servei.
    • OOMPolicy=continue: Defineix el comportament del sistema en cas de manca de memòria, permetent que el servei continuï executant-se.
  5. Habiliteu el servei per iniciar cada cop que el sistema arranqui:

    systemctl enable httpd
    
  6. Arranqueu i comproveu l'estat del servei:

    systemctl start httpd
    systemctl status httpd
    

Un cop aixecat el servei, podem comprovar que el servei està en marxa i funcionant correctament. Intenteu accedir al servidor web amb la vostra IP a través d'un navegador web. En el meu cas, la IP del servidor és :127.16.10.206. Recordeu que per veure la IP del vostre servidor podeu utilitzar la comanda ip a.

Apache

Observareu que no és possible accedir-hi i rebeu un missatge d'error ERR_CONNECTION_REFUSED. Això és normal, ja que AlmaLinux té un firewall activat per defecte que bloqueja el tràfic al port 80, que és el port per defecte del servidor web Apache.

systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
     Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2022-02-15 21:00:00 UTC; 1h 30min ago

Si desactiveu el servei de firewalld, podreu accedir al servidor web Apache. No obstant això, això no és una pràctica segura, ja que el firewall és una capa de seguretat important per protegir el vostre servidor.

systemctl stop firewalld

Apache

En aquest punt, podeu comprovar que el servidor web Apache està funcionant correctament.

Configuració del firewall

El firewall és un servei o programa que protegeix la xarxa del vostre servidor control·lant el tràfic de xarxa que entra i surt del servidor. Això és important per garantir que el vostre servidor sigui segur i protegit contra atacs maliciosos. Permetre només el tràfic necessari i bloquejar el tràfic no desitjat és una pràctica de seguretat recomanada per mantenir el vostre servidor segur. En aquest cas, necessitem permetre el tràfic HTTP (port 80) perquè el servidor web Apache sigui accessible des de l'exterior però bloquejar altres ports i serveis no necessaris.

En tots els sistmes linux el firewall es configura utilitzant les iptables. En el nostre cas, podem veure les regles amb la comanda iptables -L. Permetre el tràfic HTTP (port 80) amb les iptables seria:

iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -m state --state NEW -m udp -p udp --dport 80 -j ACCEPT

on:

  • -A INPUT: Afegeix una regla a la cadena INPUT (paquets que entren al servidor).
  • -m state --state NEW: Només s'aplica a paquets nous.
  • -m tcp -p tcp: Només s'aplica a paquets TCP.
  • -M udp -p udp: Només s'aplica a paquets UDP.
  • --dport 80: Només s'aplica als paquets que arriben al port 80.
  • -j ACCEPT: Accepta els paquets que compleixen les condicions anteriors.

Però, tenim eines que ens faciliten la tasca com firewalld o ufw. En aquest cas, utilitzarem firewalld. Firewalld és un firewall dinàmic per a sistemes Linux que proporciona una interfície de línia de comandes i una interfície gràfica per gestionar les regles del firewall. Firewalld té un programa de comandament anomenat firewall-cmd que us permet gestionar les regles del firewall de manera senzilla i eficaç. Per permetre el tràfic HTTP (port 80) amb firewalld, podeu utilitzar la comanda següent:

firewall-cmd --add-service=http --permanent

on:

  • --add-service=http: Afegeix una regla per permetre el tràfic HTTP.
  • --permanent: Afegeix la regla de manera permanent, la qual cosa significa que es mantindrà després de reiniciar el sistema.

Per aplicar els canvis, cal recarregar el firewall amb la comanda següent:

firewall-cmd --reload

Amb aquesta configuració, el vostre firewall està configurat per permetre el tràfic HTTP (port 80) al vostre servidor. Per verificar que la configuració del firewall s'ha aplicat correctament i que el servei HTTP està habilitat, podeu utilitzar la següent comanda:

firewall-cmd --list-all

Aquesta comanda mostrarà la sortida amb informació detallada sobre la configuració actual del firewall. Per identificar si el servei HTTP està habilitat, busqueu la secció services i verifiqueu que aparegui el servei http com a un dels serveis habilitats.

La sortida hauria de semblar-se així:

public
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: cockpit dhcpv6-client http ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

En aquest exemple, podeu veure que el servei HTTP està habilitat, la qual cosa significa que el tràfic HTTP hauria de ser permès a través del firewall. A més a més, podeu veure altres serveis com el servei SSH, el servei DHCPv6-client i el servei Cockpit que també estan habilitats. Aquests serveis són necessaris per a la gestió del servidor i per a la connectivitat de xarxa.

Com deshabilitareu la regla per bloquejar el tràfic?

firewall-cmd --remove-service=http --permanent
firewall-cmd --reload

Instal·lant i configurant MariaDB

Per poder utilitzar el Wordpress necessitem d'una base de dades del tipus MariaDB o MySQL. El primer pas es revisar si el paquet mariadb està disponible amb la versió correcta.

dnf search mariadb 
dnf info mariadb
Name         : mariadb
Epoch        : 3
Version      : 10.5.22
Release      : 1.el9_2.alma.1
Architecture : aarch64
Size         : 18 M
Source       : mariadb-10.5.22-1.el9_2.alma.1.src.rpm
Repository   : @System
From repo    : appstream
Summary      : A very fast and robust SQL database server
URL          : http://mariadb.org
License      : GPLv2 and LGPLv2
Description  : MariaDB is a community developed fork from MySQL - a multi-user, multi-threaded
             : SQL database server. It is a client/server implementation consisting of
             : a server daemon (mariadbd) and many different client programs and libraries.
             : The base package contains the standard MariaDB/MySQL client programs and
             : utilities.
  1. Instal·lem el paquet mariadb:

    dnf install mariadb-server mariadb -y
    
  2. Iniciem el servei de MariaDB:

    systemctl enable --now mariadb
    
  3. Comprovem l'estat del servei:

    systemctl status mariadb
    
  4. Configurem MariaDB:

    mysql_secure_installation
    1. Enter current password for root (enter for none): 
    2. Switch to unix_socket authentication [Y/n] n
    3. Set root password? Y
    4. New password: xxxxxxx
    5. Remove anonymous users? Y
    6. Disallow root login remotely? Y
    7. Remove test database and access to it? Y
    8. Reload privilege tables now? Y
    

    on:

    • Enter current password for root (enter for none): En aquest punt, si és la primera vegada que configureu MariaDB, premeu simplement Enter, ja que encara no hi ha contrasenya establerta per a l'usuari root.
    • Switch to unix_socket authentication [Y/n]: En aquest punt, respongueu n per desactivar l'autenticació de l'usuari root a través de unix_socket. Si respongueu Y, l'autenticació de l'usuari root es farà a través del sistema de fitxers, aquesta opció permet autenticacions avançades que veurem més endavant.
    • Set root password? (Y/n): Respongueu Y per indicar que voleu establir una contrasenya per a l'usuari root de MariaDB. A continuació, introduïu la nova contrasenya quan se us demani. (per exemple: 1234).
    • Remove anonymous users? (Y/n): Respongueu Y per eliminar els usuaris anònims. Això millora la seguretat del sistema, ja que no permet connexions no autenticades.
    • Disallow root login remotely? (Y/n): Respongueu Y per desactivar l'inici de sessió remot per a l'usuari root. Això significa que l'usuari root només podrà iniciar sessió des de la màquina local.
    • Remove test database and access to it? (Y/n): Respongueu Y per eliminar la base de dades de proves i l'accés a ella. Això elimina les bases de dades i els usuaris de prova, augmentant encara més la seguretat.
    • Reload privilege tables now? (Y/n): Respongueu Y per recarregar les taules de privilegis de MariaDB. Això assegura que els canvis de configuració es facin efectius de seguida.
  5. Inicieu sessió a MariaDB:

    mysql -u root -p
    
  6. Creeu una base de dades per a Wordpress:

    CREATE DATABASE wordpress_db;
    
  7. Creeu un usuari per a la base de dades:

    CREATE USER 'wordpress_user'@'localhost' IDENTIFIED BY 'password';
    
    • wordpress_user: Nom de l'usuari de la base de dades.
    • password: Contrasenya de l'usuari de la base de dades.
    • localhost: Nom de l'amfitrió on es connectarà l'usuari.

    En aquest cas, heu de substituir wordpress_user i password pels valors que vulgueu utilitzar.

  8. Atorgueu tots els permisos a l'usuari per a la base de dades:

    GRANT ALL ON wordpress_db.* TO 'wordpress_user'@'localhost';
    
    • wordpress_db: Nom de la base de dades.
    • wordpress_user: Nom de l'usuari de la base de dades.
    • localhost: Nom de l'amfitrió on es connectarà l'usuari.

    Aquesta comanda atorga tots els permisos de la base de dades wordpress_db a l'usuari wordpress_user.

  9. Actualitzeu els permisos:

    FLUSH PRIVILEGES;
    
  10. Sortiu de MariaDB:

    EXIT;
    

Aquesta configuració de MariaDB és suficient per a la instal·lació de Wordpress. S'han adaptat els passos de la documentació oficial https://developer.wordpress.org/advanced-administration/before-install/creating-database/.

Instal·lant i configurant PHP

Actualment, la documentació oficial de WordPress recomana utilitzar PHP versió 7.4 o superior per a un funcionament òptim i segur del sistema.

  1. Compovem si el paquet php està disponible:

    dnf search php
    
  2. Comprovem les versions disponibles de PHP:

    dnf module list php
    

    Aquesta comanda mostra una llista de les versions del mòdul PHP disponibles. Et permetrà veure quines versions de PHP pots instal·lar mitjançant mòduls.

  3. Instal·lem la versió 8.1 de PHP:

    dnf module install php:8.1 -y
    

    L'ús de versions més recents de PHP ofereix molts avantatges, com ara un millor rendiment, més seguretat i noves característiques. Les versions antigues de PHP poden ser més vulnerables a problemes de seguretat i tenir limitacions de rendiment. Per tant, és important seguir les recomanacions de la documentació oficial de WordPress quant a la versió de PHP que has d'utilitzar per a la teva instal·lació.

    Un cop instal·lada la versió de PHP, podem comprovar la versió actual amb la comanda php -v. I començar a instal·lar els paquets i complements necessaris:

    dnf install php-curl php-zip php-gd php-soap php-intl php-mysqlnd php-pdo -y
    
    • php-curl: Proporciona suport per a cURL, que és una llibreria per a la transferència de dades amb sintaxi URL.
    • php-zip: Proporciona suport per a la manipulació de fitxers ZIP.
    • php-gd: Proporciona suport per a la generació i manipulació d'imatges gràfiques.
    • php-soap: Proporciona suport per a la creació i consum de serveis web SOAP.
    • php-intl: Proporciona suport per a la internacionalització i localització de l'aplicació.
    • php-mysqlnd: És l'extensió MySQL nativa per a PHP, que permet la connexió i la comunicació amb bases de dades MySQL o MariaDB.
    • php-pdo: Proporciona l'abstracció de dades d'Objectes PHP (PDO) per a la connexió amb bases de dades.
  4. Per finalitzar, podem reiniciar el servei web (httpd).

    systemctl restart httpd
    

Instal·lant i configurant Wordpress

Per instal·lar WordPress ens hem de baixar el paquet de la web oficial. Per fer-ho podem utilitzar la comanda wget per descarregar el paquet de WordPress.

  1. Instal·lem el paquet wget:

    dnf install wget -y
    
  2. Descarreguem el paquet de WordPress:

    Es una bona pràctica utilitzar el directori temporal (/tmp) per descarregar el programari a instal·lar com el Wordpress. L'ús d'aquest directori ens proporciona:

    • Espai de disc temporal: Ubicació on es poden emmagatzemar fitxers sense preocupar-se pel seu ús posterior. És una ubicació amb prou espai de disc disponible, generalment, i sol estar netejada periòdicament pels sistemes operatius per evitar l'acumulació de fitxers temporals innecessaris.

    • Evitar problemes de permisos: El directori temporal (/tmp) sol tenir permisos que permeten a tots els usuaris crear fitxers temporals sense problemes de permisos. Això és important quan estàs treballant amb fitxers que poden ser manipulats per diversos usuaris o processos.

    • Seguretat: Com que el directori temporal és netejat periòdicament, hi ha menys risc de deixar fitxers temporals sensibles o innecessaris al sistema després d'una operació. Això ajuda a prevenir la acumulació de residus i a minimitzar els problemes de seguretat relacionats amb fitxers temporals.

    • Evitar col·lisions de noms de fitxers: Utilitzant el directori temporal, es redueixen les possibilitats de col·lisions de noms de fitxers. En altres paraules, si molts usuaris estan descarregant fitxers a la mateixa ubicació, utilitzar el directori temporal ajuda a garantir que els noms de fitxers siguin únics.

    En resum, garanteix l'espai, la seguretat i la gestió adequats per a aquest tipus de fitxers, com és el cas de la descàrrega i descompressió de paquets com WordPress.

    cd /tmp
    wget https://wordpress.org/latest.tar.gz -O wordpress.tar.gz
    
  3. Després d'haver descarregat el paquet, el descomprimim amb la comanda tar:

    dnf install tar -y
    tar -xvf wordpress.tar.gz
    
  4. Copiem els continguts a la carpeta del servidor Apache:

    cp -R wordpress /var/www/html/
    
  5. Assignem el ownership al usuari apache:

    chown -R apache:apache /var/www/html/wordpress
    

    El servei Apache s'executa amb l'usuari apache i el grup apache per defecte. Per tant, és important assegurar-se que els fitxers i directoris del lloc web tinguin el propietari i el grup correctes perquè el servidor web pugui accedir-hi i gestionar-los correctament. Aquesta informació la podeu trobar al fitxer de configuració del servidor web, normalment a /etc/httpd/conf/httpd.conf.

    less /etc/httpd/conf/httpd.conf
    
  6. Donem permisos (rwx) a l'usuari apache i el seu grup i permisos rw per qualsevol altre usuari:

    chmod -R 775 /var/www/html/wordpress
    

    Aquesta comanda estableix permisos de lectura, escriptura i execució per a l'usuari apache i el seu grup, i permisos de lectura i escriptura per a qualsevol altre usuari. Això permet que l'usuari apache pugui llegir, escriure i executar els fitxers i directoris del lloc web, mentre que altres usuaris poden llegir i escriure-hi. Aquesta configuració és adequada per a la majoria dels llocs web i proporciona un equilibri entre la seguretat i la facilitat d'ús. No obstant això, si teniu necessitats específiques de seguretat o de permisos, podeu ajustar aquests permisos segons les vostres necessitats. L'argument -R indica que els permisos s'aplicaran de manera recursiva a tots els fitxers i directoris dins de la carpeta especificada.

  7. Reiniciem el servei Apache:

    systemctl restart httpd
    

Instal·lació del Wordpress

Un cop hàgiu completat aquests passos, ja podeu accedir a la instal·lació web de WordPress navegant a http://ip/wordpress/. On ip és la ip del vostre servidor. En el nostre cas, la ip del servidor és 172.16.10.206. Per tant: http://172.16.10.206/wordpress/. O bé podeu utilitzar el nom de domini si teniu un configurat.

El primer pas serà completar un formulari amb la informació de la base de dades que hem creat anteriorment. Aquesta informació és necessària per connectar WordPress a la base de dades i emmagatzemar-hi la informació del lloc web.

  • Nom de la base de dades: wordpress-db
  • Nom d'usuari de la base de dades: wordpress-user
  • Contrasenya de la base de dades: password
  • Servidor de la base de dades: localhost
  • Prefix de la taula: wp_

Un cop hàgiu introduït aquesta informació, podeu continuar amb el procés d'instal·lació de WordPress.

En aquest punt, observareu el missatge d'error Unable to write to wp-config.php file és típic d'un problema de permisos en el sistema de fitxers quan s'intenta escriure un fitxer com el wp-config.php durant la instal·lació de WordPress.

Ara bé, ja hem donat permisos a l'usuari apache perquè pugui escriure a la carpeta de WordPress. El problema resideix en els permisos de SELinux.

SELinux és un sistema de seguretat que proporciona controls addicionals de seguretat basats en polítiques. Impedeix que els processos realitzin certes accions que no estan permeses per la política de seguretat. Ho podem comprovar amb la comanda:

getenforce

Aquesta comanda et mostrarà l'estat actual de SELinux, que pot ser Enforcing, Permissive o Disabled.

Una solució ràpida seria desactivar SELinux amb la comanda:

setenforce 0

No obstant això, és millor entendre com funciona i com gestionar-lo adequadament. Aquesta és la manera més segura de resoldre problemes relacionats amb permisos sense comprometre la seguretat del sistema. Quan es configuren les etiquetes SELinux correctes i es gestionen els permisos de fitxers de manera adequada, SELinux pot oferir una protecció addicional per al vostre sistema.

Mes endavant al curs veurem com configurar SELinux de manera adequada. De moment us deixo la resolució del problema amb SELinux.

  1. Instal·lem les eines de SELinux en cas de no tenir-les:

    dnf install policycoreutils-python-utils -y
    
  2. Configurem les etiquetes SELinux per a la carpeta de WordPress:

    semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/wordpress(/.*)?'
    

    on:

    • -a: Afegeix una nova regla.
    • -t httpd_sys_rw_content_t: Estableix l'etiqueta SELinux per als fitxers i directoris de la carpeta de WordPress.
    • '/var/www/html/wordpress(/.*)?': Ruta de la carpeta de WordPress.
  3. Aplicar les etiquetes SELinux configurades:

    restorecon -Rv /var/www/html/wordpress
    

    on:

    • -R: Aplica els canvis de manera recursiva a tots els fitxers i directoris dins de la carpeta especificada.
    • -v: Mostra la sortida detallada de les accions realitzades.
    • /var/www/html/wordpress: Ruta de la carpeta de WordPress.

Amb aquestes accions hem creat una política que permet als processos del servei httpd llegir i escriure a la carpeta de WordPress.

  1. Inici de la configuració:

    Click a Let's go

  2. Introdueix les dades de la base de dades:

    Configuració de la base de dades

  3. Realitza la instal·lació:

    Configuració del lloc web

  4. Configuració del lloc web:

    Configuració del lloc web

    on:

    • Site Title: Títol del lloc.
    • Username: Nom d'usuari per accedir al panell d'administració.
    • Password: Contrasenya per accedir al panell d'administració.
    • Your Email: Correu electrònic per a la recuperació de la contrasenya.

    Un cop hàgiu introduït aquesta informació, podeu continuar amb el procés d'instal·lació de WordPress. Després d'instal·lar amb èxit WordPress, podreu iniciar la sessió al panell d'administració amb el nom d'usuari i la contrasenya que heu triat i començar a personalitzar i gestionar el vostre lloc web.

  5. Inicia sessió amb les credencials creades:

    Inicia sessió

  6. Panell d'administració:

    Panell d'administració

  7. Visualització del lloc web:

    Panell d'administració

En aquest punt tenim 2 accessos al nostre servidor web. Un és el panell d'administració de WordPress i l'altre és el lloc web en si mateix:

On ip és la ip del vostre servidor o el vostre nom de domini si teniu un configurat.

Desplegament al núvol (AWS)

En aquest laboratori desplegarem un servidor web amb Wordpress a Amazon Web Services (AWS). Utilitzarem una instància EC2 amb Amazon Linux 2023 i una base de dades RDS amb MySQL.

Podeu revisar també la guía oficial de Wordpress a AWS.

Configuració de la clau SSH

La clau SSH és un mecanisme de seguretat que permet l'autenticació segura entre dos sistemes. Per a la connexió amb el servidor d'Amazon EC2, utilitzarem una clau SSH per autenticar-nos. Aquesta clau SSH es pot crear amb la utilitat ssh-keygen que ve amb la majoria de sistemes Linux o podeu fer servir una power shell de Windows.

En aquest mecanisme, el servidor d'Amazon EC2 té la clau pública i el client té la clau privada. Quan el client es connecta al servidor, el servidor comprova si la clau pública del client coincideix amb la clau privada del servidor. Si les claus coincideixen, el client es connecta al servidor. Per tant, la clau privada no s'ha de compartir amb ningú. Mentre que la clau pública es pot compartir amb qualsevol i la podeu fer servir en múltiples servidors. A dia d'avui, no hi ha cap mecanisme per obtenir la claue privada a partir de la clau pública.

Creació de la clau SSH

La comanda ssh-keygen permet crear una clau SSH. Aquesta comanda té diversos paràmetres que permeten personalitzar la clau SSH. Els paràmetres més comuns són:

  • -t: Especifica el tipus de xifratge de la clau. Els tipus més comuns són rsa, dsa, ecdsa i ed25519.
  • -f: Especifica el nom del fitxer on es guardarà la clau.
  • -b: Especifica la longitud de la clau en bits.

En el nostre cas crearem una clau SSH amb el tipus de xifratge ed25519 i la guardarem al fitxer ~/.ssh/aws-key.

ssh-keygen -t ed25519 -f ~/.ssh/aws-key
Enter passphrase (empty for no passphrase): 
Ener same passphrase again:

Nota:

Si no voleu posar una contrasenya a la clau, simplement premeu la tecla Enter quan us demani la contrasenya.

Aquesta comanda generarà dues claus, una clau privada ~/.ssh/aws-key i una clau pública ~/.ssh/aws-key.pub.

Configuració de la clau SSH a Amazon EC2

  1. Inicieu sessió al vostre compte d'Amazon Educate, aneu a moduls del Learner Lab. AWS. Fent clic a Start lab i quan el laboratori estigui en marxa, feu clic a la icona verda per obrir la consola d'Amazon AWS.

  2. A la consola d'Amazon AWS, cerqueu KEY PAIRS a la barra de recerca i feu clic a Key Pairs relacionades amb el servei EC2.

    Key Pairs

  3. Feu clic a Actions i seleccioneu Import Key Pair.

    Import Key Pair

  4. Copieu el contingut de la clau pública ~/.ssh/aws-key.pub i enganxeu-lo al camp Public key contents.

    Public Key

  5. Doneu un nom a la clau i feu clic a Import key pair.

  6. La clau s'importarà amb èxit i la podreu veure a la llista de claus.

    Import Key

Creació d'una instància EC2

  1. Anem a la consola d'Amazon AWS i cerquem EC2 a la barra de recerca.

  2. A la consola d'Amazon EC2, fem clic a Launch Instance.

  3. Omplim el formulari amb els paràmetres següents:

    • Name: WP-01
    • OS: Amazon Linux 2023 AMI
    • Instance Type: t2.micro
    • Key Pair: AMSA
    • Network: Per defecte
      • Activeu Allow SSH traffic from anywhere.
  4. Cliqueu a Launch.

  5. Espereu uns minuts fins que la instància estigui en marxa.

  6. Un cop en marxa, feu clic al identificador de la instància per veure els detalls.

    Instància

  7. Feu clic a Connect per veure les instruccions per connectar-vos a la instància.

    Connect

  8. Obriu una terminal i connecteu-vos a la instància amb la comanda ssh -i ~/.ssh/aws-key ec2-user@IP.

    SSH

  9. Si tot ha anat bé, ja esteu connectats a la instància EC2.

    SSH

  10. Un cop connectats, ja podem repetir els passos per instal·lar Apache com vam fer a la màquina local.

    sudo dnf install httpd -y
    sudo systemctl start httpd
    sudo systemctl enable httpd
    
  11. Obriu un navegador i poseu la IP de la instància EC2. En aquest punt, veureu que no podeu accedir a la pàgina web.

    • Si reviseu la màquina virtual, observareu que el firewall està desactivat i per tant, no és el culpable.
    • El núvol d'Amazon té un firewall per defecte que bloqueja el tràfic a les instàncies. Aquest firewall es diu Security Group i s'ha de configurar per permetre el tràfic HTTP.
  12. Anem a la consola d'Amazon EC2 i als detalls de la instància, fem clic a Security i Security Groups.

    Security Group

  13. Feu clic a Edit inbound rules i afegiu una regla nova per permetre el tràfic HTTP.

    • Type: HTTP
    • Source: Anywhere
    • Description: Allow HTTP traffic
    • Cliqueu a Save rules.

    Security Group

  14. Torneu a la pàgina web i refresqueu-la. Ara ja veureu la pàgina web d'Apache.

    Apache

    Nota:

    Si feu clic als enllaços igual el navegador cerca https i no http. De moment no tenim configurat el certificat SSL i per tant, no funcionarà. Assegureu-vos de posar http a la barra d'adreces i si teniu https, eliminar la s manualment i refrescar la pàgina.

  15. Ara ja podem instal·lar PHP igual que vam fer a la màquina local.

    sudo dnf install php8.1 -y
    sudo dnf install php-curl php-zip php-gd php-soap php-intl php-mysqlnd php-pdo -y
    sudo systemctl restart httpd
    

Bases de dades RDS

El servei de bases de dades relacional d'Amazon Web Services (RDS) és una opció molt interessant per a desplegar bases de dades MySQL, MariaDB, PostgreSQL, Oracle, SQL Server i Aurora. Aquest servei ofereix una gestió fàcil i eficient de les bases de dades, així com la possibilitat de fer còpies de seguretat, escalabilitat i alta disponibilitat.

Per utiltizar RDS amb WordPress, seguirem els següents passos:

  1. Anem a la consola de Amazon RDS.

    RDS

  2. A la consola de Amazon RDS, fem clic a Create database.

    • Seleccionem el mode Standard Create.
    • Seleccionem el motor de base de dades MySQL.
    • Seleccionem la versió de la base de dades MySQL 8.0.25.
    • Seleccionem la plantilla Free tier.
    • Nom de la base de dades wordpress.
    • Master username admin.
    • Seleccioneu auto-generate a password.

    La resta de paràmetres els deixarem per defecte.

    Recordatori:

    Fer clic a Connection details per veure la password generada. Si no ho feu, haureu d'anar a modificar, regenerar la password i aplicar els canvis.

  3. Espereu uns minuts fins que la base de dades estigui en marxa.

    RDS

  4. Ara ja podem connectar-nos a la base de dades amb un client MySQL com MySQL Workbench o phpMyAdmin.

    • Hostname: database-1.cik8jidkherq.us-east-1.rds.amazonaws.com
    • Port: 3306
    • Username: admin
    • Password: XXXXXXXXXXXXXXX

    Nota:

    Per simplicitat, instal·larem el client MySQL a la mateixa instància EC2 on tenim instal·lat Apache i PHP. sudo dnf install mariadb105 -y

  5. Un cop connectats, ja podem crear la base de dades wordpress i l'usuari wordpress amb tots els permisos.

    mysql -h database-1.cik8jidkherq.us-east-1.rds.amazonaws.com -u admin -p
    

    Ups! No ens podem connectar a la base de dades. Això és degut a que la base de dades està protegida per un Security Group que no permet connexions des de l'exterior. Per solucionar-ho, hem d'afegir una regla al Security Group de la base de dades per permetre connexions des de la instància EC2.

    CREATE DATABASE wordpress;
    CREATE USER 'wordpress'@'%' IDENTIFIED BY 'wordpress';
    GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'%';
    FLUSH PRIVILEGES;
    

AWS S3

Amazon Simple Storage Service (S3) és un servei de magatzematge d'objectes que ofereix escalabilitat, disponibilitat i durabilitat. Aquest servei permet emmagatzemar i recuperar dades a través d'una interfície web.

Per a més informació, consulta la documentació oficial d'Amazon S3.

La capa gratuita d'AWS inclou 5 GB de magatzematge d'objectes, 20.000 sol·licituds GET i 2.000 sol·licituds PUT al mes. Superades aquestes limitacions, es facturaran segons el consum.

Configuració d'una instància EC2 per accedir a S3

Per accedir a S3 des d'una instància EC2, primer cal configurar les credencials d'accés a S3 a la instància. Aquests són els passos a seguir:

  1. Executa el següent comandament per configurar les credencials AWS a la instància:

    aws configure
    

    Completa els camps amb les teves credencials:

    AWS Access Key ID [None]: <ACCESS_KEY>
    AWS Secret Access Key [None]: <SECRET_KEY>
    Default region name [None]: us-east-1
    Default output format [None]: None
    

    AWS S3

  2. Alternativament, pots configurar directament la teva Access Token:

    aws configure set aws_session_token <ACCESS_TOKEN>
    

Un cop configurades les credencials, la instància EC2 estarà preparada per accedir a S3.

Nota: Per obtenir les credencials d'accés a AWS, heu de visitar AWS Details.

Operacions bàsiques amb S3

  1. Copiar un document d'EC2 a S3:

    echo "Hello World" > file.txt
    aws s3 cp file.txt s3://<bucket-name>/file.txt
    

    AWS S3

  2. Copiar un document de S3 a EC2:

    # Assumeix que `a.txt` ja existeix a S3.
    dir=/home/ec2-user
    aws s3 cp s3://<bucket-name>/a.txt $dir/a.txt
    

    AWS S3

  3. Crear una carpeta a S3:

    aws s3 mb s3://<bucket-name>/folder
    
  4. Eliminar un document de S3:

    aws s3 rm s3://<bucket-name>/file.txt
    
  5. Eliminar documents de S3 de manera recursiva:

    aws s3 rm s3://<bucket-name>/ --recursive
    
  6. Llistar els documents d'un bucket de S3:

    aws s3 ls s3://<bucket-name>
    
  7. Llistar els documents d'un bucket de S3 de forma recursiva:

    aws s3 ls s3://<bucket-name> --recursive
    
  8. Sincronitzar un directori local amb un bucket de S3:

    aws s3 sync /home/ec2-user s3://<bucket-name>
    
  9. Sincronitzar un bucket de S3 amb un directori local:

    aws s3 sync s3://<bucket-name> /home/ec2-user
    

Per exemple, podem descarregar un notebook de Jupyter a la instància EC2 i pujar-lo a S3 sincronitzant la carpeta local (notebooks) amb el bucket de S3 (jordi-amsa/notebooks):

aws s3 mb s3://jordi-amsa/notebooks
mkdir notebooks
cd notebooks
wget https://github.com/JordiMateoUdL/Model-reusability-on-the-edge/blob/master/notebooks/Generating%20synthethic%20data.ipynb
mv 'Generating synthethic data.ipynb' notebook1.ipynb
aws s3 sync notebooks s3://jordi-amsa/notebooks

AWS S3

Xarxa a AWS

Virtual Private Cloud (VPC)

Una VPC és una xarxa virtual que es pot configurar a AWS. Per defecte, AWS crea una VPC per a cada compte, però també es poden crear noves VPCs. Una VPC es pot configurar amb subxarxes, taules de rutes, grups de seguretat, etc.

VPC

En la imatge es mostren 4 VPCs diferents. Cada VPC està aïllada de les altres. Una VPC es crea dins d'una regió específica i pot abastar múltiples zones de disponibilitat dins d'aquesta regió.

A més, en l'arquitectura de la imatge, el tràfic es comparteix entre dues VPCs a la mateixa regió però en diferents zones de disponibilitat. No obstant això, les VPCs de les regions 1 i 2 no poden connectar-se entre elles.

Per crear una VPC, es pot utilitzar la consola de AWS, la interfície de línia de comandes o l'API de AWS.

  1. Consola de AWS:

    1. Anar a la consola de AWS.
    2. Anar a la secció de VPC.
    3. Seleccionar "Your VPCs".
    4. Clicar a "Create VPC".
    5. Omplir els camps necessaris.
    6. Clicar a "Create VPC".
  2. Interfície de línia de comandes:

    aws ec2 create-vpc --cidr-block 10.0.0.0/16 --region us-east-1 --tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=amsa-vpc}]"
    

En aquest exemple, s’utilitza una màscara de xarxa /16, que permet disposar de fins a 65,536 adreces IP. No obstant això, algunes d’aquestes IP seran reservades per AWS per a serveis interns, de manera que el nombre efectiu d’adreces disponibles serà lleugerament inferior.

Per defecte, les VPC no tenen connexió a Internet. Per proporcionar accés, es poden configurar una Internet Gateway (IGW) per connectar la VPC a Internet o una Virtual Private Gateway (VGW) per connectar-la a una xarxa privada, com una VPN. Aquestes passarel·les permeten establir la connectivitat necessària segons les necessitats de l'entorn de xarxa.

Subxarxes

Les subxarxes són una part d'una VPC. Una VPC pot tenir múltiples subxarxes. Cada subxarxa es pot configurar amb una zona de disponibilitat específica. Això permet distribuir les càrregues de treball en diferents zones de disponibilitat. Un exemple útil de subxarxes és la creació de subxarxes públiques i privades en funció de les necessitats de seguretat i operacionals.

Subxarxes

En la imatge es mostra una VPC amb un bloc CIDR de 10.0.0.0/24 que suporta 256 adreces IP. Aquest bloc CIDR es pot dividir en dues subxarxes, cadascuna amb 128 adreces IP. Una subxarxa utilitza el bloc CIDR 10.0.0.0/25 (per a les adreces 10.0.0.0 - 10.0.0.127) i l'altra utilitza el bloc CIDR 10.0.0.128/25 (per a les adreces 10.0.0.128 - 10.0.0.255).

Per crear una subxarxa, es pot utilitzar la consola de AWS, la interfície de línia de comandes o l'API de AWS.

  1. Consola de AWS:

    1. Anar a la consola de AWS.
    2. Anar a la secció de VPC.
    3. Seleccionar "Subnets".
    4. Clicar a "Create subnet".
    5. Omplir els camps necessaris.
    6. Clicar a "Create subnet".
  2. Interfície de línia de comandes:

    aws ec2 create-subnet --vpc-id <vpc-id> --cidr-block 10.0.1.0/24 --availability-zone us-east-1a
    # Per exemple:
    # aws ec2 create-subnet --vpc-id vpc-013ece49204bdf533 --cidr-block 10.0.1.0/24 --availability-zone us-east-1a
    

Desplegant una EC2 a una VPC

En aquesta activitat, es desplegarà una VPC amb dues subxarxes, una pública i una privada. A més, es configurarà una Internet Gateway per connectar la VPC a Internet.

EC2

En aquesta figura, es mostra una VPC amb dues subxarxes, una pública i una privada. La subxarxa pública té una connexió a Internet a través d'una Internet Gateway. La subxarxa privada no té connexió a Internet. Per defecte, les VPC no tenen connexió a Internet. Per proporcionar accés, es poden configurar una Internet Gateway (IGW) i una taula de rutes per connectar la VPC a Internet.

Per desplegar aquesta arquitectura, es pot utilitzar CloudFormation. A continuació, es mostra un exemple de plantilla de CloudFormation per desplegar aquesta arquitectura.

  1. Creació del Internet Gateway (IGW):

    • Anar a VPC > Internet Gateways.
    • Clicar a "Create internet gateway".
    • Omplir els camps necessaris (AMSA-IGW).
    • Attach el AMSA-IGW a AMSA-VPC.
  2. Crear l'enrutador de la taula de rutes:

    • Anar a VPC > Route Tables.
    • Clicar a "Create route table".
      • Nom: AMSA-PublicNet-RT-TO-Internet.
      • VPC: AMSA-VPC.
    • Clicar a "Edit routes".
    • Afegir una nova ruta:
      • Destination: 0.0.0.0/0.
      • Target: AMSA-IGW.

Cadascuna de les subxarxes de la VPC es pot associar a una taula de rutes. Una subxarxa es pot associar explícitament a una taula de rutes personalitzada o implícitament a la taula de rutes principal.

  • Una associació explícita implica que una subxarxa està associada a una taula de rutes personalitzada. En l'exemple, la subxarxa pública està associada a la taula de rutes personalitzada AMSA-PublicNet-RT-TO-Internet, que redirigeix tot el tràfic a l'Internet Gateway. Aquesta associació explícita fa que la subxarxa sigui una subxarxa pública.

  • Una associació implícita implica que la subxarxa està associada a la taula de rutes principal. En l'exemple, la subxarxa privada està associada a la taula de rutes principal, que redirigeix tot el tràfic al Virtual Private Gateway. No obstant això, no té una ruta a l'Internet Gateway, fent que la subxarxa sigui una subxarxa només per a VPN.

La diferència clau entre les associacions explícites i implícites rau en la taula de rutes implicada. La taula de rutes principal està associada implícitament a totes les subxarxes de la VPC, mentre que les taules de rutes personalitzades estan associades explícitament a subxarxes específiques.

EC2

La imatge mostra una arquitectura de xarxa dins d’una VPC, amb una configuració que inclou subxarxes, taules de rutes, gateways per connectar un entorn privat a Internet i a un centre de dades mitjançant una VPN.

  • Subxarxa pública: En aquesta subxarxa és on es troben les instàncies EC2 accessibles des d’Internet. Té una associació explícita amb una taula de rutes (Route Table A) que inclou una ruta cap a l'Internet Gateway, permetent a les instàncies connectar-se a Internet. Està associada amb el Security Group A, que defineix les polítiques de seguretat per a les instàncies en aquesta subxarxa.

  • Subxarxa privada: En aquesta subxarxa és per a recursos que necessiten seguretat addicional i que no haurien de ser accessibles directament des d'Internet. Té una associació implícita amb una taula de rutes (Route Table B), que no inclou una ruta cap a l'Internet Gateway, de manera que les instàncies no poden accedir a Internet directament. Està associada amb el Security Group B, que gestiona les regles de seguretat d'aquest entorn privat.

Per tant, la taula de rutes A permet a les instàncies de la subxarxa pública accedir a Internet a través de l'Internet Gateway, mentre que la taula de rutes B permet a les instàncies de la subxarxa privada comunicar-se amb el centre de dades corporatiu a través de la VPN Gateway.

Nota: La VPN Connection és el túnel que connecta la VPN Gateway de la VPC amb el Customer Gateway situat al centre de dades corporatiu. El Customer Gateway és un dispositiu de xarxa (pot ser un router o un firewall) situat a les instal·lacions del client, que gestiona el trànsit cap a la VPC. Aquesta configuració permet als recursos de la subxarxa privada accedir al centre de dades corporatiu i viceversa, de manera segura, sense exposar aquests recursos a Internet.

Desplegant Wordpress a una VPC Privada

Wordpress

  1. Creació de la VPC i les Subxarxes

    • Crea una VPC amb un rang d'adreces IP, per exemple, 10.0.0.0/16.
    • Configura dues subxarxes públiques per a les instàncies de l'aplicació a diferents zones de disponibilitat (AZ).
      • Subxarxa 1 (pública) en AZ 1 amb rang d'IP 10.0.1.0/24 (us-east-1a).
      • Subxarxa 2 (pública) en AZ 2 amb rang d'IP 10.0.2.0/24 (us-east-1b).
      • Configura una subxarxa privada per a la base de dades en una zona de disponibilitat específica. (us-east-1c).
  2. Configuració de la Taula de Rutes

    • Crea una Internet Gateway i associa-la amb la VPC.
    • Configura una taula de rutes per a les subxarxes públiques (HDCB-APPS-R1 i HDCB-APPS-R2).
    • Configura una taula de rutes separada per la subxarxa privada (HDCB-DATA-R). Aquesta taula no tindrà rutes a Internet. Només tindrà rutes per accedir internament als recursos de la VPC.
  3. Configuració del Balancer de Càrrega (Load Balancer)

    • Crea un Application Load Balancer (ALB) i selecciona les dues subxarxes públiques.
    • Configura el balançador perquè escolti al port 80 per HTTP.
    • Crea un grup objectiu (Target Group) per a les instàncies de l'aplicació.
    • Defineix L'objectiu com a Instances i el protocol com a HTTP al port 80.
    • Assigna les instàncies que crearem a continuació al grup objectiu perquè el balançador distribueixi el tràfic entre elles.
  4. Crea Instàncies EC2 per a Wordpress una a cada instància.