Ubuntu 26.04 Desktop LTS Docker e PostgreSQL Docker.

Dialogo con Gemini.

Potresti introdurre la gestione di Docker con Ubuntu 26.04 desktop.

La gestione di Docker su Ubuntu 26.04 Desktop (LTS) consente di isolare servizi, database e stack di sviluppo mantenendo pulito l’ambiente host.

1. Installazione di Docker Engine (Repository Ufficiale)

Per avere l’ultima versione del runtime Docker (dockerd), il plugin Compose e gli strumenti CLI, è consigliabile utilizzare il repository ufficiale Docker anziché i pacchetti di sistema predefiniti.

Bash

# 1. Aggiorna l'indice dei pacchetti e installa le dipendenze
sudo apt update
sudo apt install -y ca-certificates curl gnupg

# 2. Aggiungi la chiave GPG ufficiale di Docker
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 3. Aggiungi il repository APT
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 4. Installa Docker Engine, CLI, Containerd e Docker Compose
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

2. Configurazione Post-Installazione (Senza sudo)

Per evitare di anteporre sudo a ogni comando docker, aggiungi il tuo utente al gruppo di sistema docker:

Bash

# Crea il gruppo docker (se non presente) e aggiungi l'utente corrente
sudo usermod -aG docker $USER

# Applica subito le modifiche al gruppo nella sessione corrente
newgrp docker

# Abilita l'avvio automatico del demone al boot
sudo systemctl enable --now docker

3. Comandi Essenziali di Gestione

AmbitoComandoScopo
Verificadocker run --rm hello-worldEsegue un test rapido per verificare il setup
Statodocker ps -aMostra tutti i container (attivi e fermati)
Immaginidocker imagesElenca le immagini presenti localmente
Logdocker logs -f <nome_o_id>Ispeziona i log in streaming di un container
Puliziadocker system prune -a --volumesRimuove container fermati, reti e volumi non utilizzati

4. Gestione Multi-Container con Docker Compose

Per definire servizi complessi (ad esempio un database con persistenza dati su volume dedicato), si utilizza compose.yaml:

YAML

services:
  database:
    image: postgres:17
    container_name: local_postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: devuser
      POSTGRES_PASSWORD: secretpassword
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
  • Avvio in background: docker compose up -d
  • Arresto dei container: docker compose down

5. Interfacce Grafiche su Ubuntu Desktop

Se preferisci una gestione visuale di container, log e volumi integrata con il desktop:

  • Portainer CE: Container leggero con interfaccia web accessibile da browser.Bashdocker volume create portainer_data docker run -d -p 9000:9000 --name portainer --restart=always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data portainer/portainer-ce:latest (Accessibile poi da browser su http://localhost:9000)
  • Docker Desktop per Linux: Pacchetto .deb con GUI dedicata e integrazione Kubernetes locale.

Come si configura NVIDIA Container Toolkit per Docker su Ubuntu Desktop per abilitare l’accelerazione GPU nei container?

Per abilitare l’accelerazione GPU hardware nei container Docker su Ubuntu Desktop, è necessario configurare NVIDIA Container Toolkit (nvidia-container-toolkit), che registra il runtime NVIDIA all’interno del demone Docker (dockerd).

1. Prerequisiti: Driver NVIDIA sull’Host

Prima di procedere, assicurati che i driver proprietari NVIDIA siano installati e funzionanti sull’host:

Bash

nvidia-smi

Se il comando restituisce la tabella con la GPU, il driver e la versione CUDA supportata, il sistema host è pronto.

2. Installazione di NVIDIA Container Toolkit

Aggiungi il repository ufficiale NVIDIA APT e installa il pacchetto del toolkit:

Bash

# 1. Aggiungi la chiave GPG ufficiale NVIDIA
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

# 2. Configura il repository APT
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
  sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

# 3. Aggiorna l'indice dei pacchetti e installa il toolkit
sudo apt update
sudo apt install -y nvidia-container-toolkit

3. Configurazione del Runtime Docker

Configura il demone Docker affinché riconosca nvidia come runtime alternativo (modificando /etc/docker/daemon.json) e riavvia il servizio:

Bash

# Configura automaticamente il runtime NVIDIA per Docker
sudo nvidia-ctk runtime configure --runtime=docker

# Riavvia il demone Docker per applicare le modifiche
sudo systemctl restart docker

4. Verifica del Funzionamento

Esegui un container di test per verificare che Docker possa dialogare direttamente con la GPU tramite il flag --gpus all:

Bash

docker run --rm --gpus all ubuntu:24.04 nvidia-smi

oppure utilizzando un’immagine CUDA ufficiale:

Bash

docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi

5. Utilizzo con Docker Compose

Per riservare l’accesso alla GPU all’interno di un file compose.yaml, si definisce la sezione deploy.resources.reservations:

YAML

services:
  llm-inference:
    image: ollama/ollama:latest
    container_name: local_ollama_gpu
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all          # o specifica un numero (es. 1) o ID dispositivo
              capabilities: [gpu]

volumes:
  ollama_data:

Come si configura un container Docker con PostgreSQL e pgvector per la memorizzazione di vettori ed embedding locali?

Per configurare un container PostgreSQL con l’estensione pgvector (ideale per memorizzare embedding e calcolare distanze vettoriali come coseno, L2 o prodotto scalare per pipeline RAG), il metodo più rapido e affidabile è utilizzare l’immagine ufficiale fornita dal team di pgvector: pgvector/pgvector:pg17 (o pg16).

1. Configurazione con Docker Compose

Crea una cartella di progetto con la seguente struttura:

Plaintext

rag-database/
├── compose.yaml
└── init-db/
    └── 01-init-pgvector.sql

compose.yaml

YAML

services:
  vectordb:
    image: pgvector/pgvector:pg17
    container_name: local_pgvector
    restart: unless-stopped
    environment:
      POSTGRES_DB: vectordb
      POSTGRES_USER: raguser
      POSTGRES_PASSWORD: ragpassword
    ports:
      - "5432:5432"
    volumes:
      - pgvector_data:/var/lib/postgresql/data
      # Esegue automaticamente gli script SQL all'inizializzazione del database
      - ./init-db:/docker-entrypoint-initdb.d:ro

volumes:
  pgvector_data:

2. Script di Inizializzazione Automatica (01-init-pgvector.sql)

Qualsiasi file .sql o .sh inserito in /docker-entrypoint-initdb.d viene eseguito una sola volta, alla creazione del volume dati.

SQL

-- 1. Abilita l'estensione pgvector nel database corrente
CREATE EXTENSION IF NOT EXISTS vector;

-- 2. Esempio di tabella per documenti ed embedding (es. 768 dimensioni per modelli come nomic-embed-text o bge-base)
CREATE TABLE IF NOT EXISTS documents (
    id BIGSERIAL PRIMARY KEY,
    content TEXT NOT NULL,
    metadata JSONB DEFAULT '{}'::jsonb,
    embedding vector(768),
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- 3. Indice per ricerca rapida approssimata (HNSW con distanza coseno)
CREATE INDEX IF NOT EXISTS documents_embedding_hnsw_idx 
ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

3. Avvio e Gestione

Bash

# Avvia il container in background
docker compose up -d

# Verifica che i log confermino l'avvio corretto
docker logs -f local_pgvector

4. Test Rapido con psql

Puoi accedere alla sessione interattiva di PostgreSQL dentro il container:

Bash

docker exec -it local_pgvector psql -U raguser -d vectordb

Verifica la presenza dell’estensione e prova una query di similarità vettoriale:

SQL

-- Verifica estensioni installate
\dx

-- Inserimento di dati di test con vettori a 3 dimensioni per prova rapida
CREATE TABLE test_items (id serial PRIMARY KEY, embedding vector(3));
INSERT INTO test_items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'), ('[1,1,1]');

-- Query di similarità (K-Nearest Neighbors con distanza Coseno: operatore <=>)
SELECT id, embedding, embedding <=> '[1,2,3]' AS cosine_distance
FROM test_items
ORDER BY cosine_distance ASC
LIMIT 2;

5. Tipologie di Indici pgvector consigliate

Tipo IndiceNome Operatore (Coseno)VantaggiQuando Usarlo
HNSW (hnsw)vector_cosine_ops (<=>)Massima velocità di query e recall elevatoScelta raccomandata per la maggior parte dei sistemi RAG
IVFFlat (ivfflat)vector_cosine_ops (<=>)Minor consumo di RAM, costruzione indice rapidaGrandi volumi di dati su macchine con RAM limitata

Mostrami un esempio pratico in Python per connettersi a PostgreSQL con pgvector, inserire embedding e fare una query semantica.

Ecco un esempio pratico end-to-end in Python utilizzando il driver moderno psycopg (v3) insieme all’integrazione ufficiale pgvector-python e ollama (oppure sentence-transformers) per generare gli embedding localmente.

1. Installazione delle dipendenze

Bash

pip install psycopg[binary] pgvector ollama

(Se preferisci generare gli embedding direttamente in PyTorch/CPU senza Ollama, puoi usare pip install sentence-transformers).

2. Script Python Completo (rag_pgvector_demo.py)

Questo script:

  1. Registra l’adattatore vettoriale pgvector sulla connessione psycopg.
  2. Crea la tabella con supporto vettoriale.
  3. Genera gli embedding testuali tramite il modello locale nomic-embed-text (dimensione 768).
  4. Esegue l’inserimento e una ricerca semantica basata sulla distanza coseno (<=>).

Python

import ollama
import psycopg
from pgvector.psycopg import register_vector

# Parametri di connessione al database Docker
DB_PARAMS = {
    "host": "localhost",
    "port": 5432,
    "dbname": "vectordb",
    "user": "raguser",
    "password": "ragpassword",
}

EMBED_MODEL = "nomic-embed-text"  # Dimensione output: 768


def get_embedding(text: str) -> list[float]:
    """Genera l'embedding di una stringa tramite Ollama."""
    response = ollama.embeddings(model=EMBED_MODEL, prompt=text)
    return response["embedding"]


def main():
    # 1. Connessione a PostgreSQL
    with psycopg.connect(**DB_PARAMS, autocommit=True) as conn:
        # Abilita l'estensione nel DB e registra i tipi vettoriali in psycopg
        conn.execute("CREATE EXTENSION IF NOT EXISTS vector;")
        register_vector(conn)

        with conn.cursor() as cur:
            # 2. Creazione della tabella per i documenti
            cur.execute("""
                CREATE TABLE IF NOT EXISTS articles (
                    id BIGSERIAL PRIMARY KEY,
                    title TEXT NOT NULL,
                    content TEXT NOT NULL,
                    embedding vector(768)
                );
            """)

            # Svuota la tabella per la demo
            cur.execute("TRUNCATE TABLE articles;")

            # 3. Dati di esempio da indicizzare
            dataset = [
                {
                    "title": "Fisica Classica e Meccanica",
                    "content": "La dinamica newtoniana descrive il moto dei corpi macroscopici attraverso i tre principi fondamentali della dinamica e le equazioni differenziali del secondo ordine.",
                },
                {
                    "title": "Infrastrutture Docker e GPU",
                    "content": "NVIDIA Container Toolkit consente l'accesso diretto ai dispositivi GPU dall'interno dei container Docker per accelerare l'inferenza di modelli LLM.",
                },
                {
                    "title": "Protocolli Industriali Modbus",
                    "content": "La comunicazione seriale Modbus RS-485 permette lo scambio dati deterministico tra master e slave industriali tramite registri di lettura e scrittura.",
                },
                {
                    "title": "Sistemi Elettrici a Bassa Tensione e Batterie",
                    "content": "I banchi batteria LiFePO4 a 48V offrono elevata densità energetica e stabilità termica quando abbinati a regolatori di carica solare MPPT e inverter.",
                },
            ]

            print("Generazione embedding e inserimento nel database...")
            for item in dataset:
                emb = get_embedding(item["content"])
                cur.execute(
                    """
                    INSERT INTO articles (title, content, embedding)
                    VALUES (%s, %s, %s);
                    """,
                    (item["title"], item["content"], emb),
                )

            # Crea l'indice HNSW per ottimizzare le ricerche su volumi maggiori
            cur.execute("""
                CREATE INDEX IF NOT EXISTS articles_embedding_hnsw_idx 
                ON articles USING hnsw (embedding vector_cosine_ops);
            """)

            print("Dati memorizzati con successo.\n")

            # 4. Query Semantica di Test
            query_test = "Come posso collegare accumulatori al litio con impianti fotovoltaici?"
            print(f"--- Esecuzione Query Semantica: \"{query_test}\" ---")

            query_embedding = get_embedding(query_test)

            # L'operatore <=> calcola la distanza Coseno (0.0 = identico, 2.0 = opposto)
            # Similarità Coseno = 1 - Distanza Coseno
            cur.execute(
                """
                SELECT 
                    id, 
                    title, 
                    content, 
                    1 - (embedding <=> %s) AS cosine_similarity
                FROM articles
                ORDER BY embedding <=> %s ASC
                LIMIT 2;
                """,
                (query_embedding, query_embedding),
            )

            results = cur.fetchall()
            for doc_id, title, content, similarity in results:
                print(f"\n[ID: {doc_id}] Similarità: {similarity:.4f}")
                print(f"Titolo: {title}")
                print(f"Contenuto: {content}")


if __name__ == "__main__":
    main()

3. Alternativa con SQLAlchemy + pgvector

Se utilizzi un ORM come SQLAlchemy (v2.0), la definizione del modello e la query si integrano in modo dichiarativo:

Python

from pgvector.sqlalchemy import Vector
from sqlalchemy import BigInteger, String, Text, create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, sessionmaker


class Base(DeclarativeBase):
    pass


class Article(Base):
    __tablename__ = "articles"

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
    title: Mapped[str] = mapped_column(String(255))
    content: Mapped[str] = mapped_column(Text)
    embedding = mapped_column(Vector(768))


# Connessione
engine = create_engine(
    "postgresql+psycopg://raguser:ragpassword@localhost:5432/vectordb"
)
Session = sessionmaker(bind=engine)

# Query con operatore cosine_distance
with Session() as session:
    query_vector = [...]  # Vettore float generato
    stmt = (
        select(Article)
        .order_by(Article.embedding.cosine_distance(query_vector))
        .limit(3)
    )
    results = session.scalars(stmt).all()

4. Operatori di Distanza in pgvector

Operatore SQLMetodo SQLAlchemyMetrica di DistanzaUtilizzo Tipico
<=>.cosine_distance()Distanza CosenoModelli di Embedding standard (consigliato)
<->.l2_distance()Distanza Euclidea (L2)Cluster geometrici / Coordinate fisiche
<#>.max_inner_product()Prodotto Scalare NegativoVettori già normalizzati a norma unitaria