Condividi tramite


Definizione dell'applicazione a più contenitori con docker-compose.yml

Suggerimento

Questo contenuto è un estratto dell'eBook, Architettura di microservizi .NET per applicazioni .NET in contenitori, disponibile in .NET Docs o come PDF scaricabile gratuito che può essere letto offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

In questa guida il file docker-compose.yml è stato introdotto nella sezione Passaggio 4. Definire i servizi in docker-compose.yml durante la compilazione di un'applicazione Docker multi-contenitore. Tuttavia esistono altri modi per usare i file docker-compose che vale la pena di esplorare in maggiore dettaglio.

È possibile, ad esempio, descrivere in modo esplicito la modalità di distribuzione dell'applicazione a più contenitori nel file docker-compose.yml. Facoltativamente è possibile anche descrivere come si intende compilare le immagini Docker personalizzate. Le immagini Docker personalizzate possono essere compilate anche con l'interfaccia della riga di comando di Docker.

In pratica è possibile definire ciascun contenitore da distribuire, più determinate caratteristiche per ogni distribuzione di contenitore. Dopo aver creato un file di descrizione della distribuzione di più contenitori, è possibile distribuire l'intera soluzione con un'unica azione orchestrata dal comando dell'interfaccia della riga di comando docker-compose up oppure in modo trasparente da Visual Studio. In caso contrario, è necessario usare l'interfaccia della riga di comando di Docker per eseguire la distribuzione contenitore per contenitore in più passaggi usando il comando docker run dalla riga di comando. Pertanto ogni servizio definito in docker-compose.yml deve specificare esattamente un'immagine o una build. Le altre chiavi sono facoltative e sono analoghe alle controparti della riga di comando docker run.

Il seguente codice YAML definisce un possibile file docker-compose.yml globale, ma unico per l'esempio eShopOnContainers. Questo codice non è il file docker-compose effettivo da eShopOnContainers. È invece una versione semplificata e consolidata in un singolo file, ma non è il modo migliore per lavorare con i file docker-compose, come sarà illustrato in seguito.

version: '3.4'

services:
  webmvc:
    image: eshop/webmvc
    environment:
      - CatalogUrl=http://catalog-api
      - OrderingUrl=http://ordering-api
      - BasketUrl=http://basket-api
    ports:
      - "5100:80"
    depends_on:
      - catalog-api
      - ordering-api
      - basket-api

  catalog-api:
    image: eshop/catalog-api
    environment:
      - ConnectionString=Server=sqldata;Initial Catalog=CatalogData;User Id=sa;Password=[PLACEHOLDER]
    expose:
      - "80"
    ports:
      - "5101:80"
    #extra hosts can be used for standalone SQL Server or services at the dev PC
    extra_hosts:
      - "CESARDLSURFBOOK:10.0.75.1"
    depends_on:
      - sqldata

  ordering-api:
    image: eshop/ordering-api
    environment:
      - ConnectionString=Server=sqldata;Database=Services.OrderingDb;User Id=sa;Password=[PLACEHOLDER]
    ports:
      - "5102:80"
    #extra hosts can be used for standalone SQL Server or services at the dev PC
    extra_hosts:
      - "CESARDLSURFBOOK:10.0.75.1"
    depends_on:
      - sqldata

  basket-api:
    image: eshop/basket-api
    environment:
      - ConnectionString=sqldata
    ports:
      - "5103:80"
    depends_on:
      - sqldata

  sqldata:
    environment:
      - SA_PASSWORD=[PLACEHOLDER]
      - ACCEPT_EULA=Y
    ports:
      - "5434:1433"

  basketdata:
    image: redis

La chiave radice in questo file sono i servizi. In tale chiave si definiscono i servizi da distribuire ed eseguire quando si esegue il comando o quando si esegue la docker-compose up distribuzione da Visual Studio usando questo file docker-compose.yml. In questo caso nel file docker compose.yml sono stati definiti più servizi, come descritto nella tabella seguente.

Nome servizio Descrizione
webmvc Contenitore che include l'applicazione MVC core ASP.NET che usa i microservizi dal lato server C#
catalog-api Contenitore che include il microservizio API Web ASP.NET Core che gestisce i cataloghi
ordering-api Contenitore che include il microservizio API Web ASP.NET Core che gestisce gli ordini
sqldata Contenitore che esegue SQL Server per Linux, contenente i database di microservizi
basket-api Contenitore con il microservizio API Web ASP.NET Core che gestisce i carrelli
basketdata Contenitore che esegue il servizio cache REDIS, con il database dei carrelli come cache REDIS

Un semplice contenitore di API di servizi Web

Concentrandosi su un singolo contenitore, il microservizio container-api catalog ha una definizione semplice:

  catalog-api:
    image: eshop/catalog-api
    environment:
      - ConnectionString=Server=sqldata;Initial Catalog=CatalogData;User Id=sa;Password=[PLACEHOLDER]
    expose:
      - "80"
    ports:
      - "5101:80"
    #extra hosts can be used for standalone SQL Server or services at the dev PC
    extra_hosts:
      - "CESARDLSURFBOOK:10.0.75.1"
    depends_on:
      - sqldata

La configurazione base di questo servizio con contenitore è la seguente:

  • Si basa sull'immagine personalizzata di eshop/catalog-api . Per semplicità, non esiste alcuna impostazione di compilazione: chiave nel file. Ciò significa che l'immagine deve essere stata compilata in precedenza (con docker build) oppure è stata scaricata (con il comando docker pull) da un registro Docker.

  • Definisce una variabile di ambiente denominata ConnectionString con la stringa di connessione che Entity Framework deve usare per accedere all'istanza di SQL Server contenente il modello di dati di catalogo. In questo caso, lo stesso contenitore SQL Server contiene più database. Pertanto la memoria necessaria nel computer di sviluppo per Docker è inferiore. Tuttavia è possibile anche distribuire un contenitore SQL Server per ogni database di microservizi.

  • Il nome di SQL Server è sqldata, ovvero lo stesso nome usato per il contenitore che esegue l'istanza di SQL Server per Linux. Questo è conveniente; la possibilità di usare questa risoluzione dei nomi (interna all'host Docker) risolverà l'indirizzo di rete in modo da non dover conoscere l'INDIRIZZO IP interno per i contenitori a cui si accede da altri contenitori.

Poiché la stringa di connessione viene definita da una variabile di ambiente, è possibile impostare questa variabile tramite un meccanismo diverso e in un momento diverso. Ad esempio, è possibile impostare una stringa di connessione diversa durante la distribuzione in produzione negli host finali oppure dalle pipeline CI/CD in Azure DevOps Services o dal sistema DevOps preferito.

  • Espone la porta 80 per l'accesso interno al servizio catalog-api all'interno dell'host Docker. L'host è attualmente una VM Linux perché si basa su un'immagine Docker per Linux, ma è possibile configurare il contenitore per l'esecuzione su un'immagine per Windows.

  • Inoltra la porta 80 esposta sul contenitore alla porta esterna 5101 sul computer host Docker (la VM Linux).

  • Collega il servizio Web al servizio sqldata (l'istanza di SQL Server per il database Linux in esecuzione in un contenitore). Quando si specifica questa dipendenza, il contenitore catalog-api non verrà avviato fino all'avvio del contenitore sqldata; questo aspetto è importante perché catalog-api deve avere il database di SQL Server operativo per primo. Tuttavia, questo tipo di dipendenza di contenitore non è sufficiente in molti casi poiché Docker esegue il controllo solo a livello di contenitore. In alcuni casi il servizio, in questo caso SQL Server, potrebbe non essere ancora pronto ed è quindi consigliabile implementare la logica di ripetizione con il backoff esponenziale nei microservizi client. In questo modo, se un contenitore di dipendenza non è pronto per un breve periodo di tempo, l'applicazione sarà ancora resiliente.

  • È configurato per consentire l'accesso a server esterni: l'impostazione extra_hosts consente di accedere a server o computer esterni all'host Docker (ovvero all'esterno della macchina virtuale Linux predefinita, ovvero un host Docker di sviluppo), ad esempio un'istanza locale di SQL Server nel PC di sviluppo.

Esistono anche altre impostazioni più avanzate docker-compose.yml che verranno illustrate nelle sezioni seguenti.

Utilizzo dei file docker-compose per usare più ambienti come destinazione

I docker-compose.*.yml file sono file di definizione e possono essere usati da più infrastrutture che conoscono tale formato. Lo strumento più semplice è il comando docker-compose.

Con il comando docker-compose è quindi possibile usare come destinazione i seguenti scenari principali.

Ambienti di sviluppo

Quando si sviluppano applicazioni, è importante poter eseguire un'applicazione in un ambiente di sviluppo isolato. È possibile usare il comando dell'interfaccia della riga di comando docker-compose per creare tale ambiente o Visual Studio, che usa docker-compose sotto le quinte.

Il file docker-compose.yml consente di configurare e documentare tutte le dipendenze del servizio dell'applicazione (altri servizi, cache, database, code e così via). Con il comando dell'interfaccia della riga di comando docker-compose è possibile creare e avviare uno o più contenitori per ogni dipendenza con un unico comando (docker-compose up).

I file docker-compose.yml sono file di configurazione interpretati dal motore Docker, ma servono anche come utili file di documentazione sulla composizione dell'applicazione a più contenitori.

Ambienti di test

Un aspetto importante di qualsiasi processo di distribuzione continua (CD) o di integrazione continua (CI) sono gli unit test e i test di integrazione. Questi test automatizzati richiedono un ambiente isolato in modo che non siano interessati dagli utenti o da altre modifiche nei dati dell'applicazione.

Con Docker Compose è possibile creare ed eliminare facilmente l'ambiente isolato in pochi comandi dal prompt dei comandi o dagli script, come i comandi seguenti:

docker-compose -f docker-compose.yml -f docker-compose-test.override.yml up -d
./run_unit_tests
docker-compose -f docker-compose.yml -f docker-compose-test.override.yml down

Distribuzioni in produzione

È possibile anche usare Docker Compose per eseguire la distribuzione in un motore Docker remoto. Un caso tipico consiste nella distribuzione di una singola istanza dell'host Docker, ad esempio una macchina virtuale in produzione o un server di cui viene eseguito il provisioning con Docker Machine.

Se si usa qualsiasi altro agente di orchestrazione (Microsoft Azure Service Fabric, Kubernetes e così via), può essere necessario aggiungere impostazioni di installazione e configurazione dei metadati, come quelle in docker-compose.yml, ma nel formato richiesto dall'altro agente di orchestrazione.

In ogni caso, docker-compose è un utile strumento e formato di metadati per lo sviluppo, i test e i flussi di lavoro di produzione, anche se il flusso di lavoro di produzione potrebbe variare in base all'agente di orchestrazione in uso.

Utilizzo di più file docker-compose per la gestione di ambienti diversi

Se si usano come destinazione ambienti diversi, è necessario usare più file compose. Questo approccio consente di creare più varianti di configurazione a seconda dell'ambiente.

Override del file docker-compose base

È possibile usare un singolo file docker-compose.yml, come negli esempi semplificati illustrati nelle sezioni precedenti. Tuttavia questo approccio non è consigliabile per la maggior parte delle applicazioni.

Per impostazione predefinita, Compose legge due file: docker-compose.yml e un file docker-compose.override.yml facoltativo. Come illustrato nella figura 6-11, quando si usa Visual Studio e si abilita il supporto docker, Visual Studio crea anche un file di docker-compose.vs.debug.g.yml aggiuntivo per il debug dell'applicazione, è possibile esaminare questo file nella cartella obj\Docker\ nella cartella della soluzione principale.

Files in a docker compose project.

Figura 6-11. File docker-compose in Visual Studio 2019

Struttura del file di progetto docker-compose :

  • .dockerignore - usato per ignorare i file
  • docker-compose.yml : usato per comporre microservizi
  • docker-compose.override.yml : usato per configurare l'ambiente di microservizi

È possibile modificare i file docker-compose con qualsiasi editor di codice di Visual Studio o Sublime ed eseguire l'applicazione con il comando docker-compose up.

Per convenzione, il file docker-compose.yml contiene la configurazione base e altre impostazioni statiche. Ciò significa che la configurazione del servizio non deve cambiare a seconda dell'ambiente di distribuzione di destinazione.

Il file docker-compose.override.yml, come suggerisce il nome, contiene le impostazioni di configurazione che eseguono l'override della configurazione base, ad esempio la configurazione che dipende dall'ambiente di distribuzione. È possibile anche avere più file di override con nomi diversi. I file di override in genere contengono informazioni aggiuntive necessarie per l'applicazione, ma specifiche per un ambiente o una distribuzione.

Utilizzo di più ambienti come destinazione

Un tipico caso d'uso è quello in cui si definiscono più file compose in modo da poter usare come destinazione più ambienti, ad esempio quello di produzione, staging, CI o sviluppo. Per supportare queste differenze, è possibile suddividere la configurazione di Compose in più file, come illustrato nella figura 6-12.

Diagram of three docker-compose files set to override the base file.

Figura 6-12. Più file docker-compose che eseguono l'override di valori del file docker-compose.yml base

È possibile combinare più file docker-compose*.yml per gestire ambienti diversi. Iniziare con il file docker-compose.yml base. Questo file di base contiene le impostazioni di configurazione di base o statiche che non cambiano a seconda dell'ambiente. Ad esempio, l'app eShopOnContainers ha il file di docker-compose.yml seguente (semplificato con meno servizi) come file di base.

#docker-compose.yml (Base)
version: '3.4'
services:
  basket-api:
    image: eshop/basket-api:${TAG:-latest}
    build:
      context: .
      dockerfile: src/Services/Basket/Basket.API/Dockerfile
    depends_on:
      - basketdata
      - identity-api
      - rabbitmq

  catalog-api:
    image: eshop/catalog-api:${TAG:-latest}
    build:
      context: .
      dockerfile: src/Services/Catalog/Catalog.API/Dockerfile
    depends_on:
      - sqldata
      - rabbitmq

  marketing-api:
    image: eshop/marketing-api:${TAG:-latest}
    build:
      context: .
      dockerfile: src/Services/Marketing/Marketing.API/Dockerfile
    depends_on:
      - sqldata
      - nosqldata
      - identity-api
      - rabbitmq

  webmvc:
    image: eshop/webmvc:${TAG:-latest}
    build:
      context: .
      dockerfile: src/Web/WebMVC/Dockerfile
    depends_on:
      - catalog-api
      - ordering-api
      - identity-api
      - basket-api
      - marketing-api

  sqldata:
    image: mcr.microsoft.com/mssql/server:2019-latest

  nosqldata:
    image: mongo

  basketdata:
    image: redis

  rabbitmq:
    image: rabbitmq:3-management

I valori nel file docker-compose.yml base non devono essere modificati in base ai diversi ambienti di distribuzione di destinazione.

Se, ad esempio, si esamina con attenzione la definizione del servizio webmvc, si nota come queste informazioni sono più o meno le stesse indipendentemente dall'ambiente di destinazione. Sono disponibili le seguenti informazioni:

  • Il nome del servizio: webmvc.

  • Immagine personalizzata del contenitore: eshop/webmvc.

  • Il comando per compilare l'immagine personalizzata di Docker, che indica il Dockerfile da usare.

  • Le dipendenze da altri servizi, per cui questo contenitore viene avviato solo dopo che sono stati avviati gli altri contenitori di dipendenza.

È possibile avere una configurazione aggiuntiva, ma il punto importante è che nel file docker-compose.yml base si impostano solo le informazioni comuni tra gli ambienti. Nel file docker-compose.override.yml o nei file simili per la produzione o lo staging si inserisce la configurazione specifica per ogni ambiente.

In genere, il file docker-compose.override.yml viene usato per l'ambiente di sviluppo, come nell'esempio seguente dall'applicazione eShopOnContainers:

#docker-compose.override.yml (Extended config for DEVELOPMENT env.)
version: '3.4'

services:
# Simplified number of services here:

  basket-api:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=http://0.0.0.0:80
      - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basketdata}
      - identityUrl=http://identity-api
      - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105
      - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
      - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
      - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
      - AzureServiceBusEnabled=False
      - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
      - OrchestratorType=${ORCHESTRATOR_TYPE}
      - UseLoadTest=${USE_LOADTEST:-False}

    ports:
      - "5103:80"

  catalog-api:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=http://0.0.0.0:80
      - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=[PLACEHOLDER]}
      - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://host.docker.internal:5202/api/v1/catalog/items/[0]/pic/}
      - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
      - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
      - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
      - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_CATALOG_NAME}
      - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_CATALOG_KEY}
      - UseCustomizationData=True
      - AzureServiceBusEnabled=False
      - AzureStorageEnabled=False
      - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
      - OrchestratorType=${ORCHESTRATOR_TYPE}
    ports:
      - "5101:80"

  marketing-api:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=http://0.0.0.0:80
      - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sqldata;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=[PLACEHOLDER]}
      - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata}
      - MongoDatabase=MarketingDb
      - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
      - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
      - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
      - identityUrl=http://identity-api
      - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105
      - CampaignDetailFunctionUri=${ESHOP_AZUREFUNC_CAMPAIGN_DETAILS_URI}
      - PicBaseUrl=${ESHOP_AZURE_STORAGE_MARKETING_URL:-http://host.docker.internal:5110/api/v1/campaigns/[0]/pic/}
      - AzureStorageAccountName=${ESHOP_AZURE_STORAGE_MARKETING_NAME}
      - AzureStorageAccountKey=${ESHOP_AZURE_STORAGE_MARKETING_KEY}
      - AzureServiceBusEnabled=False
      - AzureStorageEnabled=False
      - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
      - OrchestratorType=${ORCHESTRATOR_TYPE}
      - UseLoadTest=${USE_LOADTEST:-False}
    ports:
      - "5110:80"

  webmvc:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=http://0.0.0.0:80
      - PurchaseUrl=http://webshoppingapigw
      - IdentityUrl=http://10.0.75.1:5105
      - MarketingUrl=http://webmarketingapigw
      - CatalogUrlHC=http://catalog-api/hc
      - OrderingUrlHC=http://ordering-api/hc
      - IdentityUrlHC=http://identity-api/hc
      - BasketUrlHC=http://basket-api/hc
      - MarketingUrlHC=http://marketing-api/hc
      - PaymentUrlHC=http://payment-api/hc
      - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
      - UseCustomizationData=True
      - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
      - OrchestratorType=${ORCHESTRATOR_TYPE}
      - UseLoadTest=${USE_LOADTEST:-False}
    ports:
      - "5100:80"
  sqldata:
    environment:
      - SA_PASSWORD=[PLACEHOLDER]
      - ACCEPT_EULA=Y
    ports:
      - "5433:1433"
  nosqldata:
    ports:
      - "27017:27017"
  basketdata:
    ports:
      - "6379:6379"
  rabbitmq:
    ports:
      - "15672:15672"
      - "5672:5672"

In questo esempio, la configurazione di override dello sviluppo espone alcune porte all'host, definisce le variabili di ambiente con gli URL di reindirizzamento e specifica le stringhe di connessione per l'ambiente di sviluppo. Queste impostazioni sono tutte relative solo all'ambiente di sviluppo.

Quando si esegue docker-compose up o lo si avvia da Visual Studio, il comando legge automaticamente le sostituzioni come se stesse unendo entrambi i file.

Si supponga di volere un altro file Compose per l'ambiente di produzione, con valori di configurazione, porte o stringa di connessione diversi. È possibile creare un altro file di override, ad esempio un file denominato docker-compose.prod.yml con diverse impostazioni e variabili di ambiente. Questo file potrebbe essere archiviato in un diverso repository Git oppure gestito e protetto da un team diverso.

Come distribuire un file di override specifico

Per usare più file di override o un file di override con un nome diverso, è possibile usare l'opzione -f con il comando docker-compose e specificare i file. Compose unisce i file nell'ordine in che cui vengono specificati alla riga di comando. Nell'esempio seguente viene illustrato come eseguire la distribuzione con i file di override.

docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Utilizzo di variabili di ambiente nei file docker-compose

È utile, soprattutto negli ambienti di produzione, poter ottenere le informazioni di configurazione dalle variabili di ambiente, come mostrato negli esempi precedenti. È possibile fare riferimento a una variabile di ambiente nei file docker-compose usando la sintassi ${MY_VAR}. La riga seguente da un file docker compose.prod.yml mostra come fare riferimento al valore di una variabile di ambiente.

IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105

Le variabili di ambiente vengono create e inizializzate in modi diversi, a seconda dell'ambiente host (Linux, Windows, cluster basato su cloud e così via). Tuttavia, un approccio pratico consiste nell'usare un file con estensione env. I file docker-compose supportano la dichiarazione di variabili di ambiente predefinite nel file con estensione env. Questi valori per le variabili di ambiente sono i valori predefiniti. Possono tuttavia essere sostituiti dai valori eventualmente definiti in ciascun ambiente (variabili del sistema operativo host o di ambiente dal cluster). Inserire questo file con estensione env nella cartella da cui viene eseguito il comando docker-compose.

Nell'esempio seguente viene illustrato un file con estensione env, come il file .env per l'applicazione eShopOnContainers.

# .env file

ESHOP_EXTERNAL_DNS_NAME_OR_IP=host.docker.internal

ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=10.121.122.92

Docker-compose prevede che ogni riga in un file con estensione env sia nel formato <variable>=<value>.

I valori impostati nell'ambiente di runtime eseguono sempre l'override dei valori definiti all'interno del file con estensione env. In modo analogo, i valori passati tramite argomenti della riga di comando sostituiscono anche i valori predefiniti impostati nel file con estensione env.

Risorse aggiuntive

Creazione di immagini Docker ottimizzate con ASP.NET Core

Se si esplora Docker e .NET in origini su Internet, sono disponibili Dockerfile che illustrano la semplicità di creazione di un'immagine Docker copiando l'origine in un contenitore. Questi esempi suggeriscono che usando una configurazione semplice è possibile disporre di un'immagine Docker con l'ambiente fornito con l'applicazione. Nell'esempio seguente viene illustrato un Dockerfile semplice in questa ottica.

FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /app
ENV ASPNETCORE_URLS http://+:80
EXPOSE 80
COPY . .
RUN dotnet restore
ENTRYPOINT ["dotnet", "run"]

Un Dockerfile come questo funzionerà correttamente. Tuttavia è possibile ottimizzare in modo sostanziale le immagini, in particolare le immagini di produzione.

Nel modello basato su contenitori e microservizi si avviano costantemente contenitori. L'utilizzi tipico dei contenitori non comporta il riavvio di un contenitore in sospensione perché il contenitore è eliminabile. Gli agenti di orchestrazione, ad esempio Kubernetes e Azure Service Fabric, creano nuove istanze di immagini. È quindi necessario ottimizzare precompilando l'applicazione quando viene compilata in modo che il processo di creazione dell'istanza sia più veloce. Quando viene avviato, il contenitore deve essere pronto per l'esecuzione. Non ripristinare e compilare in fase di esecuzione usando i comandi dell'interfaccia della dotnet restore riga di comando e dotnet build come si può vedere nei post di blog su .NET e Docker.

Il team di .NET ha svolto importanti attività per rendere .NET e ASP.NET Core un framework ottimizzato per i contenitori. Non solo .NET è un framework leggero con un footprint di memoria ridotto; il team si è concentrato sulle immagini Docker ottimizzate per tre scenari principali e le ha pubblicate nel Registro di sistema dell'hub Docker in dotnet/, a partire dalla versione 2.1:

  1. Sviluppo: la priorità è la possibilità di eseguire rapidamente l'iterazione e il debug delle modifiche e la posizione in cui le dimensioni sono secondarie.

  2. Compilazione: la priorità è la compilazione dell'applicazione e l'immagine include file binari e altre dipendenze per ottimizzare i file binari.

  3. Produzione: lo stato attivo è la distribuzione rapida e l'avvio dei contenitori, quindi queste immagini sono limitate ai file binari e al contenuto necessari per eseguire l'applicazione.

Il team .NET fornisce quattro varianti di base in dotnet/ (nell'hub Docker):

  1. sdk: per gli scenari di sviluppo e compilazione
  2. aspnet: per gli scenari di produzione di ASP.NET
  3. runtime: per gli scenari di produzione di .NET
  4. runtime-deps: per scenari di produzione di applicazioni autonome

Per un avvio più rapido, anche le immagini di runtime impostano automaticamente aspnetcore_urls sulla porta 80 e Ngen per creare una cache di immagini nativa degli assembly.

Risorse aggiuntive