Tutorial: Incluir una aplicación de .NET Core en un contenedorTutorial: Containerize a .NET Core app

En este tutorial se ofrece información sobre cómo compilar una imagen de Docker que contiene una aplicación de .NET Core.This tutorial teaches you how to build a Docker image that contains your .NET Core application. La imagen puede usarse para crear contenedores para un entorno de desarrollo local, una nube privada o una nube pública.The image can be used to create containers for your local development environment, private cloud, or public cloud.

Aprenderá a hacer lo siguiente:You'll learn to:

  • Crear y publicar una aplicación .NET Core sencillaCreate and publish a simple .NET Core app
  • Crear y configurar un archivo Dockerfile para .NET CoreCreate and configure a Dockerfile for .NET Core
  • Creación de una imagen de DockerBuild a Docker image
  • Crear y ejecutar un contenedor de DockerCreate and run a Docker container

Aprenderá sobre las tareas de compilación e implementación de un contenedor de Docker para una aplicación .NET Core.You'll understand the Docker container build and deploy tasks for a .NET Core application. La plataforma Docker usa el motor de Docker para compilar y empaquetar rápidamente aplicaciones como imágenes de Docker.The Docker platform uses the Docker engine to quickly build and package apps as Docker images. Estas imágenes se escriben en el formato Dockerfile para implementarse y ejecutarse en un contenedor superpuesto.These images are written in the Dockerfile format to be deployed and run in a layered container.

Sugerencia

Si está trabajando con una aplicación de ASP.NET Core, consulte el tutorial Obtenga información sobre cómo incluir una aplicación ASP.NET Core en contenedores.If you're working with an existing ASP.NET Core application, see the Learn how to containerize an ASP.NET Core application tutorial.

Requisitos previosPrerequisites

Instale estos requisitos previos:Install the following prerequisites:

  • SDK de .NET Core 3.1.NET Core 3.1 SDK
    Si tiene instalado .NET Core, use el comando dotnet --info para determinar el SDK que está usando.If you have .NET Core installed, use the dotnet --info command to determine which SDK you're using.

  • Docker Community EditionDocker Community Edition

  • Una carpeta de trabajo temporal para Dockerfile y una aplicación .NET Core de ejemplo.A temporary working folder for the Dockerfile and .NET Core example app. En este tutorial, el nombre docker-working se usa como la carpeta de trabajo.In this tutorial, the name docker-working is used as the working folder.

Creación de una aplicación .NET CoreCreate .NET Core app

Necesita una aplicación .NET Core que el contenedor de Docker ejecutará.You need a .NET Core app that the Docker container will run. Abra el terminal, cree una carpeta de trabajo si todavía no lo ha hecho y entre en ella.Open your terminal, create a working folder if you haven't already, and enter it. En la carpeta de trabajo, ejecute el comando siguiente para crear un proyecto en un subdirectorio llamado app:In the working folder, run the following command to create a new project in a subdirectory named app:

dotnet new console -o app -n myapp

El árbol de carpetas tendrá un aspecto similar al siguiente:Your folder tree will look like the following:

docker-working
│
└───app
    │   myapp.csproj
    │   Program.cs
    │
    └───obj
            myapp.csproj.nuget.cache
            myapp.csproj.nuget.dgspec.json
            myapp.csproj.nuget.g.props
            myapp.csproj.nuget.g.targets
            project.assets.json

Con el comando dotnet new se crea una carpeta denominada app y se genera una aplicación "Hola mundo".The dotnet new command creates a new folder named app and generates a "Hello World" app. Entre en la carpeta app y ejecute el comando dotnet run.Enter the app folder and run the command dotnet run. Verá la salida siguiente:You'll see the following output:

> dotnet run
Hello World!

La plantilla predeterminada crea una aplicación que imprime en el terminal y luego se cierra.The default template creates an app that prints to the terminal and then exits. En este tutorial, se usará una aplicación que se repite en bucle de manera indefinida.For this tutorial, you'll use an app that loops indefinitely. Abra el archivo Program.cs en un editor de texto.Open the Program.cs file in a text editor. Actualmente debe ser similar al código siguiente:It should currently look like the following code:

using System;

namespace myapp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Reemplace el archivo por el código siguiente que cuenta números cada segundo:Replace the file with the following code that counts numbers every second:

using System;

namespace myapp
{
    class Program
    {
        static void Main(string[] args)
        {
            var counter = 0;
            var max = args.Length != 0 ? Convert.ToInt32(args[0]) : -1;
            while (max == -1 || counter < max)
            {
                counter++;
                Console.WriteLine($"Counter: {counter}");
                System.Threading.Tasks.Task.Delay(1000).Wait();
            }
        }
    }
}

Guarde el archivo y vuelva a probar el programa con dotnet run.Save the file and test the program again with dotnet run. Recuerde que esta aplicación se ejecuta de manera indefinida.Remember that this app runs indefinitely. Use el comando de cancelación CTRL+C para detenerla.Use the cancel command CTRL+C to stop it. Verá la salida siguiente:You'll see the following output:

> 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, solo se contará hasta esa cantidad y se cerrará.If you pass a number on the command line to the app, it will only count up to that amount and then exit. Inténtelo con dotnet run -- 5 para contar hasta cinco.Try it with dotnet run -- 5 to count to five.

Nota

Cualquier parámetro posterior a -- no se pasa al comando dotnet run y, en su lugar, se pasa a su aplicación.Any parameters after -- are not passed to the dotnet run command and instead are passed to your application.

Publicación de una aplicación .NET CorePublish .NET Core app

Antes de agregar la aplicación .NET Core a la imagen de Docker, publíquela.Before you add your .NET Core app to the Docker image, publish it. Quiere asegurarse de que el contenedor ejecuta la versión publicada de la aplicación al iniciarse.You want to make sure that the container runs the published version of the app when it's started.

Desde la carpeta de trabajo, entre en la carpeta app con el código fuente de ejemplo y ejecute el comando siguiente:From the working folder, enter the app folder with the example source code and run the following command:

dotnet publish -c Release

Con este comando se compila la aplicación en la carpeta publish.This command compiles your app to the publish folder. La ruta de acceso a la carpeta publish desde la carpeta de trabajo debería ser .\app\bin\Release\netcoreapp3.1\publish\.The path to the publish folder from the working folder should be .\app\bin\Release\netcoreapp3.1\publish\

En la carpeta app, obtenga un listado de los directorios de la carpeta publish para comprobar que se creó el archivo myapp.dll.From the app folder, get a directory listing of the publish folder to verify that the myapp.dll file was created.

> dir bin\Release\netcoreapp3.1\publish

    Directory:  C:\docker-working\app\bin\Release\netcoreapp3.1\publish

01/09/2020  11:41 AM    <DIR>          .
01/09/2020  11:41 AM    <DIR>          ..
01/09/2020  11:41 AM               407 myapp.deps.json
01/09/2020  12:15 PM             4,608 myapp.dll
01/09/2020  12:15 PM           169,984 myapp.exe
01/09/2020  12:15 PM               736 myapp.pdb
01/09/2020  11:41 AM               154 myapp.runtimeconfig.json

Si usa Linux o macOS, use el comando ls para obtener una lista de directorios y comprobar que se ha creado el archivo dmyapp.dll.If you're using Linux or macOS, use the ls command to get a directory listing and verify that the myapp.dll file was created.

me@DESKTOP:/docker-working/app$ ls bin/Release/netcoreapp3.1/publish
myapp.deps.json  myapp.dll  myapp.pdb  myapp.runtimeconfig.json

Creación del archivo DockerfileCreate the Dockerfile

El archivo Dockerfile lo usa el comando docker build para crear una imagen de contenedor.The Dockerfile file is used by the docker build command to create a container image. Este archivo es un archivo de texto denominado Dockerfile que no tiene ninguna extensión.This file is a text file named Dockerfile that doesn't have an extension.

En el terminal, suba un directorio a la carpeta de trabajo creada al principio.In your terminal, navigate up a directory to the working folder you created at the start. Cree un archivo denominado Dockerfile en la carpeta de trabajo y ábralo en un editor de texto.Create a file named Dockerfile in your working folder and open it in a text editor. En función del tipo de aplicación que vaya a incluir en un contenedor, elija el runtime de ASP.NET Core o el de .NET Core.Depending on the type of application you're going to containerize, you'll choose either the ASP.NET Core runtime or the .NET Core runtime. En duda, elija el runtime de ASP.NET Core, que incluye el de .NET Core.When in doubt, choose the ASP.NET Core runtime, which includes the .NET Core runtime. En este tutorial se usará la imagen del runtime de ASP.NET Core, pero la aplicación creada en las secciones anteriores es una aplicación de .NET Core.This tutorial will use the ASP.NET Core runtime image, but the application created in the previous sections is an .NET Core application.

  • Runtime de ASP.NET CoreASP.NET Core runtime

    FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
    
  • Tiempo de ejecución de .NET Core.NET Core runtime

    FROM mcr.microsoft.com/dotnet/core/runtime:3.1
    

El comando FROM indica a Docker que extraiga la imagen etiquetada 3.1 del repositorio especificado.The FROM command tells Docker to pull down the image tagged 3.1 from the specified repository. Asegúrese de extraer el runtime que coincida con el que el SDK tiene como destino.Make sure that you pull the runtime version that matches the runtime targeted by your SDK. Por ejemplo, la aplicación creada en la sección anterior usaba el SDK de .NET Core 3.1, y la imagen base a la que se hace referencia en el documento Dockerfile se etiqueta con 3.1.For example, the app created in the previous section used the .NET Core 3.1 SDK and the base image referred to in the Dockerfile is tagged with 3.1.

Guarde el archivo Dockerfile.Save the Dockerfile file. La estructura de directorios de la carpeta de trabajo debería tener el siguiente aspecto.The directory structure of the working folder should look like the following. Algunos de los archivos de carpetas y archivos inferiores se han cortado para ahorrar espacio en este artículo:Some of the deeper-level files and folders have been cut to save space in the article:

docker-working
│   Dockerfile
│
└───app
    │   myapp.csproj
    │   Program.cs
    │
    ├───bin
    │   └───Release
    │       └───netcoreapp3.1
    │           └───publish
    │                   myapp.deps.json
    │                   myapp.exe
    │                   myapp.dll
    │                   myapp.pdb
    │                   myapp.runtimeconfig.json
    │
    └───obj

Desde un terminal, ejecute el comando siguiente:From your terminal, run the following command:

docker build -t myimage -f Dockerfile .

Docker procesará cada línea en el archivo Dockerfile.Docker will process each line in the Dockerfile. . del comando docker build indica a Docker que use la carpeta actual para encontrar un archivo Dockerfile.The . in the docker build command tells Docker to use the current folder to find a Dockerfile. Este comando crea la imagen y un repositorio local denominado myimage que apunta a esa imagen.This command builds the image and creates a local repository named myimage that points to that image. Una vez que finalice este comando, ejecute docker images para ver una lista de las imágenes instaladas:After this command finishes, run docker images to see a list of images installed:

> docker images
REPOSITORY                              TAG                 IMAGE ID            CREATED             SIZE
myimage                                 latest              38db0eb8f648        4 weeks ago         346MB
mcr.microsoft.com/dotnet/core/aspnet    3.1                 38db0eb8f648        4 weeks ago         346MB

Observe que ambas imágenes comparten el mismo valor IMAGE ID.Notice that the two images share the same IMAGE ID value. El valor es el mismo entre ambas imágenes porque el único comando en Dockerfile era basar la imagen nueva en una imagen existente.The value is the same between both images because the only command in the Dockerfile was to base the new image on an existing image. Agreguemos dos comandos a Dockerfile.Let's add two commands to the Dockerfile. Cada comando crear una capa de imagen con el comando final que representa la imagen a la que apuntará el repositorio myimage.Each command creates a new image layer with the final command representing the image the myimage repository entry points to.

COPY app/bin/Release/netcoreapp3.1/publish/ app/

ENTRYPOINT ["dotnet", "app/myapp.dll"]

El comando COPY indica a Docker que copie la carpeta especificada en el equipo a una carpeta del contenedor.The COPY command tells Docker to copy the specified folder on your computer to a folder in the container. En este ejemplo, la carpeta publish se copia a una carpeta denominada app del contenedor.In this example, the publish folder is copied to a folder named app in the container.

El comando siguiente, ENTRYPOINT, indica a Docker que configure el contenedor para que se ejecute como ejecutable.The next command, ENTRYPOINT, tells Docker to configure the container to run as an executable. Cuando el contenedor se inicia, se ejecuta el comando ENTRYPOINT.When the container starts, the ENTRYPOINT command runs. Cuando este comando finaliza, el contenedor se detiene automáticamente.When this command ends, the container will automatically stop.

Desde el terminal, ejecute docker build -t myimage -f Dockerfile . y, cuando el comando finalice, ejecute docker images.From your terminal, run docker build -t myimage -f Dockerfile . and when that command finishes, run docker images.

> docker build -t myimage -f Dockerfile .
Sending build context to Docker daemon  1.624MB
Step 1/3 : FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
 ---> 38db0eb8f648
Step 2/3 : COPY app/bin/Release/netcoreapp3.1/publish/ app/
 ---> 37873673e468
Step 3/3 : ENTRYPOINT ["dotnet", "app/myapp.dll"]
 ---> Running in d8deb7b3aa9e
Removing intermediate container d8deb7b3aa9e
 ---> 0d602ca35c1d
Successfully built 0d602ca35c1d
Successfully tagged myimage:latest

> docker images
REPOSITORY                              TAG                 IMAGE ID            CREATED             SIZE
myimage                                 latest              0d602ca35c1d        4 seconds ago       346MB
mcr.microsoft.com/dotnet/core/aspnet    3.1                 38db0eb8f648        4 weeks ago         346MB

Cada comando de Dockerfile generó una capa y creó un valor IMAGE ID.Each command in the Dockerfile generated a layer and created an IMAGE ID. El valor IMAGE ID final (el suyo será distinto) es ddcc6646461b y, a continuación, usted creará un contenedor basado en esta imagen.The final IMAGE ID (yours will be different) is ddcc6646461b and next you'll create a container based on this image.

Crear un contenedorCreate a container

Ahora que tiene una imagen que contiene la aplicación, puede crear un contenedor.Now that you have an image that contains your app, you can create a container. Hay dos formas de crear un contenedor.You can create a container in two ways. En primer lugar, cree un contenedor que esté detenido.First, create a new container that is stopped.

> docker create myimage
ceda87b219a4e55e9ad5d833ee1a7ea4da21b5ea7ce5a7d08f3051152e784944

El comando docker create anterior creará un contenedor basado en la imagen myimage.The docker create command from above will create a container based on the myimage image. La salida de ese comando muestra el valor CONTAINER ID (el suyo será distinto) del contenedor creado.The output of that command shows you the CONTAINER ID (yours will be different) of the created container. Para ver una lista de todos los contenedores, use el comando docker ps -a:To see a list of all containers, use the docker ps -a command:

> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS        PORTS   NAMES
ceda87b219a4        myimage             "dotnet app/myapp.dll"   4 seconds ago       Created               gallant_lehmann

Administración del contenedorManage the container

Cada contenedor tiene asignado un nombre aleatorio que puede usar para hacer referencia a la instancia de contenedor.Each container is assigned a random name that you can use to refer to that container instance. Por ejemplo, el contenedor que se creó automáticamente eligió el nombre gallant_lehmann (el suyo será distinto) y ese nombre se puede usar para iniciar el contenedor.For example, the container that was created automatically chose the name gallant_lehmann (yours will be different) and that name can be used to start the container. Puede reemplazar el nombre automático por uno específico si usa el parámetro docker create --name.You override the automatic name with a specific one by using the docker create --name parameter.

En el ejemplo siguiente se usa el comando docker start para iniciar el contenedor y luego se usa el comando docker ps para mostrar solo los contenedores que están en ejecución:The following example uses the docker start command to start the container, and then uses the docker ps command to only show containers that are running:

> docker start gallant_lehmann
gallant_lehmann

> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS         PORTS   NAMES
ceda87b219a4        myimage             "dotnet app/myapp.dll"   7 minutes ago       Up 8 seconds           gallant_lehmann

De manera similar, el comando docker stop detendrá el contenedor.Similarly, the docker stop command will stop the container. En el ejemplo siguiente se usa el comando docker stop para detener el contenedor y luego se usa el comando docker ps para mostrar que no hay ningún contenedor en ejecución:The following example uses the docker stop command to stop the container, and then uses the docker ps command to show that no containers are running:

> docker stop gallant_lehmann
gallant_lehmann

> docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS     PORTS   NAMES

Conectarse a un contenedorConnect to a container

Una vez que se ejecuta un contenedor, puede conectarse a él para ver la salida.After a container is running, you can connect to it to see the output. Use los comandos docker start y docker attach para iniciar el contenedor y echar un vistazo al flujo de salida.Use the docker start and docker attach commands to start the container and peek at the output stream. En este ejemplo, el comando Ctrl+C se usa para desasociarse del contenedor en ejecución.In this example, the CTRL + C keystroke is used to detach from the running container. Esta pulsación de teclas podría realmente finalizar el proceso en el contenedor, lo que detendrá el contenedor.This keystroke may actually end the process in the container, which will stop the container. El parámetro --sig-proxy=false garantiza que CTRL + C no detendrá el proceso en el contenedor.The --sig-proxy=false parameter ensures that CTRL + C won't stop the process in the container.

Después de desasociarse del contenedor, reasócielo para comprobar que sigue en ejecución.After you detach from the container, reattach to verify that it's still running and counting.

> docker start gallant_lehmann
gallant_lehmann

> docker attach --sig-proxy=false gallant_lehmann
Counter: 7
Counter: 8
Counter: 9
^C

> docker attach --sig-proxy=false gallant_lehmann
Counter: 17
Counter: 18
Counter: 19
^C

Eliminación de un contenedorDelete a container

Para el propósito de este artículo, no queremos contenedores que solo existan y no hagan nada.For the purposes of this article you don't want containers just hanging around doing nothing. Elimine el contenedor que creó anteriormente.Delete the container you previously created. Si el contenedor está en ejecución, deténgalo.If the container is running, stop it.

> docker stop gallant_lehmann

En el ejemplo siguiente se muestran todos los contenedores.The following example lists all containers. Luego, usa el comando docker rm para eliminar el contenedor y después vuelve a comprobar si hay algún contenedor en ejecución.It then uses the docker rm command to delete the container, and then checks a second time for any running containers.

> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS     PORTS   NAMES
ceda87b219a4        myimage             "dotnet app/myapp.dll"   19 minutes ago      Exited             gallant_lehmann

> docker rm gallant_lehmann
gallant_lehmann

> docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS     PORTS    NAMES

Ejecución únicaSingle run

Docker proporciona el comando docker run para crear y ejecutar el contenedor como comando único.Docker provides the docker run command to create and run the container as a single command. Este comando elimina la necesidad de ejecutar docker create y luego docker start.This command eliminates the need to run docker create and then docker start. También puede establecer este comando en que elimine automáticamente el contenedor cuando este se detenga.You can also set this command to automatically delete the container when the container stops. Por ejemplo, use docker run -it --rm para hacer dos cosas: primero, use automáticamente el terminal actual para conectarse al contenedor y cuando el contenedor finalice, quítelo:For example, use docker run -it --rm to do two things, first, automatically use the current terminal to connect to the container, and then when the container finishes, remove it:

> docker run -it --rm myimage
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
^C

Con docker run -it, el comando CTRL + C detendrá el proceso que está en ejecución en el contenedor, lo que, a su vez, detendrá el contenedor.With docker run -it, the CTRL + C command will stop process that is running in the container, which in turn, stops the container. Como se proporcionó el parámetro --rm, el contenedor se elimina automáticamente cuando se detiene el proceso.Since the --rm parameter was provided, the container is automatically deleted when the process is stopped. Compruebe que no existe:Verify that it doesn't exist:

> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS    PORTS   NAMES

Cambio de ENTRYPOINTChange the ENTRYPOINT

El comando docker run también permite modificar el comando ENTRYPOINT desde el archivo Dockerfile y ejecute algún otro elemento, pero solo para ese contenedor.The docker run command also lets you modify the ENTRYPOINT command from the Dockerfile and run something else, but only for that container. Por ejemplo, use el comando siguiente para ejecutar bash o cmd.exe.For example, use the following command to run bash or cmd.exe. Edite el comando según sea necesario.Edit the command as necessary.

WindowsWindows

En este ejemplo, ENTRYPOINT cambia a cmd.exe.In this example, ENTRYPOINT is changed to cmd.exe. Se presiona CTRL+C para finalizar el proceso y detener el contenedor.CTRL+C is pressed to end the process and stop the container.

> docker run -it --rm --entrypoint "cmd.exe" myimage

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

LinuxLinux

En este ejemplo, ENTRYPOINT cambia a bash.In this example, ENTRYPOINT is changed to bash. Se ejecuta el comando quit, lo que finaliza el proceso y detiene el contenedor.The quit command is run which ends the process and stop the container.

root@user:~# docker run -it --rm --entrypoint "bash" myimage
root@8515e897c893:/# ls app
myapp.deps.json  myapp.dll  myapp.pdb  myapp.runtimeconfig.json
root@8515e897c893:/# exit
exit

Comandos esencialesEssential commands

Docker tiene muchos comandos distintos que abarcan las acciones que quiere hacer con el contenedor y las imágenes.Docker has many different commands that cover what you want to do with your container and images. Estos comandos de Docker son esenciales para la administración de los contenedores:These Docker commands are essential to managing your containers:

Limpiar los recursosClean up resources

Durante este tutorial, creó contenedores e imágenes.During this tutorial, you created containers and images. Elimine estos recursos si quiere hacerlo.If you want, delete these resources. Use los comandos siguientes paraUse the following commands to

  1. Mostrar todos los contenedoresList all containers

    > docker ps -a
    
  2. Detener los contenedores que están en ejecuciónStop containers that are running. CONTAINER_NAME representa el nombre que se asignó automáticamente al contenedor.The CONTAINER_NAME represents the name automatically assigned to the container.

    > docker stop CONTAINER_NAME
    
  3. Eliminar el contenedorDelete the container

    > docker rm CONTAINER_NAME
    

A continuación, elimine las imágenes que ya no quiere tener en la máquina.Next, delete any images that you no longer want on your machine. Elimine la imagen que creó el archivo Dockerfile y luego elimine la imagen de .NET Core en que se basó el archivo Dockerfile.Delete the image created by your Dockerfile and then delete the .NET Core image the Dockerfile was based on. Puede usar el valor IMAGE ID o la cadena con formato REPOSITORY:TAG.You can use the IMAGE ID or the REPOSITORY:TAG formatted string.

docker rmi myimage:latest
docker rmi mcr.microsoft.com/dotnet/core/aspnet:3.1

Use el comando docker images para ver una lista de las imágenes instaladas.Use the docker images command to see a list of images installed.

Nota

Los archivos de imagen pueden ser grandes.Image files can be large. Por lo general, quitaría los contenedores temporales que creó al probar y desarrollar la aplicación.Typically, you would remove temporary containers you created while testing and developing your app. Habitualmente, estas imágenes base se conservan con el runtime instalado si se planea crear otras imágenes basadas en ese runtime.You usually keep the base images with the runtime installed if you plan on building other images based on that runtime.

Pasos siguientesNext steps