Successivo: Tutorial di Scheme, Su: (dir) [Contenuti][Indice]
Questo documento presenta tutorial ed esempi dettagliati per GNU Guix, uno strumento di gestione pacchetti funzionale scritto per il sistema GNU. Si prega di vedi manuale di riferimento di GNU Guix per dettagli sul sistema, la sua API e i concetti correlati.
Questo manuale è disponibile anche in inglese (vedi GNU Guix Cookbook ), francese (vedi Livre de recettes de GNU Guix ), cinese semplificato (vedi GNU Guix 烹饪书 ), tedesco (vedi GNU-Guix-Kochbuch ), coreano (vedi GNU Guix 쿡북 ), spagnolo (vedi Libro de recetas de GNU Guix ), portoghese brasiliano (vedi Livro de receitas do GNU Guix ), russo (vedi GNU Guix Рецепты ), slovacco (vedi Receptár GNU Guix ) e svedese (vedi Kokbok för GNU Guix ). Se desideri tradurre questo documento nella tua lingua madre, considera di unirti a Weblate (vedi Tradurre Guix in Manuale di riferimento di GNU Guix).
Successivo: Impacchettamento, Precedente: Ricettario di GNU Guix, Su: Ricettario di GNU Guix [Contenuti][Indice]
GNU Guix è scritto nel linguaggio di programmazione generico Scheme, e molte delle sue funzionalità possono essere accessibili e manipolate programmaticamente. Puoi usare Scheme per generare definizioni di pacchetti, per modificarle, per compilarle, per distribuire interi sistemi operativi, ecc.
Conoscere le basi di come programmare in Scheme sbloccherà molte delle funzionalità avanzate che Guix fornisce — e non è nemmeno necessario essere un programmatore esperto per usarle!
Iniziamo!
Su: Tutorial di Scheme [Contenuti][Indice]
Guix utilizza l’implementazione Guile di Scheme. Per iniziare a giocare con
il linguaggio, installalo con guix install guile
e avvia un
REPL — abbreviazione di
read-eval-print loop — eseguendo guile
dalla riga di
comando.
In alternativa, puoi anche eseguire guix shell guile -- guile
se
preferisci non avere Guile installato nel tuo profilo utente.
Negli esempi seguenti, le righe mostrano cosa digiteresti nel REPL; le righe che iniziano con "⇒" mostrano i risultati della valutazione, mentre le righe che iniziano con "-|" mostrano le cose che vengono stampate. Vedi Using Guile Interactively in Manuale di riferimento di GNU Guile, per maggiori dettagli sul REPL.
#true
e #false
(abbreviato #t
e
#f
) rappresentano i booleani "vero" e "falso", rispettivamente.
Esempi di espressioni valide:
"Hello World!" ⇒ "Hello World!" 17 ⇒ 17 (display (string-append "Ciao " "Guix" "\n")) -| Ciao Guix! ⇒ #<unspecified>
lambda
:
La procedura sopra restituisce il quadrato del suo argomento. Poiché tutto è
un’espressione, l’espressione lambda
restituisce una procedura
anonima, che a sua volta può essere applicata a un argomento:
((lambda (x) (* x x)) 3) ⇒ 9
Le procedure sono valori regolari proprio come numeri, stringhe, booleani e così via.
define
:
(define a 3) (define square (lambda (x) (* x x))) (square a) ⇒ 9
(define (square x) (* x x))
list
:
(list 2 a 5 7) ⇒ (2 3 5 7)
(srfi srfi-1)
per
creare ed elaborare liste (vedi elaborazione di liste in Manuale di riferimento di GNU Guile). Ecco alcune delle più utili in
azione:
(use-modules (srfi srfi-1)) ;importa procedure di elaborazione di liste (append (list 1 2) (list 3 4)) ⇒ (1 2 3 4) (map (lambda (x) (* x x)) (list 1 2 3 4)) ⇒ (1 4 9 16) (delete 3 (list 1 2 3 4)) ⇒ (1 2 4) (filter odd? (list 1 2 3 4)) ⇒ (1 3) (remove even? (list 1 2 3 4)) ⇒ (1 3) (find number? (list "a" 42 "b")) ⇒ 42
Notare come il primo argomento di map
, filter
, remove
e
find
sia una procedura!
'(display (string-append "Ciao " "Guix" "\n")) ⇒ (display (string-append "Ciao " "Guix" "\n")) '(2 a 5 7) ⇒ (2 a 5 7)
quasiquote
(`
, un apice inverso) disabilita la valutazione
di un’espressione tra parentesi finché unquote
(,
, una
virgola) non la riabilita. Quindi ci fornisce un controllo preciso su cosa
viene valutato e cosa no.
`(2 a 5 7 (2 ,a 5 ,(+ a 4))) ⇒ (2 a 5 7 (2 3 5 7))
Notare che il risultato sopra è una lista di elementi misti: numeri, simboli
(qui a
) e l’ultimo elemento è una lista stessa.
quasiquote
e unquote
: #~
(o gexp
) e #$
(o
ungexp
). Ti permettono di mettere in scena il codice per
un’esecuzione successiva.
Ad esempio, incontrerai le gexps in alcune definizioni di pacchetto dove forniscono codice da eseguire durante il processo di compilazione del pacchetto. Appaiono così:
(use-modules (guix gexp) ;così possiamo scrivere gexps (gnu packages base)) ;per 'coreutils' ;; Di seguito una G-expression che rappresenta codice messo in scena. #~(begin ;; Invoca 'ls' dal package definito dalla variabile 'coreutils'. (system* #$(file-append coreutils "/bin/ls") "-l") ;; Crea la directory di output di questo pacchetto. (mkdir #$output))
Vedi G-expression in Manuale di riferimento di GNU Guix, per maggiori informazioni sulle gexps.
let
(vedi Local
Bindings in Manuale di Riferimento di GNU Guile):
(define x 10) (let ((x 2) (y 3)) (list x y)) ⇒ (2 3) x ⇒ 10 y error→ In procedure module-lookup: Variabile non legata: y
Usa let*
per permettere alle dichiarazioni di variabili successive di
fare riferimento a definizioni precedenti.
#:
(cancelletto, due
punti) seguito da caratteri alfanumerici:
#:in-questo-modo
. Vedi Keywords in Manuale di riferimento di
GNU Guile.
%
è tipicamente usata per le variabili globali di sola
lettura nella fase di compilazione. Notare che è solo una convenzione, come
_
in C. Scheme tratta %
esattamente come qualsiasi altra
lettera.
define-module
(vedi Creating Guile
Modules in Manuale di riferimento di GNU Guile). Per esempio
(define-module (guix build-system ruby)
#:use-module (guix store)
#:export (ruby-build
ruby-build-system ))
definisce il modulo guix build-system ruby
che deve essere situato in
guix/build-system/ruby.scm da qualche parte nel percorso di
caricamento di Guile. Dipende dal modulo (guix store)
ed esporta due
variabili, ruby-build
e ruby-build-system
.
Vedi Moduli di pacchetti in Manuale di riferimento di GNU Guix, per informazioni sui moduli che definiscono i pacchetti.
Andare oltre: Scheme è un linguaggio ampiamente utilizzato per insegnare la programmazione e troverai molto materiale che lo usa come veicolo. Ecco una selezione di documenti per saperne di più su Scheme:
- Un Primer di Scheme, di Christine Lemmer-Webber e lo Spritely Institute.
- Scheme in Sintesi, di Steve Litt.
- Struttura e Interpretazione dei Programmi per Elaboratore, di Harold Abelson e Gerald Jay Sussman, con Julie Sussman. Conosciuto colloquialmente come "SICP", questo libro è un riferimento.
Puoi anche installarlo e leggerlo dal tuo computer:
guix install sicp info-reader info sicpTroverai altri libri, tutorial e altre risorse su https://schemers.org/.
Successivo: Configurazione di sistema, Precedente: Tutorial di Scheme, Su: Ricettario di GNU Guix [Contenuti][Indice]
Questo capitolo è dedicato a insegnarti come aggiungere pacchetti alla collezione di pacchetti fornita con GNU Guix. Ciò comporta la scrittura di definizioni di pacchetti in Guile Scheme, l’organizzazione in moduli di pacchetti e la loro compilazione.
Successivo: Packaging Workflows, Su: Impacchettamento [Contenuti][Indice]
GNU Guix si distingue come il gestore di pacchetti hackable, principalmente perché utilizza GNU Guile, un potente linguaggio di programmazione di alto livello, uno dei dialetti Scheme della famiglia Lisp.
Anche le definizioni dei pacchetti sono scritte in Scheme, il che conferisce a Guix poteri unici, a differenza della maggior parte degli altri gestori di pacchetti che utilizzano script di shell o linguaggi semplici.
#:make-flags "..."
alla lista dei pacchetti. Non sarebbe
un’esagerazione pensare ai flag
USE di Gentoo qui, ma questo va anche oltre: le modifiche non devono essere
pensate in anticipo dal manutentore del pacchetto, possono essere
programmed dall’utente!
Il seguente tutorial copre tutte le basi sulla creazione di pacchetti con Guix. Non presuppone molta conoscenza del sistema Guix né del linguaggio Lisp. Si presume che il lettore abbia familiarità con la riga di comando e abbia alcune conoscenze di programmazione di base.
Successivo: Configurazione, Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
La sezione "Definire i pacchetti" del manuale introduce le basi dell’impacchettamento con Guix (vedi Definire i pacchetti in Manuale di riferimento di GNU Guix). Nella sezione seguente, ripercorreremo in parte queste basi.
GNU Hello è un progetto fittizio che serve come esempio idiomatico per
l’impacchettamento. Utilizza il sistema di compilazione GNU
(./configure && make && make install
). Guix fornisce già una
definizione di pacchetto che è un esempio perfetto da cui partire. Puoi
consultare la sua dichiarazione con guix edit hello
dalla riga di
comando. Vediamo come appare:
(define-public hello
(package
(name "hello")
(version "2.10")
(source (origin
(method url-fetch )
(uri (string-append "mirror://gnu/hello/hello-" version
".tar.gz"))
(sha256
(base32
"0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
(build-system gnu-build-system )
(synopsis "Ciao, mondo GNU: Un esempio di pacchetto GNU")
(description
"GNU Hello stampa il messaggio \"Ciao, mondo!\" e poi esce. Serve come esempio di pratiche di codifica standard GNU. Come tale, supporta argomenti da riga di comando, più lingue, e così via.")
(home-page "https://www.gnu.org/software/hello/")
(license gpl3+)))
Come puoi vedere, la maggior parte è piuttosto semplice. Ma esaminiamo i campi insieme:
Il nome del progetto. Usando le convenzioni di Scheme, preferiamo mantenerlo in minuscolo, senza trattini bassi e usando parole separate da trattini.
Questo campo contiene una descrizione dell’origine del codice sorgente. Il
record origin
contiene questi campi:
url-fetch
per scaricare via HTTP/FTP, ma altri metodi
esistono, come git-fetch
per i repository Git.
https://
per url-fetch
. Qui
lo speciale ‘mirror://gnu‘ si riferisce a un insieme di posizioni note,
tutte utilizzabili da Guix per recuperare il sorgente, nel caso in cui
alcune di esse fallissero.
sha256
del file richiesto. Questo è essenziale per garantire
che il sorgente non sia corrotto. Notare che Guix lavora con stringhe
base32, da cui la chiamata alla funzione base32
.
È qui che il potere di astrazione fornito dal linguaggio Scheme brilla
davvero: in questo caso, il gnu-build-system
astrae le famose
invocazioni di shell ./configure && make && make install
. Altri
sistemi di compilazione includono il trivial-build-system
che non fa
nulla e richiede al manutentore del pacchetto di programmare tutti i
passaggi di compilazione, il python-build-system
, il
emacs-build-system
e molti altri (vedi Sistemi di build in Manuale di riferimento di GNU Guix).
Dovrebbe essere un riassunto conciso di ciò che fa il pacchetto. Per molti pacchetti, uno slogan dalla home page del progetto può essere usato come sinossi.
Come per la sinossi, va bene riutilizzare la descrizione del progetto dalla homepage. Notare che Guix usa la sintassi Texinfo.
Usa HTTPS se disponibile.
Vedere guix/licenses.scm
nel sorgente del progetto per un elenco
completo delle licenze disponibili.
È ora di compilare il nostro primo pacchetto! Niente di speciale per ora: ci
atterremo a un fittizio my-hello
, una copia della dichiarazione
precedente.
Come per il rituale "Hello World" insegnato con la maggior parte dei linguaggi di programmazione, questo sarà probabilmente l’approccio più "manuale". Elaboreremo una configurazione ideale più tardi; per ora seguiremo la strada più semplice.
Salva quanto segue in un file my-hello.scm.
(use-modules (guix packages) (guix download) (guix build-system gnu) (guix licenses)) (package (name "my-hello") (version "2.10") (source (origin (method url-fetch ) (uri (string-append "mirror://gnu/hello/hello-" version ".tar.gz")) (sha256 (base32 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))) (build-system gnu-build-system ) (synopsis "Ciao, mondo Guix: Un esempio di pacchetto Guix personalizzato") (description "GNU Hello stampa il messaggio \"Ciao, mondo!\" e poi esce. Serve come esempio delle pratiche di codifica standard di GNU. Come tale, supporta argomenti da riga di comando, più linguaggi, e così via.") (home-page "https://www.gnu.org/software/hello/") (license gpl3+))
Spiegheremo il codice extra tra un momento.
Sentiti libero di giocare con i diversi valori dei vari campi. Se cambi la sorgente, dovrai aggiornare il checksum. Infatti, Guix si rifiuta di compilare qualsiasi cosa se il checksum fornito non corrisponde al checksum calcolato del codice sorgente. Per ottenere il checksum corretto della dichiarazione del pacchetto, dobbiamo scaricare la sorgente, calcolare il checksum sha256 e convertirlo in base32.
Fortunatamente, Guix può automatizzare questo compito per noi; tutto ciò di cui abbiamo bisogno è fornire l’URI:
$ guix download mirror://gnu/hello/hello-2.10.tar.gz Inizio download di /tmp/guix-file.JLYgL7 Da https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz... redirezione a `https://mirror.ibcp.fr/pub/gnu/hello/hello-2.10.tar.gz'... ...10.tar.gz 709KiB 2.5MiB/s 00:00 [##################] 100.0% /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz 0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i
In questo caso specifico l’output ci dice quale mirror è stato scelto. Se il
risultato del comando precedente non è lo stesso dello snippet sopra,
aggiorna di conseguenza la tua dichiarazione my-hello
.
Nota che i tarball dei pacchetti GNU sono dotati di una firma OpenPGP, quindi dovresti assolutamente controllare la firma di questo tarball con ‘gpg‘ per autenticarlo prima di procedere:
$ guix download mirror://gnu/hello/hello-2.10.tar.gz.sig Inizio download di /tmp/guix-file.03tFfb Da https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz.sig... redirezione a `https://ftp.igh.cnrs.fr/pub/gnu/hello/hello-2.10.tar.gz.sig'. .. ....tar.gz.sig 819B 1.2MiB/s 00:00 [##################] 100.0% /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig 0q0v86n3y38z17rl146gdakw9xc4mcscpk8dscs412j22glrv9jf $ gpg --verify /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz gpg: Firma creata dom 16 nov 2014 13:08:37 CET gpg: usando la chiave RSA A9553245FDE9B739 gpg: Buona firma da "Sami Kerola <kerolasa@iki.fi>" [sconosciuto] gpg: alias "Sami Kerola (http://www.iki.fi/kerolasa/) <kerolasa@iki.fi>" [sconosciuto] gpg: ATTENZIONE: Questa chiave non è certificata con una firma fidata! gpg: Non c'è alcuna indicazione che la firma appartenga al proprietario. Impronta della chiave primaria: 8ED3 96E3 7E38 D471 A005 30D3 A955 3245 FDE9 B739
Puoi quindi eseguire felicemente
$ guix package --install-from-file=my-hello.scm
Ora dovresti avere my-hello
nel tuo profilo!
$ guix package --list-installed=my-hello my-hello 2.10 out /gnu/store/f1db2mfm8syb8qvc357c53slbvf1g9m9-my-hello-2.10
Siamo andati il più lontano possibile senza alcuna conoscenza di Scheme. Prima di passare a pacchetti più complessi, ora è il momento giusto per rispolverare la tua conoscenza di Scheme. Vedi Un corso intensivo di Scheme per mettersi al passo.
Successivo: Esempio esteso, Precedente: Un pacchetto "Hello World", Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
Nel resto di questo capitolo faremo affidamento su alcune conoscenze di base di programmazione in Scheme. Ora analizziamo le diverse possibili configurazioni per lavorare sui pacchetti Guix.
Ci sono diversi modi per configurare un ambiente di pacchettizzazione Guix.
Ti consigliamo di lavorare direttamente sul checkout del sorgente di Guix poiché rende più facile per tutti contribuire al progetto.
Ma prima, diamo un’occhiata ad altre possibilità.
Successivo: Canali, Su: Configurazione [Contenuti][Indice]
Questo è quello che abbiamo fatto in precedenza con ‘my-hello’. Con le
basi di Scheme che abbiamo trattato, siamo ora in grado di spiegare i
blocchi iniziali. Come indicato in guix package --help
:
-f, --install-from-file=FILE installa il pacchetto a cui il codice all'interno di FILE valuta
Quindi l’ultima espressione must restituire un pacchetto, che è il caso del nostro esempio precedente.
L’espressione use-modules
indica quali moduli ci servono nel file. I
moduli sono una raccolta di valori e procedure. Sono comunemente chiamati
"librerie" o "pacchetti" in altri linguaggi di programmazione.
Successivo: Modifica diretta dal checkout, Precedente: File locale, Su: Configurazione [Contenuti][Indice]
Guix e la sua collezione di pacchetti possono essere estesi tramite canali. Un canale è un repository Git, pubblico o meno, contenente file .scm che forniscono pacchetti (vedi Definire i pacchetti in Manuale di riferimento di GNU Guix) o servizi (vedi Definire i servizi in Manuale di riferimento di GNU Guix).
Come si crea un canale? Innanzitutto, crea una directory che conterrà i tuoi file .scm, diciamo ~/my-channel:
mkdir ~/my-channel
Supponiamo che tu voglia aggiungere il pacchetto ‘my-hello’ che abbiamo visto in precedenza; prima ha bisogno di alcune modifiche:
(define-module (my-hello) #:use-module (guix licenses) #:use-module (guix packages) #:use-module (guix build-system gnu) #:use-module (guix download)) (define-public my-hello (package (name "my-hello") (version "2.10") (source (origin (method url-fetch ) (uri (string-append "mirror://gnu/hello/hello-" version ".tar.gz")) (sha256 (base32 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))) (build-system gnu-build-system ) (synopsis "Ciao, mondo Guix: Un esempio di pacchetto Guix personalizzato") (description "GNU Hello stampa il messaggio \"Ciao, mondo!\" e poi esce. Serve come esempio delle pratiche di codifica standard di GNU. Come tale, supporta argomenti da riga di comando, più linguaggi, e così via.") (home-page "https://www.gnu.org/software/hello/") (license gpl3+)))
Nota che abbiamo assegnato il valore del pacchetto a un nome di variabile
esportato con define-public
. Questo assegna effettivamente il
pacchetto alla variabile my-hello
in modo che possa essere
referenziato, tra l’altro come dipendenza di altri pacchetti.
Se usi guix package --install-from-file=my-hello.scm
sul file
precedente, fallirà perché l’ultima espressione, define-public
, non
restituisce un pacchetto. Se vuoi comunque usare define-public
in
questo caso, assicurati che il file termini con una valutazione di
my-hello
:
;; ... (define-public my-hello ;; ... ) my-hello
Quest’ultimo esempio non è molto tipico.
Ora come si rende quel pacchetto visibile ai comandi guix
in modo
da poter testare i pacchetti? È necessario aggiungere la directory al
percorso di ricerca usando l’opzione della riga di comando -L, come
in questi esempi:
guix show -L ~/my-channel my-hello guix build -L ~/my-channel my-hello
Il passo finale è trasformare ~/my-channel in un canale vero e
proprio, rendendo la tua collezione di pacchetti disponibile senza problemi
via qualsiasi comando guix
. Per farlo, devi prima renderlo un
repository Git:
cd ~/my-channel git init git add my-hello.scm git commit -m "Primo commit del mio canale."
E questo è tutto, hai un canale! Da qui in poi, puoi aggiungere questo canale alla configurazione dei tuoi canali in ~/.config/guix/channels.scm (vedi Specificare canali aggiuntivi in Manuale di riferimento di GNU Guix); supponendo che per ora tu mantenga il tuo canale locale, il file channels.scm assomiglierebbe a qualcosa del genere:
(append (list (channel
(name 'my-channel)
(url (string-append "file://" (getenv "HOME")
"/my-channel"))))
%default-channels)
La prossima volta che eseguirai guix pull
, il tuo canale verrà
rilevato e i pacchetti che definisce saranno prontamente disponibili per
tutti i comandi guix
, anche se non passerai -L. Il
comando guix describe
mostrerà che Guix sta, effettivamente,
usando sia i canali my-channel
che guix
.
Vedi Creare un canale in Manuale di riferimento di GNU Guix, per i dettagli.
Precedente: Canali, Su: Configurazione [Contenuti][Indice]
Lavorare direttamente sul progetto Guix è consigliato: riduce l’attrito quando arriva il momento di inviare le tue modifiche upstream per far sì che la comunità benefici del tuo duro lavoro!
A differenza della maggior parte delle distribuzioni software, il repository di Guix contiene in un unico posto sia gli strumenti (incluso il gestore di pacchetti) che le definizioni dei pacchetti. Questa scelta è stata fatta per dare agli sviluppatori la flessibilità di modificare l’API senza rotture, aggiornando tutti i pacchetti contemporaneamente. Ciò riduce l’inerzia dello sviluppo.
Dai un’occhiata al repository Git ufficiale:
$ git clone https://git.guix.gnu.org/guix.git
Nel resto di questo articolo, useremo ‘$GUIX_CHECKOUT’ per fare riferimento alla posizione del checkout.
Segui le istruzioni nel manuale (vedi Contribuire in Manuale di riferimento di GNU Guix) per configurare l’ambiente del repository.
Una volta pronto, dovresti essere in grado di utilizzare le definizioni dei pacchetti dall’ambiente del repository.
Sentiti libero di modificare le definizioni dei pacchetti che si trovano in ‘$GUIX_CHECKOUT/gnu/packages’.
Lo script ‘$GUIX_CHECKOUT/pre-inst-env’ ti consente di usare ‘guix’ sulla collezione di pacchetti del repository (vedi Eseguire Guix prima di installarlo in Manuale di riferimento di GNU Guix).
$ cd $GUIX_CHECKOUT $ ./pre-inst-env guix package --list-available=ruby ruby 1.8.7-p374 out gnu/packages/ruby.scm:119:2 ruby 2.1.6 out gnu/packages/ruby.scm:91:2 ruby 2.2.2 out gnu/packages/ruby.scm:39:2
$ ./pre-inst-env guix build --keep-failed ruby@2.1 /gnu/store/c13v73jxmj2nir2xjqaz5259zywsa9zi-ruby-2.1.6
$ ./pre-inst-env guix package --install ruby@2.1
$ ./pre-inst-env guix lint ruby@2.1
Guix si impegna a mantenere uno standard di pacchettizzazione elevato; quando contribuisci al progetto Guix, ricorda di
Una volta che sei soddisfatto del risultato, sei il benvenuto a inviare il tuo contributo per renderlo parte di Guix. Questo processo è anche dettagliato nel manuale. (vedi Contribuire in Manuale di riferimento di GNU Guix)
È uno sforzo della comunità, quindi più persone si uniscono, migliore diventa Guix!
Successivo: Altri sistemi di build, Precedente: Configurazione, Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
L’esempio "Ciao Mondo" sopra è il più semplice possibile. I pacchetti possono essere più complessi di così e Guix può gestire scenari più avanzati. Diamo un’occhiata a un altro pacchetto più sofisticato (leggermente modificato dalla fonte):
(define-module (gnu packages version-control) #:use-module ((guix licenses) #:prefix license:) #:use-module (guix utils) #:use-module (guix packages) #:use-module (guix git-download) #:use-module (guix build-system cmake) #:use-module (gnu packages) #:use-module (gnu packages compression) #:use-module (gnu packages pkg-config) #:use-module (gnu packages python) #:use-module (gnu packages ssh) #:use-module (gnu packages tls) #:use-module (gnu packages web)) (define-public my-libgit2 (let ((commit "e98d0a37c93574d2c6107bf7f31140b548c6a7bf") (revision "1")) (package (name "my-libgit2") (version (git-version "0.26.6" revision commit)) (source (origin (method git-fetch ) (uri (git-reference (url "https://github.com/libgit2/libgit2/") (commit commit))) (file-name (git-file-name name version )) (sha256 (base32 "17pjvprmdrx4h6bb1hhc98w9qi6ki7yl57f090n9kbhswxqfs7s3")) (patches (search-patches "libgit2-mtime-0.patch")) (modules '((guix build utils))) ;; Rimuovi software in bundle. (snippet '(delete-file-recursively "deps")))) (build-system cmake-build-system ) (outputs '("out" "debug")) (arguments `(#:tests? #true ; Esegui la suite di test (questo è il valore predefinito) #:configure-flags '("-DUSE_SHA1DC=ON") ; Rilevamento collisioni SHA-1 #:phases (modify-phases %standard-phases (add-after 'unpack 'fix-hardcoded-paths (lambda _ (substitute* "tests/repo/init.c" (("#!/bin/sh") (string-append "#!" (which "sh")))) (substitute* "tests/clar/fs.h" (("/bin/cp") (which "cp")) (("/bin/rm") (which "rm"))))) ;; Esegui i controlli in modo più verboso. (replace 'check (lambda* (#:key tests? #:allow-other-keys) (when tests? (invoke "./libgit2_clar" "-v" "-Q")))) (add-after 'unpack 'make-files-writable-for-tests (lambda _ (for-each make-file-writable (find-files "."))))))) (inputs (list libssh2 http-parser python-wrapper)) (native-inputs (list pkg-config)) (propagated-inputs ;; Queste due librerie sono in 'Requires.private' in libgit2.pc. (list openssl zlib)) (home-page "https://libgit2.github.com/") (synopsis "Libreria che fornisce i metodi core di Git") (description "Libgit2 è un'implementazione portatile e pura in C dei metodi core di Git fornita come libreria rientrante collegabile con una solida API, che consente di scrivere applicazioni Git personalizzate a velocità nativa in qualsiasi linguaggio con binding.") ;; GPLv2 con eccezione di linking (license license:gpl2))))
(Nei casi in cui si desidera solo modificare alcuni campi da una definizione di pacchetto, si dovrebbe fare affidamento sull’ereditarietà invece di copiare e incollare tutto. Vedi sotto.)
Discutiamo questi campi in dettaglio.
git-fetch
git-fetch
A differenza del metodo url-fetch
, git-fetch
si aspetta un
git-reference
che accetta un repository Git e un commit. Il commit può essere qualsiasi
riferimento Git come i tag,
quindi se la version
è taggata, allora può essere usata direttamente.
A volte il tag è preceduto da una v
, nel qual caso si userebbe
(commit (string-append "v" version))
.
Per assicurarsi che il codice sorgente dal repository Git sia memorizzato in
una
directory con un nome descrittivo, usiamo (file-name (git-file-name
name version))
.
La procedura git-version
può essere usata per derivare la versione
quando
si impacchettano programmi per un commit specifico, seguendo le linee guida
per i contributori di Guix
(vedi Numeri di versione in Manuale di riferimento di GNU Guix).
Come si ottiene l’hash sha256
che si trova lì, chiedi? Invocando
guix hash
su un checkout del commit desiderato, in questo modo:
git clone https://github.com/libgit2/libgit2/ cd libgit2 git checkout v0.26.6 guix hash -rx .
guix hash -rx
calcola un hash SHA256 sull’intera directory,
escludendo la sottodirectory .git (vedi Invocare guix hash in Manuale di riferimento di GNU Guix).
In futuro, guix download
sarà, si spera, in grado di eseguire
questi
passaggi per te, proprio come fa per i download normali.
Gli snippet sono codice Scheme quotato (cioè non valutato) che è un mezzo per applicare patch al sorgente. Sono un’alternativa in stile Guix ai tradizionali file .patch. A causa della quotatura, il codice viene valutato solo quando passato al demone Guix per la costruzione. Possono esserci quanti snippet sono necessari.
Gli snippet potrebbero aver bisogno di moduli Guile aggiuntivi che possono
essere importati dal campo modules
.
Ci sono 3 diversi tipi di input. In breve:
Richiesti per la compilazione ma non per il runtime – l’installazione di un pacchetto tramite un sostituto non installerà questi input.
Installati nello store ma non nel profilo, oltre ad essere presenti al momento della compilazione.
Installati nello store e nel profilo, oltre ad essere presenti al momento della compilazione.
Vedi Riferimenti per 'package' in Manuale di riferimento di GNU Guix per maggiori dettagli.
La distinzione tra i vari input è importante: se una dipendenza può essere gestita come un input invece di un input propagato, dovrebbe essere fatto così, altrimenti “inquina” il profilo utente senza una buona ragione.
Ad esempio, un utente che installa un programma grafico che dipende da uno strumento a riga di comando potrebbe essere interessato solo alla parte grafica, quindi non è necessario forzare lo strumento a riga di comando nel profilo utente. La dipendenza è una preoccupazione del pacchetto, non dell’utente. Gli Inputs rendono possibile gestire le dipendenze senza infastidire l’utente aggiungendo file eseguibili (o librerie) indesiderati al loro profilo.
Lo stesso vale per gli native-inputs: una volta installato il programma, le dipendenze di compilazione possono essere tranquillamente raccolte come spazzatura. È importante anche quando è disponibile un sostituto, nel qual caso verranno scaricati solo gli inputs e gli propagated inputs: gli native inputs non sono richiesti per installare un pacchetto da un sostituto.
Nota: Potresti vedere qua e là snippet in cui gli input dei pacchetti sono scritti in modo piuttosto diverso, come questo:
;; Il "vecchio stile" per gli input. (inputs `(("libssh2" ,libssh2) ("http-parser" ,http-parser) ("python" ,python-wrapper)))Questo è il “vecchio stile”, dove a ciascun input nell’elenco viene esplicitamente data un’etichetta (una stringa). È ancora supportato ma raccomandiamo di usare invece lo stile sopra. Vedi Riferimenti per 'package' in Manuale di riferimento di GNU Guix, per maggiori informazioni.
Proprio come un pacchetto può avere più input, può anche produrre più output.
Ogni output corrisponde a una directory separata nello store.
L’utente può scegliere quale output installare; questo è utile per risparmiare spazio o per evitare di inquinare il profilo utente con eseguibili o librerie indesiderate.
La separazione dell’output è opzionale. Quando il campo outputs
viene
omesso,
l’output predefinito e unico (il pacchetto completo) è indicato come
"out"
.
I nomi tipici degli output separati includono debug
e doc
.
Si consiglia di separare gli output solo quando si è dimostrato che ne vale
la pena:
se la dimensione dell’output è significativa (confrontare con guix
size
) o nel caso
in cui il pacchetto sia modulare.
L’argomento arguments
è un elenco di coppie chiave-valore utilizzato
per configurare il processo di compilazione.
L’argomento più semplice #:tests?
può essere utilizzato per
disabilitare la suite di test
durante la compilazione del pacchetto. Questo è utile soprattutto quando il
pacchetto non
dispone di alcuna suite di test. Si consiglia vivamente di mantenere la
suite di test attiva
se presente.
Un altro argomento comune è :make-flags
, che specifica un elenco di
flag da aggiungere quando si esegue make, come si farebbe dalla riga di
comando.
Ad esempio, i seguenti flag
#:make-flags (list (string-append "prefix=" (assoc-ref %outputs "out")) "CC=gcc")
si traducono in
$ make CC=gcc prefix=/gnu/store/...-<out>
Questo imposta il compilatore C a gcc
e la variabile prefix
(la
directory di installazione nel linguaggio Make) a (assoc-ref %outputs
"out")
, che è una variabile globale di fase di compilazione che punta alla
directory di destinazione
nello store (qualcosa come /gnu/store/...-my-libgit2-20180408).
Allo stesso modo, è possibile impostare i flag di configurazione:
#:configure-flags '("-DUSE_SHA1DC=ON")
La variabile %build-inputs
viene anche generata nello scope. È una
tabella di associazione che mappa i nomi degli input alle loro directory
dello store.
La parola chiave phases
elenca i passaggi sequenziali del sistema di
compilazione.
Tipicamente le fasi includono unpack
, configure
, build
,
install
e check
. Per saperne di più su queste fasi, è
necessario
trovare la definizione appropriata del sistema di compilazione in
‘$GUIX_CHECKOUT/
guix/build/gnu-build-system.scm’:
(define %standard-phases
;; Fasi di compilazione standard, come un elenco di coppie simbolo/procedura.
(let-syntax ((phases (syntax-rules ()
((_ p ... ) `((p . ,p) ... )))))
(phases set-SOURCE-DATE-EPOCH set-paths install-locale unpack
bootstrap
patch-usr-bin-file
patch-source-shebangs configure patch-generated-file-shebangs
build check install
patch-shebangs strip
validate-runpath
validate-documentation-location
delete-info-dir-file
patch-dot-desktop-files
make-dynamic-linker-cache
install-license-files
reset-gzip-timestamps
compress-documentation)))
O dalla REPL:
(add-to-load-path "/path/to/guix/checkout") ,use (guix build gnu-build-system ) (map car %standard-phases) ⇒ (set-SOURCE-DATE-EPOCH set-paths install-locale unpack bootstrap patch-usr-bin-file patch-source-shebangs configure patch-generated-file-shebangs build check install patch-shebangs strip validate-runpath validate-documentation-location delete-info-dir-file patch-dot-desktop-files make-dynamic-linker-cache install-license-files reset-gzip-timestamps compress-documentation)
Se vuoi saperne di più su cosa succede durante queste fasi, consulta le procedure associate.
Ad esempio, al momento in cui scrivo, la definizione di unpack
per il
sistema di compilazione GNU è:
(define* (unpack #:key source #:allow-other-keys)
"Decomprime SOURCE nella directory di lavoro e cambia directory all'interno del
sorgente. Quando SOURCE è una directory, copiala in una sottodirectory della
directory di lavoro corrente."
(if (file-is-directory? source)
(begin
(mkdir "source")
(chdir "source")
;; Preserva i timestamp (impostati sull'Epoch) sull'albero copiato in modo che
;; le cose funzionino in modo deterministico.
(copy-recursively source "."
#:keep-mtime? #t)
;; Rendi scrivibili i file del checkout sorgente, per comodità.
(for-each (lambda (f)
(false-if-exception (make-file-writable f)))
(find-files ".")))
(begin
(cond
((string-suffix? ".zip" source)
(invoke "unzip" source))
((tarball? source)
(invoke "tar" "xvf" source))
(else
(let ((name (strip-store-file-name source))
(command (compressor source)))
(copy-file source name)
(when command
(invoke command "--decompress" name)))))
;; Tenta di cambiare nella directory figlia.
(and=> (first-subdirectory ".") chdir ))))
Nota la chiamata chdir
: cambia la directory di lavoro dove il
sorgente è stato decompresso.
Quindi ogni fase successiva a unpack
userà il sorgente come directory
di lavoro,
ecco perché possiamo lavorare direttamente sui file sorgente. Cioè, a meno
che una fase successiva non cambi la directory di lavoro in qualcos’altro.
Modifichiamo l’elenco di %standard-phases
del sistema di compilazione
con la
macro modify-phases
secondo l’elenco delle modifiche specificate, che
possono avere le seguenti forme:
(add-before phase new-phase procedure)
: Esegue la
procedure denominata new-phase prima di phase.
(add-after phase new-phase procedure)
: Idem, ma
dopo.
(replace phase procedure)
.
(delete phase)
.
La procedure supporta gli argomenti con parola chiave inputs
e
outputs
. Ogni input (sia native, propagato o meno)
e la directory di output sono referenziati dai loro nomi in quelle
variabili. Quindi
(assoc-ref outputs "out")
è la directory dello store dell’output
principale
del pacchetto. Una procedura di fase può apparire così:
(lambda* (#:key inputs outputs #:allow-other-keys)
(let ((bash-directory (assoc-ref inputs "bash"))
(output-directory (assoc-ref outputs "out"))
(doc-directory (assoc-ref outputs "doc")))
;; ... ))
Il suo valore di ritorno viene ignorato.
Il lettore attento potrebbe aver notato la sintassi di quasi-citazione e virgola nel campo argomento. Infatti, il codice di compilazione nella dichiarazione del pacchetto non dovrebbe essere valutato lato client, ma solo quando passato al demone Guix. Questo meccanismo di passaggio di codice tra due processi in esecuzione è chiamato staging del codice.
Quando si personalizzano le phases
, spesso è necessario scrivere
codice che imita le
invocazioni di sistema equivalenti (make
, mkdir
, cp
,
ecc.)
comunemente usate durante le normali installazioni in “stile Unix”.
Alcune come chmod
sono native di Guile. Vedi Manuale di
riferimento di Guile
per un elenco completo.
Guix fornisce funzioni helper aggiuntive che si rivelano particolarmente utili nel contesto della gestione dei pacchetti.
Alcune di queste funzioni si trovano in ‘$GUIX_CHECKOUT/guix/guix/build/ utils.scm’. La maggior parte di esse riflette il comportamento dei comandi di sistema Unix tradizionali:
which
Come il comando di sistema ‘which’.
find-files
Simile al comando di sistema ‘find’.
mkdir-p
Come ‘mkdir -p’, che crea tutti i genitori se necessario.
install-file
Simile a ‘install’ quando si installa un file in una directory
(possibilmente non esistente).
Guile ha copy-file
che funziona come ‘cp’.
copy-recursively
Come ‘cp -r’.
delete-file-recursively
Come ‘rm -rf’.
invoke
Esegui un eseguibile. Questo dovrebbe essere usato al posto di
system*
.
with-directory-excursion
Esegui il corpo in una diversa directory di lavoro, quindi ripristina la precedente directory di lavoro.
substitute*
Una funzione “simile a sed
”.
Vedi Utilità di build in Manuale di riferimento di GNU Guix, per maggiori informazioni su queste utilità.
La licenza nel nostro ultimo esempio richiede un prefisso: ciò è dovuto a
come il
modulo license
è stato importato nel pacchetto, come
#:use-module ((guix licenses) #:prefix license:)
.
Il meccanismo di importazione dei moduli Guile
(vedi Using Guile Modules in Manuale di riferimento di Guile)
offre all’utente il controllo completo sulla gestione degli spazi dei nomi:
ciò è necessario per evitare conflitti tra, ad esempio, la variabile
‘zlib’ di ‘licenses.scm’
(un valore di license) e la variabile ‘zlib’ di
‘compression.scm’
(un valore di package).
Successivo: Definizione di pacchetto programmabile e automatizzata, Precedente: Esempio esteso, Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
Quanto abbiamo visto finora copre la maggior parte dei pacchetti che
utilizzano un sistema di compilazione
diverso da trivial-build-system
. Quest’ultimo non automatizza
nulla e ti lascia il compito di compilare tutto manualmente. Questo può
essere più
impegnativo e per ora non lo tratteremo qui, ma fortunatamente è raramente
necessario ricorrere a questo sistema.
Per gli altri sistemi di compilazione, come ASDF, Emacs, Perl, Ruby e molti altri, il processo è molto simile al sistema di compilazione GNU, ad eccezione di alcuni argomenti specializzati.
Vedi Sistemi di build in Manuale di riferimento di GNU Guix, per maggiori informazioni sui sistemi di compilazione, o controlla il codice sorgente nelle directory ‘$GUIX_CHECKOUT/guix/build’ e ‘$GUIX_CHECKOUT/guix/build-system’.
Successivo: Ottenere aiuto, Precedente: Altri sistemi di build, Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
Non possiamo ripeterlo abbastanza: avere un linguaggio di programmazione completo a portata di mano ci dà potere in modi che vanno ben oltre la tradizionale gestione dei pacchetti.
Illustriamo questo con alcune fantastiche funzionalità di Guix!
Successivo: Aggiornamento automatico, Su: Definizione di pacchetto programmabile e automatizzata [Contenuti][Indice]
Potresti trovare alcuni sistemi di compilazione così buoni che c’è poco da fare per scrivere un pacchetto, al punto che diventa ripetitivo e noioso dopo un po’. Una ragione d’essere dei computer è quella di sostituire gli esseri umani in questi compiti noiosi. Quindi, diciamo a Guix di farlo per noi e di creare la definizione di pacchetto di un pacchetto R da CRAN (l’output è troncato per brevità):
$ guix import cran --recursive walrus (define-public r-mc2d ; ... (license gpl2+))) (define-public r-jmvcore ; ... (license gpl2+))) (define-public r-wrs2 ; ... (license gpl3))) (define-public r-walrus (package (name "r-walrus") (version "1.0.3") (source (origin (method url-fetch) (uri (cran-uri "walrus" version)) (sha256 (base32 "1nk2glcvy4hyksl5ipq2mz8jy4fss90hx6cq98m3w96kzjni6jjj")))) (build-system r-build-system) (propagated-inputs (list r-ggplot2 r-jmvcore r-r6 r-wrs2)) (home-page "https://github.com/jamovi/walrus") (synopsis "Metodi Statistici Robusti") (description "Questo pacchetto fornisce una cassetta degli attrezzi di comuni test statistici robusti, inclusi descrittori robusti, t-test robusti e ANOVA robusta. È disponibile anche come modulo per 'jamovi' (vedere <https://www.jamovi.org> per maggiori informazioni). Walrus si basa sul pacchetto WRS2 di Patrick Mair, che a sua volta si basa sugli script e sul lavoro di Rand Wilcox. Queste analisi sono descritte in dettaglio nel libro 'Introduction to Robust Estimation & Hypothesis Testing'.") (license gpl3)))
L’importatore ricorsivo non importerà i pacchetti per i quali Guix ha già definizioni di pacchetto, ad eccezione del primissimo.
Non tutte le applicazioni possono essere impacchettate in questo modo, solo quelle che si basano su un numero selezionato di sistemi supportati. Leggi l’elenco completo degli importatori nella sezione import di guix del manuale (vedi Invocare guix import in Manuale di riferimento di GNU Guix).
Successivo: Ereditarietà, Precedente: Importatori ricorsivi, Su: Definizione di pacchetto programmabile e automatizzata [Contenuti][Indice]
Guix è abbastanza intelligente da controllare gli aggiornamenti sui sistemi che conosce. Può segnalare definizioni di pacchetto obsolete con
$ guix refresh hello
Nella maggior parte dei casi, l’aggiornamento di un pacchetto a una versione più recente richiede poco più che la modifica del numero di versione e del checksum. Guix può farlo anche automaticamente:
$ guix refresh hello --update
Precedente: Aggiornamento automatico, Su: Definizione di pacchetto programmabile e automatizzata [Contenuti][Indice]
Se hai iniziato a sfogliare le definizioni dei pacchetti esistenti, potresti
aver
notato che un numero significativo di esse ha un campo inherit
:
(define-public adwaita-icon-theme
(package (inherit gnome-icon-theme)
(name "adwaita-icon-theme")
(version "3.26.1")
(source (origin
(method url-fetch )
(uri (string-append "mirror://gnome/sources/" name "/"
(version-major+minor version ) "/"
name "-" version ".tar.xz"))
(sha256
(base32
"17fpahgh5dyckgz7rwqvzgnhx53cx9kr2xw0szprc6bnqy977fi8"))))
(native-inputs (list `(,gtk+ "bin")))))
Tutti i campi non specificati sono ereditati dal pacchetto padre. Questo è molto comodo per creare pacchetti alternativi, ad esempio con sorgenti, versioni o opzioni di compilazione diverse.
Successivo: Conclusione, Precedente: Definizione di pacchetto programmabile e automatizzata, Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
Purtroppo, alcune applicazioni possono essere difficili da impacchettare. A volte hanno bisogno di una patch per funzionare con la gerarchia del file system non standard imposta dallo store. A volte i test non vengono eseguiti correttamente. (Possono essere saltati ma questo non è raccomandato.) Altre volte il pacchetto risultante non sarà riproducibile.
Se dovessi trovarti bloccato, incapace di capire come risolvere qualsiasi tipo di problema di packaging, non esitare a chiedere aiuto alla comunità.
Vedi la homepage di Guix per informazioni sulle mailing list, IRC, ecc.
Successivo: Riferimenti, Precedente: Ottenere aiuto, Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
Questo tutorial è stato una vetrina della sofisticata gestione dei pacchetti
di cui
Guix si vanta. A questo punto abbiamo in gran parte limitato questa
introduzione
al gnu-build-system
che è un livello di astrazione fondamentale su
cui si basano
astrazioni più avanzate.
Da dove proseguiamo? Successivamente dovremmo dissezionare le viscere del
sistema di compilazione
rimuovendo tutte le astrazioni, usando il trivial-build-system
:
questo dovrebbe darci una comprensione approfondita del processo prima di
indagare su alcune tecniche di packaging più avanzate e casi limite.
Altre funzionalità degne di esplorazione sono le capacità di editing e debugging interattivi di Guix fornite dal Guile REPL.
Queste fantasiose funzionalità sono completamente opzionali e possono aspettare; ora è un buon momento per prendersi una meritata pausa. Con quanto abbiamo introdotto qui dovresti essere ben attrezzato per impacchettare molti programmi. Puoi iniziare subito e speriamo di vedere i tuoi contributi presto!
Precedente: Conclusione, Su: Tutorial sull’Impacchettamento [Contenuti][Indice]
Precedente: Tutorial sull’Impacchettamento, Su: Impacchettamento [Contenuti][Indice]
The following sections provide real-life examples on working with specific build systems, serving as extensions to the concise packaging guidelines (vedi Packaging Guidelines in GNU Guix Reference Manual).
Su: Packaging Workflows [Contenuti][Indice]
In preparation, add the following packages to our environment:
$ guix shell rust rust:cargo cargo-audit cargo-license
Successivo: Cargo Workspaces and Development Snapshots, Su: Packaging Rust Crates [Contenuti][Indice]
In this example, we’ll package cargo-audit
, which is published on the
crates.io Rust package repository. All its
dependencies are on crates.io as well.
cargo-audit
is available on crates.io, we can generate a
template via the crates.io importer (vedi Invoking guix import in GNU Guix Reference Manual):
$ guix import crate cargo-audit
After manual editing, we’ll have the following definiton:
(define-public cargo-audit
(package
(name "cargo-audit")
(version "0.21.2")
(source
(origin
(method url-fetch )
(uri (crate-uri "cargo-audit" version ))
(file-name (string-append name "-" version ".tar.gz"))
(sha256
(base32 "1a00yqpckkw86zh2hg7ra82c5fx0ird5766dyynimbvqiwg2ps0n"))))
(build-system cargo-build-system )
(arguments (list #:install-source? #f))
(inputs (cargo-inputs 'cargo-audit))
(home-page "https://rustsec.org/")
(synopsis "Audit Cargo.lock for crates with security vulnerabilities")
(description
"This package provides a Cargo subcommand, @command{cargo audit}, to
audit @file{Cargo.lock} for crates with security vulnerabilities.")
(license (list license:asl2.0 license:expat))))
The identifier used to invoke cargo-inputs
, in this case
'cargo-audit
, must be unique, usually matching the variable name of
the package.
$ cargo generate-lockfile $ cargo audit $ cargo license
cargo generate-lockfile
updates dependencies to compatible
versions. Applying it to all Rust applications helps reduce a great number
of Rust libraries we need to check later. Although sometimes libraries may
fail to follow the semantic versioning scheme,
it’s still acceptable.
cargo audit
checks known vulnerabilities and cargo
license
checks licenses, for all the dependencies. We must have an
acceptable output of cargo audit
and ensure all dependencies are
licensed with our supported licenses (vedi Defining Packages in GNU
Guix Reference Manual).
$ guix import --insert=gnu/packages/rust-crates.scm \ crate --lockfile=/path/to/Cargo.lock cargo-audit # Or use short options, in this case the shell processes file names # before passing them to Guix, allowing tilde expansion, for example. $ guix import -i gnu/packages/rust-crates.scm \ crate -f /path/to/Cargo.lock cargo-audit
cargo-audit
here must be consistent with the identifier used for
cargo-inputs
invocation in the package definition.
At this stage, the package cargo-audit
is buildable.
TODO:
comments for libraries with high probability of bundled
dependencies. cargo-build-system
also performs additional check for
binary files in its check-for-pregenerated-files
phase, which usually
indicates bundling:
$ ./pre-inst-env guix build cargo-audit … starting phase `check-for-pregenerated-files' Searching for binary files... ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/dictionary-rust ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/dictionary-rust-other ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/lib.rs.zst ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/long-window-size-lib.rs.zst ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_aclui.a ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_activeds.a ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_asycfilt.a ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_amsi.a …
Although Rust libraries are not publicly exported, we can still select them via the Guix command-line interface via a Guile expression:
$ guix build --expression='(@@ (gnu packages rust-crates) rust-ring-0.17.14)'
To unbundle most dependencies, a snippet is sufficient:
(define rust-curl-sys-0.4.80+curl-8.12.1
(crate-source "curl-sys" "0.4.80+curl-8.12.1"
"0d7ppx4kq77hc5nyff6jydmfabpgd0i3ppjvn8x0q833mhpdzxsm"
#:snippet '(delete-file-recursively "curl")))
(define rust-bzip2-sys-0.1.13+1.0.8
(crate-source "bzip2-sys" "0.1.13+1.0.8"
"056c39pgjh4272bdslv445f5ry64xvb0f7nph3z7860ln8rzynr2"
#:snippet
'(begin
(delete-file-recursively "bzip2-1.0.8")
(delete-file "build.rs")
(with-output-to-file "build.rs"
(lambda _
(format #t "fn main() {~@
println!(\"cargo:rustc-link-lib=bz2\");~@
}~%"))))))
In a more complex case, where unbundling one dependency requires a build
process that involves other packages, we should make a full package in
(gnu packages rust-sources)
first and reference it in the imported
definition.
For example, we have defined a rust-ring-0.17
in (gnu packages
rust-sources)
, then the imported definition in (gnu packages
rust-crates)
should be modified to reference it.
(define rust-ring-0.17.14 rust-ring-0.17)
When one dependency can be safely removed, modify it to #f
.
(define rust-openssl-src-300.4.2+3.4.1 #f)
To facilitate various tasks in the common workflow, several scripts are provided in the etc/teams/rust directory of Guix source tree.
Successivo: Using Rust Libraries in Other Build Systems, Precedente: Common Workflow for Rust Packaging, Su: Packaging Rust Crates [Contenuti][Indice]
In this example, we’ll package niri
, which depends on development
snapshots (also Cargo workspaces here).
As we can’t ensure compatibility of a development snapshot, before executing
cargo generate-lockfile
, we should modify Cargo.toml to pin
it to a known working revision.
To use our packaged development snapshots, it’s also necessary to modify Cargo.toml in a build phase, with a package-specific substitution pattern.
(define-public niri
(package
(name "niri")
(version "25.02")
(source (origin
(method git-fetch )
(uri (git-reference
(url "https://github.com/YaLTeR/niri")
(commit (string-append "v" version ))))
(file-name (git-file-name name version ))
(sha256
(base32
"0vzskaalcz6pcml687n54adjddzgf5r07gggc4fhfsa08h1wfd4r"))))
(build-system cargo-build-system )
(arguments
(list #:install-source? #f
#:phases
#~(modify-phases %standard-phases
(add-after 'unpack 'use-guix-vendored-dependencies
(lambda _
(substitute* "Cargo.toml"
(("# version =.*")
"version = \"*\"")
(("git.*optional")
"version = \"*\", optional")
(("^git = .*")
"")))))))
(native-inputs
(list pkg-config))
(inputs
(cons* clang
libdisplay-info
libinput-minimal
libseat
libxkbcommon
mesa
pango
pipewire
wayland
(cargo-inputs 'niri)))
(home-page "https://github.com/YaLTeR/niri")
(synopsis "Scrollable-tiling Wayland compositor")
(description
"Niri is a scrollable-tiling Wayland compositor which arranges windows in a
scrollable format. It is considered stable for daily use and performs most
functions expected of a Wayland compositor.")
(license license:gpl3+)))
niri
has Cargo workspace dependencies. When packaging a Cargo
workspace dependency, parameter #:cargo-package-crates
is required.
(define-public rust-pipewire-0.8.0.fd3d8f7
(let ((commit "fd3d8f7861a29c2eeaa4c393402e013578bb36d9")
(revision "0"))
(package
(name "rust-pipewire")
(version (git-version "0.8.0" revision commit))
(source
(origin
(method git-fetch )
(uri (git-reference
(url "https://gitlab.freedesktop.org/pipewire/pipewire-rs.git")
(commit commit)))
(file-name (git-file-name name version ))
(sha256
(base32 "1hzyhz7xg0mz8a5y9j6yil513p1m610q3j9pzf6q55vdh5mcn79v"))))
(build-system cargo-build-system )
(arguments
(list #:skip-build? #t
#:cargo-package-crates
''("libspa-sys" "libspa" "pipewire-sys" "pipewire")))
(inputs (cargo-inputs 'rust-pipewire-0.8.0.fd3d8f7))
(home-page "https://pipewire.org/")
(synopsis "Rust bindings for PipeWire")
(description "This package provides Rust bindings for PipeWire.")
(license license:expat))))
Don’t forget to modify all workspace members in (gnu packages
rust-crates)
:
(define rust-pipewire-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7) (define rust-pipewire-sys-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7) ... (define rust-libspa-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7) (define rust-libspa-sys-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7)
Precedente: Cargo Workspaces and Development Snapshots, Su: Packaging Rust Crates [Contenuti][Indice]
In this example, we’ll package libchewing
, which combines two build
systems.
When building Rust packages in other build systems, we need to add
rust
, and rust:cargo
to native-inputs
, import and use
modules from both build systems, and apply necessary build phases from
cargo-build-system
.
For cross-compilation support, we’ll also add rust-sysroot
created
with (make-rust-sysroot (%current-target-system))
to
native-inputs
, and set #:cargo-target
for
cargo-build-system
’s build phases.
(define-public libchewing
(package
(name "libchewing")
(version "0.9.1")
(source
(origin
(method git-fetch )
(uri (git-reference
(url "https://github.com/chewing/libchewing")
(commit (string-append "v" version ))))
(file-name (git-file-name name version ))
(sha256
(base32 "0gh64wvrk5pn0fhmpvj1j99d5g7f7697rk96zbkc8l72yjr819z5"))))
(build-system cmake-build-system )
(arguments
(list #:imported-modules
(append %cmake-build-system-modules
%cargo-build-system-modules)
#:modules
'(((guix build cargo-build-system ) #:prefix cargo:)
(guix build cmake-build-system )
(guix build utils))
#:phases
#~(modify-phases %standard-phases
(add-after 'unpack 'prepare-cargo-build-system
(lambda args
(for-each
(lambda (phase)
(format #t "Running cargo phase: ~a~%" phase)
(apply (assoc-ref cargo:%standard-phases phase)
;; For cross-compilation.
#:cargo-target #$(cargo-triplet)
args))
'(unpack-rust-crates
configure
check-for-pregenerated-files
patch-cargo-checksums)))))))
(native-inputs
(append
(list rust `(,rust "cargo") )
;; For cross-compilation.
(or (and=> (%current-target-system)
(compose list make-rust-sysroot))
'())))
(inputs
(cons* corrosion ncurses sqlite (cargo-inputs 'libchewing)))
(synopsis "Chinese phonetic input method")
(description "Chewing is an intelligent phonetic (Zhuyin/Bopomofo) input
method, one of the most popular choices for Traditional Chinese users.")
(home-page "https://chewing.im/")
(license license:lgpl2.1+)))
Successivo: Contenitori, Precedente: Impacchettamento, Su: Ricettario di GNU Guix [Contenuti][Indice]
Guix offre un linguaggio flessibile per configurare dichiarativamente il tuo sistema Guix. Questa flessibilità può a volte essere eccessiva. Lo scopo di questo capitolo è dimostrare alcuni concetti avanzati di configurazione.
vedi Configurazione di sistema in Manuale di riferimento di GNU Guix per un riferimento completo.
Successivo: Personalizzazione del kernel, Su: Configurazione di sistema [Contenuti][Indice]
Mentre il manuale di Guix spiega l’auto-login di un utente su tutte
le TTY (vedi auto-login to TTY in Manuale di riferimento di GNU Guix), alcuni potrebbero preferire
una
situazione in cui un utente è loggato su una TTY con le altre TTY
configurate per accedere a utenti diversi o a nessuno. Si noti che si può
auto-loggare un utente su qualsiasi TTY, ma di solito è consigliabile
evitare
tty1
, che, per impostazione predefinita, viene utilizzata per
registrare avvisi ed errori.
Ecco come si potrebbe impostare l’accesso automatico per un utente a una tty:
(define (auto-login-to-tty config tty user) (if (string=? tty (mingetty-configuration-tty config)) (mingetty-configuration (inherit config) (auto-login user)) config)) (define %my-services (modify-services %base-services ;; ... (mingetty-service-type config => (auto-login-to-tty config "tty3" "alice")))) (operating-system ;; ... (services %my-services))
Si potrebbe anche compose
(vedi Higher-Order Functions in Manuale di riferimento di Guile) auto-login-to-tty
per accedere a
più utenti su più tty.
Infine, ecco una nota di cautela. Impostare l’auto-login su una TTY significa che chiunque può accendere il tuo computer ed eseguire comandi come il tuo utente regolare. Tuttavia, se hai una partizione root crittografata, e quindi hai già bisogno di inserire una passphrase all’avvio del sistema, l’auto-login potrebbe essere un’ opzione comoda.
Successivo: API immagine di Sistema Guix, Precedente: Accesso automatico a una TTY specifica, Su: Configurazione di sistema [Contenuti][Indice]
Guix è, al suo interno, una distribuzione basata su sorgente con sostituti (vedi Sostituti in Manuale di riferimento di GNU Guix), e come tale la compilazione di pacchetti dal loro codice sorgente è una parte prevista delle normali installazioni e aggiornamenti di pacchetti. Dato questo punto di partenza, ha senso che siano fatti sforzi per ridurre il tempo impiegato nella compilazione dei pacchetti, e i recenti cambiamenti e aggiornamenti alla costruzione e distribuzione dei sostituti continuano ad essere un argomento di discussione all’interno di Guix.
Il kernel, pur non richiedendo un’eccessiva quantità di RAM per la compilazione, impiega un tempo piuttosto lungo su una macchina media. La configurazione ufficiale del kernel, come accade con molte distribuzioni GNU/Linux, tende all’inclusività, ed è proprio questo che fa sì che la compilazione richieda così tanto tempo quando il kernel viene compilato dal sorgente.
Il kernel Linux, tuttavia, può anche essere semplicemente descritto come un normale vecchio pacchetto, e come tale può essere personalizzato proprio come qualsiasi altro pacchetto. La procedura è leggermente diversa, anche se ciò è dovuto principalmente alla natura di come è scritta la definizione del pacchetto.
La definizione del pacchetto kernel linux-libre
è in realtà una
procedura
che crea un pacchetto.
(define* (make-linux-libre* version gnu-revision source supported-systems
#:key
(extra-version #f)
;; Una funzione che accetta un'architettura e una variante.
;; Vedi kernel-config per un esempio.
(configuration-file #f)
(defconfig "defconfig")
(extra-options (default-extra-linux-options version )))
... )
L’attuale pacchetto linux-libre
è per la serie 5.15.x, ed è
dichiarato così:
(define-public linux-libre-5.15
(make-linux-libre* linux-libre-5.15-version
linux-libre-5.15-gnu-revision
linux-libre-5.15-source
'("x86_64-linux" "i686-linux" "armhf-linux"
"aarch64-linux" "riscv64-linux")
#:configuration-file kernel-config))
Qualsiasi chiave a cui non sono stati assegnati valori eredita il loro
valore predefinito dalla
definizione make-linux-libre
. Confrontando i due snippet sopra,
nota il commento al codice che si riferisce a #:configuration-file
. A
causa
di ciò, non è effettivamente facile includere una configurazione
personalizzata del kernel
dalla definizione, ma non preoccuparti, ci sono altri modi per lavorare con
ciò
che abbiamo.
Ci sono due modi per creare un kernel con una configurazione kernel
personalizzata.
Il primo è fornire un defconfig standard alla procedura
customize-linux
.
Per produrre tale file è necessario ottenere il codice sorgente Linux,
creare un file .config (usando il comando make menuconfig
, ad
esempio)
o fornirne uno che già si possiede. Dopodiché sarà necessario eseguire
il comando make savedefconfig
all’interno dell’albero sorgente del
kernel — questo produrrà
il file defconfig che useremo per compilare un kernel personalizzato.
Di seguito è riportato un esempio di pacchetto kernel.
(define-public my-linux-libre
(package
(inherit (customize-linux
#:linux linux-libre
#:defconfig
(local-file "defconfig")))
(name "my-linux-libre")))
Nella stessa directory del file che definisce my-linux-libre
c’è un
file
chiamato defconfig. In questo modo puoi fornire le opzioni del kernel
che desideri
nel kernel risultante.
Il secondo modo per creare un kernel personalizzato è passare un nuovo
valore alla parola chiave extra-options
della procedura
make-linux-libre
. La parola chiave extra-options
funziona con
un’altra funzione definita subito sotto:
(define (default-extra-linux-options version ) `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #true) ;; Moduli richiesti per initrd: ("CONFIG_NET_9P" . m) ("CONFIG_NET_9P_VIRTIO" . m) ("CONFIG_VIRTIO_BLK" . m) ("CONFIG_VIRTIO_NET" . m) ("CONFIG_VIRTIO_PCI" . m) ("CONFIG_VIRTIO_BALLOON" . m) ("CONFIG_VIRTIO_MMIO" . m) ("CONFIG_FUSE_FS" . m) ("CONFIG_CIFS" . m) ("CONFIG_9P_FS" . m))) (define (config->string options) (string-join (map (match-lambda ((option . 'm) (string-append option "=m")) ((option . #true) (string-append option "=y")) ((option . #false) (string-append option "=n"))) options) "\n"))
E nello script di configurazione personalizzato del pacchetto ‘make-linux-libre‘:
;; L'aggiunta funziona anche se l'opzione non era presente nel ;; file. L'ultima prevale se duplicata. (let ((port (open-file ".config" "a")) (extra-configuration ,(config->string extra-options))) (display extra-configuration port) (close-port port)) (invoke "make" "oldconfig")
Quindi, non fornendo un file di configurazione, il .config inizia vuoto, e poi ci scriviamo la raccolta di flag che vogliamo. Ecco un altro kernel personalizzato:
(define %macbook41-full-config (append %macbook41-config-options %file-systems %efi-support %emulation ((@@ (gnu packages linux) default-extra-linux-options) version ))) (define-public linux-libre-macbook41 ;; XXX: Accedere alla procedura interna 'make-linux-libre*', che è ;; privata e non esportata, e soggetta a modifiche future. ((@@ (gnu packages linux) make-linux-libre*) (@@ (gnu packages linux) linux-libre-version) (@@ (gnu packages linux) linux-libre-gnu-revision) (@@ (gnu packages linux) linux-libre-source) '("x86_64-linux") #:extra-version "macbook41" #:extra-options %macbook41-config-options))
Nell’esempio precedente %file-systems
è una raccolta di flag che
abilitano
il supporto di diversi file system, %efi-support
abilita il supporto
EFI e
%emulation
abilita una macchina x86_64-linux a operare anche in
modalità 32 bit.
La procedura default-extra-linux-options
è quella definita
sopra, che è stata usata per evitare di perdere le opzioni di configurazione
predefinite
della parola chiave extra-options
.
Tutto questo sembra fattibile, ma come si fa a sapere quali
moduli sono richiesti per un sistema particolare? Due posti che possono
essere utili
nel tentativo di rispondere a questa domanda sono il
Manuale Gentoo e la
documentazione del kernel stesso. Dalla documentazione del kernel, sembra
che make localmodconfig
sia il comando che vogliamo.
Per poter effettivamente eseguire make localmodconfig
, dobbiamo prima
ottenere e
decomprimere il codice sorgente del kernel:
tar xf $(guix build linux-libre --source)
Una volta all’interno della directory contenente il codice sorgente, esegui
touch .config
per creare un file .config iniziale e vuoto con cui
iniziare. make
localmodconfig
funziona controllando ciò che hai già in .config e
facendoti sapere cosa ti manca. Se il file è vuoto, ti manca tutto.
Il passo successivo è eseguire:
guix shell -D linux-libre -- make localmodconfig
e annota l’output. Si noti che il file .config è ancora vuoto. L’output generalmente contiene due tipi di avvisi. I primi iniziano con "WARNING" e possono essere ignorati nel nostro caso. I secondi recitano:
il modulo pcspkr non aveva configurazioni CONFIG_INPUT_PCSPKR
Per ciascuna di queste righe, copia la porzione CONFIG_XXXX_XXXX
nel
.config nella directory, e aggiungi =m
, così alla fine
appare così:
CONFIG_INPUT_PCSPKR=m CONFIG_VIRTIO=m
Dopo aver copiato tutte le opzioni di configurazione, esegui di nuovo
make localmodconfig
per assicurarti di non avere output che iniziano con “module”.
Dopo tutti questi moduli specifici della macchina, ne rimangono un paio che
sono anche necessari.
CONFIG_MODULES
è necessario affinché tu possa compilare e caricare i
moduli separatamente
e non avere tutto compilato nel kernel. CONFIG_BLK_DEV_SD
è richiesto
per la lettura da dischi rigidi.
È possibile che tu abbia bisogno di altri moduli.
Questo post non intende tuttavia essere una guida alla configurazione del proprio kernel, quindi se decidi di compilare un kernel personalizzato dovrai cercare altre guide per creare un kernel adatto alle tue esigenze.
Il secondo modo per configurare il kernel sfrutta maggiormente le funzionalità di Guix e consente di condividere segmenti di configurazione tra kernel diversi. Ad esempio, tutte le macchine che usano EFI per l’avvio hanno una serie di flag di configurazione EFI di cui hanno bisogno. È probabile che tutti i kernel condividano un elenco di file system da supportare. Usando le variabili è più facile vedere a colpo d’occhio quali funzionalità sono abilitate e assicurarsi di non avere funzionalità in un kernel ma mancanti in un altro.
Rimane tuttavia non discusso il sistema initrd di Guix e la sua personalizzazione. È probabile che sia necessario modificare l’initrd su una macchina che utilizza un kernel personalizzato, poiché alcuni moduli che ci si aspetta siano compilati potrebbero non essere disponibili per l’inclusione nell’initrd.
Successivo: Utilizzo di chiavi di sicurezza, Precedente: Personalizzazione del kernel, Su: Configurazione di sistema [Contenuti][Indice]
Storicamente, Guix System è incentrato su una struttura
operating-system
.
Questa struttura contiene vari campi che vanno dal bootloader e dalla
dichiarazione del kernel ai servizi da installare.
A seconda della macchina di destinazione, che può variare da una macchina
x86_64
standard a un piccolo computer a scheda singola ARM come la Pine64, i
vincoli dell’immagine
possono variare molto. I produttori di hardware imporranno
diversi formati di immagine con varie dimensioni e offset delle partizioni.
Per creare immagini adatte a tutte quelle macchine, è necessaria una nuova
astrazione:
questo è l’obiettivo del record image
. Questo record contiene
tutte le informazioni necessarie per essere trasformate in un’immagine
standalone, che
può essere avviata direttamente su qualsiasi macchina di destinazione.
(define-record-type* <image>
image make-image
image?
(name image-name ;simbolo
(default #f))
(format image-format) ;simbolo
(target image-target
(default #f))
(size image-size ;dimensione in byte come intero
(default 'guess))
(operating-system image-operating-system ;<operating-system>
(default #f))
(partitions image-partitions ;lista di <partition>
(default '()))
(compression? image-compression? ;booleano
(default #t))
(volatile-root? image-volatile-root? ;booleano
(default #t))
(substitutable? image-substitutable? ;booleano
(default #t)))
Questo record contiene il sistema operativo da istanziare. Il campo
format
definisce il tipo di immagine e può essere efi-raw
, qcow2
o
iso9660
per esempio. In futuro, potrebbe essere esteso a
docker
o altri tipi di immagine.
Una nuova directory nelle fonti Guix è dedicata alla definizione delle immagini. Per ora ci sono quattro file:
Diamo un’occhiata a pine64.scm. Contiene la variabile
pine64-barebones-os
che è una definizione minima di un sistema operativo dedicata alla scheda
Pine A64 LTS.
(define pine64-barebones-os
(operating-system
(host-name "vignemale")
(timezone "Europe/Paris")
(locale "en_US.utf8")
(bootloader (bootloader-configuration
(bootloader u-boot-pine64-lts-bootloader)
(targets '("/dev/vda"))))
(initrd-modules '())
(kernel linux-libre-arm64-generic)
(file-systems (cons (file-system
(device (file-system-label "my-root"))
(mount-point "/")
(type "ext4"))
%base-file-systems ))
(services (cons (service agetty-service-type
(agetty-configuration
(extra-options '("-L")) ; nessun rilevamento portante
(baud-rate "115200")
(term "vt100")
(tty "ttyS0")))
%base-services ))))
I campi kernel
e bootloader
puntano a pacchetti
dedicati a questa scheda.
Subito sotto, è definita anche la variabile pine64-image-type
.
(define pine64-image-type
(image-type
(name 'pine64-raw)
(constructor (cut image-with-os arm64-disk-image <>))))
Sta usando un record di cui non abbiamo ancora parlato, il record
image-type
,
definito in questo modo:
(define-record-type* <image-type> image-type make-image-type image-type? (name image-type-name) ;simbolo (constructor image-type-constructor)) ;<operating-system> -> <image>
Lo scopo principale di questo record è associare un nome a una procedura
che trasforma un operating-system
in un’immagine. Per capire perché
è necessario, diamo un’occhiata al comando che produce un’immagine da un
file
di configurazione operating-system
:
guix system image my-os.scm
Questo comando si aspetta una configurazione operating-system
ma come
dovremmo
indicare che vogliamo un’immagine destinata a una scheda Pine64? Dobbiamo
fornire un’informazione extra, il image-type
, passando il flag --image-type
o -t
, in questo modo:
guix system image --image-type=pine64-raw my-os.scm
Questo parametro image-type
punta al pine64-image-type
definito sopra. Quindi, il operating-system
dichiarato in
my-os.scm
verrà applicato alla procedura (cut image-with-os
arm64-disk-image <>)
per trasformarlo in un’immagine.
L’immagine risultante si presenta così:
(image
(format 'disk-image)
(target "aarch64-linux-gnu")
(operating-system my-os)
(partitions
(list (partition
(inherit root-partition)
(offset root-offset)))))
che è l’aggregazione del operating-system
definito in
my-os.scm
al record arm64-disk-image
.
Ma basta follia Scheme. Cosa porta questa API immagine all’utente Guix?
Si può eseguire:
mathieu@cervin:~$ guix system --list-image-types I tipi di immagine disponibili sono: - unmatched-raw - rock64-raw - pinebook-pro-raw - pine64-raw - novena-raw - hurd-raw - hurd-qcow2 - qcow2 - iso9660 - uncompressed-iso9660 - tarball - efi-raw - mbr-raw - docker - wsl2 - raw-with-offset - efi32-raw
e scrivendo un file operating-system
basato su
pine64-barebones-os
,
puoi personalizzare la tua immagine secondo le tue preferenze in un file
(my-pine-os.scm) come questo:
(use-modules (gnu services linux) (gnu system images pine64)) (let ((base-os pine64-barebones-os)) (operating-system (inherit base-os) (timezone "America/Indiana/Indianapolis") (services (cons (service earlyoom-service-type (earlyoom-configuration (prefer-regexp "icecat|chromium"))) (operating-system-user-services base-os)))))
esegui:
guix system image --image-type=pine64-raw my-pine-os.scm
o,
guix system image --image-type=hurd-raw my-hurd-os.scm
per ottenere un’immagine che può essere scritta direttamente su un disco rigido e avviata.
Senza cambiare nulla in my-hurd-os.scm
, chiamando:
guix system image --image-type=hurd-qcow2 my-hurd-os.scm
produrrà invece un’immagine Hurd QEMU.
Successivo: Processo mcron per DNS dinamico, Precedente: API immagine di Sistema Guix, Su: Configurazione di sistema [Contenuti][Indice]
L’uso delle chiavi di sicurezza può migliorare la tua sicurezza fornendo una seconda fonte di autenticazione che non può essere facilmente rubata o copiata, almeno per un avversario remoto (qualcosa che hai), al segreto principale (una passphrase – qualcosa che sai), riducendo il rischio di impersonificazione.
L’esempio di configurazione dettagliato di seguito mostra quali configurazioni minime devono essere apportate al tuo sistema Guix per consentire l’uso di una chiave di sicurezza Yubico. Si spera che la configurazione possa essere utile anche per altre chiavi di sicurezza, con piccole modifiche.
Per essere utilizzabile, le regole udev del sistema dovrebbero essere estese
con regole
specifiche per la chiave. Il seguente mostra come estendere le tue regole
udev con il
file di regole udev lib/udev/rules.d/70-u2f.rules fornito dal
pacchetto libfido2
dal modulo (gnu packages security-token)
e aggiungere il tuo utente al gruppo ‘"plugdev"’ che utilizza:
(use-package-modules ... security-token ... ) ... (operating-system ... (users (cons* (user-account (name "tuo-utente") (group "users") (supplementary-groups '("wheel" "netdev" "audio" "video" "plugdev")) ;<- gruppo di sistema aggiunto (home-directory "/home/tuo-utente")) %base-user-accounts )) ... (services (cons* ... (udev-rules-service 'fido2 libfido2 #:groups '("plugdev")))))
Dopo aver riconfigurato il sistema e aver effettuato nuovamente l’accesso alla sessione grafica in modo che il nuovo gruppo sia effettivo per il tuo utente, puoi verificare che la tua chiave sia utilizzabile avviando:
guix shell ungoogled-chromium -- chromium chrome://settings/securityKeys
e verificando che la chiave di sicurezza possa essere resettata tramite il menu “Reset your security key”. Se funziona, congratulazioni, la tua chiave di sicurezza è pronta per essere utilizzata con applicazioni che supportano l’autenticazione a due fattori (2FA).
Se utilizzi una chiave di sicurezza Yubikey e sei irritato dai codici OTP
spuri
che genera quando tocchi involontariamente la chiave (ad esempio, facendoti
diventare
uno spammer nel canale ‘#guix’ mentre discuti dal tuo client IRC
preferito!), puoi disabilitarlo tramite il seguente comando ykman
:
guix shell python-yubikey-manager -- ykman config usb --force --disable OTP
In alternativa, potresti usare il comando ykman-gui
fornito dal
pacchetto yubikey-manager-qt
e disabilitare completamente
l’applicazione ‘OTP’
per l’interfaccia USB oppure, dalla vista ‘Applications -> OTP’,
eliminare la configurazione dello slot 1, che viene preconfigurata con
l’applicazione
Yubico OTP.
L’applicazione KeePassXC, gestore di password, supporta le Yubikey, ma richiede l’installazione di regole udev per il tuo sistema Guix e una certa configurazione dell’applicazione Yubico OTP sulla chiave.
Il file di regole udev necessario proviene dal pacchetto
yubikey-personalization
,
e può essere installato così:
(use-package-modules ... security-token ... ) ... (operating-system ... (services (cons* ... (udev-rules-service 'yubikey yubikey-personalization))))
Dopo aver riconfigurato il sistema (e ricollegato la tua Yubikey), dovrai poi configurare l’applicazione di sfida/risposta OTP della tua Yubikey sullo slot 2, che è ciò che KeePassXC usa. È facile farlo tramite lo strumento di configurazione grafica Yubikey Manager, che può essere invocato con:
guix shell yubikey-manager-qt -- ykman-gui
Innanzitutto, assicurati che ‘OTP’ sia abilitato nella scheda ‘Interfacce’, quindi vai a ‘Applicazioni -> OTP’ e fai clic sul pulsante ‘Configura’ nella sezione ‘Tocco lungo (Slot 2)’. Seleziona ‘Challenge-response’, inserisci o genera una chiave segreta e fai clic sul pulsante ‘Fine’. Se hai una seconda Yubikey che desideri utilizzare come backup, dovresti configurarla nello stesso modo, utilizzando la stessa chiave segreta.
La tua Yubikey dovrebbe ora essere rilevata da KeePassXC. Può essere aggiunta a un database navigando nel menu ‘Database -> Sicurezza database...’ di KeePassXC, quindi facendo clic sul pulsante ‘Aggiungi protezione aggiuntiva...’, quindi su ‘Aggiungi Challenge-Response’, selezionando la chiave di sicurezza dal menu a discesa e facendo clic sul pulsante ‘OK’ per completare la configurazione.
Successivo: Connessione a una VPN Wireguard, Precedente: Utilizzo di chiavi di sicurezza, Su: Configurazione di sistema [Contenuti][Indice]
Se il tuo ISP (Internet Service Provider) fornisce solo indirizzi IP dinamici, può essere utile configurare un servizio DNS (Domain Name System) dinamico (noto anche come DDNS (Dynamic DNS)) per associare un nome host statico a un indirizzo IP pubblico ma dinamico (spesso variabile). Esistono diversi servizi che possono essere utilizzati a questo scopo; nel seguente job mcron, DuckDNS viene utilizzato. Dovrebbe funzionare anche con altri servizi DNS dinamici che offrono un’interfaccia simile per aggiornare l’ indirizzo IP, come https://freedns.afraid.org/, con piccole modifiche.
Il job mcron è fornito di seguito, dove DOMAIN dovrebbe essere sostituito con il tuo prefisso di dominio, e il token fornito da DuckDNS associato a DOMAIN aggiunto al file /etc/duckdns/DOMAIN.token.
(define duckdns-job
;; Aggiorna l'IP del dominio personale ogni 5 minuti.
#~(job '(next-minute (range 0 60 5))
#$(program-file
"duckdns-update"
(with-extensions (list guile-gnutls) ;richiesto da (web client)
#~(begin
(use-modules (ice-9 textual-ports)
(web client))
(let ((token (string-trim-both
(call-with-input-file "/etc/duckdns/DOMAIN.token"
get-string-all )))
(query-template (string-append "https://www.duckdns.org/"
"update?domains=DOMAIN"
"&token=~a&ip=")))
(http-get (format #f query-template token))))))
"duckdns-update"
#:user "nobody"))
Il job deve quindi essere aggiunto all’elenco dei job mcron per il tuo sistema, usando qualcosa come:
(operating-system
(services
(cons* (service mcron-service-type
(mcron-configuration
(jobs (list duckdns-job ... ))))
...
%base-services )))
Successivo: Personalizzazione di un Window Manager, Precedente: Processo mcron per DNS dinamico, Su: Configurazione di sistema [Contenuti][Indice]
Per connettersi a un server VPN Wireguard è necessario che il modulo del
kernel sia caricato
in memoria e un pacchetto che fornisca strumenti di rete che lo supportino
(ad esempio,
wireguard-tools
o network-manager
).
Ecco un esempio di configurazione per Linux-Libre < 5.6, dove il modulo è esterno all’albero e deve essere caricato manualmente—le revisioni successive del kernel lo hanno integrato e quindi non necessitano di tale configurazione:
(use-modules (gnu)) (use-service-modules desktop) (use-package-modules vpn) (operating-system ;; ... (services (cons (simple-service 'wireguard-module kernel-module-loader-service-type '("wireguard")) %desktop-services )) (packages (cons wireguard-tools %base-packages)) (kernel-loadable-modules (list wireguard-linux-compat)))
Dopo aver riconfigurato e riavviato il sistema, puoi usare gli strumenti Wireguard o NetworkManager per connetterti a un server VPN.
Per testare la tua configurazione Wireguard è comodo usare
wg-quick
.
Basta dargli un file di configurazione wg-quick up ./wg0.conf
; o
metterlo
in /etc/wireguard ed eseguire wg-quick up wg0
invece.
Nota: Si noti che l’autore ha descritto questo comando come: "[...] uno script bash molto veloce e sporco [...]".
Grazie al supporto di NetworkManager per Wireguard, possiamo connetterci
alla nostra VPN
usando il comando nmcli
. Fino a questo punto, questa guida
presuppone che
stai usando il servizio Network Manager fornito da %desktop-services
.
Altrimenti devi regolare l’elenco dei tuoi servizi per caricare
network-manager-service-type
e riconfigurare il tuo sistema Guix.
Per importare la tua configurazione VPN, esegui il comando nmcli import:
# nmcli connection import type wireguard file wg0.conf Connessione 'wg0' (edbee261-aa5a-42db-b032-6c7757c60fde) aggiunta con successo
Questo creerà un file di configurazione in /etc/NetworkManager/ wg0.nmconnection. Quindi connettiti al server Wireguard:
$ nmcli connection up wg0 Connessione attivata con successo (percorso attivo D-Bus: /org/freedesktop/ NetworkManager/ActiveConnection/6)
Per impostazione predefinita, NetworkManager si connetterà automaticamente all’avvio del sistema. Per modificare questo comportamento, devi modificare la tua configurazione:
# nmcli connection modify wg0 connection.autoconnect no
Per informazioni più specifiche su NetworkManager e Wireguard, vedi questo post di Thaller.
Successivo: Eseguire Guix su un Server Linode, Precedente: Connessione a una VPN Wireguard, Su: Configurazione di sistema [Contenuti][Indice]
Successivo: Blocco sessione, Su: Personalizzazione di un Window Manager [Contenuti][Indice]
Potresti installare StumpWM con un sistema Guix aggiungendo i pacchetti
stumpwm
e
opzionalmente `(,stumpwm "lib")
a un file di configurazione di
sistema,
ad esempio: /etc/config.scm.
Una configurazione di esempio può apparire così:
(use-modules (gnu)) (use-package-modules wm) (operating-system ;; ... (packages (append (list sbcl stumpwm `(,stumpwm "lib")) %base-packages)))
Per impostazione predefinita StumpWM utilizza i font X11, che potrebbero
essere piccoli o pixelati sul tuo
sistema. Puoi risolvere questo problema installando il modulo Lisp di
StumpWM contrib sbcl-ttf-fonts
,
aggiungendolo ai pacchetti di sistema Guix:
(use-modules (gnu)) (use-package-modules fonts wm) (operating-system ;; ... (packages (append (list sbcl stumpwm `(,stumpwm "lib")) sbcl-ttf-fonts font-dejavu %base-packages)))
Quindi devi aggiungere il seguente codice a un file di configurazione di StumpWM ~/.stumpwm.d/init.lisp:
(require :ttf-fonts) (setf xft:*font-dirs* '("/run/current-system/profile/share/fonts/")) (setf clx-truetype:+font-cache-filename+ (concat (getenv "HOME") "/.fonts/font-cache.sexp")) (xft:cache-fonts) (set-font (make-instance 'xft:font :family "DejaVu Sans Mono" :subfamily "Book" :size 11))
Precedente: StumpWM, Su: Personalizzazione di un Window Manager [Contenuti][Indice]
A seconda del tuo ambiente, il blocco dello schermo della tua sessione potrebbe essere integrato o potresti doverlo configurare tu stesso. Se usi un ambiente desktop come GNOME o KDE, di solito è integrato. Se usi un semplice window manager come StumpWM o EXWM, potresti doverlo configurare tu stesso.
Su: Blocco sessione [Contenuti][Indice]
Se usi Xorg, puoi usare l’utility xss-lock per bloccare lo schermo della tua sessione. xss-lock è attivato da DPMS che da Xorg 1.8 è auto-rilevato e abilitato se ACPI è anche abilitato durante l’esecuzione del kernel.
Per usare xss-lock, puoi semplicemente eseguirlo e metterlo in background prima di avviare il tuo window manager da, ad esempio, il tuo ~/.xsession:
xss-lock -- slock & exec stumpwm
In questo esempio, xss-lock usa slock
per bloccare effettivamente lo
schermo quando lo ritiene opportuno, ad esempio quando sospendi il tuo
dispositivo.
Affinché slock possa essere un blocco schermo per la sessione grafica, deve essere reso setuid-root in modo da poter autenticare gli utenti, e ha bisogno di un servizio PAM. Ciò può essere ottenuto aggiungendo il seguente servizio al tuo config.scm:
(service screen-locker-service-type
(screen-locker-configuration
(name "slock")
(program (file-append slock "/bin/slock"))))
Se blocchi manualmente lo schermo, ad esempio chiamando direttamente slock
quando vuoi bloccare lo schermo ma non sospenderlo, è una buona idea
notificare xss-lock in modo che non si crei confusione. Ciò può essere fatto
eseguendo xset s activate
immediatamente prima di eseguire slock.
Successivo: Eseguire Guix su un Server Kimsufi, Precedente: Personalizzazione di un Window Manager, Su: Configurazione di sistema [Contenuti][Indice]
Per eseguire Guix su un server ospitato da Linode, inizia con un server Debian consigliato. Consigliamo di usare la distro predefinita come modo per avviare Guix. Crea le tue chiavi SSH.
ssh-keygen
Assicurati di aggiungere la tua chiave SSH per un facile accesso al server remoto. Questo è facilmente fatto tramite l’interfaccia grafica di Linode per l’aggiunta di chiavi SSH. Vai al tuo profilo e clicca su aggiungi chiave SSH. Copia al suo interno l’output di:
cat ~/.ssh/<nomeutente>_rsa.pub
Spegni il Linode.
Nella scheda Storage di Linode, ridimensiona il disco Debian per renderlo più piccolo. Si consigliano 30 GB di spazio libero. Quindi clicca su "Aggiungi un disco" e compila il modulo con quanto segue:
Nella scheda Configurazioni, premi "Modifica" sul profilo Debian predefinito. Sotto "Assegnazione Dispositivo a Blocchi" clicca "Aggiungi un Dispositivo". Dovrebbe essere /dev/sdc e puoi selezionare il disco "Guix". Salva le modifiche.
Ora "Aggiungi una Configurazione", con quanto segue:
Ora riaccendilo, avviando con la configurazione Debian. Una volta in
esecuzione, connettiti al tuo server via ssh con ssh
root@<il-tuo-IP-server-qui>
. (Puoi trovare l’indirizzo IP del tuo
server nella sezione Riepilogo di Linode.) Ora puoi eseguire i passaggi per
"installare Guix da vedi Installazione binaria in GNU Guix":
sudo apt-get install gpg wget https://sv.gnu.org/people/viewgpg.php?user_id=15145 -qO - | gpg --import - wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh chmod +x guix-install.sh ./guix-install.sh guix pull
Ora è il momento di scrivere una configurazione per il server. Le informazioni chiave sono qui sotto. Salva il file risultante come guix-config.scm.
(use-modules (gnu) (guix modules)) (use-service-modules networking ssh) (use-package-modules admin package-management ssh tls) (operating-system (host-name "my-server") (timezone "America/New_York") (locale "en_US.UTF-8") ;; Questo codice strambo genererà il grub.cfg ;; senza installare il bootloader grub sul disco. (bootloader (bootloader-configuration (bootloader (bootloader (inherit grub-bootloader) (installer #~(const #true)))))) (file-systems (cons (file-system (device "/dev/sda") (mount-point "/") (type "ext4")) %base-file-systems )) (swap-devices (list "/dev/sdb")) (initrd-modules (cons "virtio_scsi" ; Necessario per trovare il disco %base-initrd-modules )) (users (cons (user-account (name "janedoe") (group "users") ;; Aggiungendo l'account al gruppo "wheel" ;; lo rende un sudoer. (supplementary-groups '("wheel")) (home-directory "/home/janedoe")) %base-user-accounts )) (packages (cons* openssh-sans-x %base-packages)) (services (cons* (service dhcp-client-service-type ) (service openssh-service-type (openssh-configuration (openssh openssh-sans-x) (password-authentication? #false) (authorized-keys `(("janedoe" ,(local-file "janedoe_rsa.pub")) ("root" ,(local-file "janedoe_rsa.pub")))))) %base-services )))
Sostituisci i seguenti campi nella configurazione sopra:
(host-name "il-mio-server") ; sostituisci con il nome del tuo server ; se hai scelto un server linode fuori dagli Stati Uniti, allora ; usa tzselect per trovare una stringa di fuso orario corretta (timezone "America/New_York") ; se necessario sostituisci il fuso orario (name "janedoe") ; sostituisci con il tuo nome utente ("janedoe" ,(local-file "janedoe_rsa.pub")) ; sostituisci con la tua chiave ssh ("root" ,(local-file "janedoe_rsa.pub")) ; sostituisci con la tua chiave ssh
L’ultima riga nell’esempio sopra ti permette di accedere al server come root e impostare la password iniziale di root (vedi la nota alla fine di questa ricetta su l’accesso come root). Dopo aver fatto ciò, puoi eliminare quella riga dalla tua configurazione e riconfigurare per impedire l’accesso come root.
Copia la tua chiave pubblica ssh (es: ~/.ssh/id_rsa.pub) come <il-tuo-nomeutente-qui>_rsa.pub e metti guix-config.scm nella stessa directory. In un nuovo terminale esegui questi comandi.
sftp root@<indirizzo ip del server remoto> put /percorso/ai/files/<nomeutente>_rsa.pub . put /percorso/ai/files/guix-config.scm .
Nel tuo primo terminale, monta l’unità guix:
mkdir /mnt/guix mount /dev/sdc /mnt/guix
A causa del modo in cui abbiamo configurato la sezione del bootloader di guix-config.scm, solo il file di configurazione di grub verrà installato. Quindi, dobbiamo copiare parte del resto del GRUB già installato sul sistema Debian:
mkdir -p /mnt/guix/boot/grub cp -r /boot/grub/* /mnt/guix/boot/grub/
Ora inizializza l’installazione di Guix:
guix system init guix-config.scm /mnt/guix
Ok, spegnilo! Ora dalla console di Linode, seleziona boot e seleziona "Guix".
Una volta avviato, dovresti essere in grado di accedere via SSH! (La configurazione del server sarà cambiata però.) Potresti incontrare un errore come:
$ ssh root@<indirizzo ip del server> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ATTENZIONE: L'IDENTIFICAZIONE DELL'HOST REMOTO È CAMBIATA! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ È POSSIBILE CHE QUALCUNO STIA FACENDO QUALCOSA DI BRUTTO! Qualcuno potrebbe intercettarti in questo momento (attacco man-in-the-middle)! È anche possibile che una chiave host sia stata appena cambiata. L'impronta digitale della chiave ECDSA inviata dall'host remoto è SHA256:0B+wp33w57AnKQuHCvQP0+ZdKaqYrI/kyU7CfVbS7R4. Si prega di contattare l'amministratore del sistema. Aggiungi la chiave host corretta in /home/joshua/.ssh/known_hosts per eliminare questo messaggio. Chiave ECDSA offensiva in /home/joshua/.ssh/known_hosts:3 La chiave host ECDSA per 198.58.98.76 è cambiata e hai richiesto un controllo rigoroso. Verifica della chiave host fallita.
Elimina il file ~/.ssh/known_hosts oppure elimina la riga incriminata che inizia con l’indirizzo IP del tuo server.
Assicurati di impostare la tua password e quella di root.
ssh root@<indirizzo ip remoto> passwd ; per la password di root passwd <nomeutente> ; per la password utente
Potresti non essere in grado di eseguire i comandi sopra a questo punto. Se hai problemi ad accedere in remoto alla tua macchina Linode via SSH, potresti ancora dover impostare inizialmente la password di root e dell’utente cliccando sull’opzione “Launch Console” nel tuo Linode. Scegli “Glish” invece di “Weblish”. Ora dovresti essere in grado di accedere alla macchina tramite ssh.
Evviva! A questo punto puoi spegnere il server, eliminare il disco Debian, e ridimensionare il Guix al resto della dimensione. Congratulazioni!
A proposito, se lo salvi come immagine disco proprio a questo punto, avrai facilità a creare nuove immagini Guix! Potrebbe essere necessario ridurre la dimensione dell’immagine Guix a 6144MB, per salvarla come immagine. Quindi puoi ridimensionarla di nuovo a la dimensione massima.
Successivo: Configurazione di un bind mount, Precedente: Eseguire Guix su un Server Linode, Su: Configurazione di sistema [Contenuti][Indice]
Per eseguire Guix su un server ospitato da Kimsufi, clicca sulla scheda netboot, quindi seleziona rescue64-pro e riavvia.
OVH ti invierà via email le credenziali necessarie per accedere via ssh a un sistema Debian.
Ora puoi eseguire i passaggi per "installare Guix da vedi Installazione binaria in GNU Guix":
wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh chmod +x guix-install.sh ./guix-install.sh guix pull
Partiziona i dischi e formattali, prima ferma l’array raid:
mdadm --stop /dev/md127 mdadm --zero-superblock /dev/sda2 /dev/sdb2
Quindi azzera i dischi e configura le partizioni, creeremo un array RAID 1.
wipefs -a /dev/sda wipefs -a /dev/sdb parted /dev/sda --align=opt -s -m -- mklabel gpt parted /dev/sda --align=opt -s -m -- \ mkpart bios_grub 1049kb 512MiB \ set 1 bios_grub on parted /dev/sda --align=opt -s -m -- \ mkpart primary 512MiB -512MiB set 2 raid on parted /dev/sda --align=opt -s -m -- mkpart primary linux-swap 512MiB 100% parted /dev/sdb --align=opt -s -m -- mklabel gpt parted /dev/sdb --align=opt -s -m -- \ mkpart bios_grub 1049kb 512MiB \ set 1 bios_grub on parted /dev/sdb --align=opt -s -m -- \ mkpart primary 512MiB -512MiB \ set 2 raid on parted /dev/sdb --align=opt -s -m -- mkpart primary linux-swap 512MiB 100%
Crea l’array:
mdadm --create /dev/md127 --level=1 --raid-disks=2 \ --metadata=0.90 /dev/sda2 /dev/sdb2
Ora crea i file system sulle partizioni pertinenti, prima le partizioni di avvio:
mkfs.ext4 /dev/sda1 mkfs.ext4 /dev/sdb1
Quindi la partizione root:
mkfs.ext4 /dev/md127
Inizializza le partizioni di swap:
mkswap /dev/sda3 swapon /dev/sda3 mkswap /dev/sdb3 swapon /dev/sdb3
Monta l’unità guix:
mkdir /mnt/guix mount /dev/md127 /mnt/guix
Ora è il momento di scrivere un file di dichiarazione del sistema operativo os.scm; ecco un esempio:
(use-modules (gnu) (guix)) (use-service-modules networking ssh vpn virtualization sysctl admin mcron) (use-package-modules ssh tls tmux vpn virtualization) (operating-system (host-name "kimsufi") (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets (list "/dev/sda" "/dev/sdb")) (terminal-outputs '(console)))) ;; Aggiungi un modulo del kernel per RAID-1 (alias "mirror"). (initrd-modules (cons* "raid1" %base-initrd-modules )) (mapped-devices (list (mapped-device (source (list "/dev/sda2" "/dev/sdb2")) (target "/dev/md127") (type raid-device-mapping )))) (swap-devices (list (swap-space (target "/dev/sda3")) (swap-space (target "/dev/sdb3")))) (issue ;; Contenuti predefiniti per /etc/issue. "\ Questo è il sistema GNU su Kimsufi. Benvenuto.\n") (file-systems (cons* (file-system (mount-point "/") (device "/dev/md127") (type "ext4") (dependencies mapped-devices)) %base-file-systems )) (users (cons (user-account (name "guix") (comment "guix") (group "users") (supplementary-groups '("wheel")) (home-directory "/home/guix")) %base-user-accounts )) (sudoers-file (plain-file "sudoers" "\ root ALL=(ALL) ALL %wheel ALL=(ALL) ALL guix ALL=(ALL) NOPASSWD:ALL\n")) ;; Pacchetti installati globalmente. (packages (cons* tmux gnutls wireguard-tools %base-packages)) (services (cons* (service static-networking-service-type (list (static-networking (addresses (list (network-address (device "enp3s0") (value "indirizzo-ip-server/24")))) (routes (list (network-route (destination "default") (gateway "server-gateway")))) (name-servers '("213.186.33.99"))))) (service unattended-upgrade-service-type ) (service openssh-service-type (openssh-configuration (openssh openssh-sans-x) (permit-root-login #f) (authorized-keys `(("guix" ,(plain-file "ssh-key-name.pub" "contenuto-chiave-pubblica-ssh")))))) (modify-services %base-services (sysctl-service-type config => (sysctl-configuration (settings (append '(("net.ipv6.conf.all.autoconf" . "0") ("net.ipv6.conf.all.accept_ra" . "0")) %default-sysctl-settings ))))))))
Non dimenticare di sostituire le variabili indirizzo-ip-server, server-gateway, nome-chiave-ssh e contenuto-chiave-pubblica-ssh con i tuoi valori.
Il gateway è l’ultimo IP utilizzabile nel tuo blocco, quindi se hai un server con un IP di ‘37.187.79.10’ allora il suo gateway sarà ‘37.187.79.254’.
Trasferisci il file di dichiarazione del tuo sistema operativo os.scm
sul server tramite i comandi scp
o sftp
.
Ora non resta che installare Guix con un guix system init
e
riavviare.
Tuttavia, dobbiamo prima configurare un chroot, perché la partizione root del sistema di recupero è montata su una partizione aufs e se provi a installare Guix fallirà al passaggio di installazione di GRUB lamentandosi del percorso canonico di "aufs".
Installa i pacchetti che verranno usati nel chroot:
guix install bash-static parted util-linux-with-udev coreutils guix
Quindi esegui quanto segue per creare le directory necessarie per il chroot:
cd /mnt && \ mkdir -p bin etc gnu/store root/.guix-profile/ root/.config/guix/current \ var/guix proc sys dev
Copia il resolv.conf dell’host nel chroot:
cp /etc/resolv.conf etc/
Monta i dispositivi a blocchi, lo store e il suo database e la configurazione attuale di guix:
mount --rbind /proc /mnt/proc mount --rbind /sys /mnt/sys mount --rbind /dev /mnt/dev mount --rbind /var/guix/ var/guix/ mount --rbind /gnu/store gnu/store/ mount --rbind /root/.config/ root/.config/ mount --rbind /root/.guix-profile/bin/ bin mount --rbind /root/.guix-profile root/.guix-profile/
Chroot in /mnt e installa il sistema:
chroot /mnt/ /bin/bash guix system init /root/os.scm /guix
Infine, dall’interfaccia utente web (UI), cambia ‘netboot’ in ‘avvio da disco’ e riavvia (anche dall’interfaccia utente web).
Aspetta qualche minuto e prova a connetterti via ssh con ssh
guix@indirizzo-ip-server> -i path-to-your-ssh-key
Dovresti avere un sistema Guix attivo e funzionante su Kimsufi; congratulazioni!
Successivo: Ottenere sostituti da Tor, Precedente: Eseguire Guix su un Server Kimsufi, Su: Configurazione di sistema [Contenuti][Indice]
Per montare con bind un file system, è necessario prima impostare alcune
definizioni prima della sezione operating-system
della definizione
del sistema. In questo esempio monteremo con bind una cartella da un disco
rotante su /tmp, per risparmiare usura sul SSD primario, senza
dedicare un’intera partizione da montare come /tmp.
Innanzitutto, l’unità sorgente che ospita la cartella che desideriamo montare con bind dovrebbe essere definita, in modo che il mount bind possa dipendere da essa.
(define source-drive ;; "source-drive" può essere chiamato come vuoi. (file-system (device (uuid "UUID va qui")) (mount-point "/percorso-al-disco-rotante-va-qui") (type "ext4"))) ;Assicurati di impostarlo al tipo appropriato per la tua unità.
La cartella sorgente deve essere definita anche, in modo che guix sappia che non è un dispositivo a blocchi regolare, ma una cartella.
;; "source-directory" può essere qualsiasi nome di variabile valido. (define (%source-directory) "/percorso-al-disco-rotante-va-qui/tmp")
Infine, all’interno della definizione file-systems
, dobbiamo
aggiungere il mount stesso.
(file-systems (cons*
...<altre unità omesse per chiarezza>...
;; Deve corrispondere al nome che hai dato all'unità sorgente nella definizione precedente.
source-drive
(file-system
;; Assicurati che "source-directory" corrisponda alla tua definizione precedente.
(device (%source-directory))
(mount-point "/tmp")
;; Stiamo montando una cartella, non una partizione, quindi questo tipo deve essere "none"
(type "none")
(flags '(bind-mount))
;; Assicurati che "source-drive" corrisponda al nome che hai dato alla variabile per l'unità.
(dependencies (list source-drive))
)
...<altre unità omesse per chiarezza>...
))
Successivo: Configurazione di NGINX con Lua, Precedente: Configurazione di un bind mount, Su: Configurazione di sistema [Contenuti][Indice]
Il demone Guix può usare un proxy HTTP per ottenere i sostituti, qui lo stiamo configurando per ottenerli tramite Tor.
Avviso: Non tutto il traffico del demone Guix passerà attraverso Tor! Solo HTTP/HTTPS sarà proxato; FTP, protocollo Git, SSH, ecc. le connessioni passeranno comunque attraverso il clearnet. Ancora una volta, questa configurazione non è a prova di errore, parte del tuo traffico non sarà affatto instradato da Tor. Usala a tuo rischio e pericolo.
Si noti inoltre che la procedura qui descritta si applica solo alla sostituzione di pacchetti. Quando si aggiorna la distribuzione guix con
guix pull
, è comunque necessario utilizzaretorsocks
se si desidera instradare la connessione ai server del repository git di guix tramite Tor.
Il server di sostituzione di Guix è disponibile come servizio Onion, se vuoi usarlo per ottenere i tuoi sostituti tramite Tor, configura il tuo sistema come segue:
(use-modules (gnu)) (use-service-module base networking) (operating-system ... (services (cons (service tor-service-type (tor-configuration (config-file (plain-file "tor-config" "HTTPTunnelPort 127.0.0.1:9250")))) (modify-services %base-services (guix-service-type config => (guix-configuration (inherit config) ;; servizio Onion di ci.guix.gnu.org (substitute-urls "\ https://4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion") (http-proxy "http://localhost:9250")))))))
Questo manterrà un processo tor in esecuzione che fornisce un tunnel HTTP
CONNECT che sarà usato da guix-daemon
. Il demone può usare altri
protocolli oltre a HTTP(S) per ottenere risorse remote, le richieste che
usano tali protocolli non passeranno attraverso Tor poiché stiamo impostando
solo un tunnel HTTP qui. Si noti che substitutes-urls
sta usando
HTTPS e non HTTP o non funzionerà, questa è una limitazione del tunnel di
Tor; potresti voler usare privoxy
invece per evitare tali
limitazioni.
Se non vuoi ottenere sempre sostituti tramite Tor ma usarlo solo a volte,
allora salta la guix-configuration
. Quando vuoi ottenere un sostituto
dal tunnel Tor esegui:
sudo herd set-http-proxy guix-daemon http://localhost:9250 guix build \ --substitute-urls=https://4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion …
Successivo: Server musicale con audio Bluetooth, Precedente: Ottenere sostituti da Tor, Su: Configurazione di sistema [Contenuti][Indice]
NGINX potrebbe essere esteso con script Lua.
Guix fornisce il servizio NGINX con la capacità di caricare il modulo Lua e specifici pacchetti Lua, e di rispondere alle richieste valutando gli script Lua.
Il seguente esempio dimostra la definizione del sistema con la configurazione per valutare lo script Lua index.lua su richiesta HTTP all’endpoint http://localhost/hello:
local shell = require "resty.shell" local stdin = "" local timeout = 1000 -- ms local max_size = 4096 -- byte local ok, stdout, stderr, reason, status = shell.run([[/run/current-system/profile/bin/ls /tmp]], stdin, timeout, max_size) ngx.say(stdout)
(use-modules (gnu)) (use-service-modules #;... web) (use-package-modules #;... lua) (operating-system ;; ... (services ;; ... (service nginx-service-type (nginx-configuration (modules (list (file-append nginx-lua-module "/etc/nginx/modules/ngx_http_lua_module.so"))) (lua-package-path (list lua-resty-core lua-resty-lrucache lua-resty-signal lua-tablepool lua-resty-shell)) (lua-package-cpath (list lua-resty-signal)) (server-blocks (list (nginx-server-configuration (server-name '("localhost")) (listen '("80")) (root "/etc") (locations (list (nginx-location-configuration (uri "/hello") (body (list #~(format #f "content_by_lua_file ~s;" #$(local-file "index.lua"))))))))))))))
Precedente: Configurazione di NGINX con Lua, Su: Configurazione di sistema [Contenuti][Indice]
MPD, il Music Player Daemon, è un’applicazione flessibile lato server per riprodurre musica. I programmi client su diverse macchine della rete — un telefono cellulare, un laptop, una workstation desktop — possono connettersi ad esso per controllare la riproduzione di file audio dalla tua collezione musicale locale. MPD decodifica i file audio e li riproduce su una o più uscite.
Per impostazione predefinita MPD riprodurrà sul dispositivo audio predefinito. Nell’esempio seguente rendiamo le cose un po’ più interessanti impostando un server musicale headless. Non ci sarà interfaccia grafica utente, nessun demone Pulseaudio, e nessuna uscita audio locale. Invece configureremo MPD con due uscite: un altoparlante bluetooth e un server web per servire flussi audio a qualsiasi lettore multimediale in streaming.
Il Bluetooth è spesso piuttosto frustrante da configurare. Dovrai accoppiare
il tuo dispositivo Bluetooth e assicurarti che il dispositivo sia connesso
automaticamente non appena si accende. Il servizio di sistema Bluetooth
restituito dalla procedura bluetooth-service
fornisce
l’infrastruttura necessaria per configurarlo.
Riconfigura il tuo sistema con almeno i seguenti servizi e pacchetti:
(operating-system
;; ...
(packages (cons* bluez bluez-alsa
%base-packages))
(services
;; ...
(dbus-service #:services (list bluez-alsa))
(bluetooth-service #:auto-enable? #t)))
Avvia il servizio bluetooth
e poi usa bluetoothctl
per
scandire i dispositivi Bluetooth. Prova a identificare il tuo altoparlante
Bluetooth e ricava il suo ID dispositivo dalla lista risultante di
dispositivi che è indubbiamente dominata da un’incredibile varietà di gadget
di automazione domestica dei tuoi vicini. Questo deve essere fatto solo una
volta:
$ bluetoothctl [NEW] Controller 00:11:22:33:95:7F BlueZ 5.40 [default] [bluetooth]# power on [bluetooth]# Changing power on succeeded [bluetooth]# agent on [bluetooth]# Agente registrato [bluetooth]# default-agent [bluetooth]# Richiesta agente predefinito riuscita [bluetooth]# scan on [bluetooth]# Rilevamento avviato [CHG] Controller 00:11:22:33:95:7F Rilevamento: sì [NEW] Dispositivo AA:BB:CC:A4:AA:CD Il mio altoparlante Bluetooth [NEW] Dispositivo 44:44:FF:2A:20:DC TV del mio vicino … [bluetooth]# pair AA:BB:CC:A4:AA:CD Tentativo di accoppiamento con AA:BB:CC:A4:AA:CD [CHG] Dispositivo AA:BB:CC:A4:AA:CD Connesso: sì [My Bluetooth Speaker]# [CHG] Dispositivo AA:BB:CC:A4:AA:CD UUIDs: 0000110b-0000-1000-8000-00xxxxxxxxxx [CHG] Dispositivo AA:BB:CC:A4:AA:CD UUIDs: 0000110c-0000-1000-8000-00xxxxxxxxxx [CHG] Dispositivo AA:BB:CC:A4:AA:CD UUIDs: 0000110e-0000-1000-8000-00xxxxxxxxxx [CHG] Dispositivo AA:BB:CC:A4:AA:CD Accoppiato: sì Accoppiamento riuscito [CHG] Dispositivo AA:BB:CC:A4:AA:CD Connesso: no [bluetooth]# [bluetooth]# trust AA:BB:CC:A4:AA:CD [bluetooth]# [CHG] Dispositivo AA:BB:CC:A4:AA:CD Affidabile: sì Modifica dell'affidabilità di AA:BB:CC:A4:AA:CD riuscita [bluetooth]# [bluetooth]# connect AA:BB:CC:A4:AA:CD Tentativo di connessione a AA:BB:CC:A4:AA:CD [bluetooth]# [CHG] Dispositivo AA:BB:CC:A4:AA:CD RSSI: -63 [CHG] Dispositivo AA:BB:CC:A4:AA:CD Connesso: sì Connessione riuscita [My Bluetooth Speaker]# scan off [CHG] Dispositivo AA:BB:CC:A4:AA:CD RSSI è nullo Rilevamento interrotto [CHG] Controller 00:11:22:33:95:7F Rilevamento: no
Congratulazioni, ora puoi connetterti automaticamente al tuo altoparlante Bluetooth!
Ora è il momento di configurare ALSA per utilizzare il modulo Bluetooth
bluealsa, in modo da poter definire un dispositivo pcm ALSA
corrispondente al tuo altoparlante Bluetooth. Per un server headless che
utilizza bluealsa con un dispositivo Bluetooth fisso è probabilmente
più semplice che configurare Pulseaudio e il suo comportamento di
commutazione del flusso. Configureremo ALSA creando una
alsa-configuration
personalizzata per il alsa-service-type
. La
configurazione dichiarerà un tipo pcm
bluealsa
dal modulo
bluealsa
fornito dal pacchetto bluez-alsa
, e quindi definirà
un dispositivo pcm
di quel tipo per il tuo altoparlante Bluetooth.
Tutto ciò che resta da fare è far sì che MPD invii dati audio a questo dispositivo ALSA. Aggiungiamo anche un’uscita MPD secondaria che rende i file audio attualmente riprodotti disponibili come stream tramite un server web sulla porta 8080. Quando abilitato un dispositivo sulla rete potrebbe ascoltare il flusso audio collegando qualsiasi lettore multimediale compatibile al server HTTP sulla porta 8080, indipendentemente dallo stato dell’altoparlante Bluetooth.
Quello che segue è lo schema di una dichiarazione operating-system
che dovrebbe compiere i compiti sopra menzionati:
(use-modules (gnu)) (use-service-modules audio dbus sound #;... etc) (use-package-modules audio linux #;... etc) (operating-system ;; ... (packages (cons* bluez bluez-alsa %base-packages)) (services ;; ... (service mpd-service-type (mpd-configuration (user "il-tuo-nome-utente") (music-dir "/percorso/alla/tua/musica") (address "192.168.178.20") (outputs (list (mpd-output (type "alsa") (name "MPD") (extra-options ;; Usa lo stesso nome della configurazione ALSA ;; qui sotto. '((device . "pcm.btspeaker")))) (mpd-output (type "httpd") (name "streaming") (enabled? #false) (always-on? #true) (tags? #true) (mixer-type 'null) (extra-options '((encoder . "vorbis") (port . "8080") (bind-to-address . "192.168.178.20") (max-clients . "0") ;nessun limite (quality . "5.0") (format . "44100:16:1")))))))) (dbus-service #:services (list bluez-alsa)) (bluetooth-service #:auto-enable? #t) (service alsa-service-type (alsa-configuration (pulseaudio? #false) ;non ne abbiamo bisogno (extra-options #~(string-append "\ # Dichiara il tipo di dispositivo audio Bluetooth \"bluealsa\" dal modulo bluealsa pcm_type.bluealsa { lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_pcm_bluealsa.so") "\" } # Dichiara il tipo di dispositivo di controllo \"bluealsa\" dallo stesso modulo ctl_type.bluealsa { lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_ctl_bluealsa.so") "\" } # Definisci il dispositivo audio Bluetooth effettivo. pcm.btspeaker { type bluealsa device \"AA:BB:CC:A4:AA:CD\" # identificatore unico del dispositivo profile \"a2dp\" } # Definisci un controller associato. ctl.btspeaker { type bluealsa } "))))))
Goditi la musica con il client MPD di tua scelta o un lettore multimediale capace di streaming via HTTP!
Successivo: Macchine virtuali, Precedente: Configurazione di sistema, Su: Ricettario di GNU Guix [Contenuti][Indice]
Il kernel Linux fornisce una serie di strutture condivise che sono disponibili ai processi nel sistema. Queste strutture includono una vista condivisa sul file system, altri processi, dispositivi di rete, identità di utenti e gruppi, e alcune altre. Dal kernel Linux 3.19 un utente può scegliere di unshare alcune di queste strutture condivise per processi selezionati, fornendo loro (e ai loro processi figli) una vista diversa del sistema.
Un processo con un namespace mount
non condiviso, ad esempio, ha la
sua propria vista sul file system — sarà in grado di vedere solo le
directory che sono state esplicitamente vincolate nel suo namespace
mount. Un processo con il suo proprio namespace proc
si considererà
l’unico processo in esecuzione sul sistema, in esecuzione come PID 1.
Guix utilizza queste funzionalità del kernel per fornire ambienti completamente isolati e anche contenitori Guix System completi, macchine virtuali leggere che condividono il kernel del sistema host. Questa funzionalità è particolarmente utile quando si utilizza Guix su una distribuzione esterna per prevenire interferenze da librerie o file di configurazione esterni disponibili a livello di sistema.
Successivo: Contenitori di Sistema Guix, Su: Contenitori [Contenuti][Indice]
Il modo più semplice per iniziare è usare guix shell
con l’opzione
--container. Vedi Invocare guix shell in Manuale di
riferimento di GNU Guix per un riferimento delle opzioni valide.
Il seguente frammento avvia un processo shell minimale con la maggior parte dei namespace non condivisi dal sistema. La directory di lavoro corrente è visibile al processo, ma qualsiasi altra cosa sul file system non è disponibile. Questa estrema isolazione può essere molto utile quando si desidera escludere qualsiasi tipo di interferenza da variabili d’ambiente, librerie installate globalmente o file di configurazione.
guix shell --container
È un ambiente desolato, sterile, deserto. Scoprirai che nemmeno i coreutils GNU sono disponibili qui, quindi per esplorare questa landa deserta devi usare i comandi shell integrati. Anche la di solito gigantesca directory /gnu/store è ridotta a una flebile ombra di se stessa.
$ echo /gnu/store/* /gnu/store/…-gcc-10.3.0-lib /gnu/store/…-glibc-2.33 /gnu/store/…-bash-static-5.1.8 /gnu/store/…-ncurses-6.2.20210619 /gnu/store/…-bash-5.1.8 /gnu/store/…-profile /gnu/store/…-readline-8.1.1
Non c’è molto che tu possa fare in un ambiente come questo oltre a
uscirne. Puoi usare ^D o exit
per terminare questo ambiente
shell limitato.
È possibile rendere disponibili altre directory all’interno dell’ambiente del contenitore; utilizzare --expose=DIRECTORY per montare con bind la directory specificata come posizione di sola lettura all’interno del contenitore, o utilizzare --share=DIRECTORY per rendere la posizione scrivibile. Con un argomento di mappatura aggiuntivo dopo il nome della directory è possibile controllare il nome della directory all’interno del contenitore. Nell’esempio seguente mappiamo /etc sul sistema host a /the/host/etc all’interno di un contenitore in cui sono installati i coreutils GNU.
$ guix shell --container --share=/etc=/the/host/etc coreutils $ ls /the/host/etc
Allo stesso modo, puoi impedire che la directory di lavoro corrente venga mappata nel contenitore con l’opzione --no-cwd. Un’altra buona idea è creare una directory dedicata che fungerà da directory home del contenitore, e avviare la shell del contenitore da quella directory.
Su un sistema esterno, un ambiente container può essere utilizzato per
compilare software che non può essere collegato a librerie di sistema o alla
toolchain del compilatore del sistema. Un caso d’uso comune in un contesto
di ricerca è l’installazione di pacchetti da una sessione R. Al di fuori di
un ambiente container è molto probabile che la toolchain del compilatore
esterno e le librerie di sistema incompatibili vengano trovate per prime,
risultando in binari incompatibili che non possono essere utilizzati da
R. In una shell container questo problema scompare, poiché le librerie di
sistema e gli eseguibili semplicemente non sono disponibili a causa del
namespace mount
non condiviso.
Prendiamo un manifesto completo che fornisce un ambiente di sviluppo confortevole per l’uso con R:
(specifications->manifest
(list "r-minimal"
;; pacchetti base
"bash-minimal"
"glibc-locales"
"nss-certs"
;; Strumenti comuni da riga di comando per evitare che il contenitore sia troppo vuoto.
"coreutils"
"grep"
"which"
"wget"
"sed"
;; Strumenti R markdown
"pandoc"
;; Toolchain e librerie comuni per "install.packages"
"gcc-toolchain@10"
"gfortran-toolchain"
"gawk"
"tar"
"gzip"
"unzip"
"make"
"cmake"
"pkg-config"
"cairo"
"libxt"
"openssl"
"curl"
"zlib"))
Utilizziamolo per eseguire R all’interno di un ambiente container. Per
comodità, condividiamo il namespace net
per utilizzare le interfacce
di rete del sistema host. Ora possiamo compilare i pacchetti R dal sorgente
nel modo tradizionale senza doverci preoccupare di disallineamenti ABI o
incompatibilità.
$ guix shell --container --network --manifest=manifest.scm -- R R version 4.2.1 (2022年06月23日) -- "Funny-Looking Kid" Copyright (C) 2022 The R Foundation for Statistical Computing … > e <- Sys.getenv("GUIX_ENVIRONMENT") > Sys.setenv(GIT_SSL_CAINFO=paste0(e, "/etc/ssl/certs/ca-certificates.crt")) > Sys.setenv(SSL_CERT_FILE=paste0(e, "/etc/ssl/certs/ca-certificates.crt")) > Sys.setenv(SSL_CERT_DIR=paste0(e, "/etc/ssl/certs")) > install.packages("Cairo", lib=paste0(getwd())) … * installing *source* package 'Cairo' ... … * DONE (Cairo) I pacchetti sorgente scaricati si trovano in '/tmp/RtmpCuwdwM/downloaded_packages' > library("Cairo", lib=getwd()) > # successo!
L’uso delle shell container è divertente, ma possono diventare un po’ complicate quando si vuole andare oltre un singolo processo interattivo. Alcuni compiti diventano molto più facili quando si basano sulla solida fondazione di un vero sistema Guix e del suo ricco set di servizi di sistema. La prossima sezione ti mostrerà come avviare un sistema Guix completo all’interno di un container.
Precedente: Contenitori Guix, Su: Contenitori [Contenuti][Indice]
Il sistema Guix fornisce una vasta gamma di servizi di sistema interconnessi che sono configurati in modo dichiarativo per formare una fondazione affidabile e senza stato per il sistema GNU per qualsiasi attività tu gli assegni. Anche quando usi Guix su una distribuzione esterna, puoi beneficiare del design del sistema Guix eseguendo un’istanza di sistema come container. Usando le stesse funzionalità del kernel di namespace non condivisi menzionati nella sezione precedente, l’istanza Guix System risultante è isolata dal sistema host e condivide solo le posizioni del file system che dichiari esplicitamente.
Un contenitore del sistema Guix differisce dal processo di shell creato da
guix shell --container
in una serie di modi importanti. Mentre in
una shell contenitore il processo containerizzato è un processo shell Bash,
un contenitore del sistema Guix esegue Shepherd come PID 1. In un
contenitore di sistema tutti i servizi di sistema (vedi Services in GNU Guix Reference Manual) sono configurati esattamente come lo sarebbero
su un sistema Guix in una macchina virtuale o su hardware bare metal —
questo include i demoni gestiti da GNU Shepherd (vedi Servizi
Shepherd in Manuale di riferimento di GNU Guix) così come altri
tipi di estensioni al sistema operativo (vedi Composizione dei servizi in Manuale di riferimento di GNU Guix).
Il percepito aumento di complessità nell’esecuzione di un contenitore del sistema Guix è facilmente giustificato quando si ha a che fare con applicazioni più complesse che hanno requisiti più elevati o semplicemente più rigidi sui loro contesti di esecuzione — file di configurazione, account utente dedicati, directory per cache o file di log, ecc. Nel sistema Guix le esigenze di questo tipo di software sono soddisfatte attraverso l’implementazione di servizi di sistema.
Successivo: Networking dei contenitori, Su: Contenitori di Sistema Guix [Contenuti][Indice]
Un buon esempio potrebbe essere un server di database PostgreSQL. Gran parte della complessità della configurazione di un tale server di database è incapsulata in questa ingannevolmente breve dichiarazione di servizio:
(service postgresql-service-type
(postgresql-configuration
(postgresql postgresql-14)))
Una dichiarazione completa del sistema operativo da utilizzare con un contenitore del sistema Guix sarebbe simile a questa:
(use-modules (gnu)) (use-package-modules databases) (use-service-modules databases) (operating-system (host-name "container") (timezone "Europe/Berlin") (file-systems (cons (file-system (device (file-system-label "non-importa")) (mount-point "/") (type "ext4")) %base-file-systems )) (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets '("/dev/sdX")))) (services (cons* (service postgresql-service-type (postgresql-configuration (postgresql postgresql-14) (config-file (postgresql-config-file (log-destination "stderr") (hba-file (plain-file "pg_hba.conf" "\ local all all trust host all all 10.0.0.1/32 trust")) (extra-config '(("listen_addresses" "*") ("log_directory" "/var/log/postgresql"))))))) (service postgresql-role-service-type (postgresql-role-configuration (roles (list (postgresql-role (name "test") (create-database? #t)))))) %base-services )))
Con postgresql-role-service-type
definiamo un ruolo “test” e
creiamo un database corrispondente, in modo da poter testare subito senza
alcuna ulteriore configurazione manuale. Le impostazioni di
postgresql-config-file
permettono a un client dall’indirizzo IP
10.0.0.1 di connettersi senza richiedere autenticazione—una cattiva idea
nei sistemi di produzione, ma comoda per questo esempio.
Costruiamo uno script che avvierà un’istanza di questo sistema Guix come
contenitore. Scrivi la dichiarazione operating-system
sopra in un
file os.scm e poi usa guix system container
per costruire
il launcher. (vedi Invocare guix system in Manuale di riferimento
di GNU Guix).
$ guix system container os.scm Verranno costruite le seguenti derivazioni: /gnu/store/…-run-container.drv … costruzione di /gnu/store/…-run-container.drv... /gnu/store/…-run-container
Ora che abbiamo uno script di avvio, possiamo eseguirlo per avviare il nuovo
sistema con un servizio PostgreSQL in esecuzione. Si noti che a causa di
alcune limitazioni non ancora risolte, dobbiamo eseguire il launcher come
utente root, ad esempio con sudo
.
$ sudo /gnu/store/…-run-container il contenitore di sistema è in esecuzione come PID 5983 …
Metti in background il processo con Ctrl-z seguito da
bg
. Nota il ID del processo nell’output; ci servirà per
connetterci al contenitore più tardi. Sai cosa? Proviamo a connetterci al
contenitore subito. Useremo nsenter
, uno strumento fornito dal
pacchetto util-linux
:
$ guix shell util-linux $ sudo nsenter -a -t 5983 root@container /# pgrep -a postgres 49 /gnu/store/…-postgresql-14.4/bin/postgres -D /var/lib/postgresql/data --config-file=/gnu/store/…-postgresql.conf -p 5432 51 postgres: checkpointer 52 postgres: background writer 53 postgres: walwriter 54 postgres: autovacuum launcher 55 postgres: stats collector 56 postgres: logical replication launcher root@container /# exit
Il servizio PostgreSQL è in esecuzione nel contenitore!
Precedente: Un contenitore Database, Su: Contenitori di Sistema Guix [Contenuti][Indice]
A che serve un sistema Guix che esegue un servizio di database PostgreSQL come contenitore quando possiamo comunicare con esso solo con processi originari del contenitore? Sarebbe molto meglio se potessimo comunicare con il database tramite la rete.
Il modo più semplice per farlo è creare una coppia di dispositivi Ethernet
virtuali connessi (noti come veth
). Spostiamo uno dei dispositivi
(ceth-test
) nel namespace net
del contenitore e lasciamo
l’altra estremità (veth-test
) della connessione sul sistema host.
pid=5983 ns="guix-test" host="veth-test" client="ceth-test" # Collega il nuovo net namespace "guix-test" al PID del contenitore. sudo ip netns attach $ns $pid # Crea la coppia di dispositivi sudo ip link add $host type veth peer name $client # Sposta il dispositivo client nel namespace di rete del contenitore sudo ip link set $client netns $ns
Quindi configuriamo il lato host:
sudo ip link set $host up sudo ip addr add 10.0.0.1/24 dev $host
…e poi configuriamo il lato client:
sudo ip netns exec $ns ip link set lo up sudo ip netns exec $ns ip link set $client up sudo ip netns exec $ns ip addr add 10.0.0.2/24 dev $client
A questo punto l’host può raggiungere il contenitore all’indirizzo IP 10.0.0.2, e il contenitore può raggiungere l’host all’IP 10.0.0.1. Questo è tutto ciò di cui abbiamo bisogno per parlare con il server di database all’interno del contenitore dal sistema host all’esterno.
$ psql -h 10.0.0.2 -U test psql (14.4) Digita "help" per aiuto. test=> CREATE TABLE hello (who TEXT NOT NULL); CREATE TABLE test=> INSERT INTO hello (who) VALUES ('world'); INSERT 0 1 test=> SELECT * FROM hello; who ------- world (1 riga)
Ora che abbiamo finito con questa piccola dimostrazione, puliamo:
sudo kill $pid sudo ip netns del $ns sudo ip link del $host
Successivo: Gestione avanzata dei pacchetti, Precedente: Contenitori, Su: Ricettario di GNU Guix [Contenuti][Indice]
Guix può produrre immagini disco (vedi Invocare guix system in Manuale di riferimento di GNU Guix) che possono essere utilizzate con soluzioni di macchine virtuali come virt-manager, GNOME Boxes o il più semplice QEMU, tra gli altri.
Questo capitolo si propone di fornire esempi pratici e concreti relativi all’utilizzo e alla configurazione di macchine virtuali su un sistema Guix.
Successivo: Rete instradata per libvirt, Su: Macchine virtuali [Contenuti][Indice]
Per impostazione predefinita, QEMU utilizza un back-end di rete host
cosiddetto “user mode”, che è comodo in quanto non richiede alcuna
configurazione. Sfortunatamente, è anche piuttosto limitato. In questa
modalità, la VM (macchina virtuale) guest può accedere alla rete nello
stesso modo in cui lo farebbe l’host, ma non può essere raggiunta
dall’host. Inoltre, poiché la modalità di rete utente di QEMU si basa su
ICMP, gli strumenti di rete basati su ICMP come ping
not
funzionano in questa modalità. Pertanto, è spesso desiderabile configurare
un bridge di rete, che consente al guest di partecipare pienamente alla
rete. Ciò è necessario, ad esempio, quando il guest deve essere utilizzato
come server.
Esistono molti modi per creare un bridge di rete. Il seguente comando mostra
come usare NetworkManager e il suo strumento nmcli
da riga di
comando (CLI), che dovrebbe essere già disponibile se la dichiarazione del
tuo sistema operativo si basa su uno dei modelli desktop:
# nmcli con add type bridge con-name br0 ifname br0
Per far sì che questo bridge faccia parte della tua rete, devi associare il tuo bridge di rete all’interfaccia Ethernet usata per connetterti alla rete. Supponendo che la tua interfaccia si chiami ‘enp2s0’, il seguente comando può essere usato per farlo:
# nmcli con add type bridge-slave ifname enp2s0 master br0
Importante: Solo le interfacce Ethernet possono essere aggiunte a un bridge. Per le interfacce wireless, considerare l’approccio di rete instradata dettagliato in Vedi Rete instradata per libvirt.
Per impostazione predefinita, il bridge di rete consentirà ai tuoi ospiti di ottenere il loro indirizzo IP tramite DHCP, se disponibile sulla tua rete locale. Per semplicità, questo è ciò che useremo qui. Per trovare facilmente gli ospiti, possono essere configurati per pubblicizzare i loro nomi host tramite mDNS.
QEMU viene fornito con un programma di aiuto per utilizzare comodamente
un’interfaccia bridge di rete come utente non privilegiato vedi Network
options in Documentazione QEMU. Il binario deve essere reso setuid
root per il corretto funzionamento; questo può essere ottenuto aggiungendolo
al campo privileged-programs
della tua definizione
operating-system
(host), come mostrato sotto:
(privileged-programs (cons (privileged-program (program (file-append qemu "/libexec/qemu-bridge-helper")) (setuid? #t)) %default-privileged-programs))
Il file /etc/qemu/bridge.conf deve anche essere modificato per consentire l’interfaccia del bridge, poiché l’impostazione predefinita è di negare tutto. Aggiungi quanto segue all’elenco dei servizi per farlo:
(extra-special-file "/etc/qemu/host.conf" (plain-file "host.conf" "allow br0\n"))
Quando si invoca QEMU, le seguenti opzioni devono essere fornite in modo che il bridge di rete sia utilizzato, dopo aver selezionato un indirizzo MAC unico per il guest.
Importante: Per impostazione predefinita, viene utilizzato un singolo indirizzo MAC per tutti gli ospiti, a meno che non venga fornito. Il mancato fornitura di indirizzi MAC diversi a ciascuna macchina virtuale che utilizza il bridge causerebbe problemi di rete.
$ qemu-system-x86_64 [...] \ -device virtio-net-pci,netdev=user0,mac=XX:XX:XX:XX:XX:XX \ -netdev bridge,id=user0,br=br0 \ [...]
Per generare indirizzi MAC che hanno il prefisso registrato da QEMU, può essere utilizzato il seguente frammento:
mac_address="52:54:00:$(dd if=/dev/urandom bs=512 count=1 2>/dev/null \ | md5sum \ | sed -E 's/^(..)(..)(..).*$/1円:2円:3円/')" echo $mac_address
Se usi Docker sulla tua macchina, potresti riscontrare problemi di
connettività quando tenti di usare un bridge di rete, causati dal fatto che
Docker si basa anche sui bridge di rete e configura le proprie regole di
routing. La soluzione è aggiungere il seguente frammento iptables
alla tua dichiarazione operating-system
:
(service iptables-service-type (iptables-configuration (ipv4-rules (plain-file "iptables.rules" "\ *filter :INPUT ACCEPT [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A FORWARD -i br0 -o br0 -j ACCEPT COMMIT "))
Successivo: Rete personalizzata basata su NAT per libvirt, Precedente: Ponte di rete per QEMU, Su: Macchine virtuali [Contenuti][Indice]
Se la macchina che ospita le tue macchine virtuali è collegata in modalità
wireless alla rete, non sarai in grado di usare un vero bridge di rete come
spiegato nella sezione precedente (vedi Ponte di rete per QEMU). In
questo caso, la prossima migliore opzione è usare uno switch di rete
virtuale con routing statico e configurare una macchina virtuale basata su
libvirt per usarlo (tramite la GUI di virt-manager
per
esempio). Questo è simile alla modalità di funzionamento predefinita di
QEMU/libvirt, tranne che invece di usare NAT (Network Address
Translation), si basa su rotte statiche per unire l’indirizzo IP della
VM (macchina virtuale) alla LAN (rete locale). Questo fornisce
connettività bidirezionale da e verso la macchina virtuale, che è necessaria
per esporre i servizi ospitati sulla macchina virtuale.
Uno switch di rete virtuale consiste in un dispositivo di rete virtuale chiamato ‘bridge virtuale’, server DHCP (dnsmasq) e regole firewall (iptables). Vedi l’articolo wiki di libvirt sulle Reti Virtuali per maggiori dettagli sulle modalità di funzionamento, gestione e implementazione degli switch di rete virtuali.
Il comando virsh
, fornito dal pacchetto libvirt
, rende
molto facile creare uno switch virtuale. Per prima cosa devi scegliere una
sottorete di rete per il tuo switch virtuale; se la tua LAN domestica è
nella rete ‘192.168.1.0/24’, potresti optare per l’uso ad es.:
‘192.168.2.0/24’. Definisci un file XML, ad es.:
/tmp/virbr0.xml, contenente quanto segue:
<network> <name>virbr0</name> <bridge name="virbr0" /> <forward mode="route"/> <ip address="192.168.2.0" netmask="255.255.255.0"> <dhcp> <range start="192.168.2.1" end="192.168.2.254"/> </dhcp> </ip> </network>
Quindi crea e configura l’interfaccia usando il comando virsh
,
come root:
virsh net-define /tmp/virbr0.xml virsh net-autostart virbr0 virsh net-start virbr0
L’interfaccia ‘virbr0’ dovrebbe ora essere visibile ad es.: tramite il comando ‘ip address’. Verrà avviata automaticamente ogni volta che la tua macchina virtuale libvirt viene avviata.
Se hai configurato la tua macchina virtuale per utilizzare la tua nuova interfaccia bridge virtuale ‘virbr0’, dovrebbe già ricevere un IP tramite DHCP come ‘192.168.2.15’ ed essere raggiungibile dal server che la ospita, ad es.: tramite ‘ping 192.168.2.15’. C’è un’ultima configurazione necessaria affinché la VM possa raggiungere la rete esterna: aggiungere rotte statiche al router della rete.
In questo esempio, la rete LAN è ‘192.168.1.0/24’ e la pagina web di configurazione del router potrebbe essere accessibile ad es.: tramite la pagina http://192.168.1.1. Su un router che esegue il firmware libreCMC, dovresti navigare alla pagina Rete → Rotte Statiche (https://192.168.1.1/cgi-bin/luci/admin/network/routes), e aggiungeresti una nuova voce a ‘Rotte IPv4 Statiche’ con le seguenti informazioni:
lan
192.168.2.0
255.255.255.0
ip-server
unicast
dove server-ip è l’indirizzo IP della macchina che ospita le VM, che dovrebbe essere statico.
Dopo aver salvato/applicato questa nuova rotta statica, la connettività esterna dovrebbe funzionare all’interno della tua VM; puoi ad es.: eseguire ‘ping gnu.org’ per verificare che funzioni correttamente.
Successivo: Riferimenti, Precedente: Rete instradata per libvirt, Su: Macchine virtuali [Contenuti][Indice]
Come menzionato nella sezione precedente (vedi Rete instradata per libvirt), libvirt permette di definire reti virtuali tramite file XML e di
gestirle con il comando virsh
. I dettagli della creazione e
rimozione di switch di rete virtuali sono gestiti da libvirt, quindi
l’utente non deve occuparsene.
Tuttavia, la gestione degli switch di rete virtuali da parte di libvirt può a volte entrare in conflitto con configurazioni di rete più complesse. In particolare, le regole iptables inserite da libvirt per gli switch che operano in modalità NAT possono entrare in conflitto con regole iptables/nftables esistenti, portando a un filtraggio dei pacchetti insicuro o interrotto.
In questi casi, l’unica soluzione è configurare manualmente uno switch di rete virtuale. Questa sezione fornirà istruzioni su come farlo utilizzando i servizi del sistema Guix.
Il static-networking-service-type
può essere usato per creare un
bridge di rete virtuale e assegnargli un indirizzo IP:
(service static-networking-service-type (list (static-networking ;; La fornitura predefinita è 'networking; se stai usando qualsiasi ;; altro servizio con questa fornitura, come ;; `network-manager-service-type`, allora devi cambiare il ;; predefinito. (provision '(static-networking)) (links (list (network-link (name "virbr0") (type 'bridge) (arguments '())))) (addresses (list (network-address (device "virbr0") (value "192.168.10.1/24")))))))
Il dnsmasq-service-type
può essere usato per fornire DNS e DHCP per
gli ospiti connessi a questo switch di rete virtuale:
(service dnsmasq-service-type (dnsmasq-configuration ;; Puoi avere più istanze di `dnsmasq-service-type` purché ;; ognuna abbia una diversa shepherd-provision. (shepherd-provision '(dnsmasq-virbr0)) (extra-options (list ;; Bind solo al bridge virtuale. Questo ;; evita conflitti con altre istanze di ;; dnsmasq in esecuzione. "--except-interface=lo" "--interface=virbr0" "--bind-dynamic" ;; Indirizzi IPv4 da offrire alle VM. Questo ;; dovrebbe corrispondere alla sottorete scelta. "--dhcp-range=192.168.10.2,192.168.10.254"))))
Se intendi utilizzare lo switch di rete virtuale in modalità NAT, dovrai
utilizzare le regole nftables (o iptables) per impostare il masquerading
IP. Il seguente esempio mostra come utilizzare nftables-service-type
per farlo:
(service nftables-service-type (nftables-configuration (ruleset (plain-file "nftables.conf" "\ table inet filter { input catena { tipo filtro hook input priorità filtro; policy drop; # Aggiungi qui le tue regole di filtraggio pacchetti esistenti... iifname virbr0 udp dport 67 contatore accetta commento \"consenti DHCP su virbr0\" iifname virbr0 meta l4proto {tcp, udp} th dport 53 accetta \\ commento \"consenti DNS su virbr0\" } chain forward { type filter hook forward priority filter; policy drop; # Aggiungi qui le tue regole di inoltro esistenti... iifname virbr0 accept comment \"consenti il traffico in uscita da virbr0\" oifname virbr0 ct state {established, related } accept \\ comment \"consenti il traffico stabilito verso virbr0\" } } table inet nat { chain postrouting { type nat hook postrouting priority srcnat; policy accept; # Aggiungi qui le tue regole NAT esistenti... iifname virbr0 ip daddr { 224.0.0.0/24, 255.255.255.255/32 } return \\ comment \"non mascherare verso blocchi di indirizzi riservati\" iifname virbr0 oifname != virbr0 masquerade \\ comment \"mascherare tutto il traffico in uscita dalle VM\" } } "))))
Assicurati di avere l’inoltro IPv4 abilitato (puoi usare
sysctl-service-type
per questo).
Precedente: Rete personalizzata basata su NAT per libvirt, Su: Macchine virtuali [Contenuti][Indice]
Successivo: Sviluppo software, Precedente: Macchine virtuali, Su: Ricettario di GNU Guix [Contenuti][Indice]
Guix è un gestore di pacchetti funzionale che offre molte funzionalità oltre a ciò che i gestori di pacchetti più tradizionali possono fare. Per i non iniziati, queste funzionalità potrebbero non avere casi d’uso ovvi all’inizio. Lo scopo di questo capitolo è dimostrare alcuni concetti avanzati di gestione dei pacchetti.
vedi Gestione dei pacchetti in it, Manuale di riferimento GNU Guix per un riferimento completo.
Guix fornisce una funzionalità molto utile che potrebbe essere piuttosto estranea ai nuovi arrivati: i profiles. Sono un modo per raggruppare le installazioni di pacchetti e tutti gli utenti sullo stesso sistema sono liberi di usare quanti profili desiderano.
Che tu sia uno sviluppatore o meno, potresti scoprire che più profili ti offrono grande potenza e flessibilità. Sebbene spostino un po’ il paradigma rispetto ai gestori di pacchetti tradizionali, sono molto comodi da usare una volta che hai capito come configurarli.
Nota: Questa sezione è una guida ragionata sull’uso di più profili. Precede
guix shell
e la sua cache veloce dei profili (vedi Invocare guix shell in Manuale di riferimento di GNU Guix).In molti casi, potresti scoprire che l’utilizzo di
guix shell
per configurare l’ambiente di cui hai bisogno, quando ne hai bisogno, richiede meno lavoro rispetto al mantenimento di un profilo dedicato. A te la scelta!
Se hai familiarità con ‘virtualenv’ di Python, puoi pensare a un profilo come a una sorta di ‘virtualenv’ universale che può contenere qualsiasi tipo di software, non solo software Python. Inoltre, i profili sono autosufficienti: catturano tutte le dipendenze di runtime, il che garantisce che tutti i programmi all’interno di un profilo funzioneranno sempre in qualsiasi momento.
Più profili offrono molti vantaggi:
Concretamente, ecco alcuni profili tipici:
Immergiamoci nella configurazione!
Successivo: Pacchetti richiesti, Su: Profili Guix in pratica [Contenuti][Indice]
Un profilo Guix può essere configurato via un manifest. Un manifest è uno snippet di codice Scheme che specifica l’insieme di pacchetti che desideri avere nel tuo profilo; assomiglia a questo:
(specifications->manifest
'("pacchetto-1"
;; Versione 1.3 del pacchetto-2.
"pacchetto-2@1.3"
;; L'output "lib" del pacchetto-3.
"pacchetto-3:lib"
; ...
"pacchetto-N"))
Vedi Scrivere manifesti in Manuale di riferimento GNU Guix, per maggiori informazioni sulla sintassi.
Possiamo creare una specifica di manifest per ogni profilo e installarli in questo modo:
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles mkdir -p "$GUIX_EXTRA_PROFILES"/my-project # se non esiste ancora guix package --manifest=/percorso/a/guix-my-project-manifest.scm \ --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
Qui impostiamo una variabile arbitraria ‘GUIX_EXTRA_PROFILES’ per indicare la directory dove memorizzeremo i nostri profili nel resto di questo articolo.
Posizionare tutti i tuoi profili in una singola directory, con ogni profilo che ottiene la propria sottodirectory, è un po’ più pulito. In questo modo, ogni sottodirectory conterrà tutti i symlink per un solo profilo. Inoltre, “iterare sui profili” diventa ovvio da qualsiasi linguaggio di programmazione (ad esempio: uno script di shell) semplicemente iterando sulle sottodirectory di ‘$GUIX_EXTRA_PROFILES’.
Nota che è anche possibile scorrere l’output di
guix package --list-profiles
anche se probabilmente dovrai filtrare ~/.config/guix/current.
Per abilitare tutti i profili all’accesso, aggiungi questo al tuo ~/.bash_profile (o simile):
for i in $GUIX_EXTRA_PROFILES/*; do profile=$i/$(basename "$i") if [ -f "$profile"/etc/profile ]; then GUIX_PROFILE="$profile" . "$GUIX_PROFILE"/etc/profile fi unset profile done
Nota per gli utenti di Guix System: quanto sopra riflette come il tuo profilo predefinito ~/.guix-profile viene attivato da /etc/profile, quest’ultimo caricato da ~/.bashrc per impostazione predefinita.
Puoi ovviamente scegliere di abilitarne solo un sottoinsieme:
for i in "$GUIX_EXTRA_PROFILES"/my-project-1 "$GUIX_EXTRA_PROFILES"/my-project-2; do profile=$i/$(basename "$i") if [ -f "$profile"/etc/profile ]; then GUIX_PROFILE="$profile" . "$GUIX_PROFILE"/etc/profile fi unset profile done
Quando un profilo è disabilitato, è semplice abilitarlo per una singola shell senza "inquinare" il resto della sessione utente:
GUIX_PROFILE="percorso/al/mio-progetto" ; . "$GUIX_PROFILE"/etc/profile
La chiave per abilitare un profilo è source il suo file ‘etc/profile’. Questo file contiene codice shell che esporta le variabili d’ambiente corrette necessarie per attivare il software contenuto nel profilo. È costruito automaticamente da Guix e destinato all’esecuzione. Contiene le stesse variabili che otterresti eseguendo:
guix package --search-paths=prefix --profile=$my_profile"
Ancora una volta, vedi Invocare guix package in Manuale di riferimento di GNU Guix per le opzioni della riga di comando.
Per aggiornare un profilo, è sufficiente installare di nuovo il manifest:
guix package -m /percorso/a/guix-my-project-manifest.scm \ -p "$GUIX_EXTRA_PROFILES"/my-project/my-project
Per aggiornare tutti i profili, è abbastanza facile scorrerli. Ad esempio, supponendo che le specifiche del tuo manifest siano archiviate in ~/.guix-manifests/guix-$profile-manifest.scm, con ‘$profile’ che è il nome del profilo (es.: "project1"), potresti fare quanto segue in una shell Bourne:
for profile in "$GUIX_EXTRA_PROFILES"/*; do guix package --profile="$profile" \ --manifest="$HOME/.guix-manifests/guix-$profile-manifest.scm" done
Ogni profilo ha le sue generazioni:
guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --list-generations
Puoi tornare indietro a qualsiasi generazione di un dato profilo:
guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --switch-generations=17
Infine, se vuoi passare a un profilo senza ereditare dall’ambiente corrente, puoi attivarlo da una shell vuota:
env -i $(which bash) --login --noprofile --norc . my-project/etc/profile
Successivo: Profilo predefinito, Precedente: Configurazione di base con i manifesti, Su: Profili Guix in pratica [Contenuti][Indice]
L’attivazione di un profilo si riduce essenzialmente all’esportazione di una serie di variabili d’ambiente. Questo è il ruolo del file ‘etc/profile’ all’interno del profilo.
Nota: verranno impostate solo le variabili d’ambiente dei pacchetti che le consumano.
Ad esempio, ‘MANPATH’ non verrà impostato se non esiste un’applicazione che consuma le pagine man all’interno del profilo. Quindi, se hai bisogno di accedere in modo trasparente alle pagine man una volta caricato il profilo, hai due opzioni:
export MANPATH=/percorso/al/profilo${MANPATH:+:}$MANPATH
Lo stesso vale per ‘INFOPATH’ (puoi installare ‘info-reader’), ‘PKG_CONFIG_PATH’ (installa ‘pkg-config’), ecc.
Successivo: I benefici dei manifesti, Precedente: Pacchetti richiesti, Su: Profili Guix in pratica [Contenuti][Indice]
Che dire del profilo predefinito che Guix mantiene in ~/.guix-profile?
Puoi assegnargli il ruolo che desideri. Tipicamente installeresti il manifest dei pacchetti che vuoi usare sempre.
In alternativa, potresti mantenerlo “senza manifest” per pacchetti usa-e-getta che useresti solo per un paio di giorni. In questo modo è comodo eseguire
guix install package-foo guix upgrade package-bar
senza dover specificare il percorso di un profilo.
Successivo: Profili riproducibili, Precedente: Profilo predefinito, Su: Profili Guix in pratica [Contenuti][Indice]
I manifest ti permettono di declare l’insieme di pacchetti che vorresti avere in un profilo (vedi Scrivere manifesti in Manuale di riferimento GNU Guix). Sono un modo conveniente per tenere a portata di mano gli elenchi dei pacchetti e, ad esempio, sincronizzarli su più macchine utilizzando un sistema di controllo versione.
Una lamentela comune sui manifest è che possono essere lenti da installare quando contengono un gran numero di pacchetti. Questo è particolarmente ingombrante quando si desidera solo un aggiornamento per un pacchetto all’interno di un manifest grande.
Questo è un motivo in più per utilizzare più profili, che si rivelano perfetti per suddividere i manifest in più insiemi di pacchetti semanticamente collegati. L’utilizzo di più profili piccoli offre maggiore flessibilità e usabilità.
I manifest offrono numerosi vantaggi. In particolare, facilitano la manutenzione:
guix package --upgrade
tenta sempre di aggiornare i pacchetti che
hanno input propagati, anche se non c’è nulla da fare. I manifest di Guix
rimuovono questo problema.
guix install
, guix upgrade
,
ecc. non lo fanno, poiché producono profili diversi ogni volta anche quando
contengono gli stessi pacchetti. Vedi
la discussione correlata
sull’argomento.
guix weather -m manifest.scm
per vedere quanti sostituti sono disponibili, il che può aiutarti a decidere
se vuoi provare ad aggiornare oggi o aspettare un po’. Un altro esempio:
puoi eseguire guix pack -m manifest.scm
per creare un pacchetto
contenente tutti i pacchetti nel manifest (e i loro riferimenti transitivi).
È importante capire che, sebbene i manifest possano essere usati per
dichiarare i profili, non sono strettamente equivalenti: i profili hanno
l’effetto collaterale di “fissare” i pacchetti nello store, il che
impedisce che vengano raccolti dalla spazzatura (vedi Invocare guix gc in Manuale di riferimento GNU Guix) e assicura che saranno ancora
disponibili in qualsiasi momento in futuro. Il comando guix shell
protegge anche i profili usati di recente dalla raccolta della spazzatura; i
profili che non sono stati usati per un po’ possono essere comunque raccolti
dalla spazzatura, insieme ai pacchetti a cui si riferiscono.
Per essere sicuri al 100% che un dato profilo non verrà mai raccolto,
installare il manifest in un profilo e usare GUIX_PROFILE=/il/profilo;
. "$GUIX_PROFILE"/etc/profile
come spiegato sopra: questo garantisce che il
nostro ambiente di hacking sarà sempre disponibile.
Avviso di sicurezza: Sebbene mantenere i vecchi profili possa essere comodo, tieni presente che i pacchetti obsoleti potrebbero non aver ricevuto le ultime correzioni di sicurezza.
Precedente: I benefici dei manifesti, Su: Profili Guix in pratica [Contenuti][Indice]
Per riprodurre un profilo bit per bit, abbiamo bisogno di due informazioni:
Infatti, i soli manifest potrebbero non essere sufficienti: diverse versioni di Guix (o diversi canali) possono produrre output diversi per un dato manifest.
È possibile generare la specifica del canale Guix con ‘guix describe --format=channels’ (vedi Invocare guix describe in Manuale di riferimento GNU Guix). Salva questo in un file, ad esempio ‘channel-specs.scm’.
Su un altro computer, è possibile utilizzare il file di specifica del canale e il manifest per riprodurre lo stesso identico profilo:
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles GUIX_EXTRA=$HOME/.guix-extra mkdir -p "$GUIX_EXTRA"/my-project guix pull --channels=channel-specs.scm --profile="$GUIX_EXTRA/my-project/guix" mkdir -p "$GUIX_EXTRA_PROFILES/my-project" "$GUIX_EXTRA"/my-project/guix/bin/guix package \ --manifest=/percorso/a/guix-my-project-manifest.scm \ --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
È sicuro eliminare il profilo del canale Guix che hai appena installato con la specifica del canale, il profilo del progetto non dipende da esso.
Successivo: Gestione dell’ambiente, Precedente: Gestione avanzata dei pacchetti, Su: Ricettario di GNU Guix [Contenuti][Indice]
Guix è uno strumento utile per gli sviluppatori; guix shell
, in
particolare, fornisce un ambiente di sviluppo autonomo per il tuo pacchetto,
indipendentemente dal linguaggio/i in cui è scritto (vedi Invocare guix
shell in Manuale di riferimento GNU Guix). Per beneficiarne, devi
inizialmente scrivere una definizione di pacchetto e averla in Guix stesso,
o in un canale, o direttamente nell’albero sorgente del tuo progetto come
file guix.scm. Quest’ultima opzione è allettante: tutto ciò che gli
sviluppatori devono fare per iniziare è clonare il repository del progetto
ed eseguire guix shell
, senza argomenti.
Le esigenze di sviluppo vanno oltre gli ambienti di sviluppo. Come possono gli sviluppatori eseguire l’integrazione continua del loro codice negli ambienti di costruzione di Guix? Come possono consegnare il loro codice direttamente agli utenti più avventurosi? Questo capitolo descrive un insieme di file che gli sviluppatori possono aggiungere al loro repository per configurare ambienti di sviluppo basati su Guix, integrazione continua e consegna continua — tutto in una volta sola1.
Successivo: Livello 1: Costruire con Guix, Su: Sviluppo software [Contenuti][Indice]
Come “Guixificare” un repository? Il primo passo, come abbiamo visto, sarà
aggiungere un file guix.scm alla radice del repository in
questione. Prenderemo Guile come
esempio in questo capitolo: è scritto principalmente in Scheme e C, e ha una
serie di dipendenze — una toolchain di compilazione C, librerie C,
Autoconf e i suoi amici, LaTeX, e così via. Il file guix.scm
risultante assomiglia alla solita definizione di pacchetto (vedi Definire
i pacchetti in Manuale di riferimento GNU Guix), solo senza il pezzo
define-public
:
;; Il file «guix.scm» per Guile, da usare con «guix shell». (use-modules (guix) (guix build-system gnu) ((guix licenses) #:prefix license:) (gnu packages autotools) (gnu packages base) (gnu packages bash) (gnu packages bdw-gc) (gnu packages compression) (gnu packages flex) (gnu packages gdb) (gnu packages gettext ) (gnu packages gperf) (gnu packages libffi) (gnu packages libunistring) (gnu packages linux) (gnu packages pkg-config) (gnu packages readline ) (gnu packages tex) (gnu packages texinfo) (gnu packages version-control)) (package (name "guile") (version "3.0.99-git") ;numero di versione strano (source #f) ;nessuna fonte (build-system gnu-build-system ) (native-inputs (append (list autoconf automake libtool gnu-gettext flex texinfo texlive-base ;per "make pdf" texlive-epsf gperf git gdb strace readline lzip pkg-config) ;; Quando si esegue la compilazione incrociata, è necessaria una ;; versione nativa di Guile. (if (%current-target-system) (list this-package ) '()))) (inputs (list libffi bash-minimal)) (propagated-inputs (list libunistring libgc)) (native-search-paths (list (search-path-specification (variable "GUILE_LOAD_PATH") (files '("share/guile/site/3.0"))) (search-path-specification (variable "GUILE_LOAD_COMPILED_PATH") (files '("lib/guile/3.0/site-ccache"))))) (synopsis "Implementazione Scheme destinata in particolare alle estensioni") (description "Guile è il Linguaggio Intelligente Onnipresente GNU per le Estensioni, ed è in realtà un'implementazione Scheme completa!") (home-page "https://www.gnu.org/software/guile/") (license license:lgpl3+))
Un bel po’ di codice standard, ma ora chiunque voglia mettere mano a Guile deve solo eseguire:
guix shell
Questo fornisce loro una shell contenente tutte le dipendenze di Guile:
quelle elencate sopra, ma anche dipendenze implicite come la tool
chain GCC, GNU Make, sed, grep e così via. Vedi Invocare guix shell in Manuale di riferimento GNU Guix, per maggiori informazioni su
guix shell
.
Il consiglio dello chef: Il nostro suggerimento è di creare ambienti di sviluppo come questo:
guix shell --container --link-profile... o, in breve:
guix shell -CPQuesto fornisce una shell in un contenitore isolato, e tutte le dipendenze appaiono in
$HOME/.guix-profile
, che funziona bene con le cache come config.cache (vedi File Cache in Autoconf) e i nomi di file assoluti registrati neiMakefile
generati e simili. Il fatto che la shell venga eseguita in un contenitore porta tranquillità: nulla, tranne la directory corrente e le dipendenze di Guile, è visibile all’interno del contenitore; nulla del sistema può interferire con il tuo sviluppo.
Successivo: Livello 2: Il Repository come Canale, Precedente: Per iniziare, Su: Sviluppo software [Contenuti][Indice]
Ora che abbiamo una definizione di pacchetto (vedi Per iniziare),
perché non approfittarne anche per costruire Guile con Guix? Avevamo
lasciato il campo source
vuoto, perché guix shell
si occupa
solo degli inputs del nostro pacchetto — in modo da poter
configurare l’ambiente di sviluppo — non del pacchetto stesso.
Per costruire il pacchetto con Guix, dovremo compilare il campo
source
, seguendo queste linee:
(use-modules (guix) (guix git-download) ;per ‘git-predicate’ ...) (define vcs-file? ;; Restituisce vero se il file dato è sotto controllo di versione. (or (git-predicate (current-source-directory)) (const #t))) ;non in un checkout Git (package (name "guile") (version "3.0.99-git") ;numero di versione strano (source (local-file "." "guile-checkout" #:recursive? #t #:select? vcs-file?)) ...)
Ecco cosa abbiamo cambiato rispetto alla sezione precedente:
(guix git-download)
al nostro set di moduli
importati, in modo da poter utilizzare la sua procedura
git-predicate
.
vcs-file?
come una procedura che restituisce vero
quando le viene passato un file sotto controllo di versione. Per sicurezza,
aggiungiamo un caso di fallback per quando non siamo in un checkout Git:
restituiamo sempre vero.
source
su un
local-file
— una copia ricorsiva della directory corrente ("."
), limitata ai
file sotto controllo di versione (il pezzo #:select?
).
Da qui in poi, il nostro file guix.scm serve a un secondo scopo: ci permette di costruire il software con Guix. Il punto principale della costruzione con Guix è che si tratta di una costruzione “pulita” — puoi essere sicuro che nulla dal tuo albero di lavoro o dal sistema interferisca con il risultato della costruzione — e ti permette di testare una varietà di cose. Innanzitutto, puoi fare una semplice costruzione nativa:
guix build -f guix.scm
Ma puoi anche costruire per un altro sistema (eventualmente dopo aver configurato vedi scaricamento in Manuale di riferimento GNU Guix o vedi emulazione trasparente in Manuale di riferimento GNU Guix):
guix build -f guix.scm -s aarch64-linux -s riscv64-linux
… o compilare incrociando:
guix build -f guix.scm --target=x86_64-w64-mingw32
È inoltre possibile utilizzare le trasformazioni di pacchetto per testare le varianti di pacchetto (vedi Opzioni di trasformazione dei pacchetti in Manuale di riferimento GNU Guix):
# E se costruissimo con Clang invece di GCC? guix build -f guix.scm \ --with-c-toolchain=guile@3.0.99-git=clang-toolchain # E quel flag di configurazione poco testato? guix build -f guix.scm \ --with-configure-flag=guile@3.0.99-git=--disable-networking
Comodo!
Successivo: Bonus: Varianti di Pacchetto, Precedente: Livello 1: Costruire con Guix, Su: Sviluppo software [Contenuti][Indice]
Ora abbiamo un repository Git contenente (tra le altre cose) una definizione di pacchetto (vedi Livello 1: Costruire con Guix). Non possiamo trasformarlo in un channel (vedi Canali in Manuale di riferimento GNU Guix)? Dopotutto, i canali sono progettati per spedire le definizioni dei pacchetti agli utenti, ed è esattamente quello che stiamo facendo con il nostro guix.scm.
Si scopre che possiamo effettivamente trasformarlo in un canale, ma con una
cautela: dobbiamo creare una directory separata per il/i file .scm
del nostro canale in modo che guix pull
non carichi file
.scm
non correlati quando qualcuno scarica il canale — e in Guile
ce ne sono molti! Quindi inizieremo così, mantenendo un symlink
guix.scm di primo livello per il bene di guix shell
:
mkdir -p .guix/modules mv guix.scm .guix/modules/guile-package.scm ln -s .guix/modules/guile-package.scm guix.scm
Per renderlo utilizzabile come parte di un canale, dobbiamo trasformare il
nostro file guix.scm in un modulo pacchetto (vedi Moduli di
pacchetti in Manuale di riferimento GNU Guix): lo facciamo
cambiando la forma use-modules
in alto in una forma
define-module
. Dobbiamo anche effettivamente export una
variabile pacchetto, con define-public
, pur restituendo il valore del
pacchetto alla fine del file in modo da poter ancora usare guix
shell
e guix build -f guix.scm
. Il risultato finale assomiglia a
questo (non ripetendo cose che non sono cambiate):
(define-module (guile-package) #:use-module (guix) #:use-module (guix git-download) ;per ‘git-predicate’ ...) (define vcs-file? ;; Restituisce vero se il file dato è sotto controllo di versione. (or (git-predicate (dirname (dirname (current-source-directory)))) (const #t))) ;non in un checkout Git (define-public guile (package (name "guile") (version "3.0.99-git") ;numero di versione strano (source (local-file "../.." "guile-checkout" #:recursive? #t #:select? vcs-file?)) ...)) ;; Restituisce l'oggetto pacchetto definito sopra alla fine del modulo. guile
Ci serve un’ultima cosa: un file
.guix-channel
in modo che Guix sappia dove cercare i moduli dei pacchetti nel nostro
repository:
;; Questo file ci permette di presentare questo repository come un canale Guix. (channel (version 0) (directory ".guix/modules")) ;cerca i moduli dei pacchetti sotto .guix/modules/
Per ricapitolare, ora abbiamo questi file:
. ├── .guix-channel ├── guix.scm → .guix/modules/guile-package.scm └── .guix └── modules └── guile-package.scm
E questo è tutto: abbiamo un canale! (Potremmo fare di meglio e supportare
l’autenticazione
del canale in modo che gli utenti sappiano di scaricare codice
autentico. Ti risparmiamo i dettagli qui, ma vale la pena considerarlo!) Gli
utenti possono scaricare da questo canale
aggiungendolo
a ~/.config/guix/channels.scm
, secondo queste linee:
(append (list (channel
(name 'guile)
(url "https://git.savannah.gnu.org/git/guile.git")
(branch "main")))
%default-channels)
Dopo aver eseguito guix pull
, possiamo vedere il nuovo pacchetto:
$ guix describe Generazione 264 26 maggio 2023 16:00:35 (corrente) guile 36fd2b4 URL repository: https://git.savannah.gnu.org/git/guile.git ramo: main commit: 36fd2b4920ae926c79b936c29e739e71a6dff2bc guix c5bc698 URL repository: https://git.guix.gnu.org/guix.git commit: c5bc698e8922d78ed85989985cc2ceb034de2f23 $ guix package -A ^guile$ guile 3.0.99-git out,debug guile-package.scm:51:4 guile 3.0.9 out,debug gnu/packages/guile.scm:317:2 guile 2.2.7 out,debug gnu/packages/guile.scm:258:2 guile 2.2.4 out,debug gnu/packages/guile.scm:304:2 guile 2.0.14 out,debug gnu/packages/guile.scm:148:2 guile 1.8.8 out gnu/packages/guile.scm:77:2 $ guix build guile@3.0.99-git […] /gnu/store/axnzbl89yz7ld78bmx72vpqp802dwsar-guile-3.0.99-git-debug /gnu/store/r34gsij7f0glg2fbakcmmk0zn4v62s5w-guile-3.0.99-git
È così che, come sviluppatore, consegni il tuo software direttamente nelle mani degli utenti! Nessun intermediario, eppure nessuna perdita di trasparenza e tracciamento della provenienza.
Con questo in atto, diventa anche banale per chiunque creare immagini
Docker, pacchetti Deb/RPM o un semplice tarball con guix pack
(vedi Invocare guix pack in Manuale di riferimento GNU Guix):
# Che ne dici di un'immagine Docker del nostro snapshot Guile? guix pack -f docker -S /bin=bin guile@3.0.99-git # E un RPM rilocabile? guix pack -f rpm -R -S /bin=bin guile@3.0.99-git
Successivo: Livello 3: Configurazione dell’Integrazione Continua, Precedente: Livello 2: Il Repository come Canale, Su: Sviluppo software [Contenuti][Indice]
Ora abbiamo un canale effettivo, ma contiene un solo pacchetto (vedi Livello 2: Il Repository come Canale). Già che ci siamo, possiamo definire varianti di pacchetto (vedi Definire varianti di pacchetto in Manuale di riferimento GNU Guix) nel nostro file guile-package.scm, varianti che vogliamo poter testare come sviluppatori Guile — in modo simile a quanto fatto sopra con le opzioni di trasformazione. Possiamo aggiungerle così:
;; Questo è il file «.guix/modules/guile-package.scm». (define-module (guile-package) ...) (define-public guile ...) (define (package-with-configure-flags p flags) "Restituisce P con FLAGS come flag 'configure' aggiuntivi." (package/inherit p (arguments (substitute-keyword-arguments (package-arguments p) ((#:configure-flags original-flags #~(list )) #~(append #$original-flags #$flags)))))) (define-public guile-without-threads (package (inherit (package-with-configure-flags guile #~(list "--without-threads"))) (name "guile-without-threads"))) (define-public guile-without-networking (package (inherit (package-with-configure-flags guile #~(list "--disable-networking"))) (name "guile-without-networking"))) ;; Restituisce l'oggetto pacchetto definito sopra alla fine del modulo. guile
Possiamo costruire queste varianti come pacchetti regolari una volta che abbiamo scaricato il canale. In alternativa, da un checkout di Guile, possiamo eseguire un comando come questo dal livello superiore:
guix build -L $PWD/.guix/modules guile-without-threads
Successivo: Bonus: Manifest di costruzione, Precedente: Bonus: Varianti di Pacchetto, Su: Sviluppo software [Contenuti][Indice]
Il canale che abbiamo definito sopra (vedi Livello 2: Il Repository come Canale) diventa ancora più interessante una volta che configuriamo l’integrazione continua (CI). Ci sono diversi modi per farlo.
Puoi utilizzare uno degli strumenti di integrazione continua più diffusi, come GitLab-CI. Per farlo, devi assicurarti di eseguire i job in un’immagine Docker o in una macchina virtuale che abbia Guix installato. Se lo facessimo nel caso di Guile, avremmo un job che esegue un comando shell come questo:
guix build -L $PWD/.guix/modules guile@3.0.99-git
Fare questo funziona alla grande e ha il vantaggio di essere facile da ottenere sulla tua piattaforma CI preferita.
Detto questo, otterrai il massimo usandoti di Cuirass, uno strumento di CI progettato e strettamente integrato con Guix. Usarlo richiede più lavoro rispetto all’utilizzo di uno strumento di CI ospitato perché devi prima configurarlo, ma quella fase di configurazione è notevolmente semplificata se usi il suo servizio Guix System (vedi Integrazione continua in Manuale di riferimento GNU Guix). Tornando al nostro esempio, diamo a Cuirass un file di specifica che assomiglia a questo:
;; File di specifica Cuirass per costruire tutti i pacchetti del canale «guile». (list (specification (name "guile") (build '(channels guile)) (channels (append (list (channel (name 'guile) (url "https://git.savannah.gnu.org/git/guile.git") (branch "main"))) %default-channels))))
Differisce da ciò che faresti con altri strumenti di CI in due modi importanti:
guile
e
guix
. Infatti, il nostro pacchetto guile
dipende da molti
pacchetti forniti dal canale guix
— GCC, la GNU libc, libffi, e
così via. Le modifiche ai pacchetti del canale guix
possono
potenzialmente influenzare la nostra build di guile
e questo è
qualcosa che vorremmo vedere il prima possibile come sviluppatori Guile.
guile
ottengano in modo trasparente i binari precompilati!
(vedi Sostituti in Manuale di riferimento GNU Guix, per
informazioni di base sui sostituti.)
Dal punto di vista di uno sviluppatore, il risultato finale è questa
pagina di stato che elenca le
evaluations: ogni valutazione è una combinazione di commit dei canali
guix
e guile
che fornisce un numero di job — un job
per pacchetto definito in guile-package.scm moltiplicato per il
numero di architetture di destinazione.
Per quanto riguarda i sostituti, sono gratuiti! Ad esempio, poiché il nostro
jobset guile
è costruito su ci.guix.gnu.org, che esegue guix
publish
(vedi Invocare guix publish in Manuale di riferimento
GNU Guix) oltre a Cuirass, si ottengono automaticamente i sostituti per le
build di guile
da ci.guix.gnu.org; non è necessario alcun lavoro
aggiuntivo per questo.
Successivo: In conclusione, Precedente: Livello 3: Configurazione dell’Integrazione Continua, Su: Sviluppo software [Contenuti][Indice]
La specifica Cuirass sopra è comoda: costruisce ogni pacchetto nel nostro canale, che include alcune varianti (vedi Livello 3: Configurazione dell’Integrazione Continua). Tuttavia, questo potrebbe essere insufficientemente espressivo in alcuni casi: si potrebbero volere specifici job di cross-compilazione, trasformazioni, immagini Docker, pacchetti RPM/Deb, o persino test di sistema.
Per ottenere ciò, puoi scrivere un manifest (vedi Scrivere manifesti in Manuale di riferimento GNU Guix). Quello che abbiamo per Guile ha voci per le varianti di pacchetto che abbiamo definito sopra, così come varianti aggiuntive e build incrociate:
;; Questo è «.guix/manifest.scm». (use-modules (guix) (guix profiles) (guile-package)) ;importa il nostro modulo pacchetto (define* (package->manifest-entry* package system #:key target) "Restituisce una voce di manifest per PACKAGE su SYSTEM, opzionalmente cross-compilato su TARGET." (manifest-entry (inherit (package->manifest-entry package )) (name (string-append (package-name package ) "." system (if target (string-append "." target) ""))) (item (with-parameters ((%current-system system ) (%current-target-system target)) package )))) (define native-builds (manifest (append (map (lambda (system ) (package->manifest-entry* guile system )) '("x86_64-linux" "i686-linux" "aarch64-linux" "armhf-linux" "powerpc64le-linux")) (map (lambda (guile) (package->manifest-entry* guile "x86_64-linux")) (cons (package (inherit (package-with-c-toolchain guile `(("clang-toolchain" ,(specification->package "clang-toolchain"))))) (name "guile-clang")) (list guile-without-threads guile-without-networking guile-debug guile-strict-typing)))))) (define cross-builds (manifest (map (lambda (target) (package->manifest-entry* guile "x86_64-linux" #:target target)) '("i586-pc-gnu" "aarch64-linux-gnu" "riscv64-linux-gnu" "i686-w64-mingw32" "x86_64-linux-gnu")))) (concatenate-manifests (list native-builds cross-builds))
Non entreremo nei dettagli di questo manifest; basti dire che fornisce flessibilità aggiuntiva. Ora dobbiamo dire a Cuirass di costruire questo manifest, cosa che si fa con una specifica leggermente diversa dalla precedente:
;; File di specifica Cuirass per costruire tutti i pacchetti del canale «guile». (list (specification (name "guile") (build '(manifest ".guix/manifest.scm")) (channels (append (list (channel (name 'guile) (url "https://git.savannah.gnu.org/git/guile.git") (branch "main"))) %default-channels))))
Abbiamo cambiato la parte (build …)
della specifica in
'(manifest ".guix/manifest.scm")
in modo che prelevasse il nostro
manifest, e questo è tutto!
Precedente: Bonus: Manifest di costruzione, Su: Sviluppo software [Contenuti][Indice]
Abbiamo scelto Guile come esempio in questo capitolo e puoi vedere il risultato qui:
.guix-channel
;
.guix/modules/guile-package.scm
con il symlink guix.scm di primo livello;
.guix/manifest.scm
.
Al giorno d’oggi, i repository sono spesso cosparsi di file nascosti per
vari strumenti: .envrc
, .gitlab-ci.yml
,
.github/workflows
, Dockerfile
, .buildpacks
,
Aptfile
, requirements.txt
, e così via. Potrebbe sembrare che
stiamo proponendo un mucchio di file additional, ma in realtà questi
file sono sufficientemente espressivi da sostituire la maggior parte
o tutti quelli elencati sopra.
Con un paio di file, otteniamo il supporto per:
guix shell
);
guix build
);
guix pack
).
Questo è un bel set di strumenti unificato (a nostro avviso!) per il deployment riproducibile del software, e un’illustrazione di come tu, come sviluppatore, puoi trarne beneficio!
Successivo: Using Guix for Reproducible Research, Precedente: Sviluppo software, Su: Ricettario di GNU Guix [Contenuti][Indice]
Guix fornisce numerosi strumenti per gestire l’ambiente. Questo capitolo illustra tali utilità.
Guix fornisce un pacchetto ‘direnv’, che potrebbe estendere la shell dopo il cambio di directory. Questo strumento potrebbe essere usato per preparare un ambiente Guix puro.
L’esempio seguente fornisce una funzione di shell per il file ~/.direnvrc, che potrebbe essere utilizzata dal repository Git di Guix nel file ~/src/guix/.envrc per configurare un ambiente di build simile a quello descritto in vedi Costruire da Git in Manuale di riferimento GNU Guix.
Crea un file ~/.direnvrc con codice Bash:
# Grazie a <https://github.com/direnv/direnv/issues/73#issuecomment-152284914> export_function() { local name=1ドル local alias_dir=$PWD/.direnv/aliases mkdir -p "$alias_dir" PATH_add "$alias_dir" local target="$alias_dir/$name" if declare -f "$name" >/dev/null; then echo "#!$SHELL" > "$target" declare -f "$name" >> "$target" 2>/dev/null # Notare che aggiungiamo variabili di shell al trigger della funzione. echo "$name \$*" >> "$target" chmod +x "$target" fi } use_guix() { # Imposta il token GitHub. export GUIX_GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Disattiva 'GUIX_PACKAGE_PATH'. export GUIX_PACKAGE_PATH="" # Ricrea una radice del garbage collector. gcroots="$HOME/.config/guix/gcroots" mkdir -p "$gcroots" gcroot="$gcroots/guix" if [ -L "$gcroot" ] then rm -v "$gcroot" fi # Pacchetti vari. PACKAGES_MAINTENANCE=( direnv git git:send-email git-cal gnupg guile-colorized guile-readline less ncurses openssh xdot ) # Pacchetti ambiente. PACKAGES=(help2man guile-sqlite3 guile-gcrypt) # Grazie a <https://lists.gnu.org/archive/html/guix-devel/2016-09/msg00859.html> eval "$(guix shell --search-paths --root="$gcroot" --pure \ --development guix ${PACKAGES[@]} ${PACKAGES_MAINTENANCE[@]} "$@")" # Predefinisci i flag di configurazione. configure() { ./configure } export_function configure # Esegui make e opzionalmente costruisci qualcosa. build() { make -j 2 if [ $# -gt 0 ] then ./pre-inst-env guix build "$@" fi } export_function build # Predefinisci il comando Git push. push() { git push --set-upstream origin } export_function push clear # Pulisci lo schermo. git-cal --author='Il tuo nome' # Mostra il calendario dei contributi. # Mostra l'aiuto dei comandi. echo " build costruisce un pacchetto o solo un progetto se non viene fornito alcun argomento configure esegui ./configure con parametri predefiniti push effettua il push al repository Git upstream " }
Ogni progetto contenente .envrc con la stringa use guix
avrà
variabili d’ambiente e procedure predefinite.
Esegui direnv allow
per configurare l’ambiente per la prima volta.
Successivo: Installare Guix su un Cluster, Precedente: Gestione dell’ambiente, Su: Ricettario di GNU Guix [Contenuti][Indice]
Because it supports reproducible deployment, Guix is a solid foundation for reproducible research workflows. This section is targeted at scientists; it shows how to add Guix to one’s reproducible research toolbox2.
With Guix as the basis of your computational workflow, you can get what’s in essence executable provenance meta-data: it’s like the list of package name/version pairs some provide as an appendix to their publication, except more precise and immediately deployable.
This section is a guide in just four steps on how to make your computational experiments reproducible using Guix, and how to provide that information in your research paper.
Successivo: Step 2: Recording the Environment, Su: Using Guix for Reproducible Research [Contenuti][Indice]
The first step is to identify precisely what packages you need in your software environment to run your computational experiment.
Assuming you have a Python script that uses NumPy, you can start by creating an environment that contains these two packages and to run your code in that environment (vedi Invoking guix shell in GNU Guix Reference Manual):
guix shell -C python python-numpy -- python3 ./myscript.py
The -C
flag here (or --container
) instructs guix
shell
to create that environment in an isolated container with nothing but
the two packages you asked for. That way, if ./myscript.py
needs
more than these two packages, it’ll fail to run and you’ll immediately
notice. On some systems --container
is not supported; in that case,
you can resort to --pure
instead.
Perhaps you’ll find that you also need Pandas and add it to the environment:
guix shell -C python python-numpy python-pandas -- \ python3 ./myscript.py
If you fail to guess the name of the package (this one was easy!), try
guix search
.
Environments for Python, R, and similar high-level languages are relatively easy to set up. For C/C++ code, you may find need many more packages:
guix shell -C gcc-toolchain cmake coreutils grep sed make -- …
Or perhaps you’ll find that you could just as well provide a for your package—vedi Defining Packages in GNU Guix Reference Manual, to learn more on how to do that.
Eventually, you’ll have a list of packages that satisfies your needs.
What if a package is missing?: Guix and the main scientific channels provide about tens of thousands of packages. Yet, there’s always the possibility that the one package you need is missing.
In that case, you will need to provide a definition for it (vedi Defining Packages in GNU Guix Reference Manual) in a dedicated channel of yours (vedi Creating a Channel in GNU Guix Reference Manual). For software in Python, R, and other high-level languages, most of the work can usually be automated by using
guix import
(vedi Invoking guix import in GNU Guix Reference Manual).Join the friendly Guix community to get help!
Successivo: Step 3: Ensuring Long-Term Source Code Archiving, Precedente: Step 1: Setting Up the Environment, Su: Using Guix for Reproducible Research [Contenuti][Indice]
Now that you have that guix shell
command line with a list of
packages, the best course of action is to save it in a manifest
file—essentially a software bill of materials—that Guix can then ingest
(vedi Writing Manifests in GNU Guix Reference Manual). The easiest
way to get started is by “translating” your command line into a manifest:
guix shell python python-numpy python-pandas \ --export-manifest > manifest.scm
Put that manifest under version control! From there anyone can redeploy the software environment described by the manifest and run code in that environment:
guix shell -C -m manifest.scm -- python3 ./myscript.py
Here’s what manifest.scm reads:
;; What follows is a "manifest" equivalent to the command line you gave. ;; You can store it in a file that you may then pass to any 'guix' command ;; that accepts a '--manifest' (or '-m') option. (specifications->manifest (list "python" "python-numpy" "python-pandas"))
It’s a code snippet that lists packages. Notice that there are no version
numbers! Indeed, these version numbers are specified in package definitions,
located in Guix channels. To allow others to reproduce the exact same
environment as the one you’re running, you need to pin Guix itself ,
by capturing the current Guix channel commits with guix describe
(vedi Replicating Guix in GNU Guix Reference Manual):
guix describe -f channels > channels.scm
This channels.scm
file is similar in spirit to “lock files” that
some deployment tools employ to pin package revisions. You should also keep
it under version control in your code, and possibly update it once in a
while when you feel like running your code against newer versions of its
dependencies. With this file, anyone, at any time and on any machine,
can now reproduce the exact same environment by running:
guix time-machine -C channels.scm -- \ shell -C -m manifest.scm -- \ python3 ./myscript.py
In this example we rely solely on the guix
channel, which provides
the Python packages we need. Perhaps some of the packages you need live
in other channels—maybe
guix-cran
if you use R, maybe guix-science
. That’s fine:
guix describe
also captures that.
Of course do include a README file giving the exact command to run the code. Not everyone uses Guix so it can be helpful to also provide minimal non-Guix setup instructions: which package versions are used, how software is built, etc. As we have seen, such instructions would likely be inaccurate and inconvenient to follow at best. Yet, it can be a useful starting point to someone trying to recreate a similar environment using different tools. It should probably be presented as such, with the understanding that the only way to get the same environment is to use Guix.
Successivo: Step 4: Referencing the Software Environment, Precedente: Step 2: Recording the Environment, Su: Using Guix for Reproducible Research [Contenuti][Indice]
We insisted on version control before: for the manifest.scm and channels.scm files, but of course also for your own code. Our recommendation is to have these two .scm files in the same repository as the code they’re about.
Since the goal is enabling reproducibility, source code availability is a prime concern. Source code hosting services come and go and we don’t want our code to vanish in a whim and render our published research work unverifiable. Software Heritage (SWH for short) is the solution for this: SWH archives public source code and provides unique intrinsic identifiers to refer to it—SWHIDs. Guix itself is connected to SWH to (1) ensure that the source code of its packages is archived, and (2) to fall back to downloading from the SWH archive should code vanish from its original site.
Once your own code is available in a public version-control repository, such as a Git repository on your lab’s hosting service, you can ask SWH to archive it by going to its Save Code Now interface. SWH will process the request asynchronously and eventually you’ll find your code has made it into the archive.
Precedente: Step 3: Ensuring Long-Term Source Code Archiving, Su: Using Guix for Reproducible Research [Contenuti][Indice]
This brings us to the last step: referring to our code and software environment in our beloved paper. We already have all our code and Guix files in the same repository, which is archived on SWH. Thanks to SWH, we now have a SWHID, which uniquely identifies the relevant revision of our code.
Following
SWH’s
own guide, we’ll pick an swh:dir
kind of identifier, which refers to
the directory of the relevant revision/commit of our repository, and we’ll
keep contextual info for clarity—that includes the original
URL. Putting it all together, we’ll conclude our paper with a sentence along
these lines:
Example: The source code used to produce this study, as well as instructions to run it in the right software environment using GNU Guix, is archived on Software Heritage as
swh:1:dir:cc8919d7705fbaa31efa677ce00bef7eb374fb80;origin=https://gitlab.inria.fr/lcourtes-phd/edcc-2006-redone;visit=swh:1:snp:71a4d08ef4a2e8455b67ef0c6b82349e82870b46;anchor=swh:1:rev:36fde7e5ba289c4c3e30d9afccebbe0cfe83853a
.
With this information, the reader can:
guix time-machine
and run the
code;
Mission accomplished!
Successivo: Gestione del Sistema Guix, Precedente: Using Guix for Reproducible Research, Su: Ricettario di GNU Guix [Contenuti][Indice]
Guix è attraente per gli scienziati e i professionisti dell’HPC (calcolo ad alte prestazioni): semplifica il deployment di stack software potenzialmente complessi e consente di farlo in modo riproducibile, permettendo di ridistribuire esattamente lo stesso software su macchine diverse e in momenti diversi.
In questo capitolo esaminiamo come un amministratore di sistema di un cluster può installare Guix per un uso a livello di sistema, in modo che possa essere utilizzato su tutti i nodi del cluster, e discutiamo i vari compromessi3
Nota: Qui si assume che il cluster stia eseguendo una distribuzione GNU/Linux diversa da Guix System e che installeremo Guix su di essa.
Successivo: Configurazione dei nodi di calcolo, Su: Installare Guix su un Cluster [Contenuti][Indice]
L’approccio raccomandato è quello di configurare un nodo head che
esegue guix-daemon
ed esporta /gnu/store tramite NFS ai
nodi di calcolo.
Ricorda che guix-daemon
è responsabile dell’avvio dei processi di
costruzione e dei download per conto dei client (vedi Invocare
guix-daemon in Manuale di riferimento GNU Guix), e più in generale
dell’accesso a /gnu/store, che contiene tutti i binari dei pacchetti
costruiti da tutti gli utenti (vedi Lo store in Manuale di
riferimento GNU Guix). “Client” qui si riferisce a tutti i comandi Guix
che gli utenti vedono, come guix install
. Su un cluster, questi
comandi potrebbero essere eseguiti sui nodi di calcolo e vorremo che
comunicassero con l’istanza guix-daemon
del nodo head.
Per iniziare, il nodo head può essere installato seguendo le solite istruzioni di installazione binaria (vedi Installazione binaria in Manuale di riferimento GNU Guix). Grazie allo script di installazione, questo dovrebbe essere rapido. Una volta completata l’installazione, dobbiamo apportare alcune modifiche.
Poiché vogliamo che guix-daemon
sia raggiungibile non solo dal nodo
head ma anche dai nodi di calcolo, dobbiamo fare in modo che ascolti le
connessioni su TCP/IP. Per fare ciò, modificheremo il file di avvio di
systemd per guix-daemon
,
/etc/systemd/system/guix-daemon.service, e aggiungeremo un argomento
--listen
alla riga ExecStart
in modo che assomigli a questo:
ExecStart=/var/guix/profiles/per-user/root/current-guix/bin/guix-daemon --build-users-group=guixbuild --listen=/var/guix/daemon-socket/socket --listen=0.0.0.0
Affinché queste modifiche abbiano effetto, il servizio deve essere riavviato:
systemctl daemon-reload systemctl restart guix-daemon
Nota: Il bit
--listen=0.0.0.0
significa cheguix-daemon
elaborerà all le connessioni TCP in entrata sulla porta 44146 (vedi Invocare guix-daemon in Manuale di riferimento GNU Guix). Questo di solito va bene in una configurazione cluster in cui il nodo head è raggiungibile esclusivamente dalla rete locale del cluster — non vuoi che sia esposto a Internet!
Il passo successivo è definire le nostre esportazioni NFS in /etc/exports aggiungendo qualcosa del genere:
/gnu/store *(ro) /var/guix *(rw, async) /var/log/guix *(ro)
La directory /gnu/store può essere esportata in sola lettura poiché
solo guix-daemon
sul nodo master la modificherà. /var/guix
contiene profili utente gestiti da guix package
; quindi, per
consentire agli utenti di installare pacchetti con guix package
,
questo deve essere in lettura-scrittura.
Gli utenti possono creare tutti i profili che desiderano oltre al profilo
predefinito, ~/.guix-profile. Ad esempio, guix package -p
~/dev/python-dev -i python
installa Python in un profilo raggiungibile dal
symlink ~/dev/python-dev
. Per assicurarsi che questo profilo sia
protetto dalla raccolta della spazzatura — cioè, che Python non venga
rimosso da /gnu/store finché questo profilo esiste —, le
directory home dovrebbero essere montate anche sul nodo head in modo
che guix-daemon
sia a conoscenza di questi profili non standard ed
eviti di raccogliere il software a cui si riferiscono.
Potrebbe essere una buona idea rimuovere periodicamente i bit inutilizzati
da /gnu/store eseguendo guix gc
(vedi Invocare guix gc in Manuale di riferimento GNU Guix). Questo può essere fatto
aggiungendo una voce crontab sul nodo head:
root@master# crontab -e
... con qualcosa del genere:
# Ogni giorno alle 5 del mattino, esegui il garbage collector per assicurarti # che ci siano almeno 10 GB liberi su /gnu/store. 0 5 * * 1 /usr/local/bin/guix gc -F10G
Abbiamo finito con il nodo head! Ora passiamo ai nodi di calcolo.
Successivo: Accesso alla Rete, Precedente: Configurazione di un nodo principale, Su: Installare Guix su un Cluster [Contenuti][Indice]
Innanzitutto, abbiamo bisogno che i nodi di calcolo montino le directory NFS che il nodo head esporta. Questo può essere fatto aggiungendo le seguenti righe a /etc/fstab:
head-node:/gnu/store /gnu/store nfs defaults,_netdev,vers=3 0 0 head-node:/var/guix /var/guix nfs defaults,_netdev,vers=3 0 0 head-node:/var/log/guix /var/log/guix nfs defaults,_netdev,vers=3 0 0
... dove head-node è il nome o l’indirizzo IP del tuo nodo head. Da lì in poi, supponendo che i punti di montaggio esistano, dovresti essere in grado di montare ognuno di questi sui nodi di calcolo.
Successivamente, dobbiamo fornire un comando guix
predefinito che
gli utenti possano eseguire quando si connettono per la prima volta al
cluster (alla fine invocheranno guix pull
, che fornirà loro il
loro “proprio” comando guix
). Simile a quanto fatto dallo script
di installazione binaria sul nodo head, lo memorizzeremo in
/usr/local/bin:
mkdir -p /usr/local/bin ln -s /var/guix/profiles/per-user/root/current-guix/bin/guix \ /usr/local/bin/guix
Dobbiamo quindi dire a guix
di comunicare con il demone in esecuzione
sul nostro nodo master, aggiungendo queste righe a /etc/profile
:
GUIX_DAEMON_SOCKET="guix://head-node" export GUIX_DAEMON_SOCKET
Per evitare avvisi e assicurarsi che guix
utilizzi la locale
corretta, dobbiamo dirgli di usare i dati di locale forniti da Guix
(vedi Configurazione dell'applicazione in Manuale di riferimento
GNU Guix):
GUIX_LOCPATH=/var/guix/profiles/per-user/root/guix-profile/lib/locale export GUIX_LOCPATH # Qui dobbiamo usare un nome di locale valido. Prova "ls $GUIX_LOCPATH/*" # per vedere quali nomi possono essere usati. LC_ALL=fr_FR.utf8 export LC_ALL
Per comodità, guix package
genera automaticamente
~/.guix-profile/etc/profile, che definisce tutte le variabili
d’ambiente necessarie per utilizzare i pacchetti — PATH
,
C_INCLUDE_PATH
, PYTHONPATH
, ecc. Allo stesso modo,
guix pull
lo fa sotto ~/.config/guix/current. Quindi è una
buona idea caricare entrambi da /etc/profile
:
for GUIX_PROFILE in "$HOME/.config/guix/current" "$HOME/.guix-profile" do if [ -f "$GUIX_PROFILE/etc/profile" ]; then . "$GUIX_PROFILE/etc/profile" fi done
Infine, Guix fornisce il completamento della riga di comando, in particolare
per Bash e zsh. In /etc/bashrc
, considera di aggiungere questa riga:
. /var/guix/profiles/per-user/root/current-guix/etc/bash_completion.d/guix
Ecco fatto!
Puoi verificare che tutto sia a posto accedendo a un nodo di calcolo ed eseguendo:
guix install hello
Il demone sul nodo principale dovrebbe scaricare i binari precompilati per
tuo conto e decomprimerli in /gnu/store, e guix install
dovrebbe creare ~/.guix-profile contenente il comando
~/.guix-profile/bin/hello.
Successivo: Utilizzo del Disco, Precedente: Configurazione dei nodi di calcolo, Su: Installare Guix su un Cluster [Contenuti][Indice]
Guix richiede l’accesso alla rete per scaricare il codice sorgente e i binari precompilati. La buona notizia è che solo il nodo principale ne ha bisogno, poiché i nodi di calcolo si limitano a delegare a esso.
È consuetudine che i nodi del cluster abbiano accesso, nella migliore delle
ipotesi, a una white list di host. Il nostro nodo principale ha
bisogno almeno di ci.guix.gnu.org
in questa white list, poiché è da
qui che ottiene i binari precompilati per impostazione predefinita, per
tutti i pacchetti presenti in Guix.
Per inciso, ci.guix.gnu.org
funge anche da mirror con
indirizzamento per contenuto del codice sorgente di tali pacchetti. Di
conseguenza, è sufficiente avere only ci.guix.gnu.org
in
quella white list.
I pacchetti software mantenuti in un repository separato, come uno dei vari
canali HPC, non sono disponibili da
ci.guix.gnu.org
. Per questi pacchetti, potresti voler estendere la
white list in modo che il sorgente e i binari precompilati (supponendo che i
server di terze parti forniscano binari per questi pacchetti) possano essere
scaricati. Come ultima risorsa, gli utenti possono sempre scaricare il
sorgente sulla propria workstation e aggiungerlo a /gnu/store del
cluster, in questo modo:
GUIX_DAEMON_SOCKET=ssh://compute-node.example.org \ guix download http://starpu.gforge.inria.fr/files/starpu-1.2.3/starpu-1.2.3.tar.gz
Il comando sopra scarica starpu-1.2.3.tar.gz
and lo invia
all’istanza guix-daemon
del cluster tramite SSH.
I cluster isolati richiedono più lavoro. Al momento, il nostro suggerimento
sarebbe quello di scaricare tutto il codice sorgente necessario su una
workstation che esegue Guix. Ad esempio, usando l’opzione --sources
di guix build
(vedi Invocare guix build in Manuale di
riferimento di GNU Guix), l’esempio seguente scarica tutto il codice
sorgente da cui dipende il pacchetto openmpi
:
$ guix build --sources=transitive openmpi … /gnu/store/xc17sm60fb8nxadc4qy0c7rqph499z8s-openmpi-1.10.7.tar.bz2 /gnu/store/s67jx92lpipy2nfj5cz818xv430n4b7w-gcc-5.4.0.tar.xz /gnu/store/npw9qh8a46lrxiwh9xwk0wpi3jlzmjnh-gmp-6.0.0a.tar.xz /gnu/store/hcz0f4wkdbsvsdky3c0vdvcawhdkyldb-mpfr-3.1.5.tar.xz /gnu/store/y9akh452n3p4w2v631nj0injx7y0d68x-mpc-1.0.3.tar.gz /gnu/store/6g5c35q8avfnzs3v14dzl54cmrvddjm2-glibc-2.25.tar.xz /gnu/store/p9k48dk3dvvk7gads7fk30xc2pxsd66z-hwloc-1.11.8.tar.bz2 /gnu/store/cry9lqidwfrfmgl0x389cs3syr15p13q-gcc-5.4.0.tar.xz /gnu/store/7ak0v3rzpqm2c5q1mp3v7cj0rxz0qakf-libfabric-1.4.1.tar.bz2 /gnu/store/vh8syjrsilnbfcf582qhmvpg1v3rampf-rdma-core-14.tar.gz ...
(Nel caso ti stia chiedendo, si tratta di più di 320 MiB di codice sorgente compressed.)
Possiamo quindi creare un grande archivio contenente tutto questo (vedi Invocare guix archive in Manuale di riferimento di GNU Guix):
$ guix archive --export \ `guix build --sources=transitive openmpi` \ > openmpi-source-code.nar
… e possiamo eventualmente trasferire quell’archivio al cluster su memoria rimovibile e decomprimerlo lì:
$ guix archive --import < openmpi-source-code.nar
Questo processo deve essere ripetuto ogni volta che è necessario portare nuovo codice sorgente al cluster.
Mentre scriviamo, gli istituti di ricerca coinvolti in Guix-HPC non hanno cluster isolati. Se hai esperienza con tali configurazioni, ci piacerebbe ricevere il tuo feedback e suggerimenti.
Successivo: Considerazioni sulla Sicurezza, Precedente: Accesso alla Rete, Su: Installare Guix su un Cluster [Contenuti][Indice]
Una preoccupazione comune degli amministratori di sistema è se tutto questo consumerà molto spazio su disco. Semmai, se qualcosa esaurirà lo spazio su disco, saranno i set di dati scientifici piuttosto che il software compilato — questa è la nostra esperienza con quasi dieci anni di utilizzo di Guix sui cluster HPC. Ciononostante, vale la pena dare un’occhiata a come Guix contribuisce all’utilizzo del disco.
Innanzitutto, avere diverse versioni o varianti di un dato pacchetto in
/gnu/store non costa necessariamente molto, perché
guix-daemon
implementa la deduplicazione di file identici, e le
varianti dei pacchetti probabilmente avranno un certo numero di file comuni.
Come accennato in precedenza, consigliamo di avere un cron job per eseguire
guix gc
periodicamente, che rimuove il software unused da
/gnu/store. Tuttavia, c’è sempre la possibilità che gli utenti
mantengano molto software nei loro profili, o molte vecchie generazioni dei
loro profili, che è “vivo” e non può essere eliminato dal punto di vista
di guix gc
.
La soluzione a questo è che gli utenti rimuovano regolarmente le vecchie generazioni del loro profilo. Ad esempio, il seguente comando rimuove le generazioni più vecchie di due mesi:
guix package --delete-generations=2m
Allo stesso modo, è una buona idea invitare gli utenti ad aggiornare regolarmente il proprio profilo, il che può ridurre il numero di varianti di un dato pezzo di software memorizzato in /gnu/store:
guix pull guix upgrade
Come ultima risorsa, è sempre possibile per gli amministratori di sistema fare parte di questo per conto dei loro utenti. Tuttavia, uno dei punti di forza di Guix è la libertà e il controllo che gli utenti ottengono sul loro ambiente software, quindi raccomandiamo vivamente di lasciare gli utenti in controllo.
Precedente: Utilizzo del Disco, Su: Installare Guix su un Cluster [Contenuti][Indice]
Su un cluster HPC, Guix è tipicamente usato per gestire software
scientifico. Software critici per la sicurezza come il kernel del sistema
operativo e i servizi di sistema come sshd
e lo scheduler di batch
rimangono sotto il controllo degli amministratori di sistema.
Il progetto Guix ha un buon track record nel fornire aggiornamenti di
sicurezza in modo tempestivo (vedi Aggiornamenti di sicurezza in Manuale di riferimento di GNU Guix). Per ottenere gli aggiornamenti di
sicurezza, gli utenti devono eseguire guix pull && guix upgrade
.
Poiché Guix identifica in modo univoco le varianti del software, è facile vedere se un pezzo di software vulnerabile è in uso. Ad esempio, per verificare se la variante glibc 2.25 senza la patch di mitigazione contro “Stack Clash”, si può controllare se i profili utente vi fanno riferimento in assoluto:
guix gc --referrers /gnu/store/...-glibc-2.25
Questo riporterà se esistono profili che fanno riferimento a questa specifica variante di glibc.
Successivo: Ringraziamenti, Precedente: Installare Guix su un Cluster, Su: Ricettario di GNU Guix [Contenuti][Indice]
Poiché Guix non gestisce il packaging, la configurazione del sistema e i servizi nel modo in cui lo fanno altre distribuzioni (più “classiche”), alcuni flussi di lavoro tendono a svolgersi in modo leggermente diverso da come siamo abituati e necessitano di un leggero adattamento. Questo capitolo intende aiutare con tali questioni.
Con la deprecazione del valore predefinito per il pacchetto postgres in postgresql-configuration (vedi b93434e656eba4260df82158a96c295000d3ff44), gli aggiornamenti di sistema richiedono alcune azioni manuali prima di poter aver luogo. Ecco una pratica guida su come fare.
Si prega di notare che questo è un modo diretto per dataset più piccoli. Per
database più grandi
pg_upgrade
potrebbe essere la scelta migliore. La gestione del
servizio e l’aggiornamento del sistema come descritto in questa guida si
applicano comunque.
Impedisci al servizio di avviarsi e fallire dopo una riconfigurazione:
sudo herd stop cuirass && sudo herd disable cuirass
sudo su - postgres -s /bin/sh -c pg_dumpall > /tmp/pg.dump
A seconda che il tuo servizio postgres sia definito implicitamente (tramite
la dipendenza dal servizio cuirass) o con una propria voce nella proprietà
(services)
del tuo sistema operativo, devi aggiungere o modificare la
configurazione esistente per riflettere l’aggiornamento della versione
desiderata.
Fai attenzione a non aggiornare direttamente a postgres-16 – il servizio cuirass per qualche motivo non lo gradisce. Ho dovuto trovare ed eliminare i file rilevanti e poi reinizializzare dopo un aggiornamento fallito a postgres 16.
(service postgresql-service-type
(postgresql-configuration
(postgresql (@ (gnu packages databases) postgresql-15))))
Nota: Se per qualche motivo non hai letto il testo qui ma hai seguito ciecamente gli esempi e hai aggiornato alla versione 16, ecco come reimpostare lo stato:
Per impostazione predefinita si trovano in /var/lib/postgres/data.
sudo su - postgres -s /bin/sh -c 'pg_ctl init -D /var/lib/postgres/data'
sudo guix system reconfigure path/to/your/altered/config.scm
sudo su - postgres -s /bin/sh -c 'psql -d postgres -f /tmp/pg.dump'
sudo herd enable cuirass sudo herd start cuirass
Successivo: Licenza di Documentazione Libera GNU, Precedente: Gestione del Sistema Guix, Su: Ricettario di GNU Guix [Contenuti][Indice]
Guix è basato sul gestore di pacchetti Nix, progettato e implementato da Eelco Dolstra, con contributi di altre persone (vedi il file nix/AUTHORS in Guix). Nix ha aperto la strada alla gestione funzionale dei pacchetti e ha promosso funzionalità senza precedenti, come gli aggiornamenti e i rollback transazionali dei pacchetti, i profili per utente e i processi di costruzione referenzialmente trasparenti. Senza questo lavoro, Guix non esisterebbe.
Le distribuzioni software basate su Nix, Nixpkgs e NixOS, sono state anche un’ispirazione per Guix.
GNU Guix stesso è un lavoro collettivo con contributi di diverse persone. Consulta il file AUTHORS in Guix per maggiori informazioni su queste persone. Il file THANKS elenca le persone che hanno contribuito segnalando bug, curando l’infrastruttura, fornendo grafica e temi, dando suggerimenti e altro ancora — grazie!
Questo documento include sezioni adattate da articoli precedentemente pubblicati sul blog di Guix all’indirizzo https://guix.gnu.org/blog e sul blog di Guix-HPC all’indirizzo https://hpc.guix.info/blog.
Successivo: Indice dei concetti, Precedente: Ringraziamenti, Su: Ricettario di GNU Guix [Contenuti][Indice]
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.
The “publisher” means any person or entity that distributes copies of the Document to the public.
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.
“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.
An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (C) year your name. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''.
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:
with the Invariant Sections being list their titles, with the Front-Cover Texts being list, and with the Back-Cover Texts being list.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
Precedente: Licenza di Documentazione Libera GNU, Su: Ricettario di GNU Guix [Contenuti][Indice]
Salta a: | 2
A B C D E G H I K L M N Q R S U W Y |
---|
Salta a: | 2
A B C D E G H I K L M N Q R S U W Y |
---|
Questo capitolo è adattato da un post del blog pubblicato a giugno 2023 sul sito web di Guix.
This chapter is adapted from a blog post published on the Guix-HPC web site in 2023..
Questo capitolo è adattato da un post del blog pubblicato sul sito web di Guix-HPC nel 2017.