Installazione
Ubuntu Debian
Per prima cosa rimuovere i seguenti pacchetti che possono dare conflitto
# comando ubuntu
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)
# comando debian
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-doc podman-docker containerd runc | cut -f1)
Impostiamo il repository apt (ubuntu)
# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
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
# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
Impostiamo il repository apt (Debian)
# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
Infine installiamo docker
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Veirfichiamo che il servizio sia avviato
sudo systemctl status docker
E nel caso avviamolo
sudo systemctl start docker
Fedora / RHEL Linux
Rimuoviamo i pacchetti che posono dare conflitto
sudo dnf remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine podman runc
Impostiamo il repository con i seguenti comandi
# rhel linux
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
# fedora
sudo dnf config-manager addrepo --from-repofile https://download.docker.com/linux/fedora/docker-ce.repo
Infine installiamo docker
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Per avviare docker
sudo systemctl enable --now docker
Avvio e confiurazione post installazione
Per testare docker usare il comando
sudo docker run hello-world
Per eseguire docker senza specificare sudo seguire la seguente procedura
# aggiungere il gruppo docker
sudo groupadd docker
# aggiungere l'utente corrente al gruppo appena creato
sudo usermod -aG docker $USER
Fare il logout e poi login. Dopo si può eseguire docker senza specificare sudo
docker run hello-world
Comandi
# Versione installata
docker version
# Informazioni sul sistema
docker info
# Aiuto per un comando
docker <comando> --help
Gestione delle immagini
# Scaricare un'immagine
docker pull ubuntu:22.04
# Elencare le immagini locali
docker images
# Cercare immagini su Docker Hub
docker search nginx
# Rimuovere un'immagine
docker rmi ubuntu:22.04
# Rimuovere tutte le immagini non utilizzate
docker image prune -a
Gestione dei container
# Avviare un container
docker run ubuntu:22.04
# Avviare in modalità interattiva
docker run -it ubuntu:22.04 bash
# Avviare in background (detached)
docker run -d nginx
# Avviare con nome personalizzato
docker run -d --name mio-nginx nginx
# Avviare con mapping delle porte (host:container)
docker run -d -p 8080:80 nginx
# Avviare con variabili d'ambiente
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql:8
# Elencare i container in esecuzione
docker ps
# Elencare tutti i container (anche fermi)
docker ps -a
# Fermare un container
docker stop mio-nginx
# Avviare un container fermo
docker start mio-nginx
# Riavviare un container
docker restart mio-nginx
# Rimuovere un container
docker rm mio-nginx
# Rimuovere un container in esecuzione (forzato)
docker rm -f mio-nginx
# Eseguire un comando in un container in esecuzione
docker exec -it mio-nginx bash
# Visualizzare i log
docker logs mio-nginx
# Seguire i log in tempo reale
docker logs -f mio-nginx
Volumi e bind mount
I volumi permettono la persistenza dei dati al di fuori del ciclo di vita del container.
# Creare un volume
docker volume create mio-volume
# Elencare i volumi
docker volume ls
# Usare un volume in un container
docker run -d -v mio-volume:/var/lib/mysql mysql:8
# Bind mount (cartella locale → container)
docker run -d -v /percorso/locale:/percorso/container nginx
# Bind mount con sintassi --mount (più esplicita)
docker run -d \
--mount type=bind,source=/percorso/locale,target=/percorso/container \
nginx
# Rimuovere un volume
docker volume rm mio-volume
# Rimuovere i volumi non utilizzati
docker volume prune
Networking
# Elencare le reti
docker network ls
# Creare una rete personalizzata
docker network create mia-rete
# Connettere un container a una rete
docker run -d --network mia-rete --name app mia-app
# Connettere un container in esecuzione a una rete
docker network connect mia-rete mio-nginx
# Disconnettere un container da una rete
docker network disconnect mia-rete mio-nginx
# Ispezionare una rete
docker network inspect mia-rete
# Rimuovere le reti non utilizzate
docker network prune
Docker Compose
Docker Compose permette di gestire applicazioni multi-container tramite un file docker-compose.yml.
Esempio base: app web + database
# docker-compose.yml
services:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
- db-data:/var/lib/postgresql/data
web:
image: nginx
ports:
- "8080:80"
depends_on:
- db
volumes:
db-data:
I comandi per la gestione docker compose sono
# Avviare tutti i servizi in background
docker compose up -d
# Avviare e ricostruire le immagini
docker compose up -d --build
# Fermare i servizi
docker compose down
# Fermare e rimuovere i volumi
docker compose down -v
# Vedere i log di tutti i servizi
docker compose logs -f
# Vedere i log di un servizio specifico
docker compose logs -f web
# Elencare i container del compose
docker compose ps
# Eseguire un comando in un servizio
docker compose exec web bash
# Scalare un servizio
docker compose up -d --scale web=3
Pulizia del sistema
# Rimuovere container fermi, immagini non taggate, reti e cache build
docker system prune
# Rimuovere anche i volumi non utilizzati
docker system prune --volumes
# Rimuovere tutto (immagini, container, volumi, reti)
docker system prune -a --volumes
# Visualizzare l'utilizzo disco di Docker
docker system df
Lamp Docker
In questo capitolo andiamo a creare un ambiente lamp su uan distribuzione Debian 13
L'ambiente avrà Apache, php 8.5, mariadb e phpmyadmin. Non verrà copiato niente all'interno dei container e verrà condivisa una cartella www per la lettura e scrittura dei siti web
All'interno della cartella dbs è possibile salvare uno copia dei db presenti eseguendo lo script backup-dbs.sh
Cominciamo con la struttura del progetto che parte da una cartella $HOME/Lamp
$HOME/Lamp/
├── .env # USER_UID / USER_GID (da rigenerare in locale)
├── docker-compose.yml
├── backup-dbs.sh # dump individuale dei DB
├── stop-lamp.sh # backup + spegnimento (usare SEMPRE questo per spegnere)
├── apache/
│ ├── Dockerfile # PHP 8.5 + Apache custom
│ ├── entrypoint.sh # allinea UID/GID di www-data a quelli dell'host
│ └── php.ini-custom
├── www/ # bind mount: qui vanno i tuoi progetti (sito1/, sito2/, ...)
└── dbs/ # destinazione dei backup .sql
Passsiamo ora alla creazione dei files
Specificatamente per debian 13 bisogna applicare questa fix a docker per poteer risolvere i dns
sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{ "dns": ["8.8.8.8", "1.1.1.1"] }
EOF
# riavviare docker
sudo systemctl restart docker
Creiamo la struttura delle cartelle
mkdir -p "$HOME/Lamp/apache" "$HOME/Lamp/www" "$HOME/Lamp/dbs"
cd "$HOME/Lamp"
Creiamo il file .env
{
echo "USER_UID=$(id -u)"
echo "USER_GID=$(id -g)"
} > "$HOME/Lamp/.env"
Di seguito trovi le istruzioni per creare tutti i files necessari
File docker-compose.yml
cat > "$HOME/Lamp/docker-compose.yml" << 'EOF'
services:
apache:
build:
context: ./apache
dockerfile: Dockerfile
container_name: lamp_apache
restart: unless-stopped
environment:
USER_UID: ${USER_UID}
USER_GID: ${USER_GID}
ports:
- "8001:80"
volumes:
- ./www:/var/www/html
depends_on:
- mariadb
networks:
- lamp_network
mariadb:
image: mariadb:latest
container_name: lamp_mariadb
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- mariadb_data:/var/lib/mysql
networks:
- lamp_network
phpmyadmin:
image: phpmyadmin:latest
container_name: lamp_phpmyadmin
restart: unless-stopped
environment:
PMA_HOST: mariadb
PMA_PORT: 3306
UPLOAD_LIMIT: 128M
ports:
- "8000:80"
depends_on:
- mariadb
networks:
- lamp_network
networks:
lamp_network:
driver: bridge
volumes:
mariadb_data:
EOF
File apache/Dockerfile
cat > "$HOME/Lamp/apache/Dockerfile" << 'EOF'
FROM php:8.5-apache
# --- Dipendenze di sistema per compilare le estensioni PHP ---
RUN apt-get update && apt-get install -y --no-install-recommends \
libzip-dev \
libicu-dev \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
libwebp-dev \
libmagickwand-dev \
libonig-dev \
libxml2-dev \
unzip \
git \
less \
nano \
default-mysql-client \
&& rm -rf /var/lib/apt/lists/*
# --- Configurazione ed installazione estensioni PHP ---
# Nota: ogni estensione viene compilata in un RUN separato, senza -j$(nproc)
# aggressivo. Compilare estensioni pesanti (es. intl/ICU) in parallelo con
# troppi job può esaurire la RAM disponibile durante la build (specie in
# VM/container con poche risorse), causando build incomplete e l'errore
# "cp: cannot stat 'modules/*'".
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp
RUN docker-php-ext-install -j1 pdo_mysql
RUN docker-php-ext-install -j1 mysqli
RUN docker-php-ext-install -j1 intl
RUN docker-php-ext-install -j1 zip
RUN docker-php-ext-install -j1 gd
RUN docker-php-ext-install -j1 exif
# NOTA: da PHP 8.5 OPcache è integrato nel core di PHP e non è più
# un'estensione separata da compilare: "docker-php-ext-install opcache"
# darebbe errore ("cp: cannot stat 'modules/*'"). È già presente e attiva
# di default; la configuriamo via php.ini-custom più sotto.
RUN docker-php-ext-install -j1 bcmath
RUN docker-php-ext-install -j1 soap
RUN docker-php-ext-install -j1 mbstring
RUN docker-php-ext-install -j1 xml
# Imagick (via PECL, non incluso in docker-php-ext-install)
RUN pecl install imagick && docker-php-ext-enable imagick
# --- Moduli Apache necessari per i permalink di WordPress e simili ---
RUN a2enmod rewrite headers expires
# --- php.ini ottimizzato per WordPress / CMS moderni ---
COPY php.ini-custom /usr/local/etc/php/conf.d/zz-custom.ini
# --- Entrypoint per allineare UID/GID di www-data a quelli dell'host ---
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
WORKDIR /var/www/html
ENTRYPOINT ["entrypoint.sh"]
CMD ["apache2-foreground"]
EOF
File apache/php.ini-custom
cat > "$HOME/Lamp/apache/php.ini-custom" << 'EOF'
memory_limit = 256M
upload_max_filesize = 128M
post_max_size = 128M
max_execution_time = 300
max_input_time = 300
max_input_vars = 3000
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.validate_timestamps=1
display_errors = Off
log_errors = On
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
EOF
File apache/entrypoint.sh
cat > "$HOME/Lamp/apache/entrypoint.sh" << 'EOF'
#!/bin/bash
set -e
USER_ID=${USER_UID:-1000}
GROUP_ID=${USER_GID:-1000}
CURRENT_UID=$(id -u www-data)
CURRENT_GID=$(id -g www-data)
if [ "$CURRENT_GID" != "$GROUP_ID" ]; then
groupmod -o -g "$GROUP_ID" www-data
fi
if [ "$CURRENT_UID" != "$USER_ID" ]; then
usermod -o -u "$USER_ID" www-data
fi
exec "$@"
EOF
File backup-dbs.sh
cat > "$HOME/Lamp/backup-dbs.sh" << 'EOF'
#!/bin/bash
set -euo pipefail
LAMP_DIR="$HOME/Lamp"
BACKUP_DIR="$LAMP_DIR/dbs"
CONTAINER_NAME="lamp_mariadb"
MYSQL_ROOT_PASSWORD="root"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "[ERRORE] Il container ${CONTAINER_NAME} non è in esecuzione. Backup annullato."
exit 1
fi
echo "== Recupero elenco database da ${CONTAINER_NAME} =="
DATABASES=$(docker exec "$CONTAINER_NAME" mariadb -uroot -p"${MYSQL_ROOT_PASSWORD}" -N -e "SHOW DATABASES;" \
| grep -Ev "^(mysql|information_schema|performance_schema|sys)$" || true)
if [ -z "$DATABASES" ]; then
echo "Nessun database utente trovato. Niente da salvare."
exit 0
fi
COUNT=0
for DB in $DATABASES; do
OUTFILE="${BACKUP_DIR}/${DB}_${DATE}.sql"
echo "-> Backup di '${DB}' in ${OUTFILE}"
docker exec "$CONTAINER_NAME" mariadb-dump -uroot -p"${MYSQL_ROOT_PASSWORD}" --databases "$DB" > "$OUTFILE"
COUNT=$((COUNT+1))
done
echo "== Backup completato: ${COUNT} database salvati in ${BACKUP_DIR} =="
EOF
File stop-lamp.sh
cat > "$HOME/Lamp/stop-lamp.sh" << 'EOF'
#!/bin/bash
set -euo pipefail
LAMP_DIR="$HOME/Lamp"
cd "$LAMP_DIR"
echo "== [1/2] Backup dei database prima dello spegnimento =="
"$LAMP_DIR/backup-dbs.sh"
echo "== [2/2] Spegnimento dell'ambiente LAMP =="
docker compose down
echo "== Ambiente LAMP spento. Backup disponibili in $LAMP_DIR/dbs =="
EOF
Modifica i permessi di esecuzione dei seguenti files
chmod +x "$HOME/Lamp/backup-dbs.sh" "$HOME/Lamp/stop-lamp.sh" "$HOME/Lamp/apache/entrypoint.sh"
Per costruire i container e avviare il tutto
cd "$HOME/Lamp"
docker compose build --no-cache
docker compose up -d
Se si verificano dei problemi, per ricompilare tutto
cd "$HOME/Lamp"
docker builder prune -f
docker compose build --no-cache
docker compose up -d
Eseguendo il comando docker ps è possibile vedere se i container sono in esecuzione. Visitando i seguenti
indirizzi abbiamo
http://localhost:8001visualizzo i siti in$HOME/Lamp/www/http://localhost:8000accedo a phpMyAdmin (utente root, password root)
Per finire una lista di comandi per uan gestione quotidiano dell'ambiente creato. Tutti questi comando devono essere
lanciati dentro la cartella $HOME/Lamp
| Avviare | docker compose up -d |
| Spegnere senza backup | docker compose stop |
| Spegnere con backup automatico | cd $HOME/Lamp && ./stop-lamp.sh |
| Stato del container | docker compose ps |
| Log |
tutti i servizi: docker compose logs -fapache/php: docker compose logs -f apachemariadb: docker compose logs -f mariadb
|
| Shell |
Apache/PHP: docker exec -it lamp_apache bashMariaDB: docker exec -it lamp_mariadb bash |
| Client MariaDB root | docker exec -it lamp_mariadb mariadb -uroot -proot |
| Backup manuale immediato | ./backup-dbs.sh |
| Eseguire comandi |
PHP: docker exec -it lamp_apache php -vWPCLI: docker exec -it lamp_apache wp --info --path=/var/www/html/sito1
|