Colocar em contêiner um aplicativo .NET com dotnet publish
Os contêineres têm muitos recursos e benefícios, como o de serem uma infraestrutura imutável, fornecer uma arquitetura portátil e permitir a escalabilidade. A imagem pode ser usada para criar contêineres para seu ambiente de desenvolvimento local, nuvem privada ou nuvem pública. Neste tutorial, você aprenderá a colocar em contêiner um aplicativo .NET usando o comando dotnet publish.
Pré-requisitos
Instale os seguintes pré-requisitos:
- SDK do .NET 8+
Se você tiver o .NET instalado, use o comandodotnet --info
para determinar qual SDK está usando. - Docker Community Edition
- SDK do .NET 7+
Se você tiver o .NET instalado, use o comandodotnet --info
para determinar qual SDK está usando. - Docker Community Edition
Além desses pré-requisitos, é recomendável que você esteja familiarizado com os Serviços de trabalho no .NET.
Criar aplicativo .NET
Você precisa de um aplicativo .NET para colocar em contêiner. Por isso, comece criando um novo aplicativo a partir de um modelo. Abra o terminal, crie uma pasta de trabalho (sample-directory) caso ainda não tenha feito isso e altere os diretórios para que você esteja nela. Na pasta de trabalho, execute o seguinte comando para criar um projeto em um subdiretório denominado Trabalho:
dotnet new worker -o Worker -n DotNet.ContainerImage
A árvore de pastas será parecida com a seguinte:
📁 sample-directory
└──📂 Worker
├──appsettings.Development.json
├──appsettings.json
├──DotNet.ContainerImage.csproj
├──Program.cs
├──Worker.cs
└──📂 obj
├── DotNet.ContainerImage.csproj.nuget.dgspec.json
├── DotNet.ContainerImage.csproj.nuget.g.props
├── DotNet.ContainerImage.csproj.nuget.g.targets
├── project.assets.json
└── project.nuget.cache
O comando dotnet new
cria uma nova pasta chamada Trabalho e gera um serviço de trabalho que, quando executado, registra uma mensagem a cada segundo. Na sessão do terminal, altere os diretórios e navegue até a pasta Trabalhador. Use o comando dotnet run
para iniciar o aplicativo.
dotnet run
Building...
info: DotNet.ContainerImage.Worker[0]
Worker running at: 10/18/2022 08:56:00 -05:00
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: .\Worker
info: DotNet.ContainerImage.Worker[0]
Worker running at: 10/18/2022 08:56:01 -05:00
info: DotNet.ContainerImage.Worker[0]
Worker running at: 10/18/2022 08:56:02 -05:00
info: DotNet.ContainerImage.Worker[0]
Worker running at: 10/18/2022 08:56:03 -05:00
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
Attempting to cancel the build...
O modelo de trabalho faz loops indefinidamente. Use o comando de cancelamento Ctrl+C para interrompê-lo.
Adicionar pacote NuGet
No momento, o pacote NuGet Microsoft.NET.Build.Containers é necessário para publicar projetos que não sejam da Web como um contêiner. Para adicionar o pacote NuGet Microsoft.NET.Build.Containers
ao modelo de trabalho, execute o seguinte comando dotnet add package:
dotnet add package Microsoft.NET.Build.Containers
Dica
Se estiver criando um aplicativo Web e usando o .NET SDK 7.0.300 ou superior, o pacote não será necessário: o SDK contém a mesma funcionalidade pronta para uso.
Definir o nome da imagem de contêiner
Há várias opções de configuração disponíveis quando você publica um aplicativo como um contêiner.
Por padrão, o nome da imagem de contêiner é o AssemblyName
do projeto. Se esse nome for inválido como um nome de imagem de contêiner, substitua-o especificando ContainerRepository
, conforme mostrado no seguinte arquivo de projeto:
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>dotnet-DotNet.ContainerImage-2e40c179-a00b-4cc9-9785-54266210b7eb</UserSecretsId>
<ContainerRepository>dotnet-worker-image</ContainerRepository>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>
</Project>
Para obter mais informações, confira ContainerRepository.
Por padrão, o nome da imagem de contêiner é o AssemblyName
do projeto. Se esse nome for inválido como um nome de imagem de contêiner, você poderá substituí-lo especificando um (ContainerImageName
obsoleto) ou o preferido ContainerRepository
, conforme mostrado no seguinte arquivo do projeto:
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>dotnet-DotNet.ContainerImage-2e40c179-a00b-4cc9-9785-54266210b7eb</UserSecretsId>
<ContainerImageName>dotnet-worker-image</ContainerImageName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.NET.Build.Containers" Version="7.0.401" />
</ItemGroup>
</Project>
Para obter mais informações, confira ContainerImageName.
Publicar aplicativo .NET
Para publicar o aplicativo .NET como um contêiner, use o seguinte comando dotnet publish:
dotnet publish --os linux --arch x64 /t:PublishContainer -c Release
O comando anterior da CLI do .NET publica o aplicativo como um contêiner:
- Direcionar o Linux como o sistema operacional (
--os linux
). - Especificar uma arquitetura x64 (
--arch x64
). - Usar a configuração de versão (
-c Release
).
Importante
Para compilar o contêiner localmente, você deve ter o daemon do Docker em execução. Se ele não estiver em execução ao tentar publicar o aplicativo como um contêiner, você verá um erro semelhante ao seguinte:
..\build\Microsoft.NET.Build.Containers.targets(66,9): error MSB4018:
The "CreateNewImage" task failed unexpectedly. [..\Worker\DotNet.ContainerImage.csproj]
Dica
Dependendo do tipo de aplicativo que você está colocando em contêiner, as opções de linha de comando (opções) podem variar. Por exemplo, o argumento /t:PublishContainer
só é necessário para aplicativos .NET não Web, como modelos console
e worker
. Para modelos da Web, substitua o argumento /t:PublishContainer
por -p:PublishProfile=DefaultContainer
. Para obter mais informações, confira Builds de contêiner do SDK do .NET, problema 141.
O comando produz uma saída semelhante ao exemplo de saída:
Determining projects to restore...
All projects are up-to-date for restore.
DotNet.ContainerImage -> .\Worker\bin\Release\net8.0\linux-x64\DotNet.ContainerImage.dll
DotNet.ContainerImage -> .\Worker\bin\Release\net8.0\linux-x64\publish\
Building image 'dotnet-worker-image' with tags latest on top of base image mcr.microsoft.com/dotnet/aspnet:8.0
Pushed container 'dotnet-worker-image:latest' to Docker daemon
Determining projects to restore...
All projects are up-to-date for restore.
DotNet.ContainerImage -> .\Worker\bin\Release\net7.0\linux-x64\DotNet.ContainerImage.dll
DotNet.ContainerImage -> .\Worker\bin\Release\net7.0\linux-x64\publish\
Building image 'dotnet-worker-image' with tags 1.0.0 on top of base image mcr.microsoft.com/dotnet/aspnet:7.0
Pushed container 'dotnet-worker-image:1.0.0' to Docker daemon
Este comando compila seu aplicativo de trabalho para a pasta publish e envia o contêiner por push para o registro local do Docker.
Configurar a imagem de contêiner
Você pode controlar muitos aspectos do contêiner gerado por meio das propriedades do MSBuild. Em geral, se você puder usar um comando em um Dockerfile para definir alguma configuração, poderá fazer o mesmo por meio do MSBuild.
Observação
As únicas exceções a isso são comandos RUN
. Devido a forma em que os contêineres são criados, eles não podem ser emulados. Se você precisar dessa funcionalidade, precisará usar um Dockerfile para criar suas imagens de contêiner.
ContainerArchiveOutputPath
A partir do .NET 8, você pode criar um contêiner diretamente como um arquivo tar.gz. Esse recurso será útil se o fluxo de trabalho não for simples e exigir que você, por exemplo, execute uma ferramenta de verificação em suas imagens antes de efetuar push delas. Depois que o arquivo é criado, você pode movê-lo, examiná-lo ou carregá-lo em uma cadeia de ferramentas local do Docker.
Para publicar em um arquivo morto, adicione a propriedade ContainerArchiveOutputPath
ao seu comando dotnet publish
, por exemplo:
dotnet publish \
-p PublishProfile=DefaultContainer \
-p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz
Você pode especificar um nome de pasta ou um caminho com um nome de arquivo específico. Se você especificar o nome da pasta, o nome do arquivo gerado para o arquivo de imagem será $(ContainerRepository).tar.gz
. Esses arquivos podem conter várias tags dentro deles, apenas como um único arquivo é criado para todos os arquivos ContainerImageTags
.
Configuração de nomenclatura de imagem de contêiner
As imagens de contêiner seguem uma convenção de nomenclatura específica. O nome da imagem é composto por várias partes, o registro, a porta opcional, o repositório e a marca e a família opcionais.
REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]]
Por exemplo, considere o nome da imagem totalmente qualificada mcr.microsoft.com/dotnet/runtime:8.0-alpine
:
mcr.microsoft.com
é o registro (e, neste caso, representa o registro de contêiner da Microsoft).dotnet/runtime
é o repositório (mas alguns consideram isso ouser/repository
).8.0-alpine
é a marca, e a família (a família é um especificador opcional que ajuda a desambiguar o empacotamento do sistema operacional).
Algumas propriedades descritas nas seções a seguir correspondem ao gerenciamento de partes do nome da imagem gerada. Considere a tabela a seguir que mapeia a relação entre o nome da imagem e as propriedades de compilação:
Parte do nome da imagem | Propriedade do MSBuild | Valores de exemplo |
---|---|---|
REGISTRY[:PORT] |
ContainerRegistry |
mcr.microsoft.com:443 |
PORT |
ContainerPort |
:443 |
REPOSITORY |
ContainerRepository |
dotnet/runtime |
TAG |
ContainerImageTag |
8.0 |
FAMILY |
ContainerFamily |
-alpine |
Parte do nome da imagem | Propriedade do MSBuild | Valores de exemplo |
---|---|---|
REGISTRY[:PORT] |
ContainerRegistry |
mcr.microsoft.com:443 |
PORT |
ContainerPort |
:443 |
REPOSITORY |
ContainerImageName |
dotnet/runtime |
TAG |
ContainerImageTag |
8.0 |
As seções a seguir descrevem as várias propriedades que podem ser usadas para controlar a imagem de contêiner gerada.
ContainerBaseImage
A propriedade de imagem base do contêiner controla a imagem usada como base para sua imagem. Por padrão, os seguintes valores são inferidos com base nas propriedades do seu projeto:
- Se o projeto for autocontido, a imagem
mcr.microsoft.com/dotnet/runtime-deps
será usada como a imagem base. - Se o projeto for um projeto ASP.NET Core, a imagem
mcr.microsoft.com/dotnet/aspnet
será usada como a imagem base. - Caso contrário, a imagem
mcr.microsoft.com/dotnet/runtime
será usada como a imagem base.
A tag da imagem é inferida para ser o componente numérico do TargetFramework
escolhido. Por exemplo, um direcionamento de projeto net6.0
resulta na marca 6.0
da imagem base inferida, e um projeto net7.0-linux
usa a marca 7.0
etc.
Se você definir um valor aqui, deverá definir o nome totalmente qualificado da imagem para usar como base, incluindo qualquer tag que preferir:
<PropertyGroup>
<ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:8.0</ContainerBaseImage>
</PropertyGroup>
<PropertyGroup>
<ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:7.0</ContainerBaseImage>
</PropertyGroup>
ContainerFamily
A partir do .NET 8, você pode usar a propriedade ContainerFamily
do MSBuild para escolher uma família diferente de imagens de contêiner fornecidas pela Microsoft como a imagem base para seu aplicativo. Quando definido, esse valor é acrescentado ao final da marca específica do TFM selecionado, alterando a marca fornecida. Por exemplo, para usar as variantes do Alpine Linux das imagens base do .NET, defina ContainerFamily
como alpine
:
<PropertyGroup>
<ContainerFamily>alpine</ContainerFamily>
</PropertyGroup>
A configuração do projeto anterior resulta em uma marca final igual a 8.0-alpine
para um aplicativo direcionado ao .NET 8.
Esse campo é de forma livre e, em geral, pode ser usado para selecionar diferentes distribuições do sistema operacional, configurações de pacote padrão ou qualquer outra variante de alterações em uma imagem base. Esse campo é ignorado quando ContainerBaseImage
é definido. Para obter mais informações, consulte imagens de contêiner do .NET.
ContainerRuntimeIdentifier
A propriedade do identificador de runtime do contêiner controla o sistema operacional e a arquitetura usados pelo contêiner, caso a ContainerBaseImage dê suporte a mais de uma plataforma. Por exemplo, a imagem mcr.microsoft.com/dotnet/runtime
atualmente dá suporte todas as imagens linux-x64
, linux-arm
, linux-arm64
e win10-x64
atrás da mesma marca, portanto, o ferramental precisa saber qual dessas versões você pretende usar. Por padrão, isso é definido como o valor de RuntimeIdentifier
que você escolheu ao publicar o contêiner. Essa propriedade raramente precisa ser definida explicitamente – em vez disso, use a opção -r
para o comando dotnet publish
. Se a imagem escolhida não der suporte ao RuntimeIdentifier
escolhido, isso resultará em um erro que descreve os RuntimeIdentifiers aos quais a imagem dá suporte.
Você pode definir a propriedade ContainerBaseImage
como um nome de imagem totalmente qualificado, incluindo a marca, para evitar a necessidade de usar essa propriedade.
<PropertyGroup>
<ContainerRuntimeIdentifier>linux-arm64</ContainerRuntimeIdentifier>
</PropertyGroup>
Para obter mais informações sobre os identificadores de runtime com suporte no .NET, confira Catálogo de RIDs.
ContainerRegistry
A propriedade do registro de contêiner controla o registro de destino, o local para o qual a imagem recém-criada será enviada por push. Por padrão, ele é enviado por push para o daemon local do Docker, mas você também pode especificar um registro remoto. Ao usar um registro remoto que requer autenticação, você se autentica usando os mecanismos conhecidos docker login
. Para obter mais informações, confira Autenticação em registros de contêiner para ver mais detalhes. Para obter um exemplo concreto de como usar essa propriedade, considere o seguinte exemplo de XML:
<PropertyGroup>
<ContainerRegistry>registry.mycorp.com:1234</ContainerRegistry>
</PropertyGroup>
Essa ferramenta dá suporte à publicação em qualquer registro que dê suporte à API HTTP do Registro do Docker V2. Isso inclui os seguintes registros explicitamente (e provavelmente muitos mais implicitamente):
- Registro de Contêiner do Azure
- Registro de Contêiner Elástico da Amazon
- Registro de Artefatos do Google
- Docker Hub
- GitHub Packages
- Registro de Contêiner hospedado pelo GitLab
- Quay.io
Para obter notas sobre como trabalhar com esses registros, confira as notas específicas do registro.
ContainerRepository
O repositório de contêiner é o nome da própria imagem, por exemplo, dotnet/runtime
ou my-app
. Por padrão, o AssemblyName
do projeto é usado.
<PropertyGroup>
<ContainerRepository>my-app</ContainerRepository>
</PropertyGroup>
ContainerImageName
O nome da imagem de contêiner controla o nome da própria imagem, por exemplo, dotnet/runtime
ou my-app
. Por padrão, o AssemblyName
do projeto é usado.
<PropertyGroup>
<ContainerImageName>my-app</ContainerImageName>
</PropertyGroup>
Observação
A partir do .NET 8, ContainerImageName
é preterido em favor de ContainerRepository
.
Os nomes de imagem consistem em um ou mais segmentos delimitados por barra, cada um dos quais pode conter apenas caracteres alfanuméricos minúsculos, pontos, sublinhados e traços e deve começar com uma letra ou número. Qualquer outro caractere resultará em um erro.
ContainerImageTag(s)
A propriedade de tag de imagem de contêiner controla as tags geradas para a imagem. Para especificar uma marca individual, use ContainerImageTag
e, para várias marcas, use ContainerImageTags
.
Importante
Ao usar ContainerImageTags
, você acabará com várias imagens, uma por marca exclusiva.
Em geral, as marcas são usadas para se referir a diferentes versões de um aplicativo, mas também podem se referir a diferentes distribuições do sistema operacional ou até a configurações distintas.
A partir do .NET 8, quando uma marca não é fornecida, o padrão é latest
.
Por padrão, o Version
do projeto é usado como o valor da tag.
Para substituir o padrão, especifique um dos seguintes:
<PropertyGroup>
<ContainerImageTag>1.2.3-alpha2</ContainerImageTag>
</PropertyGroup>
Para especificar várias tags, use um conjunto delimitado por ponto e vírgula de tags na propriedade ContainerImageTags
, semelhante à configuração de vários TargetFrameworks
:
<PropertyGroup>
<ContainerImageTags>1.2.3-alpha2;latest</ContainerImageTags>
</PropertyGroup>
As tags só podem conter até 127 caracteres alfanuméricos, pontos, sublinhados e traços. Eles devem começar com um caractere alfanumérico ou um sublinhado. Qualquer outro formato resultará em um erro.
Observação
Quando ContainerImageTags
são usadas, as marcas são delimitadas por um caractere ;
. Se você estiver chamando dotnet publish
por meio da linha de comando (como é o caso da maioria dos ambientes de CI/CD), faça o encapsulamento externo dos valores com '
simples e o encapsulamento interno com aspas duplas "
, por exemplo (='"tag-1;tag-2"'
). Considere o seguinte comando dotnet publish
:
dotnet publish -p ContainerImageTags='"1.2.3-alpha2;latest"'
Isso resulta em duas imagens sendo geradas: my-app:1.2.3-alpha2
e my-app:latest
.
Dica
Se você tiver problemas com a propriedade ContainerImageTags
, considere definir o escopo de uma variável de ambiente ContainerImageTags
:
ContainerImageTags='1.2.3;latest' dotnet publish
ContainerLabel
O rótulo do contêiner adiciona um rótulo de metadados ao contêiner. Os rótulos não têm impacto sobre o contêiner em tempo de execução, mas costumam ser usados para armazenar metadados de versão e criação para uso dos verificadores de segurança e outras ferramentas da infraestrutura. Você pode especificar qualquer número de rótulos de contêiner.
O nó ContainerLabel
tem dois atributos:
Include
: a chave do rótulo.Value
: o valor do rótulo (pode estar vazio).
<ItemGroup>
<ContainerLabel Include="org.contoso.businessunit" Value="contoso-university" />
</ItemGroup>
Para obter uma lista de rótulos criados por padrão, confira rótulos de contêiner padrão.
Configurar a execução do contêiner
Para controlar a execução do contêiner, use as propriedades do MSBuild a seguir.
ContainerWorkingDirectory
O nó do diretório de trabalho do contêiner controla o diretório de trabalho do contêiner, o diretório no qual os comandos serão executados se não houver outro comando executado.
Por padrão, o valor do diretório /app
é usado como o diretório de trabalho.
<PropertyGroup>
<ContainerWorkingDirectory>/bin</ContainerWorkingDirectory>
</PropertyGroup>
ContainerPort
A porta do contêiner adiciona portas TCP ou UDP à lista de portas conhecidas para o contêiner. Isso permite que runtimes de contêiner como o Docker mapeiem essas portas para o computador host automaticamente. Isso geralmente é usado como documentação para o contêiner, mas também pode ser usado para habilitar o mapeamento automático de porta.
O nó ContainerPort
tem dois atributos:
Include
: o número de porta a se exposto.Type
: o padrão étcp
, os valores válidos sãotcp
ouudp
.
<ItemGroup>
<ContainerPort Include="80" Type="tcp" />
</ItemGroup>
A partir do .NET 8, a ContainerPort
é inferida quando não é fornecida explicitamente com base em diversas variáveis de ambiente conhecidas do ASP.NET:
ASPNETCORE_URLS
ASPNETCORE_HTTP_PORTS
ASPNETCORE_HTTPS_PORTS
Se essas variáveis de ambiente estiverem presentes, os respectivos valores serão analisados e convertidos em mapeamentos de porta TCP. Essas variáveis de ambiente são lidas da imagem base, se houver, ou das variáveis de ambiente definidas no projeto por meio de itens ContainerEnvironmentVariable
. Para obter mais informações, confira ContainerEnvironmentVariable.
ContainerEnvironmentVariable
O nó de variável de ambiente de contêiner permite que você adicione variáveis de ambiente ao contêiner. As variáveis de ambiente são acessíveis para o aplicativo em execução no contêiner imediatamente e geralmente são usadas para alterar o comportamento de runtime do aplicativo em execução.
O nó ContainerEnvironmentVariable
tem dois atributos:
Include
: o nome da variável de ambiente.Value
: o valor da variável de ambiente.
<ItemGroup>
<ContainerEnvironmentVariable Include="LOGGER_VERBOSITY" Value="Trace" />
</ItemGroup>
Para obter mais informações, confira Variáveis de ambiente do .NET.
Configurar comandos de contêiner
Por padrão, as ferramentas de contêiner iniciam seu aplicativo usando o binário AppHost gerado para o aplicativo (caso o aplicativo use um AppHost) ou o comando dotnet
mais a DLL do aplicativo.
No entanto, você pode controlar como o aplicativo é executado usando uma combinação de ContainerAppCommand
, ContainerAppCommandArgs
, ContainerDefaultArgs
e ContainerAppCommandInstruction
.
Esses diferentes pontos de configuração existem porque imagens base diferentes usam combinações distintas do contêiner ENTRYPOINT
e das propriedades COMMAND
, e o ideal é conseguir dar suporte a todas elas. Os padrões devem ser utilizáveis na maioria dos aplicativos, mas caso deseje personalizar o comportamento de inicialização do aplicativo, você deve:
- Identificar o binário a ser executado e defini-lo como
ContainerAppCommand
- Identificar quais argumentos são obrigatórios para que o aplicativo seja executado e defini-los como
ContainerAppCommandArgs
- Identificar quais argumentos (se houver) são opcionais e podem ser substituídos por um usuário e defini-los como
ContainerDefaultArgs
- Defina
ContainerAppCommandInstruction
comoDefaultArgs
Para obter mais informações, confira os itens de configuração a seguir.
ContainerAppCommand
O item de configuração do comando do aplicativo é o ponto de entrada lógico do aplicativo. Na maioria dos aplicativos, esse é o AppHost, o binário executável gerado para o aplicativo. Se o aplicativo não gerar um AppHost, esse comando normalmente será dotnet <your project dll>
. Esses valores são aplicados após qualquer ENTRYPOINT
no contêiner base ou diretamente se nenhum ENTRYPOINT
foi definido.
A configuração ContainerAppCommand
tem uma propriedade Include
individual, que representa o comando, a opção ou o argumento a ser usado no comando de ponto de entrada:
<ItemGroup Label="ContainerAppCommand Assignment">
<!-- This is how you would start the dotnet ef tool in your container -->
<ContainerAppCommand Include="dotnet" />
<ContainerAppCommand Include="ef" />
<!-- This shorthand syntax means the same thing, note the semicolon separating the tokens. -->
<ContainerAppCommand Include="dotnet;ef" />
</ItemGroup>
ContainerAppCommandArgs
Esse item de configuração de argumentos do comando do aplicativo representa todos os argumentos logicamente necessários para o aplicativo que devem ser aplicados ao ContainerAppCommand
. Por padrão, não é gerado nenhum para um aplicativo. Quando presentes, os argumentos são aplicados ao contêiner quando ele é executado.
A configuração ContainerAppCommandArgs
tem uma propriedade Include
individual, que representa a opção ou o argumento a ser aplicado ao comando ContainerAppCommand
.
<ItemGroup>
<!-- Assuming the ContainerAppCommand defined above,
this would be the way to force the database to update.
-->
<ContainerAppCommandArgs Include="database" />
<ContainerAppCommandArgs Include="update" />
<!-- This is the shorthand syntax for the same idea -->
<ContainerAppCommandArgs Include="database;update" />
</ItemGroup>
ContainerDefaultArgs
Esse item de configuração de argumentos padrão representa todos os argumentos substituíveis pelo usuário para o aplicativo. Essa é uma boa maneira de fornecer padrões dos quais o aplicativo poderá precisar para ser executado de uma forma que facilite a inicialização, mas ainda seja fácil de personalizar.
A configuração ContainerDefaultArgs
tem uma propriedade Include
individual, que representa a opção ou o argumento a ser aplicado ao comando ContainerAppCommand
.
<ItemGroup>
<!-- Assuming the ContainerAppCommand defined above,
this would be the way to force the database to update.
-->
<ContainerDefaultArgs Include="database" />
<ContainerDefaultArgs Include="update" />
<!-- This is the shorthand syntax for the same idea -->
<ContainerDefaultArgs Include="database;update" />
</ItemGroup>
ContainerAppCommandInstruction
A configuração de instrução do comando do aplicativo ajuda a controlar a maneira como ContainerEntrypoint
, ContainerEntrypointArgs
, ContainerAppCommand
, ContainerAppCommandArgs
e ContainerDefaultArgs
são combinados para formar o comando final que é executado no contêiner. Isso depende muito de um ENTRYPOINT
estar presente na imagem base. Essa propriedade usa um destes três valores: "DefaultArgs"
, "Entrypoint"
ou "None"
.
Entrypoint
:- Nesse modo, o ponto de entrada é definido por
ContainerAppCommand
,ContainerAppCommandArgs
eContainerDefaultArgs
.
- Nesse modo, o ponto de entrada é definido por
None
:- Nesse modo, o ponto de entrada é definido por
ContainerEntrypoint
,ContainerEntrypointArgs
eContainerDefaultArgs
.
- Nesse modo, o ponto de entrada é definido por
DefaultArgs
:- Esse é o modo mais complexo, caso nenhum dos itens
ContainerEntrypoint[Args]
esteja presente,ContainerAppCommand[Args]
eContainerDefaultArgs
são usados para criar o ponto de entrada e o comando. O ponto de entrada para as imagens base que o têm codificado emdotnet
ou/usr/bin/dotnet
é ignorado, para que você tenha controle completo. - Se
ContainerEntrypoint
eContainerAppCommand
estiverem presentes,ContainerEntrypoint
passará a ser o ponto de entrada eContainerAppCommand
passará a ser o comando.
- Esse é o modo mais complexo, caso nenhum dos itens
Observação
Os itens de configuração ContainerEntrypoint
e ContainerEntrypointArgs
foram preteridos a partir do .NET 8.
Importante
Para usuários avançados: a maioria dos aplicativos não precisa personalizar o ponto de entrada nesse grau. Para obter mais informações e caso você deseje fornecer casos de uso para seus cenários, confira GitHub: Discussões sobre builds de contêiner do SDK do .NET.
ContainerUser
A propriedade de configuração do usuário controla o usuário padrão como o qual o contêiner é executado. Em geral, isso é usado para executar o contêiner como um usuário não raiz, o que é uma melhor prática de segurança. Há algumas restrições a essa configuração das quais você deve estar ciente:
- Ela pode assumir várias formas: nome de usuário, IDs de usuário do Linux, nome do grupo, ID de grupo do Linux,
username:groupname
e outras variantes de ID. - Não há nenhuma verificação de que o usuário ou o grupo especificado existe na imagem.
- A alteração o usuário pode alterar o comportamento do aplicativo, especialmente em relação a itens como permissões do sistema de arquivos.
O valor padrão desse campo varia de acordo com o TFM do projeto e o sistema operacional de destino:
- Se o destino for o .NET 8 ou versão superior e você estiver usando as imagens de runtime da Microsoft:
- no Linux, o usuário sem raiz
app
é usado (embora seja referenciado pela identificação de usuário) - no Windows, o usuário sem raiz
ContainerUser
é usado
- no Linux, o usuário sem raiz
- Caso contrário, nenhum
ContainerUser
padrão é usado
<PropertyGroup>
<ContainerUser>my-existing-app-user</ContainerUser>
</PropertyGroup>
Dica
A variável de ambiente APP_UID
é usada para definir as informações do usuário no contêiner. Esse valor pode ser obtido de variáveis de ambiente definidas na imagem base (como as imagens do Microsoft .NET) ou você mesmo pode defini-lo por meio da sintaxe ContainerEnvironmentVariable
.
No entanto, você pode controlar como seu aplicativo é executado usando ContainerEntrypoint
e ContainerEntrypointArgs
.
ContainerEntrypoint
O ponto de entrada do contêiner pode ser usado para personalizar o ENTRYPOINT
do contêiner, que é o executável chamado quando o contêiner é iniciado. Por padrão, para builds que criam um host de aplicativo, ele é definido como o ContainerEntrypoint
. Para builds que não criam um executável, o dotnet path/to/app.dll
é usado como o ContainerEntrypoint
.
O nó ContainerEntrypoint
tem um único atributo:
Include
: o comando, a opção ou o argumento a ser usado no comandoContainerEntrypoint
.
Por exemplo, considere o seguinte grupo de itens de projeto .NET de exemplo:
<ItemGroup Label="Entrypoint Assignment">
<!-- This is how you would start the dotnet ef tool in your container -->
<ContainerEntrypoint Include="dotnet" />
<ContainerEntrypoint Include="ef" />
<!-- This shorthand syntax means the same thing.
Note the semicolon separating the tokens. -->
<ContainerEntrypoint Include="dotnet;ef" />
</ItemGroup>
ContainerEntrypointArgs
O nó args do ponto de entrada do contêiner controla os argumentos padrão fornecidos para o ContainerEntrypoint
. Isso deve ser usado quando o ContainerEntrypoint
é um programa que o usuário pode querer usar por conta própria. Por padrão, nenhum ContainerEntrypointArgs
é criado em seu nome.
O nó ContainerEntrypointArg
tem um único atributo:
Include
: a opção ou o argumento a ser aplicado ao comandoContainerEntrypoint
.
Considere o seguinte grupo de itens de projeto .NET de exemplo:
<ItemGroup>
<!-- Assuming the ContainerEntrypoint defined above,
this would be the way to update the database by
default, but let the user run a different EF command. -->
<ContainerEntrypointArgs Include="database" />
<ContainerEntrypointArgs Include="update" />
<!-- This is the shorthand syntax for the same idea -->
<ContainerEntrypointArgs Include="database;update" />
</ItemGroup>
Rótulos do contêiner padrão
Os rótulos geralmente são usados para fornecer metadados consistentes em imagens de contêiner. Esse pacote fornece alguns rótulos padrão para incentivar uma melhor manutenção das imagens geradas.
- O
org.opencontainers.image.created
é definido como o formato ISO 8601 doDateTime
UTC atual.
Para obter mais informações, confira Implementar rótulos convencionais sobre a infraestrutura de rótulo existente.
Limpar os recursos
Neste artigo, você publicou um trabalho do .NET como uma imagem de contêiner. Se desejar, exclua este recurso. Use o comando docker images
para ver uma lista de imagens instaladas.
docker images
Considere a seguinte saída de exemplo:
REPOSITORY TAG IMAGE ID CREATED SIZE
dotnet-worker-image 1.0.0 25aeb97a2e21 12 seconds ago 191MB
Dica
Arquivos de imagem podem ser grandes. Normalmente, você removeria contêineres temporários criados durante o teste e o desenvolvimento de seu aplicativo. Em geral, mantenha as imagens de base com o runtime instalado se você planeja construir outras imagens com base nesse runtime.
Para excluir a imagem, copie o ID da imagem e execute o comando docker image rm
:
docker image rm 25aeb97a2e21