Files
proxmox-ha-setup/scripts/DOCKER_REGISTRY_GUIDE.md
2025-11-29 19:51:15 +01:00

611 lines
16 KiB
Markdown

# Guida Docker Registry Privato
Questa guida spiega come configurare un registry Docker privato e utilizzare gli script per buildare e distribuire le immagini degli orchestrator.
## Indice
1. [Setup Registry Docker Privato](#setup-registry-docker-privato)
2. [Protezione Codice Sorgente (Bytecode)](#protezione-codice-sorgente-bytecode)
3. [Build e Push dell'Immagine](#build-e-push-dellimmagine)
4. [Aggiornamento Docker Compose](#aggiornamento-docker-compose)
5. [Deploy sulle VM](#deploy-sulle-vm)
---
## Setup Registry Docker Privato
### Opzione 1: Registry Locale Semplice (HTTP - Solo per sviluppo)
```bash
# Avvia un registry Docker locale sulla porta 5000
docker run -d -p 5000:5000 --name registry --restart=always registry:2
# Verifica che sia in esecuzione
curl http://localhost:5000/v2/_catalog
```
### Opzione 2: Registry Locale con Persistenza
```bash
# Crea directory per i dati
mkdir -p /opt/docker-registry/data
# Avvia registry con volume persistente
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /opt/docker-registry/data:/var/lib/registry \
registry:2
```
### Opzione 3: Registry con HTTPS (Certificato Self-Signed con SANs)
⚠️ **IMPORTANTE**: I certificati moderni devono usare Subject Alternative Names (SANs) invece del campo Common Name.
```bash
# Usa lo script per generare certificati corretti
./scripts/generate-registry-cert.sh 192.168.1.204 registry.local
# Oppure manualmente:
mkdir -p /opt/docker-registry/{data,certs}
# Crea file di configurazione OpenSSL con SANs
cat > /opt/docker-registry/certs/openssl.cnf << 'EOF'
[req]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
C = IT
ST = Italy
L = City
O = Docker Registry
CN = registry.local
[req_ext]
subjectAltName = @alt_names
[v3_ca]
subjectAltName = @alt_names
basicConstraints = critical, CA:TRUE
keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign
extendedKeyUsage = serverAuth
[alt_names]
DNS.1 = registry.local
DNS.2 = localhost
IP.1 = 192.168.1.204
IP.2 = 127.0.0.1
EOF
# Genera certificato con SANs
openssl req -newkey rsa:4096 \
-nodes -sha256 \
-keyout /opt/docker-registry/certs/domain.key \
-x509 -days 365 \
-config /opt/docker-registry/certs/openssl.cnf \
-out /opt/docker-registry/certs/domain.crt
# Verifica SANs nel certificato
openssl x509 -in /opt/docker-registry/certs/domain.crt -text -noout | grep -A 3 "Subject Alternative Name"
# Avvia registry con HTTPS
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /opt/docker-registry/data:/var/lib/registry \
-v /opt/docker-registry/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
```
### Opzione 4: Registry con Autenticazione + HTTPS
```bash
# Genera certificati (vedi Opzione 3)
./scripts/generate-registry-cert.sh 192.168.1.204 registry.local
# Crea utente e password
mkdir -p /opt/docker-registry/auth
docker run --rm --entrypoint htpasswd httpd:2 \
-Bbn myuser mypassword > /opt/docker-registry/auth/htpasswd
# Avvia registry con autenticazione e HTTPS
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /opt/docker-registry/data:/var/lib/registry \
-v /opt/docker-registry/auth:/auth \
-v /opt/docker-registry/certs:/certs \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
# Login al registry
docker login 192.168.1.204:5000
```
### Configurazione Client Docker per Registry HTTPS (Self-Signed)
Se usi certificati self-signed, devi installare il certificato sui client Docker:
#### Metodo Automatico (Raccomandato)
```bash
# Sul tuo computer di sviluppo o sulle VM client
./scripts/setup-registry-client.sh 192.168.1.204
# Lo script scaricherà e installerà automaticamente il certificato
```
#### Metodo Manuale
```bash
# 1. Crea directory per i certificati Docker
sudo mkdir -p /etc/docker/certs.d/192.168.1.204:5000
# 2. Copia il certificato dal registry
scp root@192.168.1.204:/opt/docker-registry/certs/domain.crt /tmp/registry.crt
sudo cp /tmp/registry.crt /etc/docker/certs.d/192.168.1.204:5000/ca.crt
# 3. Riavvia Docker
sudo systemctl restart docker
# 4. (Opzionale) Installa anche nel sistema per curl/wget
sudo cp /tmp/registry.crt /usr/local/share/ca-certificates/registry.crt
sudo update-ca-certificates
```
#### Test Connessione con Curl
```bash
# Test con certificato insecure (disabilita verifica)
curl -k https://192.168.1.204:5000/v2/
# Test con certificato installato nel sistema
curl https://192.168.1.204:5000/v2/_catalog
# Test con certificato specificato
curl --cacert /etc/docker/certs.d/192.168.1.204:5000/ca.crt https://192.168.1.204:5000/v2/_catalog
# Con autenticazione
curl -k -u myuser:mypassword https://192.168.1.204:5000/v2/_catalog
```
### Configurazione Client Docker per Registry Insicuro (HTTP)
Se usi un registry HTTP locale, devi configurare Docker per accettare connessioni insicure:
```bash
# Edita /etc/docker/daemon.json
sudo nano /etc/docker/daemon.json
# Aggiungi:
{
"insecure-registries": ["localhost:5000", "192.168.1.X:5000"]
}
# Riavvia Docker
sudo systemctl restart docker
```
---
## Protezione Codice Sorgente (Bytecode)
Le immagini Docker vengono buildare con una configurazione speciale che protegge il codice sorgente Python.
### Come Funziona
Il Dockerfile è configurato per:
1. **Compilare** tutti i file Python in bytecode (`.pyc`) usando Python con ottimizzazione `-OO`
2. **Rimuovere** tutti i file sorgente `.py`
3. **Mantenere** solo i file bytecode compilati in `__pycache__/`
```dockerfile
# Compila tutti i file Python in bytecode
# Usa -OO per rimuovere docstring e assert (ottimizzazione massima)
RUN python -OO -m compileall /app/src /app/env || true
# Rimuovi tutti i file sorgente .py, lasciando solo i .pyc compilati in __pycache__
RUN find /app/src -type f -name "*.py" -delete && \
find /app/env -type f -name "*.py" -delete || true
```
### Vantaggi
**Protezione del Codice**: I file sorgente non sono accessibili nell'immagine
**Dimensione Ridotta**: I file `.pyc` sono più compatti dei `.py`
**Performance**: Leggero miglioramento delle prestazioni (no compilazione a runtime)
**Rimozione Docstring**: Con `-OO` vengono rimossi anche commenti e docstring
### Limitazioni
⚠️ **Debug Difficile**: I traceback mostrano solo numeri di riga, non il codice sorgente
⚠️ **No Reverse Engineering**: Impossibile vedere la logica senza decompilare
⚠️ **Serve Backup**: Mantieni sempre i sorgenti in un repository git separato
### Test dell'Immagine Bytecode
Usa lo script `test-pyc-image.sh` per verificare che l'immagine funzioni correttamente:
```bash
# Test immagine locale
./scripts/test-pyc-image.sh orchestrator-app:latest
# Test immagine dal registry
./scripts/test-pyc-image.sh 192.168.1.203:5000/orchestrator-app:v1.0.0
```
Il test verifica:
- ✅ Assenza di file `.py` in `/app/src`
- ✅ Presenza di file `.pyc` compilati
- ✅ Importazione corretta dei moduli
- ✅ Esecuzione dei moduli orchestrator
- ✅ Configurazione ambiente Python
### Struttura File nell'Immagine
**Prima (con sorgenti):**
```
/app/src/
├── load_orchestrator.py
├── elab_orchestrator.py
├── send_orchestrator.py
└── ftp_csv_receiver.py
```
**Dopo (solo bytecode):**
```
/app/src/
├── __pycache__/
│ ├── load_orchestrator.cpython-312.opt-2.pyc
│ ├── elab_orchestrator.cpython-312.opt-2.pyc
│ ├── send_orchestrator.cpython-312.opt-2.pyc
│ └── ftp_csv_receiver.cpython-312.opt-2.pyc
```
---
## Build e Push dell'Immagine
### Script: `build-and-push-image.sh`
Lo script automatizza il processo di build e push dell'immagine Docker.
#### Sintassi
```bash
./scripts/build-and-push-image.sh [registry_url] [image_name] [tag] [dockerfile_type]
```
#### Parametri
- `registry_url` - URL del registry privato (default: `192.168.1.204:5000`)
- `image_name` - Nome dell'immagine (default: `orchestrator-app`)
- `tag` - Tag dell'immagine (default: `latest`)
- `dockerfile_type` - Tipo di Dockerfile: `standard` o `distroless` (default: `standard`)
#### Tipi di Dockerfile
**`standard`** - Usa `Dockerfile` (python:3.12-slim)
- Dimensione: ~333MB
- Include shell per debugging
- Ideale per sviluppo e staging
**`distroless`** - Usa `Dockerfile.distroless` (gcr.io/distroless/python3)
- Dimensione: ~180MB (50% più piccola!)
- Nessuna shell (massima sicurezza)
- Ideale per produzione
#### Esempi
```bash
# Build standard (default)
./scripts/build-and-push-image.sh
# Build distroless per produzione
./scripts/build-and-push-image.sh 192.168.1.204:5000 orchestrator-app latest distroless
# Build distroless con versione specifica
./scripts/build-and-push-image.sh 192.168.1.204:5000 orchestrator-app v1.2.3 distroless
# Build standard per staging
./scripts/build-and-push-image.sh 192.168.1.204:5000 orchestrator-app staging standard
```
#### Cosa fa lo script
1. ✅ Verifica prerequisiti (Docker)
2. ✅ Controlla che esistano Dockerfile e directory progetto
3. ✅ Mostra configurazione e chiede conferma
4. ✅ Builda l'immagine Docker
5. ✅ Tagga l'immagine per il registry
6. ✅ Mostra informazioni sull'immagine (dimensione, layer)
7. ✅ Opzionalmente testa l'immagine localmente
8. ✅ Pusha l'immagine al registry
9. ✅ Opzionalmente rimuove l'immagine locale
---
## Aggiornamento Docker Compose
### Script: `update-compose-image.sh`
Questo script aggiorna i file `docker-compose.yml` in `vm1/` e `vm2/` per usare l'immagine dal registry invece di buildarla localmente.
#### Sintassi
```bash
./scripts/update-compose-image.sh <registry_url> <image_name> <tag>
```
#### Esempio
```bash
# Aggiorna docker-compose.yml per usare l'immagine dal registry
./scripts/update-compose-image.sh registry.example.com:5000 orchestrator-app latest
```
#### Cosa fa lo script
1. ✅ Crea backup dei file docker-compose.yml (`.backup`)
2. ✅ Sostituisce `build: .` con `image: registry_url/image_name:tag`
3. ✅ Aggiorna entrambi i file vm1/ e vm2/
#### Prima e Dopo
**Prima:**
```yaml
orchestrator-1-load:
build: .
container_name: orchestrator-1-load
...
```
**Dopo:**
```yaml
orchestrator-1-load:
image: registry.example.com:5000/orchestrator-app:latest
container_name: orchestrator-1-load
...
```
---
## Deploy sulle VM
### 1. Setup Registry su una VM Proxmox (Opzionale)
Se vuoi hostare il registry su una delle VM Proxmox:
```bash
# Crea una VM per il registry
./scripts/create-vm.sh 203 registry-server 2 4096 50G
# SSH nella VM
ssh root@192.168.1.203
# Avvia il registry
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v /opt/registry-data:/var/lib/registry \
registry:2
```
### 2. Build e Push dell'Immagine
```bash
# Sul tuo computer locale, dalla directory del progetto
cd /home/alex/devel/proxmox-ha-setup
# Build e push al registry
./scripts/build-and-push-image.sh 192.168.1.203:5000 orchestrator-app v1.0.0
```
### 3. Aggiorna Docker Compose Files
```bash
# Aggiorna i file docker-compose.yml
./scripts/update-compose-image.sh 192.168.1.203:5000 orchestrator-app v1.0.0
```
### 4. Deploy su VM1 e VM2
```bash
# Copia i file aggiornati sulle VM
scp -r vm1/* root@192.168.1.201:/opt/myapp/
scp -r vm2/* root@192.168.1.202:/opt/myapp/
# Su VM1
ssh root@192.168.1.201
cd /opt/myapp
docker pull 192.168.1.203:5000/orchestrator-app:v1.0.0
docker compose up -d
# Su VM2
ssh root@192.168.1.202
cd /opt/myapp
docker pull 192.168.1.203:5000/orchestrator-app:v1.0.0
docker compose up -d
```
### 5. Verifica Deploy
```bash
# Controlla i container in esecuzione
ssh root@192.168.1.201 'docker ps'
ssh root@192.168.1.202 'docker ps'
# Verifica i log
ssh root@192.168.1.201 'docker logs orchestrator-1-load'
ssh root@192.168.1.202 'docker logs orchestrator-1-load'
```
---
## Workflow Completo di Esempio
### Scenario: Deploy Iniziale
```bash
# 1. Setup registry su VM dedicata
./scripts/create-vm.sh 203 registry 2 4096 50G
ssh root@192.168.1.203 'docker run -d -p 5000:5000 --restart=always -v /opt/registry:/var/lib/registry --name registry registry:2'
# 2. Configura Docker per accettare il registry insicuro (su tutte le VM)
for vm in 201 202; do
ssh root@192.168.1.$vm 'echo "{\"insecure-registries\": [\"192.168.1.203:5000\"]}" > /etc/docker/daemon.json && systemctl restart docker'
done
# 3. Build e push immagine
./scripts/build-and-push-image.sh 192.168.1.203:5000 orchestrator-app v1.0.0
# 4. Aggiorna docker-compose files
./scripts/update-compose-image.sh 192.168.1.203:5000 orchestrator-app v1.0.0
# 5. Deploy sulle VM
for vm in 201 202; do
scp -r vm$((vm-200))/* root@192.168.1.$vm:/opt/myapp/
ssh root@192.168.1.$vm 'cd /opt/myapp && docker compose pull && docker compose up -d'
done
```
### Scenario: Aggiornamento dell'Applicazione
```bash
# 1. Build nuova versione
./scripts/build-and-push-image.sh 192.168.1.203:5000 orchestrator-app v1.1.0
# 2. Aggiorna docker-compose (se necessario)
./scripts/update-compose-image.sh 192.168.1.203:5000 orchestrator-app v1.1.0
# 3. Update sulle VM con zero downtime
# Prima aggiorna VM2 (backup)
ssh root@192.168.1.202 'cd /opt/myapp && docker compose pull && docker compose up -d'
# Attendi che sia stabile
sleep 30
# Poi aggiorna VM1 (master)
ssh root@192.168.1.201 'cd /opt/myapp && docker compose pull && docker compose up -d'
```
---
## Comandi Utili
### Gestione Registry
```bash
# Lista immagini nel registry
curl http://192.168.1.203:5000/v2/_catalog
# Lista tag di un'immagine
curl http://192.168.1.203:5000/v2/orchestrator-app/tags/list
# Verifica dimensione del registry
du -sh /opt/registry-data
```
### Gestione Immagini
```bash
# Pull immagine dal registry
docker pull 192.168.1.203:5000/orchestrator-app:v1.0.0
# Lista immagini locali
docker images | grep orchestrator-app
# Rimuovi immagini vecchie
docker image prune -a
```
### Debug
```bash
# Testa connessione al registry
telnet 192.168.1.203 5000
# Verifica log del registry
docker logs registry
# Test pull senza deploy
docker pull 192.168.1.203:5000/orchestrator-app:latest
```
---
## Best Practices
1. **Versioning**: Usa tag semantici (v1.0.0, v1.1.0) invece di `latest` per produzione
2. **Backup**: Monta un volume per `/var/lib/registry` per persistenza
3. **Security**: Usa HTTPS e autenticazione per registri in produzione
4. **Cleanup**: Rimuovi regolarmente immagini vecchie dal registry
5. **Testing**: Testa sempre l'immagine localmente prima del push
6. **Documentation**: Documenta le modifiche in ogni versione
---
## Troubleshooting
### Errore: "connection refused" durante il push
**Soluzione:**
```bash
# Verifica che il registry sia in esecuzione
docker ps | grep registry
# Verifica connettività
curl http://192.168.1.203:5000/v2/
```
### Errore: "http: server gave HTTP response to HTTPS client"
**Soluzione:**
Aggiungi il registry come insicuro in `/etc/docker/daemon.json`:
```json
{
"insecure-registries": ["192.168.1.203:5000"]
}
```
Poi riavvia Docker: `systemctl restart docker`
### Errore: "denied: requested access to the resource is denied"
**Soluzione:**
Fai login al registry:
```bash
docker login 192.168.1.203:5000
```
### Le immagini non si aggiornano sulle VM
**Soluzione:**
```bash
# Forza il pull della nuova immagine
docker compose pull
docker compose up -d --force-recreate
```
---
## Note
- Lo script `build-and-push-image.sh` builderà l'immagine dalla directory `/home/alex/devel/proxmox-ha-setup/vm1`
- I file docker-compose.yml in `vm1/` e `vm2/` devono usare `build: .` per i servizi orchestrator
- Puoi usare più tag per la stessa immagine (es: `latest`, `v1.0.0`, `production`)