做网站只买一个程序,wordpress文章自动发布功能,asp 网站开发教程,废旧网站那个做的最好解决方案内部项目之间引用很正常#xff0c;但我docker不是很熟#xff0c;对一些基础命令含义还理解不深入#xff0c;部署引用其他项目的项目总不成功。搜到了一篇非常适合初学者#xff0c;从dockerfile命令讲解#xff0c;到解决引用其他项目时如何docker部署的文章。… 解决方案内部项目之间引用很正常但我docker不是很熟对一些基础命令含义还理解不深入部署引用其他项目的项目总不成功。搜到了一篇非常适合初学者从dockerfile命令讲解到解决引用其他项目时如何docker部署的文章。原论文链接以下为翻译。 当你了解Docker命令的基础知识时从有项目引用的dotnet解决方案创建Docker镜像很容易但是对于初学者来说编写适当的Dockerfile可能会很棘手。 大多数示例展示了如何容器化.net项目假设它没有本地依赖项。那么让我们分析一下当我们的项目引用了解决方案中的其他项目时我们能做些什么。我们将首先深入研究一个没有依赖项的简单示例以了解我们引入了哪些更改以及为什么要进行更改。 如果你只是想跳到解决方案并复制粘贴它当然你可以这样做但不建议这样做因为迟早你会因为不理解发生了什么而被另一个障碍所阻碍结果你会浪费更多的时间。本文非常适合开始学习Docker指令和命令因为所有内容都用简明易懂的语言进行了解释。我们将使用.net core 2.2因为它在撰写本文时是当前版本。 示例容器化dotnet core应用程序是可用的在GitHub上请随意使用它来满足您的需求。
官方Docker示例分析 官方.net Core应用容器化的文章向我们展示了Dockerfile位于project文件夹(.csproj文件存储的地方):
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 --frombuild-env /app/out .
ENTRYPOINT [dotnet, PROJECT_NAME.dll]
这两个命令要从Dockerfile所在的项目文件夹中运行:(编者注,docker build是用于使用 Dockerfile 创建镜像docker run是创建一个新的容器并运行一个命令
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 --frombuild-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因为官方示例假设我们用项目目录作为构建上下文。我的版本是这样的:
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /appCOPY . ./
RUN dotnet publish PROJECT_NAME -c Release -o outFROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
COPY --frombuild-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——frombuild-env /app/PROJECT_NAME/out。 在哪里保存.dockerignore文件 官方文章说将.dockerignore文件添加到项目目录以使构建上下文尽可能小降低缓存无效的风险这当然是合理的。但是Docker CLI在构建上下文的根目录中查找.dockerignore文件所以现在我们需要将其移动到解决方案目录。但在我看来这样更好因为我们不需要为许多项目创建和维护许多.dockerignore文件我们为所有项目保留一个。示例规则:
*/bin
*/obj
.dockerignore
.env
.git
.gitignore
.vs
.vscode
**/.toolstarget
.idea
总结 当我第一次需要dockerize.net core应用程序时我只是从上述文章中获取Dockerfile复制粘贴Docker命令当我遇到障碍时我试图在不分析Docker如何工作的情况下解决它。在以这种方式浪费了一些时间之后我又浪费了时间——试图从网上复制粘贴解决方案——同样没有分析我做了什么也没有成功。然后我又一次明白了(在我的生命中……)匆匆忙忙并不会节省时间反而会适得其反——浪费时间。因为我没有找到合适的文章或教程所以我从官方文档和手册开始这些文档和手册写得很好但对于初学者来说有太多的细节。本文展示了分析的要点并用通俗易懂的语言解释了基础知识。我希望这样可以很好地开始编写适当的Dockerfile而不会遇到像这里所呈现的情况那样的麻烦- dotnet项目从解决方案中引用其他项目也不会遇到任何其他障碍。