SaaS & back-office
Les deux exemples déploient des produits open source existants, avec leurs images ou leurs dépôts officiels : ils s’importent sans rien écrire. Le premier est une stack à compose en ligne (le compose est dans le blueprint), le second une stack Git (le compose est lu dans le dépôt du produit).
Prise de rendez-vous : Cal.com
Section intitulée « Prise de rendez-vous : Cal.com »Cal.com est une application de planification : pages de réservation, agendas
connectés, rappels. L’image officielle calcom/cal.com applique elle-même ses migrations au
démarrage. Elle a besoin de DATABASE_URL et de DATABASE_DIRECT_URL ; comme un binding
n’injecte qu’une seule variable par add-on, la base PostgreSQL est un conteneur de la stack, avec son
volume.
apiVersion: cassiope.eu/v1alpha2kind: Blueprintproject: slug: planification name: Planification environments: - slug: production name: Production stacks: - slug: calcom name: Cal.com compose: | services: calcom: image: calcom/cal.com:v6.2.0 environment: NEXT_PUBLIC_WEBAPP_URL: ${NEXT_PUBLIC_WEBAPP_URL} NEXTAUTH_SECRET: ${NEXTAUTH_SECRET} CALENDSO_ENCRYPTION_KEY: ${CALENDSO_ENCRYPTION_KEY} DATABASE_HOST: database:5432 DATABASE_URL: postgresql://calcom:${POSTGRES_PASSWORD}@database:5432/calendso DATABASE_DIRECT_URL: postgresql://calcom:${POSTGRES_PASSWORD}@database:5432/calendso CALCOM_TELEMETRY_DISABLED: "1" depends_on: database: condition: service_healthy restart: always
database: image: postgres:16-alpine environment: POSTGRES_DB: calendso POSTGRES_USER: calcom POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - database-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U calcom -d calendso"] interval: 5s timeout: 5s retries: 10 restart: always
volumes: database-data: services: - { name: calcom, cpuMillicores: 1000, ramMb: 2048 } - { name: database, cpuMillicores: 500, ramMb: 1024 } volumes: - { name: database-data, sizeGb: 10 } exposed: - { serviceName: calcom, port: 3000 } env: - key: NEXT_PUBLIC_WEBAPP_URL value: ${CASSIOPE_PUBLIC_URL} - key: NEXTAUTH_SECRET fromSecret: true - key: CALENDSO_ENCRYPTION_KEY fromSecret: true - key: POSTGRES_PASSWORD fromSecret: trueValeurs à fournir à l’import, jamais dans le fichier. Générez-les avec
openssl rand -base64 32 (NEXTAUTH_SECRET, CALENDSO_ENCRYPTION_KEY) et openssl rand -hex 24
(POSTGRES_PASSWORD : sans caractère spécial, il entre dans une URL) :
{ "production/calcom": { "NEXTAUTH_SECRET": "…", "CALENDSO_ENCRYPTION_KEY": "…", "POSTGRES_PASSWORD": "…" }}Ce qu’il faut savoir :
- L’adresse publique est injectée.
NEXT_PUBLIC_WEBAPP_URLvaut${CASSIOPE_PUBLIC_URL}: la plateforme y met l’adresse du conteneur exposé (calcom), ou votre domaine personnalisé une fois vérifié, à chaque déploiement — rien à copier. - Le premier démarrage applique les migrations : comptez quelques minutes avant que la page d’inscription réponde. Le premier compte créé devient l’administrateur.
CALENDSO_ENCRYPTION_KEYchiffre les identifiants d’agenda en base : la perdre rend ces identifiants illisibles. Conservez-la avec vos sauvegardes.
CRM interne : Twenty
Section intitulée « CRM interne : Twenty »Twenty est un CRM open source (contacts, entreprises, opportunités). Son
dépôt publie un docker-compose.yml officiel — serveur, worker de tâches de fond, PostgreSQL et
Redis — que la plateforme lit directement, sans copie, à la version épinglée. Le dépôt est
public : aucune connexion GitHub n’est nécessaire.
apiVersion: cassiope.eu/v1alpha2kind: Blueprintproject: slug: crm-interne name: CRM interne environments: - slug: production name: Production stacks: - slug: twenty name: Twenty gitProvider: github gitRepo: twentyhq/twenty gitBranch: twenty/v2.51.0 composeLocation: /packages/twenty-docker/docker-compose.yml services: - { name: server, cpuMillicores: 1000, ramMb: 2048 } - { name: worker, cpuMillicores: 500, ramMb: 1024 } - { name: db, cpuMillicores: 500, ramMb: 1024 } - { name: redis, cpuMillicores: 250, ramMb: 512 } volumes: - { name: db-data, sizeGb: 10 } - { name: server-local-data, sizeGb: 5 } exposed: - { serviceName: server, port: 3000 } composeOverride: | services: server: ports: !reset [] deploy: resources: limits: cpus: "1" memory: "2048M" healthcheck: interval: 10s retries: 20 start_period: 480s worker: deploy: resources: limits: cpus: "0.5" memory: "1024M" db: deploy: resources: limits: cpus: "0.5" memory: "1024M" redis: deploy: resources: limits: cpus: "0.25" memory: "512M" env: - key: TAG value: v2.51.0 - key: SERVER_URL value: ${CASSIOPE_PUBLIC_URL} - key: STORAGE_TYPE value: local - key: DISABLE_DB_MIGRATIONS value: "false" - key: DISABLE_CRON_JOBS_REGISTRATION value: "false" - key: STORAGE_S3_REGION value: "" - key: STORAGE_S3_NAME value: "" - key: STORAGE_S3_ENDPOINT value: "" - key: STORAGE_S3_ACCESS_KEY_ID value: "" - key: STORAGE_S3_SECRET_ACCESS_KEY value: "" - key: FALLBACK_ENCRYPTION_KEY value: "" - key: ENCRYPTION_KEY fromSecret: true - key: PG_DATABASE_PASSWORD fromSecret: trueValeurs à fournir à l’import (openssl rand -base64 32 pour la clé, openssl rand -hex 32 pour le mot
de passe de base) :
{ "production/twenty": { "ENCRYPTION_KEY": "…", "PG_DATABASE_PASSWORD": "…" }}Ce qu’il faut savoir :
- Deux versions à garder alignées.
gitBranchfixe la version du compose lu dans le dépôt,TAGcelle de l’image qu’il démarre : changez-les ensemble. SERVER_URLvaut${CASSIOPE_PUBLIC_URL}, l’adresse du conteneurserverinjectée par la plateforme. Les variablesSTORAGE_S3_*sont vides parce que le stockage est local ; le compose les référence sans valeur de repli, elles doivent donc exister.- Le compose du dépôt publie le port 3000 sur la machine : la plateforme retire cette publication
et expose le conteneur
serverà la place. - Le premier démarrage dure plusieurs minutes. Le serveur crée le schéma puis applique les
migrations avant d’écouter, et le compose du dépôt ne lui laisse qu’environ 100 s. Le bloc
composeOverrideporte la sonde à 8 minutes de grâce (start_period) ; sans lui, le déploiement échoue en « unhealthy » au milieu des migrations et laisse une base à moitié initialisée que les redéploiements ne réparent pas. Il reprend aussi la publication de port retirée et les plafonds CPU/RAM du blueprint, qu’un override saisi à la main ne génère plus. ENCRYPTION_KEYprotège les secrets stockés par Twenty (jetons d’agenda, de messagerie) : gardez-la.- Un CRM interne ne doit pas être ouvert à tous : restreignez les inscriptions dans les paramètres de Twenty une fois le premier espace de travail créé.