Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este tutorial, aprenderá a incluir en contenedores una aplicación .NET con Docker. Los contenedores tienen muchas características y ventajas, como ser una infraestructura inmutable, proporcionar una arquitectura portátil y habilitar la escalabilidad. La imagen se puede usar para crear contenedores para el entorno de desarrollo local, la nube privada o la nube pública.
En este tutorial, harás lo siguiente:
- Creación y publicación de una aplicación .NET sencilla
- Creación y configuración de un Dockerfile para .NET
- Creación de una imagen de Docker
- Creación y ejecución de un contenedor de Docker
Explorará la compilación del contenedor de Docker e implementará tareas para una aplicación .NET. La plataforma Docker usa el motor de Docker para compilar y empaquetar rápidamente aplicaciones como imágenes de Docker. Estas imágenes se escriben en el formato Dockerfile que se va a implementar y ejecutar en un contenedor en capas.
Sugerencia
Si está interesado en publicar la aplicación de .NET como contenedor sin necesidad de Docker o Podman, consulte Containerize a .NET app with dotnet publish (Incluir en contenedores una aplicación de .NET con dotnet publish).
Nota:
Este tutorial no es para aplicaciones de ASP.NET Core. Si usa ASP.NET Core, consulte el tutorial Sobre cómo incluir en contenedores una aplicación ASP.NET Core .
Prerrequisitos
Instale los siguientes requisitos previos:
- SDK de .NET 9+.
Si tiene instalado .NET, use eldotnet --info
comando para determinar qué SDK usa.
- SDK de .NET 8+.
Si tiene instalado .NET, use eldotnet --info
comando para determinar qué SDK usa.
- Docker Community Edition.
- Una carpeta de trabajo temporal para la aplicación de ejemplo Dockerfile y .NET. En este tutorial, el nombre docker-working se usa como carpeta de trabajo.
Creación de una aplicación .NET
Necesita una aplicación de .NET que ejecute el contenedor de Docker. Abra el terminal, cree una carpeta de trabajo si aún no lo ha hecho y escríbala. En la carpeta de trabajo, ejecute el siguiente comando para crear un nuevo proyecto en un subdirectorio denominado App:
dotnet new console -o App -n DotNet.Docker
El árbol de carpetas tiene un aspecto similar a la siguiente estructura de directorios:
📁 docker-working
└──📂 App
├──DotNet.Docker.csproj
├──Program.cs
└──📂 obj
├── DotNet.Docker.csproj.nuget.dgspec.json
├── DotNet.Docker.csproj.nuget.g.props
├── DotNet.Docker.csproj.nuget.g.targets
├── project.assets.json
└── project.nuget.cache
El dotnet new
comando crea una nueva carpeta denominada App y genera una aplicación de consola "Hello World". Ahora, cambia los directorios y navega a la carpeta Aplicación desde la sesión de terminal. Use el dotnet run
comando para iniciar la aplicación. La aplicación se ejecuta e imprime Hello World!
debajo del comando:
cd App
dotnet run
Hello World!
La plantilla predeterminada crea una aplicación que se imprime en el terminal y, a continuación, finaliza inmediatamente. En este tutorial, usarás una aplicación que se ejecuta indefinidamente en un bucle. Abra el archivo Program.cs en un editor de texto.
Sugerencia
Si usa Visual Studio Code, en la sesión de terminal anterior, escriba el siguiente comando:
code .
Este comando abre la carpeta App que contiene el proyecto en Visual Studio Code.
El Program.cs debe tener un aspecto similar al siguiente código de C#:
Console.WriteLine("Hello World!");
Reemplace el archivo por el código siguiente que cuenta números cada segundo:
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
Guarde el archivo y vuelva a probar el programa con dotnet run
. Recuerde que esta aplicación se ejecuta indefinidamente. Use el comando cancelar Ctrl+C para detenerlo. Considere la siguiente salida de ejemplo:
dotnet run
Counter: 1
Counter: 2
Counter: 3
Counter: 4
^C
Si pasa un número en la línea de comandos a la aplicación, limita el recuento a esa cantidad y, a continuación, sale. Pruébelo con dotnet run -- 5
para contar hasta cinco.
Importante
Cualquier parámetro posterior a --
no se pasa al comando dotnet run
y, en su lugar, se pasa a su aplicación.
Publicación de la aplicación .NET
Para que la aplicación sea adecuada para crear una imagen, debe compilarse. El dotnet publish
comando es el más adecuado para esto, ya que compila y publica la aplicación. Para obtener una referencia detallada, consulte la documentación de comandos dotnet build y dotnet publish .
dotnet publish -c Release
Sugerencia
Si está interesado en publicar la aplicación .NET como contenedor sin necesidad de Docker, consulte Contenedorización de una aplicación de .NET con dotnet publish.
El dotnet publish
comando compila la aplicación en la carpeta publish . La ruta de acceso a la carpeta publish desde la carpeta de trabajo debe ser ./App/bin/Release/TFM>/<publish/:
En la carpeta Aplicación , obtenga una lista de directorios de la carpeta publish para comprobar que se creó el archivo DotNet.Docker.dll .
dir .\bin\Release\net9.0\publish\
Directory: C:\Users\default\docker-working\App\bin\Release\net9.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 1/6/2025 10:11 AM 431 DotNet.Docker.deps.json
-a---- 1/6/2025 10:11 AM 6144 DotNet.Docker.dll
-a---- 1/6/2025 10:11 AM 145408 DotNet.Docker.exe
-a---- 1/6/2025 10:11 AM 11716 DotNet.Docker.pdb
-a---- 1/6/2025 10:11 AM 340 DotNet.Docker.runtimeconfig.json
dir .\bin\Release\net8.0\publish\
Directory: C:\Users\default\docker-working\App\bin\Release\net8.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/22/2023 9:17 AM 431 DotNet.Docker.deps.json
-a--- 9/22/2023 9:17 AM 6144 DotNet.Docker.dll
-a--- 9/22/2023 9:17 AM 157696 DotNet.Docker.exe
-a--- 9/22/2023 9:17 AM 11688 DotNet.Docker.pdb
-a--- 9/22/2023 9:17 AM 353 DotNet.Docker.runtimeconfig.json
Creación del Dockerfile
El comando usa el docker build
archivo Dockerfile para crear una imagen de contenedor. Este archivo es un archivo de texto denominado Dockerfile que no tiene una extensión.
Cree un archivo denominado Dockerfile en el directorio que contiene el archivo .csproj y ábralo en un editor de texto. En este tutorial se usa la imagen en tiempo de ejecución de ASP.NET Core (que contiene la imagen en tiempo de ejecución de .NET) y se corresponde con la aplicación de consola de .NET.
FROM mcr.microsoft.com/dotnet/sdk:9.0@sha256:3fcf6f1e809c0553f9feb222369f58749af314af6f063f389cbd2f913b4ad556 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:9.0@sha256:b4bea3a52a0a77317fa93c5bbdb076623f81e3e2f201078d89914da71318b5d8
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Nota:
La imagen en tiempo de ejecución de ASP.NET Core se usa intencionadamente aquí, aunque la mcr.microsoft.com/dotnet/runtime:9.0
imagen podría usarse en su lugar.
FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:6c4df091e4e531bb93bdbfe7e7f0998e7ced344f54426b7e874116a3dc3233ff
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Nota:
La imagen en tiempo de ejecución de ASP.NET Core se usa intencionadamente aquí, aunque la mcr.microsoft.com/dotnet/runtime:8.0
imagen podría usarse en su lugar.
Importante
Incluir un algoritmo hash seguro (SHA) después de la etiqueta de imagen en un Dockerfile es un procedimiento recomendado. Esto garantiza que la imagen no se manipule y que la imagen sea la misma que espera. SHA es un identificador único para la imagen. Para obtener más información, consulte Documentos de Docker: Extracción de una imagen por resumen.
Sugerencia
Este Dockerfile utiliza compilaciones de varias fases, que optimizan el tamaño final de la imagen al aplicar capas al proceso de compilación y dejando solo los artefactos necesarios. Para más información, consulte Docker Docs: compilaciones en varias fases.
La palabra clave FROM
requiere un nombre completo de imagen de contenedor de Docker. Microsoft Container Registry (MCR, mcr.microsoft.com) es un sindicato de Docker Hub, que hospeda contenedores accesibles públicamente. El dotnet
segmento es el repositorio de contenedores, mientras que el sdk
o aspnet
es el nombre de la imagen del contenedor. La imagen se etiqueta con 9.0
, que se usa para el control de versiones. Por lo tanto, mcr.microsoft.com/dotnet/aspnet:9.0
es el entorno de ejecución de .NET 9.0. Asegúrese de extraer el runtime que coincida con el que el SDK tiene como destino. Por ejemplo, la aplicación creada en la sección anterior usó el SDK de .NET 9.0 y la imagen base a la que se hace referencia en dockerfile se etiqueta con la versión 9.0.
Importante
Al usar imágenes de contenedor basadas en Windows, debe especificar la etiqueta de imagen más allá de simplemente 9.0
, por ejemplo, mcr.microsoft.com/dotnet/aspnet:9.0-nanoserver-1809
en lugar de mcr.microsoft.com/dotnet/aspnet:9.0
. Seleccione un nombre de imagen en función de si usa Nano Server o Windows Server Core y la versión de ese sistema operativo. Puede encontrar una lista completa de todas las etiquetas compatibles en la página de Docker Hub de .NET.
Guarde el archivo Dockerfile . La estructura de directorios de la carpeta de trabajo debe ser similar a la siguiente. Algunos de los archivos y carpetas de nivel más profundo se omiten para ahorrar espacio en el artículo:
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └───📂 Release
│ └───📂 net9.0
│ ├───📂 publish
│ │ ├─── DotNet.Docker.deps.json
│ │ ├─── DotNet.Docker.dll
│ │ ├─── DotNet.Docker.exe
│ │ ├─── DotNet.Docker.pdb
│ │ └─── DotNet.Docker.runtimeconfig.json
│ ├─── DotNet.Docker.deps.json
│ ├─── DotNet.Docker.dll
│ ├─── DotNet.Docker.exe
│ ├─── DotNet.Docker.pdb
│ └─── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
La palabra clave FROM
requiere un nombre completo de imagen de contenedor de Docker. Microsoft Container Registry (MCR, mcr.microsoft.com) es un sindicato de Docker Hub, que hospeda contenedores accesibles públicamente. El dotnet
segmento es el repositorio de contenedores, mientras que el sdk
o aspnet
es el nombre de la imagen del contenedor. La imagen se etiqueta con 8.0
, que se usa para el control de versiones. Por lo tanto, mcr.microsoft.com/dotnet/aspnet:8.0
es el entorno de ejecución de .NET 8.0. Asegúrese de extraer el runtime que coincida con el que el SDK tiene como destino. Por ejemplo, la aplicación creada en la sección anterior usó el SDK de .NET 8.0 y la imagen base a la que se hace referencia en dockerfile se etiqueta con la versión 8.0.
Importante
Al usar imágenes de contenedor basadas en Windows, debe especificar la etiqueta de imagen más allá de simplemente 8.0
, por ejemplo, mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-1809
en lugar de mcr.microsoft.com/dotnet/aspnet:8.0
. Seleccione un nombre de imagen en función de si usa Nano Server o Windows Server Core y la versión de ese sistema operativo. Puede encontrar una lista completa de todas las etiquetas admitidas en la página de Docker Hub de .NET.
Guarde el archivo Dockerfile . La estructura de directorios de la carpeta de trabajo debe ser similar a la siguiente. Algunos de los archivos y carpetas de nivel más profundo se omiten para ahorrar espacio en el artículo:
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └──📂 Release
│ └──📂 net8.0
│ └──📂 publish
│ ├── DotNet.Docker.deps.json
│ ├── DotNet.Docker.exe
│ ├── DotNet.Docker.dll
│ ├── DotNet.Docker.pdb
│ └── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
La ENTRYPOINT
instrucción establece dotnet
como host para .DotNet.Docker.dll
Sin embargo, es posible definir el ENTRYPOINT
como el ejecutable de la propia aplicación, confiando en el sistema operativo como host de la aplicación.
ENTRYPOINT ["./DotNet.Docker"]
Esto hace que la aplicación se ejecute directamente, sin dotnet
, y en su lugar se basa en el host de la aplicación y en el sistema operativo subyacente. Para obtener más información sobre la implementación de archivos binarios multiplataforma, vea Generar un binario multiplataforma.
Para compilar el contenedor, desde el terminal, ejecute el siguiente comando:
docker build -t counter-image -f Dockerfile .
Docker procesa cada línea del Dockerfile. En .
el comando docker build
establece el contexto de compilación de la imagen. El modificador -f
es la ruta de acceso al archivo Dockerfile. Este comando compila la imagen y crea un repositorio local denominado counter-image que apunta a esa imagen. Una vez finalizado este comando, ejecute docker images
para ver una lista de imágenes instaladas:
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 1c1f1433e51d 32 seconds ago 223MB
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 2f15637dc1f6 10 minutes ago 217MB
El counter-image
repositorio es el nombre de la imagen. Además, la etiqueta de imagen, el identificador de imagen, el tamaño y cuándo se creó están incluidos en la salida. Los pasos finales del Dockerfile son crear un contenedor a partir de la imagen y ejecutar la aplicación, copiar la aplicación publicada en el contenedor y definir el punto de entrada:
FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
El FROM
comando especifica la imagen base y la etiqueta que se van a usar. El WORKDIR
comando cambia el directorio actual dentro del contenedor a App.
El COPY
comando indica a Docker que copie el directorio de origen especificado en una carpeta de destino. En este ejemplo, el contenido de publicación de la build
capa se genera en la carpeta denominada App/out, por lo que es el origen desde el que se va a copiar. Todos los contenidos publicados en el directorio App/out se copian en el directorio de trabajo actual (App).
El siguiente comando, ENTRYPOINT
, indica a Docker que configure el contenedor para que se ejecute como un archivo ejecutable. Cuando se inicia el contenedor, se ejecuta el ENTRYPOINT
comando . Cuando finaliza este comando, el contenedor se detiene automáticamente.
Sugerencia
Antes de .NET 8, los contenedores configurados para ejecutarse como de solo lectura podrían producir un error con Failed to create CoreCLR, HRESULT: 0x8007000E
. Para solucionar este problema, especifique una DOTNET_EnableDiagnostics
variable de entorno como 0
(justo antes del ENTRYPOINT
paso):
ENV DOTNET_EnableDiagnostics=0
Para obtener más información sobre varias variables de entorno de .NET, consulte Variables de entorno de .NET.
Nota:
.NET 6 normaliza el prefijo DOTNET_
en lugar de COMPlus_
para las variables de entorno que configuran el comportamiento en tiempo de ejecución de .NET. Sin embargo, el prefijo COMPlus_
seguirá funcionando. Si usa una versión anterior del entorno de ejecución de .NET, debe seguir usando el prefijo COMPlus_
para las variables de entorno.
Creación de un contenedor
Ahora que tiene una imagen que contiene la aplicación, puede crear un contenedor. Puede crear un contenedor de dos maneras. En primer lugar, cree un contenedor que esté detenido.
docker create --name core-counter counter-image
El comando docker create
crea un contenedor basado en la imagen counter-image. La salida del docker create
comando muestra el ID del contenedor (el identificador será diferente):
d0be06126f7db6dd1cee369d911262a353c9b7fb4829a0c11b4b2eb7b2d429cf
Para ver una lista de todos los contenedores, use el docker ps -a
comando :
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0be06126f7d counter-image "dotnet DotNet.Docke…" 12 seconds ago Created core-counter
Administración del contenedor
El contenedor se creó con un nombre core-counter
específico. Este nombre se usa para administrar el contenedor. En el ejemplo siguiente se usa el docker start
comando para iniciar el contenedor y, a continuación, se usa el docker ps
comando para mostrar solo los contenedores que se ejecutan:
docker start core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf01364df453 counter-image "dotnet DotNet.Docke…" 53 seconds ago Up 10 seconds core-counter
Del mismo modo, el docker stop
comando detiene el contenedor. En el ejemplo siguiente se usa el docker stop
comando para detener el contenedor y, a continuación, se usa el docker ps
comando para mostrar que no hay contenedores en ejecución:
docker stop core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Conexión a un contenedor
Después de ejecutar un contenedor, puede conectarse a él para ver la salida. Use los docker start
comandos y docker attach
para iniciar el contenedor y examinar el flujo de salida. En este ejemplo, la pulsación de tecla Ctrl+C se usa para desasociar del contenedor en ejecución. Esta pulsación de tecla finaliza el proceso en el contenedor a menos que se especifique lo contrario, lo que detendría el contenedor. El --sig-proxy=false
parámetro garantiza que Ctrl+C no detenga el proceso en el contenedor.
Después de desconectarse del contenedor, reconéctelo para verificar que todavía esté funcionando y contando.
docker start core-counter
core-counter
docker attach --sig-proxy=false core-counter
Counter: 7
Counter: 8
Counter: 9
^C
docker attach --sig-proxy=false core-counter
Counter: 17
Counter: 18
Counter: 19
^C
Eliminación de un contenedor
En este artículo, no quiere que haya contenedores que no hagan nada. Elimine el contenedor que creó anteriormente. Si el contenedor está en ejecución, deténgalo.
docker stop core-counter
En el ejemplo siguiente se enumeran todos los contenedores. A continuación, usa el docker rm
comando para eliminar el contenedor y, a continuación, comprueba una segunda vez si hay contenedores en ejecución.
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f6424a7ddce counter-image "dotnet DotNet.Dock…" 7 minutes ago Exited (143) 20 seconds ago core-counter
docker rm core-counter
core-counter
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Ejecución única
Docker proporciona el docker run
comando para crear y ejecutar el contenedor como un solo comando. Este comando elimina la necesidad de ejecutar docker create
y, a continuación, docker start
. También puede establecer este comando para eliminar automáticamente el contenedor cuando se detenga el contenedor. Por ejemplo, use docker run -it --rm
para hacer dos cosas, en primer lugar, use automáticamente el terminal actual para conectarse al contenedor y, a continuación, cuando finalice el contenedor, quítelo:
docker run -it --rm counter-image
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
^C
El contenedor también pasa parámetros a la ejecución de la aplicación .NET. Para indicar a la aplicación .NET que cuente hasta tres, pase el número 3.
docker run -it --rm counter-image 3
Counter: 1
Counter: 2
Counter: 3
Con docker run -it
, el comando Ctrl+C detiene el proceso que se ejecuta en el contenedor, que a su vez detiene el contenedor. Dado que se proporcionó el --rm
parámetro , el contenedor se elimina automáticamente cuando se detiene el proceso. Compruebe que no existe:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Cambio de ENTRYPOINT
El docker run
comando también le permite modificar el ENTRYPOINT
comando desde dockerfile y ejecutar otra cosa, pero solo para ese contenedor. Por ejemplo, use el siguiente comando para ejecutar bash
o cmd.exe
. Edite el comando según sea necesario.
En este ejemplo, ENTRYPOINT
se cambia a cmd.exe
. Ctrl+C se presiona para finalizar el proceso y detener el contenedor.
docker run -it --rm --entrypoint "cmd.exe" counter-image
Microsoft Windows [Version 10.0.17763.379]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\>dir
Volume in drive C has no label.
Volume Serial Number is 3005-1E84
Directory of C:\
04/09/2019 08:46 AM <DIR> app
03/07/2019 10:25 AM 5,510 License.txt
04/02/2019 01:35 PM <DIR> Program Files
04/09/2019 01:06 PM <DIR> Users
04/02/2019 01:35 PM <DIR> Windows
1 File(s) 5,510 bytes
4 Dir(s) 21,246,517,248 bytes free
C:\>^C
Nota:
Este ejemplo solo funciona en contenedores de Windows. Los contenedores de Linux no tienen cmd.exe
.
Comandos esenciales
Docker tiene muchos comandos diferentes que crean, administran e interactúan con contenedores e imágenes. Estos comandos de Docker son esenciales para administrar los contenedores:
Limpieza de recursos
Durante este tutorial, ha creado contenedores e imágenes. Si lo desea, elimine estos recursos. Use los comandos siguientes para
Enumerar todos los contenedores
docker ps -a
Detener los contenedores que están en ejecución por nombre
docker stop core-counter
Eliminación del contenedor
docker rm core-counter
A continuación, elimine las imágenes que ya no desee en la máquina. Elimine la imagen que creó el archivo Dockerfile y luego elimine la imagen de .NET en que se basó el archivo Dockerfile. Puede usar el identificador de imagen o la cadena con formato REPOSITORY:TAG .
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:9.0
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:8.0
Use el docker images
comando para ver una lista de imágenes instaladas.
Sugerencia
Los archivos de imagen pueden ser grandes. Normalmente, quitaría los contenedores temporales que creó al probar y desarrollar la aplicación. Normalmente, las imágenes base se mantienen instaladas con el tiempo de ejecución si planea crear otras imágenes basadas en ese tiempo de ejecución.