# 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 ``` #### 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`)