多项目的.net core解决方案(项目间引用)如何使用Docker部署

解决方案内部项目之间引用很正常,但我docker不是很熟,对一些基础命令含义还理解不深入,部署引用其他项目的项目总不成功。搜到了一篇非常适合初学者,从dockerfile命令讲解,到解决引用其他项目时如何docker部署的文章。原论文链接,以下为翻译。

当你了解Docker命令的基础知识时,从有项目引用的dotnet解决方案创建Docker镜像很容易,但是对于初学者来说,编写适当的Dockerfile可能会很棘手。

大多数示例展示了如何容器化.net项目,假设它没有本地依赖项。那么,让我们分析一下,当我们的项目引用了解决方案中的其他项目时,我们能做些什么。我们将首先深入研究一个没有依赖项的简单示例,以了解我们引入了哪些更改以及为什么要进行更改。

如果你只是想跳到解决方案并复制粘贴它,当然你可以这样做,但不建议这样做,因为迟早你会因为不理解发生了什么而被另一个障碍所阻碍,结果你会浪费更多的时间。本文非常适合开始学习Docker指令和命令,因为所有内容都用简明易懂的语言进行了解释。我们将使用.net core 2.2,因为它在撰写本文时是当前版本。

示例容器化dotnet core应用程序是可用的,在GitHub上,请随意使用它来满足您的需求。

官方Docker示例分析

官方.net Core应用容器化的文章向我们展示了Dockerfile位于project文件夹(.csproj文件存储的地方):

bash 复制代码
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "PROJECT_NAME.dll"]

这两个命令,要从Dockerfile所在的项目文件夹中运行:(编者注,docker build是用于使用 Dockerfile 创建镜像,docker run是创建一个新的容器并运行一个命令)

bash 复制代码
docker build -t aspnetapp .
docker run -d -p 8080:80 --name myapp aspnetapp

Dockerfile FROM指令

我们的Dockerfile以FROM指令开始:

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env

这意味着我们的镜像基于官方Microsoft Dotnet Core SDK 2.2版本。我们现在使用SDK,而不是production runtime,因为我们将在构建镜像期间在Docker中编译我们的应用程序。所以你甚至不需要在你的主机上安装.net core SDK,这个Dockerfile是用一种你无需自己为Docker镜像编译应用程序的方式准备的------Docker会编译它。您可以使用在您的主机上构建的二进制文件,但这并不安全------由于兼容性问题,它可能无法工作。为什么有AS build-env 指令-我们将在后面(在Docker多阶段构建部分)讨论。

Dockerfile WORKDIR 指令

在第二行,我们看到WORKDIR /app指令,这意味着,在我们的Dockerfile下面的RUN, CMD, ENTRYPOINT, COPY和ADD指令将在/app目录执行。如果它不存在,它将被创建(即使它不会被使用)。

Dockerfile COPY 指令

接下来我们看到COPY *.csproj ./指令,这意味着Docker构建上下文中的所有csproj文件将被复制到Docker镜像中的workdir (/app)目录下。Docker构建命令将在后面解释,但简而言之,构建上下文是来自主机的目录,指向Docker构建命令。.路径指向执行命令的目录。因此,在我们的示例中,我们只复制一个csproj文件,因为我们运行构建命令时将项目目录设置为构建上下文。

Dockerfile RUN 指令

接下来是RUN dotnet restore指令,它只是在我们的工作目录(/app)中运行dotnet restore命令。此时,在我们的镜像的/app目录中,除了我们项目的.csproj之外什么都没有,因为我们在前面的步骤中只复制了它,但它足以还原nuget依赖。

Copy和compile应用程序源代码

我们再次看到COPY指令------COPY . ./从我们的构建上下文复制所有内容------在我们的例子中,它指的是项目文件(.cs文件等),因为我们运行docker build命令时将项目目录设置为构建上下文。然后使用run指令- run dotnet publish -c Release -o out,我们只需在镜像内部的workdir (/app)目录中运行dotnet publish,并使用-c Release -o out参数。这个dotnet命令用发布配置编译我们的应用,并在out目录下发布结果(在我们的例子中是/app/out)。我们可以编译源代码,因为我们将镜像像基于开发人员的sdk。

Docker多阶段构建

我们再一次看到FROM指令,它设置了我们的镜像基于哪个镜像...怎么可能再次指定它,使用不同的基?这是一个非常新的Docker特性(从Docker 17.05版本开始),称为多阶段构建。当我们再次使用FROM关键字时,我们的意思是上面指定的先前镜像是临时的,并且仅用于某些目的。在我们的示例中,它仅用于编译我们的应用程序---这就是为什么我们使用SDK作为基础映像。现在我们再次指定基本镜像,这次我们准备的是实际镜像------即将部署到生产环境中的镜像,这个镜像不基于SDK,只基于生产运行时,因此会产生较小的大小。我们将从临时镜像复制我们编译的应用程序。所以我们再次指定工作目录到/app目录,然后复制我们的二进制文件------copy --from=build-env /app/out。这意味着从build-env镜像(这就是为什么我们在第一行给它一个名字)的/app/out/目录复制文件到当前工作目录(/app)。

Dockerfile ENTRYPOINT 指令

这个Dockerfile中的最后一个指令是ENTRYPOINT,它(简单地说)指定了一个在容器启动时将执行的命令。所以在我们的例子中- ENTRYPOINT ["dotnet", "PROJECT_NAME.dll"] - Docker将运行带有PROJECT_NAME.dll参数(当然应该替换为我们的项目名)的dotnet,以启动我们的应用程序。

Docker build命令

有了这样的Dockerfile,我们被告知在项目目录(存放Dockerfile的地方)运行docker build -t aspnetapp .命令。选项:-t name(------tag name)不是强制性的------它允许标记镜像(给它命名,并有选择性地以' name:tag '格式给它一个标记),所以不要关注它,并以这种方式查看这个命令:docker build .,因为重要的事情是在之后的选项-构建上下文参数。构建上下文是主机上,Dockerfile指令构建镜像时可以访问的路径。在我们的例子中是 . 路径,这意味着我们运行该命令的目录将作为构建上下文传递。因为我们被告知要在项目目录(.csproj文件存储的地方)中运行这个命令,所以我们的项目文件被作为构建上下文传递。

Docker run命令

Docker run命令从镜像创建容器。镜像是Docker的只读手册,用于创建容器,容器是我们应用程序所在的虚拟机。我们可以这样想:镜像就像面向对象编程中的一个类,容器就像从这个类创建的实例。因此,我们可以创建任意数量的容器(实例),而不会影响镜像(类)------镜像只是让Docker知道如何创建容器。我们被告知这样运行:

docker run -d -p 8080:80 --name myapp aspnetapp

如果没有------detach选项(-d),我们将开始看到来自容器的应用控制台输出。使用------publish (-p)选项,我们将容器的端口绑定到主机(默认使用TCP,但您也可以指定UDP和SCTP)。使用------name选项,我们为容器指定一个名字(没有这个选项,Docker会为我们选择一些有趣的名字)。最后,我们传递镜像名称,Docker将读取它来创建容器。因为我们将图像命名为aspnetapp,所以这里使用这个名称。

解决方案

合适的Docker命令

问题当然是,我们运行Docker构建命令从项目目录传递.路径作为构建上下文。这意味着,在构建映像期间,只能访问这个目录中的文件,而依赖于项目的文件当然在其他目录中。我们有几个选项来解决这个问题。我们可以将Dockerfile向上移动一级(到解决方案目录),并从那里运行docker build。但建议在项目目录中存Dockerfile,以便能够在解决方案中有多个Dockerfile(针对不同的项目)。您也可以像以前一样运行docker build(从项目目录),但将构建上下文路径更改为上一级(..)。在我看来,更优雅的是第三种解决方案-从解决方案目录运行docker构建,通过.作为构建上下文,并使用------file (-f)选项指定我们要读取哪个Dockerfile,如下所示:

docker build -f PROJECT_DIRECTORY/Dockerfile -t IMAGE_NAME .

如何调整Dockerfile

接下来我们需要调整Dockerfile,因为官方示例假设我们用项目目录作为构建上下文。我的版本是这样的:

bash 复制代码
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /app

COPY . ./
RUN dotnet publish PROJECT_NAME -c Release -o out

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
COPY --from=build-env /app/PROJECT_NAME/out .

ENTRYPOINT ["dotnet", "PROJECT_NAME.dll"]

我跳过了恢复nuget包作为单一步骤来简化,恢复包含在dotnet发布中,如果由于nuget失败而失败,错误信息是清晰的。但是如果你有很多nuget依赖,你可能想要有单独的步骤,因为这样Docker将其视为不同的层,并在没有任何csproj文件更改的情况下重用它,这样可以缩短构建时间(我在另一篇文章中描述过)。在这个演示中,恢复nugets的速度足够快,可以跳过它,但如果您有很长的构建时间(特别是-在...时间内完成恢复),请记住这一点。

所以我们将所有项目(因为构建上下文现在是解决方案目录)复制到容器内的/app目录。接下来,我们在/app workdir中运行dotnet publish命令,指定要编译的项目- run dotnet publish PROJECT_NAME -c Release -o out -这里的PROJECT_NAME是目录名,里面有.csproj文件。

其他指令保持不变,只有一个小小的改变------在从临时镜像复制编译后的应用程序时,这次我们需要将项目名称传递给path:

COPY------from=build-env /app/PROJECT_NAME/out。

在哪里保存.dockerignore文件

官方文章说,将.dockerignore文件添加到项目目录,以使构建上下文尽可能小,降低缓存无效的风险,这当然是合理的。但是Docker CLI在构建上下文的根目录中查找.dockerignore文件,所以现在我们需要将其移动到解决方案目录。但在我看来,这样更好,因为我们不需要为许多项目创建和维护许多.dockerignore文件,我们为所有项目保留一个。示例规则:

bash 复制代码
*/bin
*/obj
.dockerignore
.env
.git
.gitignore
.vs
.vscode
**/.toolstarget
.idea

总结

当我第一次需要dockerize.net core应用程序时,我只是从上述文章中获取Dockerfile,复制粘贴Docker命令,当我遇到障碍时,我试图在不分析Docker如何工作的情况下解决它。在以这种方式浪费了一些时间之后,我又浪费了时间------试图从网上复制粘贴解决方案------同样没有分析我做了什么,也没有成功。然后我又一次明白了(在我的生命中......),匆匆忙忙并不会节省时间,反而会适得其反------浪费时间。因为我没有找到合适的文章或教程,所以我从官方文档和手册开始,这些文档和手册写得很好,但对于初学者来说有太多的细节。本文展示了分析的要点,并用通俗易懂的语言解释了基础知识。我希望这样可以很好地开始编写适当的Dockerfile,而不会遇到像这里所呈现的情况那样的麻烦- dotnet项目从解决方案中引用其他项目,也不会遇到任何其他障碍。

相关推荐
❀͜͡傀儡师11 小时前
docker部署Arcane容器可视化管理平台
运维·docker·容器
老姚---老姚11 小时前
docker常用命令
运维·docker·容器
❀͜͡傀儡师16 小时前
docker一键部署HFish蜜罐
运维·docker·容器
DO_Community16 小时前
DigitalOcean容器注册表推出多注册表支持功能
服务器·数据库·docker·kubernetes
dnpao16 小时前
linux onlyoffice服务向docker容器中添加中文字体
linux·运维·docker
java_logo18 小时前
Dify 开源 LLM 应用开发平台企业级 Docker Compose 部署手册
docker·容器·开源·dify部署·dify部署文档·dify部署方案·dify部署教程
jarreyer19 小时前
【docker的gpu加速相关问题解决记录】
运维·docker·容器
韭菜钟19 小时前
制作自定义Docker镜像并部署使用
运维·docker·容器
椰汁菠萝19 小时前
docker部署gitlab
docker·容器·gitlab
知识分享小能手19 小时前
Ubuntu入门学习教程,从入门到精通,Ubuntu 22.04 中安装 Docker 容器 —— 知识点详解(26)
学习·ubuntu·docker