Cosa sono i container nel cloud computing?
Da quando Docker ha fatto il suo ingresso sulla scena nel 2013, i container sono diventati sempre più popolari. Molte aziende hanno già integrato i container nei loro flussi di lavoro perché consentono di distribuire, distribuire, gestire e scalare facilmente il software.
In questo articolo spiegheremo cosa sono i container nel cloud computing. Parleremo dei vantaggi dell’uso dei container, dei loro casi d’uso, li confronteremo con le macchine virtuali e daremo un’occhiata a Docker e Kubernetes. Infine, vi insegneremo come codificare, dockerizzare e distribuire un’applicazione web su Back4app Containers – in modo assolutamente gratuito!
Contents
- 1 Definizione di contenitore
- 2 Vantaggi dell’utilizzo dei contenitori
- 3 Casi d’uso dei contenitori
- 4 Contenitori contro macchine virtuali
- 5 Docker e Kubernetes
- 6 Sviluppare un’applicazione utilizzando l’architettura basata su container
- 7 Conclusione
- 8 FAQ
- 9 Che cos’è un container?
- 10 Quali sono i vantaggi dell’uso dei container?
- 11 Qual è la differenza tra container e macchine virtuali?
- 12 Qual è la differenza tra Docker e Kubernetes?
- 13 Come sviluppare un’app utilizzando un’architettura basata su container?
Definizione di contenitore
Un contenitore è un pacchetto eseguibile autonomo che include tutto ciò che serve per eseguire un’applicazione: codice, runtime, librerie, variabili d’ambiente e file di configurazione. L’aspetto più interessante delle applicazioni containerizzate è che possono essere eseguite ovunque, dall’ambiente di sviluppo locale ai cloud pubblici e così via. I contenitori sono di dimensioni ridotte, efficienti e consentono un isolamento efficace.
Vantaggi dell’utilizzo dei contenitori
L’uso dei contenitori presenta diversi vantaggi. Vediamone alcuni.
Efficienza
I container richiedono meno risorse di sistema rispetto ai server tradizionali o alle macchine virtuali perché non includono un’immagine del sistema operativo. Ciò li rende estremamente efficienti, di dimensioni ridotte (solitamente misurate in MB) e consente di eseguire un numero significativo di applicazioni su un unico server.
Isolamento dell’applicazione
I container isolano l’applicazione e le sue dipendenze dal sistema host. Allo stesso tempo, sono in grado di condividere il kernel del sistema operativo e le risorse di sistema come la CPU, la memoria, lo storage e la rete.
Portabilità
Il software containerizzato può essere eseguito e comportarsi allo stesso modo praticamente su qualsiasi macchina che abbia installato il motore del container. Questo facilita la distribuzione e lo spostamento delle applicazioni tra ambienti diversi ed elimina il problema “funziona sulla mia macchina”.
Separazione delle responsabilità
I container consentono di separare le responsabilità dividendo i compiti e le responsabilità tra sviluppatori e team operativi IT. Gli sviluppatori sono responsabili della creazione e della manutenzione del codice dell’applicazione e delle dipendenze, mentre i team operativi IT si concentrano sulla distribuzione e sulla gestione dei container e dell’infrastruttura sottostante.
Sviluppo di applicazioni più rapido
La containerizzazione facilita lo sviluppo, il test, la gestione e la distribuzione del software. I container possono essere facilmente integrati con i sistemi CI/CD, accelerando notevolmente il processo di sviluppo e spedizione del software.
Facile scalabilità
Le applicazioni containerizzate in combinazione con una piattaforma di orchestrazione come Kubernetes possono facilmente scalare su richiesta. Ciò consente all’azienda di gestire carichi di lavoro elevati riducendo al minimo i costi.
Casi d’uso dei contenitori
La tecnologia dei container ha molti casi d’uso sia per gli sviluppatori che per i team operativi IT.
Sviluppo Container-Nativo
Lo sviluppo container-nativo è un approccio allo sviluppo del software che sfrutta i container come elemento principale. Nello sviluppo container-native, le applicazioni vengono impacchettate come container ed eseguite in un ambiente containerizzato. Questo approccio di sviluppo offre tutti i vantaggi che i container hanno da offrire.
Integrazione continua e consegna continua (CI/CD)
In una pipeline CI/CD, i container vengono utilizzati per pacchettizzare le applicazioni ed eseguire test automatici, rendendo possibile testare e distribuire le applicazioni in modo coerente e ripetibile. I container possono essere facilmente creati, testati e distribuiti come parte della pipeline CI/CD, riducendo il rischio di errori e migliorando l’efficienza complessiva del processo di sviluppo del software.
Microservizi
I container possono essere utilizzati per sviluppare applicazioni che seguono un’architettura a microservizi. Con i container, si può facilmente dividere l’applicazione monolitica in una collezione di servizi ad accoppiamento libero e a grana fine, che vengono eseguiti in container diversi.
Ambiente di sviluppo
I container facilitano ai team di sviluppatori la configurazione rapida degli ambienti di sviluppo. Forniscono ambienti di sviluppo coerenti, indipendentemente dal sistema operativo e dalle librerie host.
Processi batch
I processi batch possono essere facilmente containerizzati e distribuiti nel cloud. Ogni task è confezionato come immagine di un container individuale ed eseguito come istanza di un container separato. Ciò consente un utilizzo efficiente delle risorse, poiché ogni task viene eseguito nel proprio ambiente e non interferisce con altri task.
Contenitori contro macchine virtuali
I container e le macchine virtuali sono due approcci diversi alla virtualizzazione. Sebbene abbiano alcune somiglianze, sono molto diversi.
Le macchine virtuali (VM) sono un’astrazione dell’hardware fisico. Permettono di trasformare un server in più server. Ogni macchina virtuale ha il proprio sistema operativo e di solito è gestita da un hypervisor. Le macchine virtuali sono adatte per l’esecuzione di più applicazioni (sullo stesso server), applicazioni monolitiche e applicazioni che richiedono un elevato grado di isolamento e sicurezza. Il loro svantaggio è che tendono a occupare molto spazio e possono essere piuttosto lente ad avviarsi.
I container, invece, sono virtualizzati a livello di sistema operativo. Occupano meno spazio perché condividono lo stesso kernel Linux, sono più efficienti, si avviano più velocemente, sono altamente scalabili e possono gestire più applicazioni. I container sono gestiti da un Container Engine. I loro principali casi d’uso, a differenza delle macchine virtuali, sono i microservizi e le applicazioni che devono essere portatili, leggere e scalabili.
È anche possibile combinare container e macchine virtuali per ottenere i vantaggi di entrambi.
Docker e Kubernetes
Due degli strumenti più popolari per lavorare con i container sono Docker e Kubernetes. Spieghiamo come funzionano ed esaminiamo le loro differenze.
Docker è un progetto open-source basato su Linux e utilizzato per automatizzare la distribuzione e la gestione delle applicazioni in contenitori leggeri. Ciò consente alle applicazioni containerizzate di funzionare in modo efficiente in ambienti diversi. Al giorno d’oggi Docker si trova praticamente ovunque, dalle macchine Linux ai grandi provider di cloud e così via.
Le alternative più popolari a Docker sono Podman, LXD e Containerd.
Kubernetes (K8s) è un sistema di orchestrazione di container open-source per automatizzare il deployment, lo scaling e la gestione di applicazioni containerizzate. Dal suo rilascio nel 2014, è diventato lo standard di fatto per la distribuzione e la gestione di applicazioni containerizzate in ambienti cloud. I vantaggi di Kubernetes includono scalabilità, alta disponibilità, operazioni automatizzate, astrazione dell’infrastruttura e monitoraggio dello stato di salute.
Altre piattaforme di orchestrazione includono: AWS ECS, Nomad e Red Hat OpenShift.
Qual è la differenza tra Docker e Kubernetes? In parole povere, Docker ci permette di impacchettare e distribuire applicazioni all’interno di container, mentre Kubernetes semplifica il lavoro di più container in armonia tra loro.
Sviluppare un’applicazione utilizzando l’architettura basata su container
In questa sezione dell’esercitazione, creeremo, dockerizzeremo e distribuiremo una semplice API REST su Back4app Containers.
Che cos’è Back4app Containers?
Back4app Containers è una piattaforma open-source gratuita per la distribuzione e la scalabilità di applicazioni su container distribuiti a livello globale in un’infrastruttura cloud.
Vi permette di concentrarvi sul vostro software e di spedirlo più velocemente senza dovervi preoccupare di DevOps. La piattaforma è strettamente integrata con GitHub, ha un sistema CI/CD integrato e consente di rendere operativa la vostra applicazione in pochi minuti!
Perché utilizzare Back4app Containers?
- Si integra bene con GitHub
- Distribuzioni a tempo zero
- Facile da usare e con un livello gratuito
- Assistenza clienti eccellente
Introduzione al progetto
Costruiremo una semplice API REST che servirà come lista di film da guardare. L’applicazione web consentirà operazioni CRUD di base, come l’aggiunta di un film, l’eliminazione di un film e così via. Per creare l’API utilizzeremo il framework Flask. Infine, faremo Dockerizzare il progetto e dimostreremo quanto sia facile distribuirlo su Back4app Containers.
Prerequisiti
- Esperienza con il framework Flask
- Conoscenza di base di Docker e dei container
- Capacità di utilizzare Git e GitHub
Codice App
I passi seguenti richiedono l’installazione di Python. Se non avete ancora installato Python, scaricatelo.
Inizializzazione del progetto
Per prima cosa, create una directory dedicata alla vostra applicazione e navigate al suo interno:
$ mkdir flask-watchlist
$ cd flask-watchlist
Quindi, creare un nuovo ambiente virtuale e attivarlo:
$ python3 -m venv venv && source venv/bin/activate
Poiché utilizzeremo Flask come framework, dobbiamo installarlo:
$ (venv) pip install Flask==2.2.2
Creare app.py con i seguenti contenuti:
# app.py
from flask import Flask
app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
@app.route('/')
def index_view():
return {
'detail': 'Hello world!'
}
Questo codice inizializza Flask e crea un semplice endpoint che restituisce un messaggio.
Eseguire il server con:
$ flask run
Andate all’indirizzo http://localhost:5000/ e dovreste vedere un messaggio con scritto Hello world!
Database
Per il database utilizzeremo SQLite. SQLite è un sistema di gestione di database relazionali integrato e senza server. Per semplificare il lavoro con il database, installeremo Flask-SQLAlchemy, un’estensione per Flask che aggiunge il supporto per SQLAlchemy alla vostra applicazione.
Procedete all’installazione eseguendo:
$ (venv) pip install Flask-SQLAlchemy==3.0.3
Quindi, andare all’inizio di app.py e modificarlo in questo modo per inizializzare il database:
# app.py
db = SQLAlchemy()
app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
app.config['SECRET_KEY'] = '5b3cd5b80eb8b217c20fb37074ff4a33'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///default.db"
db.init_app(app)
Non dimenticatevi dell’importazione:
from flask_sqlalchemy import SQLAlchemy
Quindi, definiamo i nostri modelli di database.
Dato che stiamo costruendo una semplice applicazione per la visione di film, avremo bisogno di un solo modello. Definiamo il modello Movie
in questo modo:
# app.py
class Movie(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(128), nullable=False)
release_date = db.Column(db.Date(), nullable=False)
is_watched = db.Column(db.Boolean, default=False)
watched_at = db.Column(db.DateTime, default=None, nullable=True)
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
def __repr__(self):
return '<Movie %r>' % self.title
Per inizializzare e popolare il nostro database creeremo un semplice script Python. Navigare nella radice del progetto e creare un nuovo file chiamato init_db.py con il seguente contenuto:
# init_db.py
from datetime import date
from app import db, app
from app import Movie
with app.app_context():
db.create_all()
if Movie.query.count() == 0:
movies = [
Movie(title='Fight Club', release_date=date(1999, 9, 15)),
Movie(title='The Matrix', release_date=date(1999, 3, 31)),
Movie(title='Donnie Darko', release_date=date(2001, 1, 19)),
Movie(title='Inception', release_date=date(2010, 7, 16)),
]
for movie in movies:
db.session.add(movie)
db.session.commit()
L’ultima cosa da fare è eseguire lo script:
$ (venv) python init_db.py
Questo crea il database, le tabelle del database e le popola. Il file del database sarà collocato nella cartella dell’istanza.
Endpoint API
La nostra applicazione web avrà i seguenti endpoint:
/
restituisce le informazioni API di base/api/
restituisce l’elenco dei filmati/api/create/
aggiunge un nuovo film alla watchlist/api/
/ restituisce i dettagli di un film specifico/api/watch/
/ contrassegna il filmato come visto
Procedere con la definizione degli endpoint in fondo ad app.py:
# app.py
@app.route('/')
def index_view():
return {
'name': 'flask-watchlist',
'description': 'a simple app for tracking the movies you want to watch',
'version': 1.1,
}
@app.route('/api/')
def list_view():
json = [movie.as_dict() for movie in Movie.query.all()]
return jsonify(json)
@app.route('/api/<int:movie_id>/', methods=['GET', 'DELETE'])
def detail_view(movie_id):
movie = db.get_or_404(Movie, movie_id)
if request.method == 'DELETE':
db.session.delete(movie)
db.session.commit()
return {
'detail': 'Movie has been successfully deleted.'
}
else:
return movie.as_dict()
@app.route('/api/create/', methods=['POST'])
def create_view():
title = request.form.get('title')
release_date = request.form.get('release_date', type=float)
if title is None or release_date is None:
return {
'detail': 'Please provide the title and release_date.'
}, 400
movie = Movie(title=title, release_date=datetime.fromtimestamp(release_date))
db.session.add(movie)
db.session.commit()
return movie.as_dict()
@app.route('/api/watch/<int:movie_id>/')
def watch_view(movie_id):
movie = db.get_or_404(Movie, movie_id)
if movie.is_watched:
return {
'detail': 'Movie has already been watched.'
}, 400
movie.is_watched = True
movie.watched_at = datetime.now()
db.session.commit()
return movie.as_dict()
Non dimenticatevi delle importazioni:
from datetime import datetime
from flask import request, jsonify
Bene, la nostra applicazione è ora più o meno completa. Eseguire il server di sviluppo:
$ (venv) flask run
Verificare se è possibile recuperare l’elenco dei film:
$ (venv) curl http://localhost:5000/api/ | jq '.'
[
{
"id": 1,
"title": "Fight Club",
"release_date": "Wed, 15 Sep 1999 00:00:00 GMT",
"is_watched": false,
"watched_at": null
},
{
"id": 2,
"title": "The Matrix",
"release_date": "Wed, 31 Mar 1999 00:00:00 GMT",
"is_watched": false,
"watched_at": null
},
...
]
Gunicorno
Il server di sviluppo Flask non è adatto alla produzione, quindi sostituiamolo con Gunicorn. Gunicorn o “Unicorno verde” è un server HTTP Python WSGI per Unix pronto per la produzione.
Installatelo eseguendo:
$ (venv) pip install gunicorn==20.1.0
Una volta installato il pacchetto, si può avviare il server WSGI in questo modo:
$ (venv) gunicorn -w 2 -b 0.0.0.0:5000 app:app
[INFO] Starting gunicorn 20.1.0
[INFO] Listening at: http://0.0.0.0:5000 (1)
[INFO] Using worker: sync
[INFO] Booting worker with pid: 7
[INFO] Booting worker with pid: 8
Tenete presente che questo comando funziona solo sui sistemi operativi basati su UNIX.
In questo modo si avviano due worker Gunicorn e si espone l’applicazione a Internet. Per accedere all’applicazione, aprire il browser web preferito e navigare su http://localhost:5000.
requisiti.txt
L’ultima cosa da fare prima di Dockerizzare la nostra applicazione è creare un file requirements.txt. Il file requirements.txt è usato per specificare le dipendenze del progetto.
Il modo più semplice per generarlo è eseguire:
$ (venv) pip freeze > requirements.txt
App Dockerize
I passaggi seguenti richiedono l’installazione di Docker. Il modo più semplice per installare Docker è scaricare Docker Desktop.
Per verificare che Docker sia installato, eseguire:
$ docker --version
Docker version 20.10.22, build 3a2c30b
Profilo Docker
Per dockerizzare la nostra applicazione useremo un Dockerfile. Un Dockerfile è un file di testo semplice che ci permette di definire l’immagine di base, l’ambiente, le variabili ambientali, i comandi, le impostazioni di rete, i volumi e così via.
Creare un file Docker nella root del progetto con i seguenti contenuti:
# syntax=docker/dockerfile:1.4
FROM --platform=$BUILDPLATFORM python:3.10-alpine
# set the working directory
WORKDIR /app
# set environmental variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install the requirements
COPY requirements.txt /app
RUN --mount=type=cache,target=/root/.cache/pip \
pip3 install -r requirements.txt
# copy the code to the container
COPY . .
# initialize the database (create DB, tables, populate)
RUN python init_db.py
# expose
EXPOSE 5000/tcp
# entrypoint command
CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:5000", "app:app"]
- Abbiamo usato
python:3.10-alpine
come immagine di base. - Impostando
PYTHONDONTWRITEBYTECODE
a1
, Python non scriverà più i file .pyc su disco. - Impostando
PYTHONUNBUFFERED
a1
si assicura che i flussi di output di Python siano inviati direttamente al terminale.
Per ulteriori informazioni sulla scrittura dei file Docker, consultare il riferimento ai file Docker.
.dockerignore
Prima di creare un’immagine, Docker cerca un file .dockerignore. Un file .dockerignore ci permette di definire quali file non vogliamo includere nell’immagine. Questo può ridurre notevolmente le dimensioni dell’immagine. Funziona in modo simile a un file .gitignore.
Creare un file .dockerignore nella radice del progetto con i seguenti contenuti:
# .dockerignore
.git/
instance/
__pycache__/
.idea/
Assicuratevi di aggiungere altre directory o file che desiderate escludere.
Creare ed eseguire l’immagine
Procediamo con la creazione e l’etichettatura della nostra immagine Docker.
$ docker build -t flask-watchlist:1.0 .
[+] Building 11.1s (15/15) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 32B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 34B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1.4 0.5s
=> CACHED docker-image://docker.io/docker/dockerfile:1.4@sha256:9ba7531a0dbc 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load metadata for docker.io/library/python:3.10-alpine 0.5s
=> [stage-0 1/6] FROM docker.io/library/python:3.10-alpine@sha256:da5ab5e911253dfb 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 182.45kB 0.2s
=> CACHED [stage-0 2/6] WORKDIR /app 0.0s
=> [stage-0 3/6] COPY requirements.txt /app 0.0s
=> [stage-0 4/6] RUN --mount=type=cache,target=/root/.cache/pip
pip3 install -r requirements.txt 7.2s
=> [stage-0 5/6] COPY . . 0.3s
=> [stage-0 6/6] RUN python init_db.py 1.5s
=> exporting to image 0.3s
=> => exporting layers 0.3s
=> => writing image sha256:2671ccb7546a0594807c721a0600a 0.0s
=> => naming to docker.io/library/flask-watchlist:1.0
Se si elencano le immagini, si dovrebbe vedere la nostra nuova immagine:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-watchlist 1.0 7bce66230eb1 8 hours ago 110MB
Infine, utilizzare l’immagine per avviare un nuovo contenitore Docker:
$ docker run -it -p 5000:5000 flask-watchlist:1.0
[2023-02-02 20:08:57 +0000] [1] [INFO] Starting gunicorn 20.1.0
[2023-02-02 20:08:57 +0000] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)
[2023-02-02 20:08:57 +0000] [1] [INFO] Using worker: sync
[2023-02-02 20:08:57 +0000] [7] [INFO] Booting worker with pid: 7
[2023-02-02 20:08:57 +0000] [8] [INFO] Booting worker with pid: 8
È possibile usare
-d
per avviare il contenitore Docker in modalità distaccata. Ciò significa che il contenitore viene eseguito in background nel terminale e non riceve input né visualizza output.
Ben fatto, la vostra applicazione è ora in esecuzione in un contenitore! Navigare su http://localhost:5000 e ottenere la seguente risposta:
{
"name": "flask-watchlist",
"description": "a simple app for tracking the movies you want to watch",
"version": 1
}
GitHub
Per distribuire l’applicazione su Back4app Containers è necessario caricare il codice sorgente su un repository GitHub. Creare un nuovo repository su GitHub, aggiungere il remote, aggiungere .gitignore e fare il commit del codice. Una volta che il codice è su GitHub, passare al passo successivo.
Distribuzione dell’applicazione nei contenitori Back4app
Per eseguire i passaggi seguenti è necessario disporre di un account Back4app. Se lo avete già , accedete, altrimenti procedete con la registrazione dell’account gratuito.
Per lavorare con Back4app è necessario creare un’app. Quando si accede alla dashboard, viene visualizzato l’elenco delle app. Fare clic su “Crea una nuova app” per creare una nuova app.
Quindi, selezionare “Containers as a Service”.
Se non l’avete ancora fatto, collegate GitHub a Back4app e importate i repository che desiderate distribuire. Una volta collegato GitHub, i repository saranno visualizzati nella tabella.
Scegliere il repository che si desidera distribuire facendo clic su “Seleziona”.
Successivamente, Back4app chiederà di configurare l’ambiente. Scegliete il nome dell’applicazione, io sceglierò flask-watchlist
. Sentitevi liberi di lasciare tutto il resto come predefinito.
Infine, fare clic su “Create App” per creare automaticamente l’applicazione e distribuirla.
Si verrà quindi reindirizzati ai dettagli dell’applicazione, dove si potranno vedere i registri di distribuzione.
Attendete qualche minuto per la distribuzione dell’applicazione e voilà! La vostra applicazione è ora disponibile su Back4app Containers. Per vedere la vostra applicazione in azione, fate clic sull’URL verde visualizzato a sinistra.
Conclusione
Nel corso dell’articolo abbiamo spiegato cosa sono i container, i loro vantaggi e dimostrato come si possono implementare i container nel proprio flusso di lavoro. A questo punto dovreste essere in grado di costruire la vostra semplice API REST, dockerizzarla e distribuirla su Back4app Containers.
Prendete il codice sorgente finale dal repo GitHub.
Passi futuri
- Non si dovrebbe memorizzare il database nell’immagine. Al momento, ogni riallocazione reimposta il database. Considerate di passare a un’istanza PostgreSQL o MySQL gestita.
- Imparate a conoscere le build multi-stadio per ottimizzare i vostri file Docker.
- Leggete l’articolo Deploying Docker Containers per un’esercitazione passo-passo.
FAQ
Che cos’è un container?
Un container è un pacchetto eseguibile autonomo che include tutto il necessario per eseguire un’applicazione. Include codice, runtime, librerie, variabili d’ambiente e file di configurazione.
Quali sono i vantaggi dell’uso dei container?
– Efficienza
– Isolamento dell’applicazione
– Separazione delle responsabilità
– Sviluppo più rapido delle applicazioni
Qual è la differenza tra container e macchine virtuali?
Le VM sono un’astrazione dell’hardware fisico, mentre i container sono virtualizzati a livello del sistema operativo. Le VM offrono maggiore isolamento e sicurezza, mentre i container occupano meno spazio e sono efficienti e scalabili.
Qual è la differenza tra Docker e Kubernetes?
Docker consente di impacchettare e distribuire applicazioni all’interno di container, mentre Kubernetes facilita la gestione di più container che lavorano insieme.
Come sviluppare un’app utilizzando un’architettura basata su container?
1. Scegli un linguaggio di programmazione e scrivi il codice della tua app.
2. Contenerizza la tua app con un Dockerfile o Docker Compose.
3. Crea un’immagine Docker e testala localmente.
4. Scegli un CaaS come Back4app Containers e carica lì il tuo codice.
Attendi il completamento del deployment del servizio e il gioco è fatto!