Visão geral da criação de contêiner do SDK do .NET
Embora seja possível conteinerizar aplicativos .NET com um Dockerfile, há motivos atraentes para conteinerizar aplicativos diretamente com o SDK do .NET. Este artigo fornece uma visão geral do recurso de criação de contêiner do SDK do .NET, com detalhes relacionados à telemetria, considerações de publicação, propriedades de build e autenticação para registros de contêiner.
Considerações sobre a publicação do projeto
Agora que você tem um aplicativo .NET, pode publicá-lo como um contêiner. Antes de fazer isso, há várias considerações importantes a serem consideradas. Antes do SDK do .NET versão 8.0.200, você precisava do pacote NuGet 📦 Microsoft.NET.Build.Containers. Esse pacote não é necessário para o SDK do .NET versão 8.0.200 e posterior, pois o suporte ao contêiner é incluído por padrão.
Para habilitar a publicação de um aplicativo .NET como um contêiner, as seguintes propriedades de build são necessárias:
IsPublishable
: definido comotrue
. Essa propriedade é definida implicitamente comotrue
para tipos de projeto executáveis, comoconsole
,webapp
eworker
.EnableSdkContainerSupport
: defina comotrue
quando o tipo de projeto for um aplicativo de console.
Para habilitar explicitamente o suporte ao contêiner do SDK, considere o seguinte snippet de arquivo de projeto:
<PropertyGroup>
<IsPublishable>true</IsPublishable>
<EnableSdkContainerSupport>true</EnableSdkContainerSupport>
</PropertyGroup>
Publicação de chaves de troca e propriedades de build
Assim como acontece com todos os comandos da CLI do .NET, você pode especificar propriedades do MSBuild na linha de comando. Há muitos formulários de sintaxe válidos disponíveis para fornecer propriedades, como:
/p:PropertyName=Value
-p:PropertyName=Value
-p PropertyName=Value
--property PropertyName=Value
Você é livre para usar qualquer sintaxe que preferir, mas a documentação mostra exemplos usando o formulário -p
.
Dica
Para ajudar a solucionar problemas, considere o uso dos logs do MSBuid. Para gerar um arquivo de log binário (binlog), adicione a opção -bl
ao comando dotnet publish
. Os arquivos binlog são úteis para diagnosticar problemas de build e podem ser abertos no do Visualizador de Log Estruturado do MSBuild. Eles fornecem um rastreamento detalhado do processo de build, essencial para a análise do MSBuild. Para obter mais informações, consulte Solucionar problemas e criar logs para o MSBuild.
Publicar perfis e destinos
Ao usar o dotnet publish
, especificar um perfil com -p PublishProfile=DefaultContainer
pode definir uma propriedade que faz o SDK acionar outro alvo após o processo de publicação. Essa é uma maneira indireta de alcançar o resultado desejado. Por outro lado, usar dotnet publish /t:PublishContainer
invoca diretamente o destino PublishContainer
, alcançando o mesmo resultado, mas de maneira mais simples.
Em outras palavras, o seguinte comando da CLI do .NET:
dotnet publish -p PublishProfile=DefaultContainer
O que define a propriedade PublishProfile
como DefaultContainer
, é equivalente ao seguinte comando:
dotnet publish /t:PublishContainer
A diferença entre os dois métodos é que o primeiro utiliza um perfil para configurar a propriedade, enquanto o segundo invoca diretamente o destino. O motivo pelo qual isso é importante é que os perfis são um recurso do MSBuild e podem ser usados para definir propriedades de uma maneira mais complexa do que apenas defini-las diretamente.
Um problema importante é que nem todos os tipos de projeto dão suporte a perfis ou têm o mesmo conjunto de perfis disponíveis. Além disso, há uma disparidade no nível de suporte para perfis entre diferentes ferramentas, como o Visual Studio e a CLI do .NET. Portanto, o uso de metas geralmente é um método mais claro e mais amplamente aceito para obter o mesmo resultado.
Autenticar em registros de contêiner
Interagir com registros de contêiner privado requer autenticação com esses registros.
O Docker tem um padrão estabelecido com isso por meio do comando docker login
, que é uma maneira de interagir com um arquivo de configuração do Docker que contém regras para autenticação com registros específicos. Esse arquivo e os tipos de autenticação codificados por ele têm suporte do Microsoft.Net.Build.Containers para autenticação do Registro. Isso deve garantir que esse pacote funcione perfeitamente com qualquer registro do qual você possa docker pull
e docker push
. Normalmente, esse arquivo é armazenado em ~/.docker/config.json, mas pode ser especificado adicionalmente por meio da variável DOCKER_CONFIG
, que aponta para um diretório que contém um arquivo config.json.
Tipos de autenticação
O arquivo config.json contém três tipos de autenticação:
- Nomes de usuário/senhas explícitos
- ajudantes de credenciais
- Chaveiro do sistema
Nome de usuário/senha explícito
A seção auths
do arquivo config.json é um mapa de chave/valor entre nomes de registro e cadeias de caracteres username:password codificadas em Base64. Em um cenário comum do Docker, executar docker login <registry> -u <username> -p <password>
cria novos itens neste mapa. Essas credenciais são populares em sistemas de CI (integração contínua), em que o logon é feito por tokens no início de uma execução. No entanto, são menos utilizados em computadores de desenvolvimento por usuários finais devido ao risco de segurança de ter credenciais expostas em um arquivo.
Auxiliares de credenciais
A seção credHelpers
do arquivo config.json é um mapa de chave/valor entre os nomes do Registro e os nomes de programas específicos que podem ser usados para criar e recuperar credenciais para esse registro. Isso geralmente é usado quando registros específicos têm requisitos de autenticação complexos. Para que esse tipo de autenticação funcione, você deve ter um aplicativo chamado docker-credential-{name}
no PATH
do sistema. Esses tipos de credenciais tendem a ser seguras, mas podem ser difíceis de configurar em máquinas de desenvolvimento ou integração contínua (CI).
Conjuntos de chaves do sistema
A seção credsStore
é uma única propriedade de cadeia de caracteres cujo valor é o nome de um programa auxiliar de credencial do docker que sabe como fazer a interface com o gerenciador de senhas do sistema. Para o Windows, isso pode ser wincred
por exemplo. Eles são populares entre os instaladores do Docker para macOS e Windows.
Autenticação por meio de variáveis de ambiente
Em alguns cenários, o mecanismo de autenticação padrão do Docker descrito acima simplesmente não é suficiente. Essa ferramenta tem um mecanismo adicional para fornecer credenciais aos registros: variáveis de ambiente. Se variáveis de ambiente forem usadas, o mecanismo de fornecer credencial não será usado. Há suporte para as seguintes variáveis de ambiente:
DOTNET_CONTAINER_REGISTRY_UNAME
: esse deve ser o nome de usuário do registro. Se a senha do registro for um token, o nome de usuário deverá ser"<token>"
.DOTNET_CONTAINER_REGISTRY_PWORD
: essa deve ser a senha ou o token do registro.
Nota
A partir do SDK do .NET 8.0.400, as variáveis de ambiente para operações de contêiner foram atualizadas. As variáveis SDK_CONTAINER_*
agora são prefixadas com DOTNET_CONTAINER_*
.
Esse mecanismo é potencialmente vulnerável ao vazamento de credenciais, portanto, ele só deve ser usado em cenários em que o outro mecanismo não está disponível. Por exemplo, se você estiver usando as ferramentas de contêiner do SDK dentro de um contêiner do Docker em si. Além disso, esse mecanismo não é namespaced — ele tenta usar as mesmas credenciais para o registro de origem (onde sua imagem base está localizada) e o registro de destino (onde você está enviando sua imagem final).
Usando registros inseguros
A maioria do acesso ao Registro é considerada segura, o que significa que HTTPS é usado para interagir com o registro. No entanto, nem todos os registros são configurados com certificados TLS , especialmente em situações como um registro corporativo privado por trás de uma VPN. Para dar suporte a esses casos de uso, as ferramentas de contêiner fornecem maneiras de declarar que um registro específico usa comunicação insegura.
A partir do .NET 8.0.400, o SDK entende esses arquivos e formatos de configuração e usará automaticamente essa configuração para determinar se HTTP ou HTTPS devem ser usados. Configurar um registro para comunicação insegura varia de acordo com sua ferramenta de contêiner de escolha.
Docker
O Docker armazena sua configuração de registro na configuração do daemon . Para adicionar novos registros inseguros, novos hosts serão adicionados à propriedade da matriz "insecure-registries"
:
{
"insecure-registries": [
"registry.mycorp.net"
]
}
Nota
Você deve reiniciar o daemon do Docker para aplicar quaisquer alterações a esse arquivo.
Podman
O Podman usa um arquivo TOML registries.conf
para armazenar informações de conexão do Registro. Esse arquivo normalmente vive em /etc/containers/registries.conf
. Para adicionar novos registros inseguros, uma seção TOML é adicionada para manter as configurações do registro e, em seguida, a opção insecure
deve ser definida como true
.
[[registry]]
location = "registry.mycorp.net"
insecure = true
Nota
Você deve reiniciar o Podman para aplicar quaisquer alterações ao arquivo registries.conf.
Variáveis de ambiente
A partir da 9.0.100, o SDK do .NET reconhece registros inseguros passados pela variável de ambiente DOTNET_CONTAINER_INSECURE_REGISTRIES
. Essa variável usa uma lista separada por vírgulas de domínios para tratar como inseguro da mesma maneira que os exemplos de Docker e Podman acima.
$Env:DOTNET_CONTAINER_INSECURE_REGISTRIES=localhost:5000,registry.mycorp.com; dotnet publish -t:PublishContainer -p:ContainerRegistry=registry.mycorp.com -p:ContainerBaseImage=localhost:5000/dotnet/runtime:9.0
Telemetria
Quando você publica um aplicativo .NET como um contêiner, as ferramentas de contêiner do SDK do .NET coletam e enviam telemetria de uso sobre como as ferramentas são usadas. Os dados coletados se somam à telemetria enviada pela .NET CLI, mas usam os mesmos mecanismos e, principalmente, aderem aos mesmos controles de exclusão .
A telemetria coletada destina-se a ser de natureza geral e não vazar informações pessoais. A finalidade pretendida é ajudar a medir:
- Uso geral do recurso de contêinerização do SDK do .NET.
- Taxas de êxito e falha, juntamente com informações gerais sobre quais tipos de falhas ocorrem com mais frequência.
- Uso de recursos específicos da tecnologia, como publicação em vários tipos de registro ou como a publicação foi invocada.
Para recusar a telemetria, defina a variável de ambiente DOTNET_CLI_TELEMETRY_OPTOUT
como true
. Para obter mais informações, consulte telemetria da CLI do .NET.
Telemetria de inferência
As seguintes informações sobre como o processo de inferência de imagem base ocorreu são registradas:
Ponto de data | Explicação | Valor de exemplo |
---|---|---|
InferencePerformed |
Se os usuários estiverem especificando manualmente imagens base em vez de usando a inferência. | true |
TargetFramework |
O TargetFramework escolhido ao fazer inferência de imagem base. |
net8.0 |
BaseImage |
O valor da imagem base escolhida, mas somente se essa imagem base for uma das imagens produzidas pela Microsoft. Se um usuário especificar qualquer imagem diferente das imagens produzidas pela Microsoft em mcr.microsoft.com, esse valor será nulo. | mcr.microsoft.com/dotnet/aspnet |
BaseImageTag |
O valor da tag escolhida, mas somente se essa tag for para uma das imagens produzidas pela Microsoft. Se um usuário especificar qualquer imagem diferente das imagens produzidas pela Microsoft em mcr.microsoft.com, esse valor será nulo. | 8.0 |
ContainerFamily |
O valor da propriedade ContainerFamily se um usuário usou o recurso ContainerFamily para escolher um "sabor" de uma de nossas imagens base. Isso só será definido se o usuário tiver escolhido ou inferido uma das imagens do .NET produzidas pela Microsoft de mcr.microsoft.com |
jammy-chiseled |
ProjectType |
O tipo de projeto que está sendo conteinerizado. | AspNetCore ou Console |
PublishMode |
Como o aplicativo foi empacotado. | Aot , Trimmed , SelfContained ou FrameworkDependent |
IsInvariant |
Se a imagem escolhida exigir globalização invariável ou se o usuário tiver optado por essa opção manualmente. | true |
TargetRuntime |
O RID para o qual este aplicativo foi publicado. | linux-x64 |
Telemetria de criação de imagem
As seguintes informações sobre como ocorreu o processo de criação e publicação do contêiner são registradas:
Ponto de data | Explicação | Valor de exemplo |
---|---|---|
RemotePullType |
Se a imagem base veio de um registro remoto, que tipo de registro era? | Azure, AWS, Google, GitHub, DockerHub, MRC ou outros |
LocalPullType |
Se a imagem base veio de uma fonte local, como um daemon de contêiner ou um tarball. | Docker, Podman, Tarball |
RemotePushType |
Se a imagem foi enviada por push para um registro remoto, que tipo de registro era? | Azure, AWS, Google, GitHub, DockerHub, MRC ou outros |
LocalPushType |
Se a imagem foi enviada por push para um destino local, qual foi o destino? | Docker, Podman, Tarball |
Além disso, se vários tipos de erros ocorrerem durante o processo, os dados serão coletados sobre que tipo de erro foi:
Ponto de data | Explicação | Valor de exemplo |
---|---|---|
Error |
O tipo de erro que ocorreu | unknown_repository , credential_failure , rid_mismatch , local_load . |
Direction |
Se o erro for um credential_failure , foi no registro de push ou pull? |
push |
RID de Destino | Se o erro foi um rid_mismatch , qual RID foi solicitado? |
linux-x64 |
RIDs disponíveis | Se o erro foi um rid_mismatch , quais RIDs a imagem base suportava? |
linux-x64,linux-arm64 |