28 KiB
Private Docker Registry
1. Introduzione
Le informazioni contenute in questa guida sono frutto di una serie di approfondimenti condotti al fine di realizzare un ambiente operativo idoneo allo studio e alla sperimentazione di Docker e Kubernetes. In particolare, l’impulso iniziale per tale approfondimento è scaturito dal tentativo di esecuzione del comando kubectl per creare ed esegure un Pod:
kubectl run
nome-pod --image=
nome-immagine
L’effettivo funzionamento di questo comando è subordinato alla reperibilità dell’immagine richiesta. Se l’immagine specificata con nome-immagine non può essere ritrovata, il Pod creato non entrerà in funzione. Questa situazione si è in effetti verificata seguendo le indicazioni pratiche del libro Kubernetes Up and Running. Le istruzioni fornite nel libro presuppongono la disponibilità del servizio gcr.io per il caricamento e il recupero di immagini Docker, ovvero un servizio registry.
$ kubectl run kuard --image=gcr.io/kuar-demo/kuard-amd64:blue
pod/kuard created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kuard 0/1 ErrImagePull 0 6s
L’errore riportato, ErrImagePull, indica l’impossibilità di scaricare l’immagine richiesta. Le cause di queto tipo di problema possono essere diverse. In questo caso l’errore è dovuto al fatto che il servizio gcr.io è stato deprecato e che quindi non è stato possibile caricarvi l’immagine non essendo il servizio più disponibile.
Per proseguire con lo studio del libro è stato perciò necessario trovare una soluzione alternativa al registry gcr.io. Fra le possibilità considerate, si è alla fine deciso predisporre un registry privato.
Questa guida descrive appunto l’infrastruttura hardware e software impiegata per la soluzione e le procedure per realizzarla.
2. Infrastruttura hardware e software
Lo studio sui container e sulla loro orchestrazione si è inizialmente concentrato sulla costruzione e gestione di un cluster Kubernetes. Per tale finalità è stata impiegata una macchina virtuale Linux con sistema operativo Fedora 42. La macchina virtuale è attiva su un mini-pc casalingo anch’esso funzionante con Fedora 42.
In seguito al verificarsi della situazione descritta in introduzione, nell’ambiente è stato incluso anche un server remoto VPS esposto su Internet nel quale è stato appunto realizzato il servizio registry privato.
2.1. Cluster Kubernetes
Per la realizzazione del cluster Kubernetes è stata impiegata una macchina virtuale Fedora 42 con le seguenti caratteristiche.
2.1.1. Componenti hadware
Caratteristica |
Valore |
Host-name |
fedoravm |
Sistema operativo |
Fedora 42 |
Hypervisor |
QEMU/KVM |
Tipo CPU |
x86_64 |
Numero CPU |
2 |
Memoria |
4 GB |
Storage |
60 GB |
Network |
Bridge (rete LAN domestica) |
La macchina virtuale fedoravm è eseguita su host Minis Forum, attualmente connesso alla rete LAN domestica mediante link WiFi. Il sistema operativo del mini-pc è raggiungibile via SSH da Internet grazie all’impostazione di un port-forward sul router di casa.
Caratteristica |
Valore |
Host-name |
minis.portale-stac.it |
Sistema operativo |
Fedora 42 |
Tipo CPU |
12th Gen Intel® Core™ i7-12650H (x86_64) |
Numero CPU logiche |
16 |
Memoria |
32 GB |
Storage |
1 TB SSD M.2 NVMe |
Network |
2 Ethernet, 1 WiFi |
2.1.2. Componenti software
Per l’uso di Docker su fedoravm sono stati installati i pacchetti disponibili in Fedora 42.
docker-buildx.x86_64 0.25.0-1.fc42 docker-cli.x86_64 28.2.2-1.fc42
Per altre sperimentazioni, sul sistema è anche presente il pacchetto podman.x86_64 5:5.5.2-1.fc42.
Fra le opzioni dispobili per la creazione di un cluster Kubernetes è stato scelto KinD, Kubernetes in Docker, o più semplicemente kind. I requisiti per l’installazione di kind sono
[fedoravm]$ go install sigs.k8s.io/kind@v0.29.0
...
Il commando di soprà scaricherà una serie di moduli Go e produrrà l’eseguibile kind nel path ~/go/bin/kind
.
[fedoravm]$ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
[fedoravm]$ sudo mv kubectl /usr/local/bin (1)
1 | todo verificare funzionamento comando |
Per ulteriori informazioni vedere Install and Set Up kubectl on Linux Before you
[fedoravm]$ kind create cluster
...
[fedoravm]$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:34905
CoreDNS is running at https://127.0.0.1:34905/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Per soluzioni alternive a kind vedere minikube, Killercoda, KodeKloud, Play with Kubernetes.
2.2. Docker registry
Per la realizzazione di un docker registry esistono diverse guide nel web. Tali guide spiegano come attivare un servizio registry basato sull’omonima immagine disponibile su Docker Hub e utilizzando una configurazione Docker Compose. Ecco alcuni riferimenti per l’attivazione di un registry su un proprio sistema:
Un’altra possibilità è l’uso di Harbor.
La soluzione descritta in questa guida si basa su un Virtual Private Server, VPS, sul quale sono già attivi dei servizi raggiungibili tramite il dominio portale-stac.it. Esempi:
Sullo stesso server è inoltre in corso di sperimentazione un’installazione di CapRover, la cui console è raggiungibile all’URL Captain. Per le app attive in CapRover è stato registrato nel DNS di Aruba il recordo *.paas.portale-stac.it. In tal modo ad un’app chiamata ad esempio myapp sarà automaticamente assgnato il nome host myapp.paas.portale-stac.it.
Sia i servizi preesstenti che la console CapRover non sono direttamente esposti su Internet ma mediati tramite un reverse proxy basato su Apache web server, httpd, e i suoi virtual host.
In questo contesto si è deciso quindi di realizzare un registry attraverso i seguenti passaggi:
-
Creazione di un app CapRover con nome hub in cui eseguire il servizio registry
-
Definizione dell’app basata sull’immagine registry di Docker Hub.
-
Creazione di un volume per lo storage delle immagini
-
Configurazione di un meccanismo di autenticazione
-
-
Configurazione di un nuovo virtual-host per la raggiungibilità del registry da Internet (gateway).
-
Il nome di dominio assegnato è hub.paas.portale-stac.it.
-
2.2.1. Creazione registry come app CapRover
Come accennato sopra, il nome scelto per l’app CapRover che implementarà il registry Docker è hub e, di conseguenza, essendo paas.portale-stac.it il sotto-dominio assegnato all’istanza CapRover, il suo nome di dominio completo risulta hub.paas.portale-stac.it.
Il registry si basa sull’immagine registry:3 disponibile in Docker Hub. Il programma contenuto nell’immagine e che implementa il servizio registry si chiama anch’esso registry. Ciò che serve sapere dell’immagine e del programma che esegue sono le variabili d’ambiente necessarie al suo funzionamento. Quelle considerate nel caso in esame sono le seguenti:
# Tipo di credenziali
REGISTRY_AUTH=htpasswd
# Dominio delle credenziali
REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
# Percorso logico dell'archivio (file) delle credenziali
REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password
# Percorso logico della directory delle immagini Docker
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/data
L’app hub attualmente in funzione sull’istanza CapRover è stata creata attraverso l’interfaccia web Captain.
In questa sezione si ripercorrono i passaggi eseguiti nel VPS per giungere al docker registry funzionante.
Predisposizione dei volumi logici del registry
Dai valori delle variabili d’ambiente REGISTRY_AUTH_HTPASSWD_PATH e REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY si ricava che, per il suo funzionamento, l’appplicazione eseguita nell’immagine registry necessita di due aree di storage che sopravvivano all’app stessa:
-
File delle credenziali degli utenti per l’accesso al registry
-
Directory del registro vero e proprio, dove l’app archivia le immagini dei container.
Nel container dell’app saranno definiti quindi due volumi logici:
-
/auth nel quale sarà reperibile il file delle credenziali registry.password.
-
/data in cui saranno registrate le immagini.
La configurazione predefinita di Docker in Fedora predispone nel server host la directory fisica /var/lib/docker/volumes
nella quale sono creati i volumi fisici corrispondenti a quelli logici dei container.
Normalmente i nomi delle directory fisiche dei volumi sono identificate con stringhe alfanumeriche, ad esempio fc17967070f949c325b6417388d6e600f69d6fe8b55fda99e04ff4a48cce072d, non riconducibili immediatamente ai container che fanno riferimento a quelle directory tramite i rispettivi volumi logici.
CapRover ha fissato una convenzione basata su etichette per la creazione delle directory dei volumi fisici con nomi predittibili. Nell’associazione fra volumi logici e fisici, CapRover consente in alternativa di indicare in modo esplicito il percorso fisico delle directory. Quest’ultima soluzione è quella adottata per l’app registry hub.
Per l’esecuzione dei comandi seguenti sono richiesti privilegi di amministratore sul server fisico, accessibilità SSH e il tool htpasswd.
Accedere al VPS mediante SSH.
# Variabile utile per abbreviare i percorsi
[vps]$ VOLUMES=/var/lib/docker/volumes
# Creazione delle directory fisiche
[vps]$ sudo mkdir -p ${VOLUMES}/manual--hub-registry/data
# Creazione archivio delle credenziali con l'utente iniziale camoroso
[vps]$ sudo htpasswd -c -B ${VOLUMES}/manual--hub-registry/registry.password camoroso
Per ragioni storiche, il vero host name del VPS è impostato col nome di dominio www.portale-stac.it. In questa sede, nelle sessioni CLI si è preferito indicare il VPS con il nome vps per meglio identificare l’host su cui si deve operare. |
Nel comando htpasswd l’opzione -c è richiesta solo per la creazione del file, mentre -B è necessario per selezionare la modalità bcrypt riconosciuta dal programma registry.
|
Creazione del reverse proxy
Per consetire l’accesso al registry da Internet, l’implementazione del gateway, anche detto reverse proxy, richiede di:
-
Creare un nuovo record di tipo A nel servizio DNS per impostare il puntamento del nome hub.paas.portale-stac.it all’indirizzo IP del server VPS.
-
Ottenere un certificato digtale firmato da una CA pubblica per il nome hub.paas.portale-stac.it.
-
Configurare un nuovo virtual-host in Apache web server per il gateway vero e proprio.
Nel caso del dominio portale-stac.it il DNS di riferimento (Aruba) è già configurato per indirizzare l’intero sotto-dominio paas.portale-stac.it all’indirizzo IP del VPS.
Per quanto riguarda il certificato digitale, il web server Apache fa già uso di un certificato Let’s encrypt SAN (Subject Alternative Names),. Per semplificare le operazioni si effettua una nuova richiesta per lo stesso certificato SAN con l’aggiunta del nome hub.paas.portale-stac.it.
Prima di procedere con il certificato, conviene definire il virtual-host Apache perché nella sua configurazione si specifica il percorso del DocumentRoot utilizzato dal tool di richiesta dei certificati Let’s encrypt.
Unresolved directive in <stdin> - include::vhost_hub.conf[]
Usando privilegi di amministratore (root o sudo), copiare la configurazione del virtual-host nel file:
/etc/httpd/conf.d/vhost_hub.paas.conf
La configurazione del virtual-host potrebbe eventualmente essere completata con ulteriori parametri di mod_ssl per, ad esempio, selezionare i protocolli SSL/TLS supportati e gli algoritmi crittografici ammessi. Ciò però non è necessario perché il tool certbot, utilizzato per l’aggiornamento del certificato SAN, estende automaticamente la configurazione con i parametri più appropriati e sicuri (vedi oltre).
# Directory DocumentRoot
[vps]$ sudo mkdir -p /var/www/vhosts/paas.portale-stac.it/hub
# Directory log
[vps]$ sudo mkdir -p /var/log/httpd/paas.portale-stac.it/hub
# Riavvio Apache web server
[vps]$ sudo systemctl restart httpd.service
# Verifica assenza di problemi
[vps]$ sudo systemctl httpd.service
Per l’estensione del certificato SAN con il nuovo nome si utilizza il tool certbot, disponibile nei pacchetti di Fedora.
# Elenco abbreviato dei domini (notare puntini sospensivi ...)
[vps]$ sudo certbot -d cloud.portale-stac.it,git.portale-stac.it,captain.paas.portale-stac.it,hub.paas.portale-stac.it,...,www.portale-stac.it
Il comando certbot, dopo aver ottenuto il nuovo certificato, procede con la revisione di tutti i virtual-host presenti in /etc/httpd/conf.d
aggiungendo o aggiornando le seguenti righe alle loro configurazioni:
Unresolved directive in <stdin> - include::letsencrypt-section.conf[]
# Riavvio Apache web server
[vps]$ sudo systemctl restart httpd.service
# Verifica assenza di problemi
[vps]$ sudo systemctl httpd.service
La configurazione del virtual-host a questo punto è completa ma non è ancora operativo in quanto il server effettivo al quale il gateway punta, hub.paas.portale-stac.it:5000, non è ancora stato creato.
2.2.2. Creazione app registry in CapRover
Per la creazione dell’app registry in CapRover, si farà uso della console Captain.
Accedere alla console puntando il browser all’URL https://captain.paas.portale-stac.it e autenticarsi nella form di login.
Creazione app
Nel menù di sinistra cliccare su Apps e, quindi, sul bottone Create A New App sulla destra, in alto.
Nella casella di testo my amazing app inserire il nome dell’app, in questo caso hub, e sotto la casella spuntare il check-box Has Persistent Data.
La spunta su "Has Persistent Data" è fondamentale perché, se assente, non si potranno definire i volumi logici nel container. |
A questo punto procedere con la creazione cliccando sul bottone Create New App.
Dopo la creazione, l’app hub compare nell’elenco delle app dell’istanza CapRover.
Cliccare sul nome hub nella colonna App Name per accedere alla GUI di configurazione dell’app.
Variabili d’ambiente
Attivare la scheda App Config. Qui si imposterà il maggior numero di parametri richiesti per il registry.
Definire le variabili d’ambiente anticipate in Variabili d’ambiente nella sezione "Environment Variables". Per facilitare l’inserimento cliccare sul commutatore "Bulk Edit" che attiverà l’inserimento testuale. Copiare le variabili seguenti nell’editor appena attivato.
REGISTRY_AUTH=htpasswd
REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/data
A propria convenienza, dopo l’inserimento disattivare l’editor cliccando nuovamente sul commutatore Bulk Edit.
Port mapping
Definizione della mappatura fra la porta interna 5000 impostanta nella sezione HTTP e quella esterna, anch’essa di valore 5000:
Definizione volumi
Nella sezione Persistent Directory aggiungere due directory cliccando sul bottone Add Persistent Directory:
Attivare la corrispondenza esplicita fra i volumi logici e le directory fisiche cliccando sui bottoni Set specific host path e impostare le caselle di testo con i valori indicati in Volumi.
/auth --> /var/lib/docker/volumes/manual--hub-registry /data --> /var/lib/docker/volumes/manual--hub-registry/data
Il risultato dovrà apparire come in figura.
Deploy immagine registry
Infine si deve indicare l’immagine registry di Docker Hub in cui è presente l’applicazione che implementa effettivamente il servizio.
La scheda Deployment consente diversi metodi per il deploy di un’applicazione, sia partendo dai sorgenti che da immagini già pronte all’uso. Per il registry fornito come immagine si possono considerare i metodi dal 4 al 6.
Nel caso attuale è stato utilizzato il metodo 4, Method 4: Deploy plain Dockerfile. In pratica, nella corrispondente casella di testo è stato inserita la sola direttiva FROM del Dockerfile con il testo seguente.
FROM registry:3 AS registry
Copiare il testo di sopra nella casella di testo come mostrato in figura.
Cliccare sul bottone Deploy Now per avviare il caricamento dell’immagine e la sua attivazione.
Verifica finale
La procedura di deploy è completa. Verificare il funzionamento del registry effettuando il login e provare a caricarvi un’immagine Docker.
[fedoravm]$ docker login -u camoroso https://hub.paas.portale-stac.it
Password:
Login Succeeded
[fedoravm]$ docker push hub.paas.portale-stac.it/kuard-amd64:amo1
The push refers to repository [hub.paas.portale-stac.it/kuard-amd64]
96844c0866be: Layer already exists
fd2758d7a50e: Layer already exists
amo1: digest: sha256:f8ff90f6715f4708afe556f5b708befeb5f0480c175fc369c2e59202f3374f04 size: 739
3. Pod Kubernetes con immagine dal registry
Con le procedure spiegate nel capitolo precedente è stato realizzato un servizio registry per immagini Docker. In questo capitolo si esaminano le condizioni e le azioni che consentono la creazione di Pod Kubernetes che utilizzano immagini scaricate dal servizio registry creato.
Nella prima parte di questo capitolo si mostra come definire e creare un Pod attraverso un file manifest. In seguito si capirà come eseguire direttamente procedere con l’esecuzione diretta di un Pod con il comando "kubectl run …".
Di seguito i link ad alcune pagine della documentazione Kubernetes utili per il tema del capitolo.
3.1. File manifest
Un file manifest definisce le caratteristiche di un oggetto Kubernetes, ad esempio quelle di un Pod.
L’esempio seguente specifica gli attributi di un Pod per l’esecuzione dell’applicazione kuard. In particolare, specifica che la sorgente dell’immagine da utilizzare per il container è quella caricata nel registry privato hub.paas.portale-stac.it.
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: hub.paas.portale-stac.it/kuard-amd64:amo1
name: kuard
ports:
- containerPort: 8080
name: http
protocol: TCP
Se si tentasse di attivare il Pod secondo la specifica di sopra, si otterrebbe l’errore ErrImagePull che indica l’impossibilità di scaricare l’immagine richiesta.
Per verificare questa situazione, registrare il manifest nel file YAML kuard-pod.yaml ed eseguire le istruzioni seguenti.
# Creazione del Pod
[fedoravm]$ kubectl apply -f kuard-pod.yaml
pod/kuard created
# Stato del Pod: ErrImagePull
[fedoravm]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kuard 0/1 ErrImagePull 0 5s
# Distruzione del Pod
[fedoravm]$ kubectl delete pods/kuard
pod "kuard" deleted
In questo caso, la causa dell’errore risiede nel fatto che il Pod non dispone delle credenziali per accedere al registry remoto.
Per risolvere questo problema è necessario, innanzitutto, definire un oggetto contenitore per le credenziali, detto secret. Poi serve associare questo oggetto al Pod che le utilizzerà.
L’associazione di un secret ad un Pod può essere effetuata in due modi:
-
associazione diretta, con specifica del secret nel Pod manifest;
-
associazione indiretta, mediante l’uso di ServiceAccount.
3.1.1. Creazione secret
I secret sono oggetti che consentono ai Pod l’accesso a servizi esterni. Esistono diversi tipi di credenziali, una delle quali è quella basata su username e password per accedere ai registry delle immagini Docker.
La pagina di riferimento nella documentazione Kubernetes è Secret.
Copia credenziali Docker
Le credenziali Docker possono essere recuperate dal suo file di configurazione ~/.docker/config.json
nel quale sono registrate automaricamente dal comando docker dopo un’operazione di login conclusa con successo. Questa modalità è appropriata per connessioni a servizi registry.
Se non già fatto, eseguire il login al registry con il comando docker.
[fedoravm]$ docker login -u camoroso https://hub.paas.portale-stac.it
Password:
Login Succeeded
[fedoravm]$ cat ~/.docker/config.json
{
"auths": {
"hub.paas.portale-stac.it": {
"auth": "Y2Ftb3Jvc286SHViLkFtbw=="
}
}
}
Procedere ora con la creazione del secret con le credenziali registrate dal login in ~/.docker/config.json
.
# Creazione secret con nome regcred
[fedoravm]$ kubectl create secret generic regcred \
--from-file=.dockerconfigjson=${HOME}/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
# Verifica secret
[fedoravm]$ kubectl get secret regcred --output=yaml
apiVersion: v1
data:
.dockerconfigjson: ewoJImF1dGhzIjogewoJCSJodWIucGFhcy5wb3J0YWxlLXN0YWMuaXQiOiB7CgkJCSJhdXRoIjogIlkyRnRiM0p2YzI4NlNIVmlMa0Z0Ync9PSIKCQl9Cgl9Cn0=
kind: Secret
metadata:
creationTimestamp: "2025-07-04T20:23:17Z"
name: regcred
namespace: default
resourceVersion: "284323"
uid: 6ca08567-aa66-455d-8245-ab0e8a48d3c4
type: kubernetes.io/dockerconfigjson
# Eventualmente, è possibile richiedere uno specifico attributo
[fedoravm]$ kubectl get secret regcred \
--output="jsonpath={.data.\.dockerconfigjson}"
ewoJImF1dGhzIjogewoJCSJodWIucGFhcy5wb3J0YWxlLXN0YWMuaXQiOiB7CgkJCSJhdXRoIjogIlkyRnRiM0p2YzI4NlNIVmlMa0Z0Ync9PSIKCQl9Cgl9Cn0=
# Lista dei secrets
[fedoravm]$ kubectl get secrets
NAME TYPE DATA AGE
regcred kubernetes.io/dockerconfigjson 1 4d10h
3.1.2. Associazione del secret al Pod
L’associazione al Pod del secret creato si realizza semplicemente aggiungendo l’attributo imagePullSecrets al file manifest.
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: hub.paas.portale-stac.it/kuard-amd64:amo1
name: kuard
ports:
- containerPort: 8080
name: http
protocol: TCP
imagePullSecrets:
- name: regcred
Salvare la modifica nel file manifest ed attivare il Pod come mostrato in Attivazione Pod. Questa volta lo stato dovrebbe essere Running.
3.1.3. Creazione di un ServiceAccount
todo, spiegare la funzione dei ServiceAccount
# Creazione ServiceAccount
[fedoravm]$ kubectl create serviceaccount amo-sc
serviceaccount/amo-sc created
# Associazione del secret regcred al ServiceAccount
[fedoravm]$ kubectl patch serviceaccount amo-sc \
-p '{"imagePullSecrets": [{"name": "regcred"}]}'
serviceaccount/amo-sc patched
3.1.4. Associazione del ServiceAccount al Pod
Anche l’associazione del ServiceAccount al Pod si esegue con l’aggiunta di un attributo, serviceAccountName.
apiVersion: v1
kind: Pod
metadata:
name: kuard
spec:
containers:
- image: hub.paas.portale-stac.it/kuard-amd64:amo1
name: kuard
ports:
- containerPort: 8080
name: http
protocol: TCP
serviceAccountName: amo-sc
Anche in questo caso, verificare il funzionamento del Pod con i comandi di Attivazione Pod.
Celestino Amoroso
celestino . amoroso @ gmail . com
