Installazione
La distribuzione dei servizi della piattaforma avviene mediante immagini docker, non ci sono requisiti particolari in merito all'orchestratore utilizzato (docker swarm, kubernetes, nomad, mesos).
Installazione ambiente di Test / Sviluppo
Per una installazione di test su singolo nodo si consiglia di usare il service compose presente nei due repository principali:
docker-compose.yml dal repo dei sito istituzionale e leggere con attenzione il README.
docker-compose.yml dal core dei servizi digitali e leggere con attenzione il README.
Installazione ambiente di Produzione
Per un ambiente di produzione è indispensabile predisporre un ambiente con adeguati livelli di ridondanza e dimensionamento dei singoli servizi in base alla propria infrastruttura e ai propri requisiti in termini di affidabilità e livelli di servizio da garantire.
Non c'e' una ricetta valida a priori per dimensionare il sistema, si consiglia di partire da una configurazione con 2 repliche di ogni servizio stateless e un dimensionamento molto largo (es: 1GB di ram, 1 vCPU) e poi monitorare il proprio sistema per stabilire i requisiti di ogni singolo container: si potrà verificare facilmente che molti microservizi richiedono pochi Mb di ram.
Elenco dei servizi necessari
Ogni servizio si basa su una immagine docker specifica e necessita di adeguate configurazioni. Le configurazioni e i valori di default delle stesse sono documentate nei singoli repository dei microservizi.
Al fine di dare una corretta configurazione dei vari servizi vengono indicate inoltre:
la dipendenza dalle persistenze usate dalla piattaforma
la necessità di pubblicare un endpoint per quel servizio pubblicamente raggiungibile
Sito istituzionale
cms-core
Servizio principale del CMS, consente l'accesso della radazione per la gestione dei contenuti e fornisce l'interfaccia di navigazione per i cittadini
solr
Motore di ricerca in cui il cms indicizza i contenuti per rendere performante la ricerca sul sito
Servizi digitali e Area Personale
app-web
Servizio principale della piattaforma, gestisce pratiche, appuntamenti, offre interfacce di configurazione per gli amministratori e di gestione operativa per i funzionari degli enti. E' inoltre l'interfaccia principale anche per l'esperienza utente.
app-worker
Esecuzione delle operazioni asincrone del Core (creazione PDF, invio di messaggi, webhooks, ...)
form-builder
Applicativo per la gestione dei subform condivisi da tutti i moduli form.io
payment- dispatcher-v1
Genera, se necessario, un evento Versione 1 di pagamento da un evento di una pratica
payment- dispatcher-v2
Genera, se necessario, un evento Versione 2 di pagamento da un evento di una pratica
payment-updater
Ascolta sul topic di kafka dei pagamenti e aggiorna lo stato delle pratiche di conseguenza
ksqldb
Ascolta su tutti i topic di kafka ed espone via API dati aggregati sugli eventi della piattaforma
kafka-core-api
Espone un endpoint http che il core usa per inviare eventi sui topic di kafka
payments poller
Legge da Ksql i pagamenti pendenti e per ognuno di essi chiama il proxy che lo gestisce per aggiornare lo stato del pagamento
XXX-payment proxy
Servizio per l'integrazione con l'intermediario di pagamento XXX (vedi Integrazioni per la lista completa)
YYY-protocol- proxy
Servizio per l'integrazione con il sistema di protocollo YYY (vedi Integrazioni per la lista completa)
registry-api
API per l'app Django con cui abbiamo integrato una decina di protocolli
registry-scheduler
Scheduler per gli errori registrati durante un tentativo di protocollazione
analytics-first-availability-aggregator
Servizio per il calcolo dei KPI sui Calendari
satisfy-api
API per la raccolta di ratings e questionari di Customer Satisfaction
satisfy-ratings-aggregator
Servizio per il calcolo dei KPI della Customer Satisfaction
pdnd-connector
Servizio che gestisce l'interazione con la pdnd e gli enti erogatori degli e-service utilizzati dalla piattaforma
retry-orchestrator
Servizio che gestisce i retry dei messaggi provenienti dai vari topic di kafka
Esempio di un file di deployment per orchestratore Docker Swarm:
Prima di procedere all’avvio dei microservizi si devono compiere alcune operazioni:
Creazione del file delle istanze
Va creato un file instances.yml
sull'ambiente che ospiterà la piattaforma, questo file dovrà poi essere condiviso con i servizi che ne hanno bisogno (vedi file di esempio di distribuzione).
Il file è così formato:
instances:
# dominio dell'sitanza con prefisso
stanzadelcittadino.localtest.me/comune-di-bugliano:
# codice meccanografico dell'ente
codice_meccanografico: c_cbug
# identificativo dell'istanza
identifier: comune-di-bugliano
# lingue disponibili (it, de, en)
app_locales: it|en
# tipo di login (da scegliere in base al provider dell'ente)
login_route: login_pat
Andrà creato un blocco istanza per ogni ente che si vorrà ospitare sulla piattaforma
Creazione dei database
Singole istanze degli enti (Symfony core)
Il tipo di multi-tenancy implementata in OpenCity Area personale è di singolo stack applicativo con database dedicato per tenant.
Per poter effettuare un’installazione dell’infrastruttura abbiamo quindi bisogno di un singolo database per tenant con le seguenti caratteristiche.
Postgres >= 11 con estensione postgis >= 3
Permessi
Per ridurre i rischi dovuti a errori o a compromissione delle credenziali vengono usati due utenti differenti:
un utente oc_manager che viene utilizzato per creare i database ed eseguire operazione di struttura (creazione, modifica e cancellazione di tabelle, viste, colonne ecc ecc)
un utente oc_user che viene utilizzato dall’applicativo per effettuare operazioni sui dati
Attualmente nella nostra infrastruttura la creazione del database avviene con l'utente oc_manager, a partire da un template preimpostato con i privilegi necessari.
Creazione del template
Come utente postgres si crea il database impostando i privilegi di default che verranno assegnati a tutti gli oggetti creati in seguito.
A postgres verranno dati privilegi ampi, mentre a oc_user verranno dati privilegi minimali:
CREATE DATABASE _oc ENCODING='utf8' CONNECTION LIMIT=50;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT ALL ON TYPES TO postgres WITH GRANT OPTION;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO postgres;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT ALL ON SEQUENCES TO postgres;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT ALL PRIVILEGES ON TABLES TO postgres;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT USAGE ON TYPES TO oc_user;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT EXECUTE ON FUNCTIONS TO oc_user;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT ALL ON SEQUENCES TO oc_user;
ALTER DEFAULT PRIVILEGES FOR USER oc_manager IN SCHEMA "public" GRANT SELECT,INSERT,UPDATE,DELETE ON TABLES TO oc_user;
CREATE EXTENSION IF NOT EXISTS postgis;
In seguito la proprietà del database viene assegnata ad oc_manager
ALTER DATABASE _oc OWNER TO oc_manager;
ALTER SCHEMA public OWNER TO oc_manager;
Per creare database come utente postgres gli viene dato il ruolo oc_manager
GRANT oc_manager TO postgres;
Creazione di un nuovo database
Per creare il database e impostarne subito come owner l'utente corretto, si esegue come utente postgres
CREATE DATABASE oc_firenze TEMPLATE = _oc OWNER='oc_manager' ENCODING='utf8' CONNECTION LIMIT=50;Some code
Sistema di protocollazione (registry)
Il sistema di protocollazione ha invece bisogno di un singolo database con le seguenti caratteristiche:
Postgres >= 11
Creazione di un nuovo utente
CREATE USER registry_user WITH PASSWORD 'password';
Tuning di alcuni parametri di connessione (questi comandi sono opzionali ma suggeriti da django)
ALTER ROLE registry_user SET client_encoding TO 'utf8';
ALTER ROLE registry_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE registry_user SET timezone TO 'UTC';
Creo il database e lo assegno all'utente
CREATE DATABASE oc_registry ENCODING='utf8' CONNECTION LIMIT=50;
GRANT ALL PRIVILEGES ON DATABASE oc_registry TO registry_user;
Configurazione dei proxy di pagamento
Per garantire una corretta comunicazione tra l'area personale e i proxy di pagamento è necessaria configurare appropriatamente gli endpoint sul proxy di riferimento.
Configurazione dei CORS
Il requisito di base affinchè questi endpoint siano correttamente funzionanti è che siano correttamente racchiuse all'interno di un middleware che gestisca i CORS in maniera adeguata. In particolare questo middleware dovrà essere configurato come segue:
Access-Control-Allow-Credentials
true
Access-Control-Allow-Headers
Authorization,Origin,Content-Type,Accept,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,access-control-allow-credentials,Referer
Access-Control-Allow-Methods
GET,POST,HEAD,PUT,DELETE,PATCH,OPTIONS
Access-Control-Allow-Origin-List
*
Access-Control-Max-Age
100
Add-Vary-Header
true
Di seguito un esempio di configurazione del middleware:
traefik.http.middlewares.cors.headers.accesscontrolallowcredentials: 'true'
traefik.http.middlewares.cors.headers.accesscontrolallowheaders: 'Authorization,Origin,Content-Type,Accept,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,access-control-allow-credentials,Referer'
traefik.http.middlewares.cors.headers.accesscontrolallowmethods: 'GET,POST,HEAD,PUT,DELETE,PATCH,OPTIONS'
traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist: '*'
traefik.http.middlewares.cors.headers.accesscontrolmaxage: 100
traefik.http.middlewares.cors.headers.addvaryheader: 'true'
Endpoint interni (non necessita di CORS)
L'unico endpoint interno in questo caso è quello per richiedere l'aggiornamento dello stato di un pagamento. Per garantire quindi che questo venga chiamato solo ed esclusivamente dal microservizio di polling, è necessario che questo venga configurato come endpoint raggiungibile solo internamente alla rete di docker. Di seguito un esempio:
networks:
backplane-sdc:
external: true
internal:
traefik-sdc:
external: true
swarm-backplane:
external: true
...
networks:
- traefik-sdc
- backplane-sdc
deploy:
<<: *deploy-snippet
labels:
traefik.enable: 'true'
traefik.docker.network: 'traefik-sdc'
traefik.http.routers.silfi-proxy-qa-internal.entrypoints: 'backplane'
traefik.http.routers.silfi-proxy-qa-internal.rule: 'Host(`silfi-proxy-qa.boat-backplane.opencontent.io`) && PathPrefix(`/payment-proxy/silfi/update/{id:[^/]+}`) && METHOD(`GET`, `HEAD`, `OPTIONS`)'
Endpoint pubblici
Gli endpoint pubblici sono:
Pagamento online (
/online-payment/{payment_id}
)Download dell'avviso cartaceo (
/offline-payment/{payment_id}
)Download della ricevuta telematica (
/receipt/{payment_id}
)Ritorno alla area personale (detta anche landing url) (
/landing/{payment_id}
)Form schema per la configurazione del tenant (
/tenants/schema
)Form schema per la configurazione del servizio (
/services/schema
)Documentazione Swagger delle API (
/docs
)Status (
/status
, facoltativo)Metriche di monitoraggio (
/metrics
, facoltativo)
Di seguito un esempio di configurazione degli endpoint
traefik.http.routers.silfi-proxy-qa.entrypoints: 'web, websecure'
traefik.http.routers.silfi-proxy-qa.rule: 'Host(`api.qa.stanzadelcittadino.it`) && PathPrefix(`/payment-proxy/silfi/{op:(notice|online-payment|receipt|landing)}/{id:[^/]+}`, `/payment-proxy/silfi/{op:(docs|status|metrics)}`, `/payment-proxy/silfi/{op:(tenants|services)}/schema`) && METHOD(`GET`, `POST`, `PUT` ,`PATCH`, `DELETE`, `HEAD`, `OPTIONS`)'
traefik.http.routers.silfi-proxy-qa.tls: 'true'
traefik.http.routers.silfi-proxy-qa.tls.certresolver: 'mydnschallenge'
traefik.http.routers.silfi-proxy-qa.middlewares: 'goodheaders, cors'
Endpoint protetti
Gli endpoint protetti da autenticazione sono:
Inserimento, recupero, modifica e cancellazione della configurazione del tenant (
/tenants/{id}
)Inserimento, recupero, modifica e cancellazione della configurazione del servizio (
/services/{id}
)
Di seguito un esempio di configurazione degli endpoint:
# Quando pronti aggiungere il middleware
# sdc-qa-jwt-decode
traefik.http.routers.silfi-proxy-qa-protected.entrypoints: 'web, websecure'
traefik.http.routers.silfi-proxy-qa-protected.rule: 'Host(`api.qa.stanzadelcittadino.it`) && PathPrefix(`/payment-proxy/silfi/{op:(tenants|services)}`, `/payment-proxy/silfi/{op:(tenants|services)}/{id:[^/]+}`) && METHOD(`GET`, `POST`, `PUT` ,`PATCH`, `DELETE`,>
traefik.http.routers.silfi-proxy-qa-protected.tls: 'true'
traefik.http.routers.silfi-proxy-qa-protected.tls.certresolver: 'mydnschallenge'
# MIDDLEWARE ABILITATO PER CONTROLLO JWT
# traefik.http.routers.silfi-page-proxy-qa-protected.middlewares: 'sdc-qa-jwt-decode, goodheaders, cors'
traefik.http.routers.silfi-proxy-qa-protected.middlewares: 'goodheaders, cors'
Last updated
Was this helpful?