sequenceDiagram
autonumber
participant S as systemd
participant E as echo
S->>S: Starting salutacio.service
S->>E: fork + execve
E->>E: escriu hola al journal
E-->>S: exit 0
S->>S: Deactivated successfully
S->>S: Finished salutacio.service
Serveis amb systemd
Col·lecció d’exercicis sobre systemd.
systemctl startactiva una unitat ara;systemctl enablenomés crea els enllaços simbòlics que la faran activar en arrencar (segons[Install]). Són coses independents.Type=és el contracte entre el programa i systemd: defineix quan es considera iniciat el servei.simple: just després delfork().exec: després de l’execve().forking: quan el procés pare surt.oneshot: quan el procés acaba.notify: quan el programa enviaREADY=1.Wants=(feble) iRequires=(fort) diuen què s’activa; no ordenen. L’ordre el donenAfter=iBefore=. Són dimensions independents.- Tot el que llança un servei queda al seu grup de control (cgroup). Amb
KillMode=control-group(per defecte), en aturar el servei es maten tots els processos del grup. - Un temporitzador (
.timer) activa un servei. - Un socket escolta en nom d’un servei i l’inicia quan arriba trànsit.
- Sistema de referència: Debian 12.
- Tots els
ExecStart=s’inicien a l’instant. - La sortida de
echoi els missatges de systemd van al journal (journalctl -u NOM). - Els fitxers de les unitats d’administrador viuen a
/etc/systemd/system/.
Un administrador crea la unitat següent:
# /etc/systemd/system/cua-treball.service
[Unit]
Description=Procés de treball de llarga durada
[Service]
Type=simple
ExecStart=/usr/bin/sleep infinityA continuació executa:
sudo systemctl start cua-treball.serviceEl servei queda actiu. Després de reiniciar la màquina, però, el servei no s’ha iniciat.
- Per què pot estar actiu ara però no iniciar-se automàticament després d’un reinici?
- Quina diferència hi ha entre
start,enableienable --now? - Quina ordre utilitzaries per configurar l’inici automàtic i activar el servei immediatament? Què cal canviar a la unitat?
- Com comprovaries si està habilitat i si està en execució?
Repte: si s’edita el fitxer d’una unitat ja carregada, quina ordre fa que systemd en torni a llegir la configuració? Què passa si no es fa?
Pots veure el raonament
systemctl startinicia la unitat en la sessió actual, però no crea cap enllaç d’arrencada. A més, la unitat no té secció[Install]: no diu a quin objectiu s’ha d’enllaçar, i per tantenableno té res a fer.startactiva la unitat ara;enablecrea els enllaços definits a[Install]perquè s’activi en arrencar;enable --nowfa les dues coses.Cal afegir a la unitat:
[Install] WantedBy=multi-user.targeti després habilitar-la i iniciar-la:
sudo systemctl daemon-reload sudo systemctl enable --now cua-treball.servicePer comprovar-ho:
systemctl is-enabled cua-treball.service systemctl is-active cua-treball.service systemctl status cua-treball.serviceis-enabledretornaenabled,disabled,static(la unitat no té[Install]; només s’activa per dependència) omasked, entre d’altres.
Repte. sudo systemctl daemon-reload fa que systemd torni a llegir els fitxers de les unitats i reconstrueixi les dependències. Sense aquesta ordre, systemd continua usant la versió en memòria i avisa que el fitxer ha canviat al disc. No reinicia cap servei: un servei en marxa continua executant-se amb la configuració antiga fins que es faci restart.
enable també recarrega la configuració en acabar, però és bona pràctica fer el daemon-reload explícit després d’editar un fitxer i abans del start o restart.
# salutacio.service
[Unit]
Description=Salutació
[Service]
Type=oneshot
ExecStart=/bin/echo holaS’executa sudo systemctl start salutacio.service i després systemctl status salutacio.service.
- Quin valor té la línia
Active:? Indica un error? - Descriu, en ordre, els esdeveniments que apareixen al journal (no cal el text literal).
Repte: què canvia si s’afegeix RemainAfterExit=yes a [Service]?
Pots veure el raonament
inactive (dead). No és un error: el procés ha acabat amb codi 0 i, com que unoneshotno té cap procés en marxa, la unitat torna a quedar inactiva.statusmostra tambéstatus=0/SUCCESSa la línia del procés.- Ordre dels esdeveniments: (1) systemd anuncia l’inici de la unitat; (2)
echoescriuhola; (3) systemd informa que la unitat s’ha desactivat correctament; (4) systemd informa que la unitat ha acabat. Un exemple de sortida:
Starting salutacio.service - Salutació...
echo[1234]: hola
salutacio.service: Deactivated successfully.
Finished salutacio.service - Salutació.
Repte. Amb RemainAfterExit=yes la unitat es queda activa després que el procés acabi: Active: active (exited), i no apareix la línia Deactivated successfully. Fins que algú l’aturi amb systemctl stop, systemd la considera iniciada.
# /etc/systemd/system/web.service
[Unit]
Description=Servidor web
[Service]
ExecStart=/usr/sbin/webd
[Install]
WantedBy=multi-user.target graphical.target
Alias=servidor.service
Also=web.socket# /etc/systemd/system/web.socket
[Socket]
ListenStream=8080
[Install]
WantedBy=sockets.targetS’executa sudo systemctl enable web.service.
- Quins enllaços simbòlics es creen? On apunta cadascun?
- S’ha iniciat
webd?
Repte: què és servidor.service després de l’enable? Com ho comprovaries?
Pots veure el raonament
- Quatre enllaços: un per cada objectiu de
WantedBy=(dos:multi-user.targetigraphical.target), un per l’àlies (Alias=) i un pel[Install]del socket, que habilitaAlso=.
Created symlink /etc/systemd/system/servidor.service → /etc/systemd/system/web.service.
Created symlink /etc/systemd/system/multi-user.target.wants/web.service → /etc/systemd/system/web.service.
Created symlink /etc/systemd/system/graphical.target.wants/web.service → /etc/systemd/system/web.service.
Created symlink /etc/systemd/system/sockets.target.wants/web.socket → /etc/systemd/system/web.socket.
flowchart LR
MU["multi-user.target.wants/web.service"] --> W["web.service"]
GR["graphical.target.wants/web.service"] --> W
AL["servidor.service"] --> W
SO["sockets.target.wants/web.socket"] --> WS["web.socket"]
- No.
enablenomés prepara l’arrencada següent. Per activar-lo ara caldriastart(oenable --now).
Repte. servidor.service és un nom alternatiu (àlies) de la mateixa unitat: un enllaç simbòlic cap a web.service. No és una segona unitat. Es pot comprovar amb ls -l /etc/systemd/system/servidor.service i amb systemctl status servidor.service, que mostra la unitat web.service.
El programa infod és un dimoni clàssic: en arrencar fa fork(); el fill escriu el seu PID a /run/infod.pid i continua en marxa; el pare surt amb codi 0. Completa la unitat:
[Unit]
Description=Dimoni clàssic
[Service]
Type=______(1)______
PIDFile=______(2)______
ExecStart=/usr/sbin/infod --pidfile /run/infod.pid
ExecReload=/bin/kill -HUP ______(3)______
[Install]
WantedBy=multi-user.targetPregunta extra: per què Type=simple seria incorrecte aquí?
Pots veure el raonament
forking/run/infod.pid$MAINPID(systemd el substitueix pel PID del procés principal, que ha après del fitxer de PID)
sequenceDiagram
autonumber
participant S as systemd
participant P as infod pare
participant D as infod fill
S->>P: fork + execve
P->>D: fork
D->>D: escriu el PID a /run/infod.pid
P-->>S: exit 0
S->>S: llegeix PIDFile i el declara principal
Note over D: procés principal del servei
Amb forking, la sortida del pare és el senyal ja estic a punt; PIDFile= li diu a systemd quin és el procés que queda (el fill).
Pregunta extra. Amb Type=simple, el procés principal seria el pare. Quan surt amb codi 0, systemd considera que el servei ha acabat i el desactiva; en fer-ho, neteja el grup de control i el fill també es mata.
# a.service # b.service # c.service # d.service
[Unit] [Unit] [Unit] [Service]
Wants=b.service Wants=c.service Requires=d.service Type=oneshot
After=d.service ExecStart=/bin/falseLes unitats a, b i c són Type=simple i executen /usr/bin/sleep infinity. S’executa sudo systemctl start a.service.
- Quines unitats participen en la transacció?
- Quin és l’estat final de cadascuna?
systemctl startacaba amb error?
Repte: canvia Wants= per Requires= + After= a a (cap a b) i a b (cap a c). Torna a respondre les tres preguntes.
Pots veure el raonament
- Les quatre:
aarrossegab(Wants=),barrossegac, icarrossegad(Requires=). dfalla (ExecStart=/bin/falsesurt amb codi 1):failed.ctéRequires=d+After=d: espera quedacabi i, com que falla, no s’arriba a iniciar (Dependency failed for c.service);systemctl status cel mostra comfailed (Result: dependency). En canvi,bianomés tenenWants=: una fallada no es propaga cap amunt a través d’un requeriment feble, i s’inicien normalment (active (running)).- No. El treball de
aha tingut èxit: les fallades de les unitats desitjades ambWants=no compten.
flowchart TD
A["a.service · active"] -->|"Wants"| B["b.service · active"]
B -->|"Wants"| C["c.service · failed (dependency)"]
C -->|"Requires + After"| D["d.service · failed"]
Repte. Ara la fallada puja per tota la cadena: d falla → c no s’inicia → b (té Requires=c + After=c) tampoc → a tampoc. Les tres queden failed (Result: dependency), i systemctl start acaba amb error: A dependency job for a.service failed. See ‘journalctl -xe’ for details.
Amb After=, la unitat dependent espera que la requerida acabi d’iniciar-se i, si falla, el seu inici es cancel·la. Sense After=, les dues unitats s’inicien en paral·lel i el resultat és menys previsible. Per això, a la pràctica, Requires= es combina gairebé sempre amb After=.
Un programa pot acabar de cinc maneres. Per a cada causa i per a cada valor de Restart=, digues si systemd reinicia el servei (sí / no). El servei és Type=simple.
| Causa | always |
on-success |
on-failure |
on-abnormal |
|---|---|---|---|---|
El programa fa exit(0) |
||||
El programa fa exit(1) |
||||
kill -9 (SIGKILL) des de fora |
||||
kill -TERM (SIGTERM) des de fora |
||||
systemctl stop |
Repte: un programa amb un error surt amb codi 0 just en arrencar. Quin és el resultat amb Restart=always i els valors per defecte (RestartSec=100ms, 5 inicis cada 10 s)?
Pots veure el raonament
| Causa | always |
on-success |
on-failure |
on-abnormal |
|---|---|---|---|---|
exit(0) |
sí | sí | no | no |
exit(1) |
sí | no | sí | no |
SIGKILL |
sí | no | sí | sí |
SIGTERM |
sí | sí | no | no |
systemctl stop |
no | no | no | no |
- Per a systemd, una sortida neta és el codi 0 o un dels senyals
SIGHUP,SIGINT,SIGTERMiSIGPIPE. Per aixòSIGTERMes comporta comexit(0), i no com un error. - Una aturada explícita amb
systemctl stopmai provoca un reinici, sigui quin sigui el valor.
Repte. Bucle: el servei s’inicia, surt amb 0, always el torna a iniciar, i així successivament. Amb 0,1 s de retard, es superen els 5 inicis en 10 s en menys d’un segon. La unitat queda failed amb el resultat start-limit-hit. Per recuperar-la, cal corregir la causa i executar systemctl reset-failed.
Cal tenir en compte que Restart=always no és vàlid per a Type=oneshot.
# /lib/systemd/system/web.service (instal·lat pel paquet)
[Service]
ExecStart=/usr/sbin/webd --port 80
Environment=MODE=prod# /etc/systemd/system/web.service.d/10-mode.conf
[Service]
Environment=MODE=debug# /etc/systemd/system/web.service.d/20-port.conf
[Service]
ExecStart=
ExecStart=/usr/sbin/webd --port 8080- Quina ordre s’executa, i amb quin valor de
MODE? - S’afegeix
30-log.confambExecStart=/usr/sbin/webd --port 8080 --verbose(sense línia buida abans). Què passa? - Amb quina ordre es veu la unitat efectiva? Amb quina ordre es crearia un fragment com
20-port.confsense escriure el camí a mà?
Repte: i si web.service fos Type=oneshot?
Pots veure el raonament
flowchart LR
O["web.service · paquet"] --> D1["10-mode.conf"]
D1 --> D2["20-port.conf"]
D2 --> E["unitat efectiva"]
/usr/sbin/webd --port 8080ambMODE=debug. Els fragments es llegeixen en ordre alfabètic i se superposen a l’original. Per aEnvironment=, si una variable s’assigna dues vegades, preval l’última. Per aExecStart=(que normalment només admet una ordre), la línia buida esborra la llista anterior; sense aquesta línia, la nova ordre s’afegiria a la de l’original.- Ara hi ha dues línies
ExecStart=(la de20-port.confi la de30-log.conf), i el servei no ésoneshot. La unitat es rebutja:
web.service: Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.
- La unitat efectiva (fitxer original i fragments) es veu amb
systemctl cat web.service. L’ordresudo systemctl edit web.serviceobre un editor i desa el fragment com/etc/systemd/system/web.service.d/override.conf; en acabar fa eldaemon-reloadautomàticament. Així no es modifica mai el fitxer del paquet, que una actualització sobreescriuria.
Repte. Un oneshot admet diverses línies ExecStart= i les executa en seqüència, en l’ordre en què apareixen. Si una falla, les següents no s’executen.
El servei informes.service no s’inicia. La unitat és:
# /etc/systemd/system/informes.service
[Unit]
Description=Generació d'informes
[Service]
Type=exec
User=informes
WorkingDirectory=/srv/informes
ExecStart=/opt/informes/bin/informesd
[Install]
WantedBy=multi-user.targetAquests són tres registres de fallades diferents (cada un correspon a un escenari diferent):
── Registre A ──
informes.service: Failed to determine user credentials: No such process
informes.service: Failed at step USER spawning /opt/informes/bin/informesd: No such process
informes.service: Main process exited, code=exited, status=217/USER
informes.service: Failed with result 'exit-code'.
── Registre B ──
informes.service: Changing to the requested working directory failed: No such file or directory
informes.service: Failed at step CHDIR spawning /opt/informes/bin/informesd: No such file or directory
informes.service: Main process exited, code=exited, status=200/CHDIR
informes.service: Failed with result 'exit-code'.
── Registre C ──
informes.service: Failed to locate executable /opt/informes/bin/informesd: No such file or directory
informes.service: Failed at step EXEC spawning /opt/informes/bin/informesd: No such file or directory
informes.service: Main process exited, code=exited, status=203/EXEC
informes.service: Failed with result 'exit-code'.
- Per a cada registre, quina línia de la unitat (o quin element del sistema) és la causa?
- Qui genera els codis
217/USER,200/CHDIRi203/EXEC: el programa o systemd? S’ha arribat a executarinformesden algun cas? - Amb
Type=simple,systemctl startretorna error en algun dels tres casos? I ambType=exec? - Per al registre A: quines ordres utilitzaries per comprovar si l’usuari existeix, validar la unitat, corregir el problema i tornar a provar el servei?
Repte: el registre C també apareix si el fitxer existeix però no té permís d’execució. Quin canvi hi ha al missatge i com ho corregiries?
Pots veure el raonament
A:
User=informes: l’usuari no existeix (el missatge No such process és unESRCHpoc intuïtiu). B:WorkingDirectory=/srv/informes: el directori no existeix. C:ExecStart=: el binari no existeix.Els genera systemd: formen una família de codis a partir del 200 (
200/CHDIR,203/EXEC,217/USER…) documentada asystemd.exec(5). El nom indica el pas que ha fallat: el procés fill de systemd ha fallat mentre es preparava el context d’execució.informesdno s’ha arribat a executar en cap cas: el missatge no ve del programa.El criteri fiable no és el número, sinó la línia
Failed at step X spawning, perquè un programa pot sortir amb qualsevol codi, també amb valors alts.Amb
simple, no:startnomés espera que es faci elfork(), i l’error només es veu al journal o asystemctl status. Ambexec, sí: systemd espera que l’execve()tingui èxit, i en els tres casos la fallada ve abans.Per al registre A:
getent passwd informes # no retorna res (codi de sortida 2) si no existeix sudo systemd-analyze verify /etc/systemd/system/informes.service sudo useradd --system --no-create-home --shell /usr/sbin/nologin informes sudo systemctl start informes.service systemctl status informes.service sudo journalctl -u informes.service -b --no-pagersystemd-analyze verifydetecta errors de la unitat (sintaxi, directives desconegudes, fitxers que falten), però no substitueix la lectura del journal, perquè no comprova l’entorn real d’execució. No caldaemon-reloadperquè el fitxer de la unitat no s’ha modificat; només caldria si s’hagués editat. Una alternativa a crear l’usuari ésDynamicUser=yes, amb implicacions sobre els permisos dels directoris.
Repte. Si el fitxer existeix però no és executable, el pas continua sent EXEC, però l’error passa a ser Permission denied. La correcció és sudo chmod +x /opt/informes/bin/informesd (i comprovar també que els directoris del camí són accessibles per a l’usuari del servei).
Volem que el servei copia.service es comprovi abans d’executar-se i que, si falla, s’enregistri un avís mitjançant un segon servei.
# /etc/systemd/system/copia.service
[Unit]
Description=Còpia de seguretat
OnFailure=avis@%n.service
[Service]
Type=oneshot
ExecStartPre=/usr/bin/test -d /srv/dades
ExecStart=/usr/local/bin/copia# /etc/systemd/system/avis@.service
[Unit]
Description=Avís de fallada de %i
[Service]
Type=oneshot
ExecStart=/usr/bin/logger -t avis -p user.err "Ha fallat %i"El directori /srv/dades no existeix. S’executa sudo systemctl start copia.service.
- S’executa
ExecStart=? Quin és l’estat final decopia.service? - Què fa
OnFailure=? Quina unitat s’activa exactament i què valen%ni%i? - Com es consulta l’avís?
Repte: què canviaria si la línia fos ExecStartPre=-/usr/bin/test -d /srv/dades?
Pots veure el raonament
- No.
test -dsurt amb codi 1; una fallada d’ExecStartPre=avorta l’inici: no s’executaExecStart=i la unitat quedafailed(Result: exit-code). OnFailure=activa les unitats indicades quan la unitat entra a l’estatfailed.%nés el nom complet de la unitat (copia.service), de manera que s’activa la instànciaavis@copia.service.servicede la plantillaavis@.service, on%ivalcopia.service.- Amb
journalctl -t avis(el-tdelloggerés l’identificador) ojournalctl -u 'avis@*'.
sequenceDiagram
autonumber
participant S as systemd
participant C as copia.service
participant A as avis@copia.service
S->>C: ExecStartPre: test -d /srv/dades
C-->>S: codi 1
S->>C: marca failed (ExecStart no s'executa)
S->>A: OnFailure=
A->>A: logger "Ha fallat copia.service"
Repte. El prefix - fa que systemd ignori el resultat de l’ordre: la comprovació deixa de ser una condició, ExecStart= s’executaria igualment i OnFailure= no s’activaria per aquesta causa. Si el que es vol és saltar-se el servei sense considerar-ho un error, la directiva adequada és ConditionPathIsDirectory=/srv/dades.
Volem que informe.service s’executi cada dilluns a les 04:00 i que, si la màquina estava apagada a aquella hora, s’executi tan bon punt arrenqui. Completa:
# informe.timer
[Unit]
Description=Informe setmanal
[Timer]
OnCalendar=______(1)______
______(2)______=true
[Install]
WantedBy=______(3)______Per activar-lo ara i en arrencar: sudo systemctl ______(4)______ informe.timer.
Pregunta extra: per què informe.service no necessita secció [Install]? Amb quina ordre comprovaries l’expressió abans d’activar-la?
Pots veure el raonament
Mon *-*-* 04:00:00(també s’acceptaMon 04:00)Persistenttimers.targetenable --now
sequenceDiagram
autonumber
participant T as informe.timer
participant S as informe.service
Note over T: dilluns 04:00, màquina apagada
Note over T: dilluns 09:00, arrencada
T->>S: Persistent=true, s'executa ara
Amb Persistent=true, systemd desa a disc l’instant de l’última execució (a /var/lib/systemd/timers/); quan el temporitzador s’activa, si n’ha perdut alguna, dispara el servei immediatament. Només té efecte amb OnCalendar=.
Pregunta extra. Perquè el servei no s’inicia en arrencar: l’activa el temporitzador. S’habilita el .timer, no el .service. L’expressió es comprova amb systemd-analyze calendar 'Mon *-*-* 04:00:00', que mostra la forma normalitzada i la propera execució. Els temporitzadors actius i la propera execució es veuen amb systemctl list-timers.
Dos serveis independents, treball-a.service i treball-b.service, són Type=oneshot i executen /usr/bin/sleep 180 (triguen 3 minuts). Cadascun té el seu temporitzador, activat en arrencar (minut 0):
# treball-a.timer # treball-b.timer
[Timer] [Timer]
OnBootSec=2min OnBootSec=2min
OnUnitActiveSec=10min OnUnitInactiveSec=10min
AccuracySec=1s AccuracySec=1sEn quin minut comença cadascuna de les quatre primeres execucions de A i de B?
Pots veure el raonament
OnUnitActiveSec= compta des del moment en què el servei comença a activar-se (surt de l’estat inactiu); OnUnitInactiveSec= des que es va desactivar (és a dir, des que va acabar). Pots veure el resultat amb systemctl list-timers.
| Execució | A (ActiveSec) |
B (InactiveSec) |
|---|---|---|
| 1 | minut 2 | minut 2 (acaba al 5) |
| 2 | minut 12 | minut 15 (acaba al 18) |
| 3 | minut 22 | minut 28 (acaba al 31) |
| 4 | minut 32 | minut 41 |
gantt
dateFormat HH:mm
axisFormat %M
section A
execució 1 :a1, 00:02, 3m
execució 2 :a2, 00:12, 3m
execució 3 :a3, 00:22, 3m
execució 4 :a4, 00:32, 3m
section B
execució 1 :b1, 00:02, 3m
execució 2 :b2, 00:15, 3m
execució 3 :b3, 00:28, 3m
execució 4 :b4, 00:41, 3m
A dóna un període fix de 10 minuts entre inicis. B dóna un descans de 10 minuts entre el final d’una execució i l’inici de la següent, de manera que el període real és de 13 minuts. Si el que importa és no solapar-se amb l’execució anterior, B és el que es vol.
# /etc/systemd/system/eco.socket
[Socket]
ListenStream=127.0.0.1:9000
[Install]
WantedBy=sockets.target# /etc/systemd/system/eco.service
[Service]
ExecStart=/usr/local/bin/ecoeco és un servidor que, si ha estat iniciat per un socket, usa el socket que li passa systemd. S’executa sudo systemctl enable --now eco.socket.
- Quin és l’estat de
eco.servicejust després? Qui escolta al port 9000? Amb quina ordre ho comprovaries? - Un client es connecta amb
nc 127.0.0.1 9000. Què passa? - Per què s’habilita
eco.socketi noeco.service? Per quèeco.serviceno té[Install]?
Repte: què canvia amb Accept=yes al .socket?
Pots veure el raonament
eco.serviceésinactive (dead): encara no s’ha iniciat. El que escolta al port 9000 és systemd (PID 1), en nom del servei. Es comprova ambsudo ss -ltnp 'sport = :9000'isystemctl status eco.socket(Active: active (listening)).- En arribar la primera connexió, systemd inicia
eco.service(per defecte, el servei amb el mateix nom que el socket) i li passa el socket que escolta; el programa agafa la connexió pendent. - Perquè qui ha d’estar actiu des de l’arrencada és el socket; el servei s’activa sota demanda. No necessita
[Install]perquè l’activa el socket.
sequenceDiagram
autonumber
participant C as client
participant S as systemd (eco.socket)
participant E as eco.service
S->>S: escolta a 127.0.0.1:9000
C->>S: connexió
S->>E: inicia el servei i li passa el socket
E->>C: respon
Si eco.service s’atura, el socket continua escoltant i la propera connexió el torna a iniciar. Les connexions que arriben mentre no és viu queden en cua, de manera que no es perden.
Repte. Amb Accept=yes, systemd accepta ell mateix cada connexió i inicia una instància nova per connexió, que rep la connexió ja acceptada. Això obliga que el servei sigui una plantilla (eco@.service) i que el programa llegeixi de l’entrada estàndard (StandardInput=socket).
El servei processa-dades.service llegeix i escriu fitxers a /srv/dades. Aquest directori correspon a un volum separat (per exemple, un disc extern) que es munta des de /etc/fstab amb l’opció nofail:
UUID=<uuid> /srv/dades ext4 defaults,nofail 0 2
# /etc/systemd/system/processa-dades.service
[Unit]
Description=Processament de dades
[Service]
Type=oneshot
User=processador
Group=processador
ExecStart=/usr/local/bin/processa-dades --entrada /srv/dades/entrada --sortida /srv/dades/sortida
[Install]
WantedBy=multi-user.target- Quin problema pot aparèixer si el servei s’inicia quan el volum no està muntat?
- Quina directiva de systemd permet expressar que el servei necessita els muntatges requerits per accedir a
/srv/dades? - Completa la secció
[Unit]amb aquesta directiva. - Per què no és equivalent afegir només
After=local-fs.target? - Com comprovaries si el sistema de fitxers està muntat i si el servei ha fallat per aquesta causa?
Repte: si el volum no està muntat però /srv/dades existeix al sistema de fitxers arrel, què passa? Quines mesures el protegeixen? Canviaria alguna cosa si s’afegís WorkingDirectory=/srv/dades a la unitat?
Pots veure el raonament
El programa podria no trobar les dades esperades o, si el punt de muntatge buit és accessible i escrivible, podria escriure al sistema de fitxers arrel en lloc del volum previst, sense cap error visible.
RequiresMountsFor=.La secció queda així:
[Unit] Description=Processament de dades RequiresMountsFor=/srv/dadessystemd afegeix
Requires=iAfter=sobre totes les unitats de muntatge necessàries per accedir a aquest camí.Amb
nofail, el muntatge no és un requisit delocal-fs.target: aquest objectiu no exigeix que tingui èxit.After=local-fs.targetés, per tant, només una relació d’ordre i no declara que el muntatge sigui un requisit del servei: si el muntatge falla, el servei s’iniciaria igualment.RequiresMountsFor=el converteix en un requisit: si el muntatge no es pot fer, el servei no s’inicia (dependency failed).Amb muntatges d’arrencada sense
nofail, el sistema ja depèn delocal-fs.targeti l’After=seria sovint redundant.RequiresMountsFor=continua sent útil per a muntatges tardans (x-systemd.automount,_netdev) i per expressar la intenció.Per exemple:
findmnt /srv/dades systemd-escape -p --suffix=mount /srv/dades # srv-dades.mount systemctl status srv-dades.mount systemctl status processa-dades.service sudo journalctl -u processa-dades.service -b --no-pager
Repte. El servei llegiria dades incorrectes o escriuria al lloc equivocat. Mesures de protecció:
RequiresMountsFor=/srv/dades(el servei no s’inicia si el volum no es pot muntar);ConditionPathIsMountPoint=/srv/dades(el servei s’omet sense error si no és un punt de muntatge);sudo chattr +i /srv/dadesamb el volum desmuntat (el directori buit del sistema arrel deixa de ser escrivible).
Segons systemd.exec(5), WorkingDirectory= també afegeix automàticament dependències sobre els muntatges d’aquest camí, però no ho fa per camins que només apareixen com a arguments de l’ordre, com en aquest enunciat. Per això aquí RequiresMountsFor= és necessari.
Volem que el servei informe-segur.service generi un fitxer de resultat a /var/lib/informes/ sense executar-se com a root i sense poder modificar lliurement la resta del sistema. L’usuari i el grup informes existeixen.
# /etc/systemd/system/informe-segur.service
[Unit]
Description=Generació segura d'un informe
[Service]
Type=oneshot
User=informes
Group=informes
StateDirectory=informes
ProtectSystem=strict
PrivateTmp=yes
NoNewPrivileges=yes
ExecStart=/bin/sh -c 'date > /var/lib/informes/resultat.txt'
[Install]
WantedBy=multi-user.target- Quin usuari executa el procés?
- Quin directori crea i prepara
StateDirectory=informes? - Per què l’escriptura a
/var/lib/informes/resultat.txtpot funcionar malgratProtectSystem=strict? - Quina funció tenen
PrivateTmp=yesiNoNewPrivileges=yes? - Com comprovaries que el servei ha acabat correctament i que el fitxer existeix? Quina ordre avalua el nivell d’aïllament de la unitat?
Repte: es canvia la sortida a /etc/resultat.txt. Per aïllar l’efecte de ProtectSystem=strict, es proven tres variants: (a) la unitat tal com està; (b) sense User= ni Group= (com a root), amb ProtectSystem=strict; (c) com a root i sense ProtectSystem. Quin resultat esperes a cada una?
Pots veure el raonament
El procés s’executa com a usuari
informesi grupinformes, no com aroot.StateDirectory=informesdemana a systemd que creï i prepari el directori d’estat/var/lib/informes, amb propietat de l’usuari i el grup configurats.ProtectSystem=strictfa que tota la jerarquia del sistema de fitxers sigui de només lectura per al servei, però systemd deixa escrivible el directori declarat ambStateDirectory=.PrivateTmp=yesdóna al servei un/tmpi un/var/tmpprivats, invisibles per a la resta del sistema.NoNewPrivileges=yesimpedeix que el procés guanyi privilegis addicionals en executar altres programes (per exemple, els que tenen el bit set-user-ID).Es pot fer servir:
sudo systemctl start informe-segur.service systemctl status informe-segur.service sudo journalctl -u informe-segur.service -b --no-pager sudo cat /var/lib/informes/resultat.txt systemd-analyze security informe-segur.serviceCom que és
Type=oneshoti no hi haRemainAfterExit=yes, després d’una execució correcta la unitat quedainactive (dead); això no és una fallada.systemd-analyze securitymostra una puntuació d’exposició i les directives que encara es poden endurir.
Repte.
| Variant | Resultat esperat |
|---|---|
(a) informes + strict |
Falla. El sistema de fitxers és de només lectura abans que es comprovin els permisos: Read-only file system. |
(b) root + strict |
Falla amb Read-only file system: ni root pot escriure. |
(c) root, sense ProtectSystem |
Funciona. |
(a’) informes, sense ProtectSystem |
Falla per permisos: Permission denied. |
Comparant (b) amb (c) s’aïlla l’efecte de ProtectSystem=strict. Comparant (a’) amb (c), l’efecte de User=. La diferència entre els dos missatges (Read-only file system davant Permission denied) mostra que són dues barreres independents: el muntatge de només lectura i els permisos de fitxer.
Escriu l’ordre (o ordres) adequada per a cada situació. Totes es refereixen a web.service.
- Canviar un paràmetre sense tocar el fitxer del paquet.
- Veure la configuració efectiva, incloent-hi els fragments.
- Veure només els errors del servei des de l’últim arrencada.
- Seguir el journal del servei en temps real.
- Veure els missatges dels últims 10 minuts.
- Mostrar l’estat actiu, el subestat i el resultat com a propietats.
- Trobar la propera execució dels temporitzadors.
Repte: per què systemctl status no es suficient per diagnosticar una fallada ocorreguda fa tres dies?
Pots veure el raonament
sudo systemctl edit web.service(creaoverride.confi recarrega).systemctl cat web.servicejournalctl -u web.service -b -p err(-p errinclouerri més greus).journalctl -u web.service -fjournalctl -u web.service --since "10 min ago"systemctl show -p ActiveState,SubState,Result web.servicesystemctl list-timers
Repte. status només mostra les últimes línies del journal i l’estat actual de la unitat. Per a un historial cal journalctl, amb filtres de temps (--since, --until) o d’arrencada (-b -1 per a l’arrencada anterior). Aquest últim exigeix que el journal sigui persistent (/var/log/journal/ existent o Storage=persistent a journald.conf).