添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

你将了解用于 .NET Core 应用的 Docker 容器生成和部署任务。 Docker 平台 使用 Docker 引擎 快速生成应用,并将应用打包为 Docker 映像 。 这些映像采用 Dockerfile 格式编写,以供在分层容器中部署和运行。

Warning

本教程不适用于 ASP.NET Core 应用。 如果使用的是 ASP.NET Core,请参阅教程 了解如何容器化 ASP.NET Core 应用程序

安装以下必备组件:

  • .NET Core 3.1 SDK
    如果已安装 .NET Core,请使用 dotnet --info 命令来确定使用的是哪个 SDK。

  • Docker 社区版

  • Dockerfile 和 .NET Core 示例应用的临时工作文件夹 。 在本教程中,docker-working 用作工作文件夹的名称。

    创建 .Net Core 应用

    需要有可供 Docker 容器运行的 .NET Core 应用。 打开终端、创建工作文件夹(如果尚没有),然后进入该文件夹。 在工作文件夹中,运行下面的命令,在名为“app”的子目录中新建一个项目 :

    dotnet new console -o app -n myapp
    

    文件夹树将如下所示:

    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
    

    dotnet new 命令会新建一个名为“应用”的文件夹,并生成一个“Hello World”应用 。 进入“应用”文件夹并运行命令 dotnet run 。 输出如下:

    > dotnet run
    Hello World!
    

    默认模板创建应用,此应用先打印输出到终端,再退出。 本教程将使用无限循环的应用。 在文本编辑器中,打开“Program.cs” 文件。 它应如以下代码所示:

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

    将此文件替换为以下每秒计数一次的代码:

    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();
    

    保存此文件,并使用 dotnet run 再次测试程序。 请注意,此应用无限期运行。 使用取消命令 CTRL+C 可以停止运行。 输出如下:

    > dotnet run
    Counter: 1
    Counter: 2
    Counter: 3
    Counter: 4
    

    如果你在命令行中向应用传递一个数字,它就只会计数到这个数字,然后退出。 试一试用 dotnet run -- 5 计数到 5。

    -- 之后的参数都不传递到 dotnet run 命令,而是传递到你的应用程序。

    发布 .Net Core 应用

    请先发布 .NET Core 应用,再将它添加到 Docker 映像。 需确保容器在启动时运行应用的发布版本。

    在工作文件夹中,进入包含示例源代码的“应用”文件夹,并运行以下命令 :

    dotnet publish -c Release
    

    此命令将应用编译到“发布”文件夹中 。 从工作文件夹到“发布”文件夹的路径应为 .\app\bin\Release\netcoreapp3.1\publish\

    在“应用” 文件夹中获取“发布”文件夹的目录清单,以验证 myapp.dll 文件是否已创建。

    > 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
    

    如果使用的是 Linux 或 macOS,请使用 ls 命令获取目录列表,并验证是否已创建 myapp 文件。

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

    创建 Dockerfile

    docker build 命令使用 Dockerfile 文件来创建容器映像。 此文件是名为“Dockerfile” 的文本文件,它没有扩展名。

    在终端中,导航到你在启动时创建的工作文件夹的目录。 在工作文件夹中创建名为“Dockerfile”的文件,在文本编辑器中打开它 。 根据要容器化的应用程序类型,选择 ASP.NET Core 运行时或 .NET Core 运行时。 如有疑问,请选择包含 .NET Core 运行时的 ASP.NET Core 运行时。 本教程将使用 ASP.NET Core 运行时映像,但在前面部分中创建的应用是 .NET Core 应用。

  • ASP.NET Core 运行时

    FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
    
  • .NET Core 运行时

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

    FROM 命令指示 Docker 从指定存储库中拉取标记为“3.1” 的映像。 请确保拉取的运行时版本与 SDK 面向的运行时一致。 例如,在上一节中创建的应用使用的是 .NET Core 3.1 SDK,并且 Dockerfile 中引用的基本映像标记有 3.1 。

    保存 Dockerfile 文件 。 工作文件夹的目录结果应如下所示。 为节省本文的空间,删掉了一些更深级别的文件和文件夹:

    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
    

    在终端中运行以下命令:

    docker build -t myimage -f Dockerfile .
    

    Docker 会处理 Dockerfile 中的每一行。 docker build 命令中的 . 指示 Docker 在当前文件夹中查找 Dockerfile 。 此命令生成映像,并创建指向相应映像的本地存储库“myimage” 。 在此命令完成后,运行 docker images 以列出已安装的映像:

    > 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
    

    请注意,两个映像共用相同的“IMAGE ID” 值。 两个映像使用的 ID 值相同是因为,Dockerfile 中的唯一命令是在现有映像的基础之上生成新映像。 接下来,在 Dockerfile 中添加两个命令。 两个命令都新建映像层,最后一个命令表示 myimage 存储库条目指向的映像。

    COPY app/bin/Release/netcoreapp3.1/publish/ app/
    ENTRYPOINT ["dotnet", "app/myapp.dll"]
    

    COPY 命令指示 Docker 将计算机上的指定文件夹复制到容器中的文件夹。 在此示例中,“发布” 文件夹被复制到容器中的“应用” 文件夹。

    下一个命令 ENTRYPOINT 指示 Docker 将容器配置为可执行文件运行。 在容器启动时,ENTRYPOINT 命令运行。 当此命令结束时,容器也会自动停止。

    在终端中,运行 docker build -t myimage -f Dockerfile .;在此命令完成后,运行 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
    

    Dockerfile 中的每个命令生成了一个层,并创建了“IMAGE ID” 。 最终“IMAGE ID” 是“ddcc6646461b” (你的 ID 会有所不同),接下来在此映像的基础之上创建容器。

    至此,已有包含应用的映像,可以创建容器了。 可以通过两种方式来创建容器。 首先,新建已停止的容器。

    > docker create myimage
    ceda87b219a4e55e9ad5d833ee1a7ea4da21b5ea7ce5a7d08f3051152e784944
    

    上面的 docker create 命令在 myimage 映像的基础之上创建容器。 此命令的输出显示已创建容器的“CONTAINER ID” (你的 ID 会有所不同)。 若要查看所有 容器的列表,请使用 docker ps -a 命令:

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

    每个容器都分配有随机名称,可用来引用相应容器实例。 例如,自动创建的容器选择了名称“gallant_lehmann” (你的名称会有所不同),此名称可用于启动容器。 可以使用 docker create --name 参数将自动名称替代为特定名称。

    下面的示例使用 docker start 命令来启动容器,然后使用 docker ps 命令仅显示正在运行的容器:

    > 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
    

    同样,docker stop 命令会停止容器。 下面的示例使用 docker stop 命令来停止容器,然后使用 docker ps 命令来显示未在运行的容器:

    > docker stop gallant_lehmann
    gallant_lehmann
    > docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS     PORTS   NAMES
    

    连接到容器

    在容器运行后,可以连接到它来查看输出。 使用 docker startdocker attach 命令,启动容器并查看输出流。 在此示例中,CTRL + C 击键用于从正在运行的容器中分离出来。 此击键其实是结束容器中的进程,进而停止容器。 --sig-proxy=false 参数可确保 Ctrl + C 不停止容器中的进程。

    从容器中分离出来后重新连接,以验证它是否仍在运行和计数。

    > docker start gallant_lehmann
    gallant_lehmann
    > docker attach --sig-proxy=false gallant_lehmann
    Counter: 7
    Counter: 8
    Counter: 9
    > docker attach --sig-proxy=false gallant_lehmann
    Counter: 17
    Counter: 18
    Counter: 19
    

    就本文而言,你不希望存在不执行任何操作的容器。 删除前面创建的容器。 如果容器正在运行,停止容器。

    > docker stop gallant_lehmann
    

    下面的示例列出了所有容器。 然后,它使用 docker rm 命令来删除容器,并再次检查是否有任何正在运行的容器。

    > 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
    

    Docker 提供了 docker run 命令,用于将容器作为单一命令进行创建和运行。 使用此命令,无需依次运行 docker createdocker start。 另外,还可以将此命令设置为,在容器停止时自动删除容器。 例如,使用 docker run -it --rm 可以执行两项操作,先自动使用当前终端连接到容器,再在容器完成时删除容器:

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

    使用 docker run -itCTRL + C 命令会停止在容器中运行的进程,进而停止容器。 由于提供了 --rm 参数,因此在进程停止时自动删除容器。 验证它是否不存在:

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

    更改 ENTRYPOINT

    使用 docker run 命令,还可以修改 Dockerfile 中的 ENTRYPOINT 命令,并运行其他内容,但只能针对相应容器。 例如,使用以下命令来运行 bashcmd.exe。 根据需要,编辑此命令。

    Windows

    在本例中,ENTRYPOINT 更改为 cmd.exe。 通过按下 CTRL+C 来结束进程并停止容器。

    > 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
    

    Linux

    在本例中,ENTRYPOINT 更改为 bash。 通过运行 quit 命令来结束进程并停止容器。

    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
    

    Docker 有许多不同的命令,可用于执行你要对容器和映像执行的操作。 下面这些 Docker 命令对于管理容器来说至关重要:

  • docker build
  • docker run
  • docker ps
  • docker stop
  • docker rm
  • docker rmi
  • docker image
  • 在本教程中,你创建了容器和映像。 如果需要,请删除这些资源。 以下命令可用于

  • 列出所有容器

    > docker ps -a
    
  • 停止正在运行的容器。 CONTAINER_NAME 表示自动分配给容器的名称。

    > docker stop CONTAINER_NAME
    
    > docker rm CONTAINER_NAME
    

    接下来,删除计算机上不再需要的任何映像。 依次删除 Dockerfile 创建的映像,以及 Dockerfile 所依据的 .NET Core 映像。 可以使用 IMAGE ID 或 REPOSITORY:TAG 格式字符串。

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

    使用 docker images 命令来列出已安装的映像。

    映像文件可能很大。 通常情况下,需要删除在测试和开发应用期间创建的临时容器。 如果计划在相应运行时的基础之上生成其他映像,通常会将基础映像与运行时一同安装。

  • 了解如何容器化 ASP.NET Core 应用程序。
  • 试学“ASP.NET Core 微服务”教程。
  • 查看支持容器的 Azure 服务。
  • 了解 Dockerfile 命令。
  • 了解用于 Visual Studio 的容器工具
  •