Files
Lesstime/doc/deployment-docker.md
T
Matthieu 8e00c5f5a8
Pull Request — Quality gate / Frontend (build) (pull_request) Successful in 1m8s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m37s
fix(deploy) : seed RBAC system roles during deployment
deploy.sh only synced the permission catalog; the system roles (admin, user)
were never seeded, leaving the admin Roles page empty after a fresh deploy.
Add app:seed-rbac (idempotent) to the deploy script, refresh the embedded
script in deployment-docker.md, document the RBAC post-deploy step (with the
manual fix for an already-deployed prod), and note it in CLAUDE.md.
2026-06-23 16:11:58 +02:00

10 KiB

Deploiement Docker — Lesstime

Pre-requis

Docker

# Ubuntu
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker $USER

Se deconnecter/reconnecter pour que le groupe docker prenne effet.

Nginx

sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx

PostgreSQL

PostgreSQL tourne dans un conteneur Docker separe (voir le repo infra-postgres). Il doit etre installe et accessible avant de deployer Lesstime.

Creer la base de donnees pour Lesstime :

cd /var/www/postgres
docker compose exec postgres psql -U admin
-- Si le user n'existe pas encore
CREATE USER malio WITH PASSWORD 'motdepasse';

-- Creer la base
CREATE DATABASE lesstime_prod OWNER malio;
\q

Premiere installation (nouvelle machine)

Guide complet pour mettre en ligne Lesstime sur une machine vierge. Inclut les pre-requis, la BDD et l'app.

1. Installer les pre-requis

Installer Docker, Nginx et PostgreSQL (voir section Pre-requis ci-dessus).

2. Creer le dossier de deploiement

sudo mkdir -p /var/www/lesstime
sudo chown -R $(whoami):$(whoami) /var/www/lesstime
cd /var/www/lesstime

3. Se connecter au registry Docker de Gitea

docker login gitea.malio.fr
  • Username : le nom d'utilisateur du compte organisation Gitea MALIO
  • Password : le token REGISTRY_TOKEN dispo dans le bitwarden

Le login est sauvegarde dans ~/.docker/config.json, pas besoin de le refaire a chaque deploiement.

4. Creer les fichiers de deploiement

Creer docker-compose.yml :

services:
  app:
    image: gitea.malio.fr/malio-dev/lesstime:${LESSTIME_IMAGE_TAG:-latest}
    container_name: lesstime-app
    env_file: .env
    ports:
      - "8080:80"
    volumes:
      - ./config/jwt:/var/www/html/config/jwt:ro
      - ./uploads:/var/www/html/var/uploads
    extra_hosts:
      - "host.docker.internal:host-gateway"
    restart: unless-stopped

Creer deploy.sh :

#!/usr/bin/env bash
set -euo pipefail

cd "$(dirname "$0")"

TAG="${1:-latest}"
export LESSTIME_IMAGE_TAG="$TAG"

echo "==> Deploying lesstime:${TAG}..."

echo "==> Enabling maintenance mode..."
touch maintenance.on

echo "==> Pulling image..."
sudo docker compose pull

echo "==> Starting container..."
sudo docker compose up -d

echo "==> Waiting for container to be ready..."
sleep 3

echo "==> Extracting maintenance page..."
mkdir -p public
sudo docker compose cp app:/var/www/html/public/maintenance.html public/maintenance.html

echo "==> Running migrations..."
sudo docker compose exec -T -u www-data app php bin/console doctrine:migrations:migrate --no-interaction

echo "==> Seeding RBAC system roles (idempotent)..."
sudo docker compose exec -T -u www-data app php bin/console app:seed-rbac

echo "==> Syncing RBAC permissions catalog..."
sudo docker compose exec -T -u www-data app php bin/console app:sync-permissions

echo "==> Clearing cache..."
sudo docker compose exec -T -u www-data app php bin/console cache:clear --env=prod
sudo docker compose exec -T -u www-data app php bin/console cache:warmup --env=prod

echo "==> Disabling maintenance mode..."
rm -f maintenance.on

VERSION=$(sudo docker compose exec -T app cat config/version.yaml | grep 'app.version' | awk -F"'" '{print $2}')
echo "==> Deployed v${VERSION}"

Rendre executable :

chmod +x deploy.sh

5. Configurer l'environnement

Creer .env avec les variables suivantes :

# Symfony
APP_ENV=prod
APP_DEBUG=0
APP_SECRET=<generer avec: openssl rand -hex 32>

# Database (host.docker.internal = la machine hote, ou le PG tourne en Docker)
DATABASE_URL="postgresql://malio:password@host.docker.internal:5432/lesstime_prod?serverVersion=16&charset=utf8"

# JWT
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=<generer avec: openssl rand -hex 32>
JWT_COOKIE_SECURE=1
JWT_COOKIE_SAMESITE=lax
JWT_TOKEN_TTL=86400
JWT_COOKIE_TTL=86400

# CORS
CORS_ALLOW_ORIGIN='^https?://project\.malio-dev\.fr$'

# App
DEFAULT_URI=https://project.malio-dev.fr

6. Generer les cles JWT

mkdir -p config/jwt
openssl genpkey -algorithm RSA -out config/jwt/private.pem -pkeyopt rsa_keygen_bits:4096
openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem

Rendre les cles lisibles par le conteneur (www-data = uid 33) :

sudo chown 33:33 config/jwt/private.pem config/jwt/public.pem
sudo chmod 644 config/jwt/private.pem config/jwt/public.pem

7. Creer le dossier uploads

mkdir -p uploads

8. Configurer Nginx systeme

Creer /etc/nginx/sites-available/lesstime.conf :

server {
    listen 80;
    listen [::]:80;
    server_name project.malio-dev.fr;

    root /var/www/lesstime/public;

    # Maintenance mode
    if (-f /var/www/lesstime/maintenance.on) {
        return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /maintenance.html break;
    }

    location = /maintenance.html {
        internal;
    }

    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 55m;
    }
}

Activer le site :

sudo ln -sf /etc/nginx/sites-available/lesstime.conf /etc/nginx/sites-enabled/lesstime.conf
sudo nginx -t && sudo systemctl reload nginx

9. Deployer

./deploy.sh

10. Importer les donnees (optionnel)

Si tu as un dump SQL a importer :

# Depuis ton PC, envoyer le dump vers le serveur
scp lesstime.sql user@serveur:/tmp/lesstime.sql

# Sur le serveur, vider la base puis importer
cd /var/www/postgres
docker compose exec -T postgres psql -U malio lesstime_prod -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
docker compose exec -T postgres psql -U malio lesstime_prod < /tmp/lesstime.sql

# Creer les tables manquantes (si le dump a des erreurs de syntaxe)
cd /var/www/lesstime
docker compose exec -u www-data app php bin/console doctrine:schema:update --force --env=prod

# Nettoyer
rm /tmp/lesstime.sql

Structure finale du dossier

/var/www/lesstime/
├── docker-compose.yml
├── deploy.sh
├── .env
├── config/jwt/
│   ├── private.pem
│   └── public.pem
├── public/
│   └── maintenance.html    # extrait automatiquement par deploy.sh
└── uploads/

Deployer une nouvelle version

Quand l'app est deja installee, deployer une mise a jour :

cd /var/www/lesstime
./deploy.sh           # deploie la derniere version (latest)
./deploy.sh v0.3.13   # deploie une version specifique

C'est tout. Le script pull l'image, redemarre le conteneur, lance les migrations, seed les roles systeme RBAC, synchronise le catalogue des permissions et vide le cache.


RBAC : roles & permissions (post-deploiement)

Le module RBAC (entites Role / Permission) repose sur des donnees qui ne sont pas inserees par les migrations (celles-ci creent uniquement les tables). Deux commandes idempotentes les peuplent, integrees au deploy.sh :

Commande Effet
app:seed-rbac Cree les roles systeme admin (Administrateur) et user (Utilisateur). Idempotent : ne recree rien si deja present.
app:sync-permissions (Re)synchronise le catalogue des permissions a partir des modules actifs. A relancer a chaque ajout de permission dans le code.

Symptome si elles n'ont pas tourne : la page d'admin Roles affiche « Aucun role trouve ».

Correctif manuel sur une prod deja deployee (sans relancer un deploiement complet) :

cd /var/www/lesstime
sudo docker compose exec -T -u www-data app php bin/console app:seed-rbac
sudo docker compose exec -T -u www-data app php bin/console app:sync-permissions

Rollback

Image seule (pas de changement de schema BDD)

./deploy.sh v0.3.12

Avec rollback de migration

# 1. Rollback schema (pendant que la version actuelle tourne encore)
docker compose exec -T -u www-data app php bin/console doctrine:migrations:migrate prev --no-interaction
# 2. Deployer l'ancienne version
./deploy.sh v0.3.12

CI/CD

Le workflow .gitea/workflows/build-docker.yml se declenche automatiquement sur push de tag v* :

  1. Build l'image multi-stage
  2. Push vers gitea.malio.fr/malio-dev/lesstime:<tag> et :latest

Combine avec auto-tag-develop.yml, chaque push sur develop cree automatiquement un tag → build → image disponible.


Voir les logs

cd /var/www/lesstime
docker compose logs -f            # tous les logs
docker compose logs -f --tail=100 # 100 dernieres lignes

Logs Symfony :

docker compose exec app cat var/log/prod.log

Migration depuis l'ancien deploiement (bare-metal)

Si l'application tourne deja en bare metal :

  1. Installer Docker (voir pre-requis)
  2. Creer le dossier /var/www/lesstime-docker/ (ne pas ecraser l'ancien)
  3. Copier les fichiers existants :
    cp /var/www/lesstime/.env /var/www/lesstime-docker/.env
    cp -a /var/www/lesstime/config/jwt /var/www/lesstime-docker/config/jwt
    cp -a /var/www/lesstime/var/uploads /var/www/lesstime-docker/uploads
    
  4. Creer docker-compose.yml et deploy.sh dans /var/www/lesstime-docker/ (voir etape 4 ci-dessus)
  5. Editer /var/www/lesstime-docker/.env : changer DATABASE_URL pour utiliser host.docker.internal au lieu de 127.0.0.1
  6. Se connecter au registry Gitea (voir etape 3 ci-dessus)
  7. Mettre a jour Nginx systeme avec la conf reverse proxy (voir etape 8 ci-dessus)
  8. Arreter l'ancien PHP-FPM : sudo systemctl stop php8.4-fpm
  9. Deployer : cd /var/www/lesstime-docker && ./deploy.sh
  10. Verifier que tout marche, puis renommer le dossier : mv /var/www/lesstime-docker /var/www/lesstime