原文:https://blogs.msdn.microsoft.com/dotnet/2018/06/13/using-net-and-docker-together-dockercon-2018-update/
去年我写了一篇关于 共同使用 .NET 和 Docker 的文章。随着本周 DockerCon 2018 的开始,似乎是一个更新的好时机。从上一篇文章以来,我们启用了一系列的 .NET Core 和 .NET Framework 向导和示例的 Docker 工作流,用于开发,CI/CD 和 生产。我们也提供了更多的 Windows 和 Linux 的镜像。如果你最近没有关注 Docker 和 .NET,现在是一个好时机。
在和 .NET 开发者对话中 Docker 和容器越来越多的被提到。它已经成为许多人部署服务端应用程序的方式。由于一致性和轻量级的主要优点代替了虚拟机。在 DockerCon 的主题中,有多个 .NET 演示了如何应用 Docker 到现代应用和传统架构的旧应用中。它使得通过微软和 Docker 的工具封装 .NET 应用更容易。
关于 .NET 容器镜像的信息请看与.NET容器映像保持同步.
尝试 Docker
我们维护了 .NET Core 和 .NET Framework 的示例仓库。只需命令行中的几个命令,就可以用这些示例镜像测试 Docker。
最简单的(支持大多数操作系统)是 .NET Core 控制台应用示例。你只需要输入以下命令:
docker run --rm microsoft/dotnet-samples
你也可尝试其他的示例,都是控制台和 ASP.NET 应用:
如何使用 Docker
Docker 是灵活的,使你能够以多种不同的方式使用它。当采用 Docker 时主要有三种主要的方案需要考虑:
- 构建源代码
- 测试二进制文件
- 在生产环境运行应用程序/服务
你可以采用 Docker 来处理所有这些角色或者一个子集。从我们所看到的,大多数开发者从生产场景开始,然后在他们发现有用的基础架构采用更多的 Docker。这种处理是有意义的,选择使用 Docker 通常用它来运行应用程序为中心。
在 .NET 团队,我们在构建和测试代码时已经大量的使用 Docker。高保真和即时启动计算环境的价值非常高,例如,当你可以可以在几秒钟内启动完全正确的环境时,无需在 Debian 上推迟产品调查。
以下部分显示了针对这三种方案的 .NET Core 和 .NET Framework 混合的示例。
使用二进制文件构建容器镜像
在生产环境中运行 Docker 的主要需求是容器化应用程序。在现有的构建基础结构中创建镜像最简单的方式是复制构建文件到镜像里。这个模型的主要价值是环境之间的一致性,比如 staging 环境和生产环境。
以下 Dockerfile 将当前目录中的构建资产复制到基于 Docker Hub 上的 .NET Core 运行时镜像的新镜像。
FROM microsoft/dotnet:2.1-runtime WORKDIR /app COPY . . ENTRYPOINT ["dotnet","app.dll"]
以下命令通过上边的 Dockerfile 创建了一个 app 的镜像,假设命令在 Dockerfile 和 app.dll 所在的目录运行:
docker build --pull -t app .
以下命令基于 app 镜像创建了一个运行的容器:
docker run --rm app
注意:--rm 参数在容器结束后移除该容器。保持容器只有在你想调查为什么他们表现某一(不希望的)方式时。
使用源文件构建容器镜像
Docker 使为应用程序构建源文件并在一个步骤中生成容器镜像变得容易。这也被称为多级构建。在容器内构建源文件的价值如下:
- 在构建和运行/生产环境之间的一致性。
- 由于 Docker 层缓存,对于增量构建的速度比你自己的构建系统更快。
- Docker 不依赖于外部功能构建(如果你在 Docker 内构从源文件构建)。
下边的 Dockerfile 基于 Docker Hub 上的 .NET Framework SDK 镜像从当前目录复制源文件到新的镜像。Dockerfile 命令使用 NuGet 和 MSBuild 来构建源代码。将基于 .NET Framework 运行时镜像的二进制文件在构建阶段复制到一个新镜像。构建阶段镜像被丢弃。所选的镜像名称仅用于从最后阶段生成的镜像。
上边的第二部分是 Docker 闪光的地方。Docker 中的每一个命令创建 Docker 镜像中的不同的层。如果 Docker 发现给定层的输入没有改变,那么后续 Docker 的构建不会重新构建该层。第二部分复制了 msbuild 资产,比如项目文件,然后运行 nuget 恢复。如果 msbuild 资产没有改变,则跳过执行恢复。这样最终节省了大量时间。它也解释了为什么 Dockerfile 编写的方式。
接下来的命令使用上边的 Dockerfile 创建了一个 aspnetapp 的新镜像,假设该命令是从 Dockerfile 和 源文件所在的目录运行的:
docker build --pull -t aspnetapp .
例如,如果 Docker Hub 上存在 --pull 参数会拉取新的 microsoft/dotnet-framework 镜像,这个参数会花费更长的时间(如果没有新的镜像存在)在每次 docker 构建,但要保持最新环境。从长远来看,最新的方法是非常有用的,因为它使你的环境于没有缓存镜像的环境保持同步。
下边的命令创建了一个基于 aspnetapp 镜像的容器:
docker run --rm -it -p 8000:80 aspnetapp
-p 参数把主机端口映射到 Docker 客户端端口。
更多用 Docker 构建源代码的信息请参考下面的示例:
用 Docker 测试二进制文件
测试场景展示了 Docker 的价值,因为当测试环境和目标环境保持高度一致时测试具有更多价值。假设你的应用支持多个操作系统或操作系统版本。你可以在他们每一个的 Docker 中测试你的应用。它很容易做到并且非常有价值。
到目前为止,在本篇文章中你看到有运行命令的 Dockerfile ,它描述了需要用 Docker 构建执行的逻辑以及用 Docker 运行的最终结果。通过 Docker 构建运行测试作为早期反馈是有用的,主要是通过打印到控制台/终端的通过/失败结果。这种模型可以很好的用于测试,但是有两个原因规模不大:
- 如果测试存在固有的错误有错误,则 docker 构建会失败。
- docker 构建不允许 volume 安装,这是手机测试日志所必须的。
使用 docker 运行测试时一个很好的选择,因为它不受这两个挑战的任何一个的影响。使用 docker 构建测试很有用,假如测试失败你也想让你的构建失败。本文档中的说明展示了如何使用 docker 运行测试。
下面的 Dockerfile 在正常使用中与上面看到的 .NET Framework 类似。然后,这其中包含了一些技巧来实现测试。包括一个通常非常接近 no-op testrunner 阶段,但这对测试非常有用。
为了测试,创建一个 testrunner 阶段镜像,这将包括所有内容构建成一点。结果镜像是基于 .NET Core SDK 镜像的,包括所有 .NET Core 测试基础设施。这个 Dockerfile 的诀窍在于 testrunner 阶段提供了一个替代的 ENTRYPOINT,调用 dotnet 测试来启动测试。如果你一直通过运行 Dockerfile (不针对特定的阶段),那么第一个 ENTRYPOINT 会被最后一个替换,这是应用程序的 ENTRYPOINT。
下面的命令创建一个 dotnetapp:test 的新镜像,使用上面的 Dockerfile 只限构建和包括 testrunner 阶段,假设命令是从 Dockerfile 和 源文件目录运行的:
docker build --pull --target testrunner -t dotnetapp:test .
为了在本地机器上手机测试日志,需要使用 volume 安装。简而言之,你可以将你机器上的目录作为统一目录导入容器中。 Volume 安装是一种获取容器内或从容器输出很好的方法。
下面的命令基于 dotnetapp:test 创建了一个容器。volume 将 C:appTestResults 本地目录安装到应用中的 /app/tests/TestResults。本地目录必须已经存在,并且 C 盘必须共享给 Docker。
docker run --rm -v C:appTestResults:/app/tests/TestResults dotnetapp:test
运行命令后,你应该在 C:appTestResults 文件中看到 .trx 文件。
用 Docker 运行 .NET Core 单元测试 显示了如何在容器中进行更详细的测试。包括 Windows,macOS 和 Linux。还包括本节中描述的管理测试工作流的脚本。
在容器中开发
以上场景关注于生成或验证容器镜像。Docker 的使用可以进一步向上游发展。
Visual Studio 允许在容器中进行开发。你可以添加 Dockerfile 到一个 .NET 项目中,Windows 容器或者 Linux 容器。经验几乎是无缝的。很难说你在使用 Docker,就像你在下面的图片中看到的一样。
你还可以在命令行的容器内开发。.NET Core SDK 镜像包含了很多功能,你可以创建一个 Dockerfile 来毫不费力的使用它。事实上,你可以通过命令行运行,构建或者测试你的应用程序。
在容器中开发 ASP.NET Core 应用程序说明了如何通过 Docker 构建和重新构建 ASP.NET Core 应用程序,例如你可以在本地机器上在本地机器上从 Visual Studio Code 中编辑他们。
下面的命令行通过 dotnet 宿主一个 ASP.NET Core 应用程序守候在 macOS 或者 Linux 上。在容器中开发 ASP.NET Core 应用程序中Windows 说明是可用的。每次在本地机器上编辑和保存应用程序时,它将在容器中重新构建。我从来没有试过连续1000次这样做,但是你很可能做到。此方案依赖于 volume 安装,将本地化的源代码投影到正在运行的容器中。正如你所见,通过编写 Dockerfile 来实现 volume 安装是一个强有力的选择。
docker run --rm -it -p 8000:80 -v ~/git/aspnetapp:/app/ -w /app/aspnetapp microsoft/dotnet:2.1-sdk dotnet watch run
有关 .NET Core 控制台应用程序的类似指令请参见在容器中开发 .NET Core 应用程序。
ASP.NET Core 和 HTTPS
用 HTTPS 来托管 Web 应用程序时很中亚哦的。在许多情况下,在到达 ASP.NET Core 站点前会种终止 HTTPS 请求。在 ASP.NET Core 需要直接处理 HTTPS 流量的情况并且在容器中运行你的站点时,则需要一个解决方案。
通过 HTTPS 在 Docker 中托管 ASP.NET Core 镜像描述了如何用 HTTPS 来托管我们的 ASP.NET Core 样品镜像。所描述的模型非常类似于如何用你自己的证书来托管自己的镜像。
以下命令可用于在 Windows 上使用 Linux 容器运行 dev 证书的 ASP.NET Core 示例镜像:
dotnet dev-certs https -ep %USERPROFILE%.aspnethttpsaspnetapp.pfx -p crypticpassword
dotnet dev-certs https --trust
docker pull microsoft/dotnet-samples:aspnetapp
docker run --rm -it -p 8000:80 -p 8001:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=8001 -e ASPNETCORE_Kestrel__Certificates__Default__Password="crypticpassword" -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx -v %USERPROFILE%.aspnethttps:/https/ microsoft/dotnet-samples:aspnetapp
在 Docker 中通过 HTTPS 指令托管 ASP.NET Core 镜像可以用在 Windows,macOS 和 Linux 上。
结尾
你可能会发现我们在一起使用 .NET 和 Docker 的方法上比我们在最初2017的主题文章中走的更远。我们远没有完成所有可以想象的容器控件,但已经为你提供了一个更完整的基础作为你采用 Docker 的使用。