Depuració del desplegament del programari amb strace

Depuració del desplegament del programari amb strace

La meva feina diària és principalment el desplegament de programari, el que significa que passo molt de temps intentant respondre preguntes com:

  • Aquest programari funciona per al desenvolupador, però no per a mi. Per què?
  • Ahir aquest programari em va funcionar, però avui no. Per què?

Aquest és un tipus de depuració que és lleugerament diferent de la depuració de programari normal. La depuració regular tracta de la lògica del codi, però la depuració de desplegament tracta de la interacció entre el codi i l'entorn. Encara que l'arrel del problema sigui un error lògic, el fet que tot funcioni en una màquina i no en una altra significa que el problema es troba d'alguna manera a l'entorn.

Així, en lloc de les eines de depuració habituals com gdb Tinc un conjunt diferent d'eines per al desplegament de depuració. I la meva eina preferida per fer front al problema, com ara "Per què aquest programari no em funciona?" va trucar strace.

Què és strace?

strace és una eina per al "rastreig de trucades del sistema". Es va crear originalment per a Linux, però els mateixos trucs de depuració es poden fer amb eines per a altres sistemes (DTrace o ktració).

L'aplicació bàsica és molt senzilla. Només heu d'executar Strace amb qualsevol ordre i bolcarà totes les trucades del sistema (tot i que primer probablement haureu d'instal·lar-lo vosaltres mateixos strace):

$ strace echo Hello
...Snip lots of stuff...
write(1, "Hellon", 6)                  = 6
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

Quines són aquestes trucades al sistema? Això és com una API per al nucli del sistema operatiu. Hi havia una vegada, el programari tenia accés directe al maquinari amb el qual funcionava. Si, per exemple, necessitava mostrar alguna cosa a la pantalla, es jugava amb ports o registres assignats a memòria per a dispositius de vídeo. Quan els sistemes informàtics multitasca es van fer populars, el caos va regnar quan diverses aplicacions lluitaven pel maquinari. Els errors en una aplicació podrien fer caure altres, si no tot el sistema. Aleshores van aparèixer els modes de privilegi (o "protecció d'anell") a la CPU. El nucli es va convertir en el més privilegiat: va rebre accés complet al maquinari, generant aplicacions menys privilegiades que ja havien de sol·licitar accés al nucli per interactuar amb el maquinari mitjançant trucades al sistema.

A nivell binari, una trucada de sistema és lleugerament diferent d'una simple trucada de funció, però la majoria de programes utilitzen un embolcall a la biblioteca estàndard. Aquells. la biblioteca estàndard POSIX C conté una crida de funció write (), que conté tot el codi específic de l'arquitectura per a la trucada del sistema escriure.

Depuració del desplegament del programari amb strace

En resum, qualsevol interacció entre una aplicació i el seu entorn (sistemes informàtics) es realitza mitjançant trucades al sistema. Per tant, quan el programari funciona en una màquina però no en una altra, seria bo mirar els resultats del seguiment de trucades del sistema. Més concretament, aquí hi ha una llista de punts típics que es poden analitzar mitjançant una traça de trucades del sistema:

  • E/S de la consola
  • E/S de xarxa
  • Accés al sistema de fitxers i E/S de fitxers
  • Gestió de la vida útil d'un fil de procés
  • Gestió de memòria de baix nivell
  • Accés a controladors de dispositiu específics

Quan utilitzar Strace?

En teoria, strace s'utilitza amb qualsevol programa de l'espai d'usuari, perquè qualsevol programa de l'espai d'usuari ha de fer trucades al sistema. Funciona de manera més eficient amb programes compilats de baix nivell, però també funciona amb llenguatges d'alt nivell com Python si podeu reduir el soroll addicional del temps d'execució i de l'intèrpret.

En tota la seva esplendor strace es manifesta durant la depuració de programari que funciona bé en una màquina, però de sobte deixa de funcionar en una altra, produint missatges vagues sobre fitxers, permisos o intents infructuosos d'executar algunes ordres o alguna cosa més... És una llàstima, però no ho fa. combina molt bé amb problemes d'alt nivell, com ara errors de verificació de certificats. Normalment això requereix una combinació stracede vegades traça i eines de nivell superior (com l'eina de línia d'ordres openssl per depurar el certificat).

Utilitzarem un servidor autònom com a exemple, però el seguiment de trucades del sistema sovint es pot fer en plataformes de desplegament més complexes. Només cal triar les eines adequades.

Exemple simple de depuració

Suposem que voleu executar la increïble aplicació de servidor foo, i això és el que acabeu:

$ foo
Error opening configuration file: No such file or directory

Pel que sembla, no ha pogut trobar el fitxer de configuració que heu escrit. Això passa perquè de vegades, quan els gestors de paquets compilen una aplicació, anul·len les ubicacions esperades dels fitxers. I si seguiu la guia d'instal·lació d'una distribució, en una altra trobareu fitxers completament diferents d'on esperàveu. El problema es podria resoldre en un parell de segons si el missatge d'error indiqués on buscar el fitxer de configuració, però no ho fa. Llavors, on mirar?

Si teniu accés al codi font, podeu llegir-lo i esbrinar-ho tot. Un bon pla de còpia de seguretat, però no la solució més ràpida. Podeu recórrer a un depurador pas a pas com gdb i veure què fa el programa, però és molt més efectiu utilitzar una eina dissenyada específicament per mostrar la interacció amb l'entorn: strace.

Sortida strace pot semblar redundant, però la bona notícia és que la majoria es pot ignorar amb seguretat. Sovint és útil utilitzar l'operador -o per desar els resultats de la traça en un fitxer separat:

$ strace -o /tmp/trace foo
Error opening configuration file: No such file or directory
$ cat /tmp/trace
execve("foo", ["foo"], 0x7ffce98dc010 /* 16 vars */) = 0
brk(NULL)                               = 0x56363b3fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=25186, ...}) = 0
mmap(NULL, 25186, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f12cf1000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113 3 > 1 260A2 "..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f12cef000
mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2f12b2e000
mprotect(0x7f2f12b50000, 1658880, PROT_NONE) = 0
mmap(0x7f2f12b50000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f2f12b50000
mmap(0x7f2f12c98000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f2f12c98000
mmap(0x7f2f12ce5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f2f12ce5000
mmap(0x7f2f12ceb000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2f12ceb000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f2f12cf0500) = 0
mprotect(0x7f2f12ce5000, 16384, PROT_READ) = 0
mprotect(0x56363b08b000, 4096, PROT_READ) = 0
mprotect(0x7f2f12d1f000, 4096, PROT_READ) = 0
munmap(0x7f2f12cf1000, 25186)           = 0
openat(AT_FDCWD, "/etc/foo/config.json", O_RDONLY) = -1 ENOENT (No such file or directory)
dup(2)                                  = 3
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
brk(NULL)                               = 0x56363b3fb000
brk(0x56363b41c000)                     = 0x56363b41c000
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), ...}) = 0
write(3, "Error opening configuration file"..., 60) = 60
close(3)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

Aproximadament tota la primera pàgina de sortida strace - Normalment és una preparació de baix nivell per al llançament. (Moltes trucades mmap, mprotect, ploma per a coses com detectar memòria de baix nivell i mostrar biblioteques dinàmiques.) De fet, durant la depuració de la sortida strace És millor llegir des del final. A continuació hi haurà un repte escriure, que mostra un missatge d'error. Mirem a dalt i veiem la primera trucada del sistema errònia: la trucada oberta, que genera un error ENOENT ("no s'ha trobat el fitxer o el directori") intentant obrir /etc/foo/config.json. Aquí és on hauria d'estar el fitxer de configuració.

Aquest era només un exemple, però diria que el 90% del temps que faig servir strace, no hi ha res més difícil de fer que això. A continuació es mostra una guia completa de depuració pas a pas:

  • Enfadar-se a causa d'un missatge vague sobre un error del sistema i d'un programa
  • Reinicieu el programa amb strace
  • Trobeu el missatge d'error als resultats de la traça
  • Aneu més amunt fins que arribeu a la primera trucada del sistema fallida

És molt probable que la trucada al sistema del pas 4 reveli què ha fallat.

Consells

Abans de mostrar-vos un exemple de depuració més complexa, us mostraré alguns trucs per a un ús efectiu strace:

l'home és el teu amic

En molts sistemes *nix, es pot obtenir una llista completa de trucades del sistema al nucli executant home syscalls. Veureu coses com brk (2), el que significa que es pot obtenir més informació executant home 2brk.

Petit rastell: home 2 forquilla em mostra la pàgina del shell forquilla () в GNU libc, que, resulta que s'implementa cridant clonar (). Semàntica de la trucada forquilla segueix sent el mateix si escriviu un programa utilitzant forquilla (), i executeu un rastre: no trobaré cap trucada forquilla, en comptes d'ells n'hi haurà clonar (). Aquests rastrells només us confonen si comenceu a comparar la font amb la sortida strace.

Utilitzeu -o per desar la sortida en un fitxer

strace pot generar una sortida extensa, de manera que sovint és útil emmagatzemar els resultats de traça en fitxers separats (com a l'exemple anterior). Això també ajuda a evitar confondre la sortida del programa amb la sortida strace a la consola.

Utilitzeu -s per veure més dades d'argument

És possible que hàgiu notat que la segona meitat del missatge d'error no es mostra a la traça d'exemple anterior. És perquè strace per defecte només mostra els primers 32 bytes de l'argument de cadena. Si en voleu veure més, afegiu alguna cosa com -s 128 a la trucada strace.

-y facilita el seguiment de fitxers, sòcols, etc.

"Tot és fitxer" vol dir que els sistemes *nix fan totes les E/S utilitzant descriptors de fitxers, tant si s'aplica a un fitxer com a una xarxa o canalitzacions entre processos. Això és convenient per a la programació, però dificulta fer un seguiment del que està passant realment quan veieu comú llegir и escriure als resultats de la traça de la trucada del sistema.

Afegint un operador y, forçaràs strace anoteu cada descriptor de fitxer a la sortida amb una nota del que apunta.

Adjunta a un procés que ja està en execució amb -p**

Com veureu a l'exemple següent, de vegades cal traçar un programa que ja s'està executant. Si se sap que s'està executant com a procés 1337 (per exemple, des de la sortida ps), llavors el podeu seguir així:

$ strace -p 1337
...system call trace output...

És possible que necessiteu drets d'arrel.

Utilitzeu -f per supervisar processos fills

strace Per defecte, només rastreja un procés. Si aquest procés genera processos secundaris, es pot veure la crida al sistema per generar el procés fill, però les trucades al sistema del procés fill no es mostraran.

Si creieu que l'error es troba en un procés secundari, utilitzeu la instrucció -f, això permetrà el seu rastreig. L'inconvenient d'això és que la sortida us confondrà encara més. Quan strace rastreja un procés o un fil, mostra un sol flux d'esdeveniments de trucada. Quan rastreja diversos processos alhora, és possible que vegeu l'inici d'una trucada interrompuda per un missatge , llavors - un munt de trucades per a altres branques d'execució, i només llavors - el final de la primera <...foocall reprenat>. O dividiu tots els resultats de la traça en fitxers diferents, també utilitzant l'operador -ff (detalls a lideratge en strace).

Filtra traces utilitzant -e

Com podeu veure, el resultat de la traça és un munt real de totes les possibles trucades al sistema. Bandera -e Podeu filtrar el rastre (vegeu lideratge en strace). El principal avantatge és que és més ràpid executar una traça filtrada que fer una traça completa i després grep`a les. Per ser sincer, gairebé sempre m'és igual.

No tots els errors són dolents

Un exemple senzill i comú és un programa que busca un fitxer en diversos llocs alhora, com un shell que busca un directori que conté un fitxer executable:

$ strace sh -c uname
...
stat("/home/user/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/bin/uname", {st_mode=S_IFREG|0755, st_size=39584, ...}) = 0
...

Les heurístiques com "última sol·licitud fallida abans d'informar un error" són bones per trobar errors rellevants. Sigui com sigui, és lògic començar des del final.

Els tutorials de programació en C us poden ajudar a entendre les trucades del sistema.

Les trucades estàndard a les biblioteques C no són trucades al sistema, sinó només una capa superficial fina. Per tant, si enteneu almenys una mica com i què fer a C, us serà més fàcil entendre els resultats de la traça de trucades del sistema. Per exemple, teniu problemes per depurar trucades a sistemes de xarxa, mireu el mateix clàssic Guia de Bija per a la programació en xarxa.

Un exemple de depuració més complex

Ja he dit que l'exemple de depuració simple és un exemple del que he de tractar sobretot quan treballo strace. Tanmateix, de vegades es requereix una investigació real, així que aquí teniu un exemple real de depuració més avançada.

bcron - planificador de processament de tasques, una altra implementació del dimoni *nix cron. Està instal·lat al servidor, però quan algú intenta editar la programació, això és el que passa:

# crontab -e -u logs
bcrontab: Fatal: Could not create temporary file

D'acord, això vol dir bcron va intentar escriure un fitxer determinat, però no va funcionar, i no admetrà per què. Descobrint strace:

# strace -o /tmp/trace crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
# cat /tmp/trace
...
openat(AT_FDCWD, "bcrontab.14779.1573691864.847933", O_RDONLY) = 3
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
read(3, "#Ansible: logsaggn20 14 * * * lo"..., 8192) = 150
read(3, "", 8192)                       = 0
munmap(0x7f82049b4000, 8192)            = 0
close(3)                                = 0
socket(AF_UNIX, SOCK_STREAM, 0)         = 3
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/bcron-spool"}, 110) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
write(3, "156:Slogs #Ansible: logsaggn20 1"..., 161) = 161
read(3, "32:ZCould not create temporary f"..., 8192) = 36
munmap(0x7f82049b4000, 8192)            = 0
close(3)                                = 0
write(2, "bcrontab: Fatal: Could not creat"..., 49) = 49
unlink("bcrontab.14779.1573691864.847933") = 0
exit_group(111)                         = ?
+++ exited with 111 +++

Hi ha un missatge d'error a prop del final escriure, però aquesta vegada alguna cosa és diferent. En primer lloc, no hi ha cap error de trucada del sistema rellevant, que normalment es produeix abans. En segon lloc, està clar que en algun lloc algú ja ha llegit el missatge d'error. Sembla que el problema real està en un altre lloc, i bcrontab simplement reprodueix el missatge.

Si us fixeu home 2 llegir, podeu veure que el primer argument (3) és un descriptor de fitxer, que *nix utilitza per a tot el processament d'E/S. Com puc saber què representa el descriptor de fitxer 3? En aquest cas concret, podeu córrer strace amb operador y (vegeu més amunt) i us ho dirà automàticament, però per esbrinar coses com aquesta, és útil saber com llegir i analitzar els resultats de la traça.

L'origen d'un descriptor de fitxer pot ser una de moltes trucades al sistema (tot depèn de per a què serveixi el descriptor: una consola, un sòcol de xarxa, el fitxer en si mateix o una altra cosa), però sigui com sigui, busquem trucades retornant 3 (és a dir, busquem "= 3" als resultats de la traça). En aquest resultat n'hi ha 2: oberta a la part superior i endoll Al mig. oberta obre el fitxer però tancar(3) mostrarà que es torna a tancar. (Rake: els descriptors de fitxers es poden reutilitzar quan s'obren i es tanquen). Anomenada endoll() adequat perquè és l'últim abans llegir (), i resulta que bcrontab funciona amb alguna cosa a través d'un sòcol. La línia següent mostra que el descriptor del fitxer està associat socket de domini unix de camí /var/run/bcron-spool.

Per tant, hem de trobar el procés associat sòcol Unix per una altra banda. Hi ha un parell de trucs nets per a aquest propòsit, tots dos útils per depurar desplegaments de servidors. El primer és utilitzar netstat o més recent ss (estat del sòcol). Les dues ordres mostren les connexions de xarxa actives del sistema i prenen la declaració -l per descriure les preses d'escolta, així com l'operador -p per mostrar els programes connectats al sòcol com a client. (Hi ha moltes més opcions útils, però aquestes dues són suficients per a aquesta tasca.)

# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0   128   /var/run/bcron-spool 1466637   * 0   users:(("unixserver",pid=20629,fd=3))

Això suggereix que l'oient és l'ordre inixserver, que s'executa amb l'ID de procés 20629. (I, casualment, utilitza el descriptor de fitxer 3 com a sòcol.)

La segona eina realment útil per trobar la mateixa informació es diu lsof. Llista tots els fitxers oberts (o descriptors de fitxers) al sistema. O podeu obtenir informació sobre un fitxer específic:

# lsof /var/run/bcron-spool
COMMAND   PID   USER  FD  TYPE  DEVICE              SIZE/OFF  NODE    NAME
unixserve 20629 cron  3u  unix  0x000000005ac4bd83  0t0       1466637 /var/run/bcron-spool type=STREAM

El procés 20629 és un servidor de llarga vida, de manera que podeu connectar-lo strace fent servir alguna cosa així strace -o /tmp/trace -p 20629. Si editeu un treball cron en un altre terminal, rebreu una sortida de traça amb un error. I aquí teniu el resultat:

accept(3, NULL, NULL)                   = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21181
close(4)                                = 0
accept(3, NULL, NULL)                   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21181, si_uid=998, si_status=0, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 21181
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]})                 = 43
accept(3, NULL, NULL)                   = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21200
close(4)                                = 0
accept(3, NULL, NULL)                   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21200, si_uid=998, si_status=111, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 111}], WNOHANG|WSTOPPED, NULL) = 21200
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]})                 = 43
accept(3, NULL, NULL

(Últim acceptar () no es completarà quan es traça.) De nou, malauradament, aquest resultat no conté l'error que estem buscant. No veiem cap missatge que bcrontag envia o rep des del sòcol. En lloc d'això, controleu el procés complet (clonar, espera 4, SIGCHLD etc.) Aquest procés genera un procés fill, que, com podeu suposar, fa el treball real. I si necessiteu agafar el seu rastre, afegiu-lo a la trucada strace -f. Això és el que trobarem quan cerquem el missatge d'error al nou resultat amb strace -f -o /tmp/trace -p 20629:

21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied) 
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111)                   = ?
21470 +++ exited with 111 +++

Ara, això és alguna cosa. El procés 21470 rep un error "accés denegat" quan s'intenta crear un fitxer a la ruta tmp/spool.21470.1573692319.854640 (relacionat amb el directori de treball actual). Si només coneguéssim el directori de treball actual, també sabríem el camí complet i podríem esbrinar per què el procés no pot crear-hi el seu fitxer temporal. Malauradament, el procés ja s'ha acabat, de manera que no només podeu utilitzar-lo lsof -p 21470 per trobar el directori actual, però podeu treballar en la direcció oposada: busqueu les trucades al sistema PID 21470 que canviïn el directori. (Si no n'hi ha cap, el PID 21470 els ha d'haver heretat del seu pare, i això ja ha acabat lsof -p no es pot esbrinar.) Aquesta trucada al sistema és chdir (que és fàcil de trobar amb l'ajuda dels motors de cerca en línia moderns). I aquí teniu el resultat de les cerques inverses basades en els resultats de la traça, fins al PID 20629 del servidor:

20629 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21470
...
21470 execve("/usr/sbin/bcron-spool", ["bcron-spool"], 0x55d2460807e0 /* 27 vars */) = 0
...
21470 chdir("/var/spool/cron")          = 0
...
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied) 
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111)                   = ?
21470 +++ exited with 111 +++

(Si us heu perdut, potser voldreu llegir la meva publicació anterior sobre la gestió de processos *nix i els shells.) Per tant, el PID del servidor 20629 no va rebre permís per crear un fitxer al camí /var/spool/cron/tmp/spool.21470.1573692319.854640. El més probable és que la raó d'això sigui la configuració clàssica de permisos del sistema de fitxers. Comprovem:

# ls -ld /var/spool/cron/tmp/
drwxr-xr-x 2 root root 4096 Nov  6 05:33 /var/spool/cron/tmp/
# ps u -p 20629
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
cron     20629  0.0  0.0   2276   752 ?        Ss   Nov14   0:00 unixserver -U /var/run/bcron-spool -- bcron-spool

Aquí és on està enterrat el gos! El servidor s'executa com a cron d'usuari, però només el root té permís per escriure al directori /var/spool/cron/tmp/. Comandament senzill chown cron /var/spool/cron/tmp/ forçarà bcron treballar correctament. (Si aquest no era el problema, llavors el següent sospitós més probable és un mòdul de seguretat del nucli com SELinux o AppArmor, així que comprovaria el registre de missatges del nucli amb dmesg.)

En total

Els rastres de trucades del sistema poden ser aclaparadors per a un principiant, però espero haver demostrat que són una manera ràpida de depurar tota una classe de problemes comuns de desplegament. Imagineu-vos que intenteu depurar un multiprocés bcronutilitzant un depurador pas a pas.

L'anàlisi dels resultats de traça cap enrere al llarg d'una cadena de trucades al sistema requereix habilitat, però com he dit, gairebé sempre, utilitzar strace, acabo d'obtenir el resultat de la traça i cerco errors començant des del final. De totes maneres, strace m'ajuda a estalviar molt de temps en la depuració. Espero que també us sigui útil.

Font: www.habr.com

Afegeix comentari