当前位置: 首页 > news >正文

多项目的.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文件存储的地方):

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是创建一个新的容器并运行一个命令)

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,因为官方示例假设我们用项目目录作为构建上下文。我的版本是这样的:

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 --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文件,我们为所有项目保留一个。示例规则:

*/bin
*/obj
.dockerignore
.env
.git
.gitignore
.vs
.vscode
**/.toolstarget
.idea

总结

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

相关文章:

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

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

使用raise语句抛出异常

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 如果某个函数或方法可能会产生异常,但不想在当前函数或方法中处理这个异常,则可以使用raise语句在函数或方法中抛出异常。rai…...

vue组件中data为什么必须是一个函数?

在 Vue 中,组件的 data 必须是一个函数,而不是一个对象,这是为了保证每个组件实例都可以维护一份被返回对象的独立的拷贝。如果 data 是一个对象,那么所有的组件实例将共享同一个引用,导致一个组件实例的数据变化会影响…...

10-Django项目--Ajax请求

目录 Ajax请求 简单示范 html 数据添加 py文件 html文件 demo_list.html Ajax_data.py 图例 Ajax请求 简单示范 html <input type"button" id"button-one" class"btn btn-success" value"点我"> ​ ​ <script>/…...

二进制安装Prometheus

从 https://prometheus.io/download/ 下载相应版本&#xff0c;安装到服务器上官网提供的是二进制版&#xff0c;解压就 能用&#xff0c;不需要编译 1、下载软件 [rootlocalhost ~]# wget -c https://github.com/prometheus/prometheus/releases/download/v2.45.5/prometheus…...

Git配置SSH-Key

git config --global user.name 沈健 git config --global user.email sjshenjianoutlook.com初次使用 SSH 协议进行代码克隆、推送等操作时&#xff0c;需按下述提示完成 SSH 配置 1 生成 RSA 密钥 ssh-keygen -t rsa2. 获取 RSA 公钥内容&#xff0c;并配置到 SSH公钥 中 …...

处理多语言文案的工具

处理多语言文案的工具 离线的处理多语言文案的工具 用于开发软件过程中&#xff0c;加速多语言文案的导出&#xff0c;导入&#xff0c;校对&#xff0c;复用已经翻译的多语言文案 SDL Trados Studio&#xff1a;一款专业的离线多语言翻译管理工具&#xff0c;支持导入、导出…...

手把手教你MMDetection实战

论文下载地址:点击这里 本页提供有关MMDetection用法的基本教程。有关安装说明,请参阅INSTALL.md。 目录 预训练模型的推论训练模型有用的工具如何预训练模型的推论 我们提供测试脚本以评估整个数据集(COCO,PASCAL VOC等),还提供一些高级api,以便更轻松地集成到其他项…...

C++的爬山算法

爬山算法&#xff08;Hill Climbing Algorithm&#xff09;是一种局部搜索算法&#xff0c;它通过迭代搜索的方式寻找问题的局部最优解。在爬山过程中&#xff0c;算法总是选择当前状态邻域中最好&#xff08;即函数值最大或最小&#xff09;的状态作为下一个状态&#xff0c;直…...

Lumière:开创性的视频生成模型及其应用

视频内容创造领域迎来了突破性进展&#xff0c;但视频生成模型由于运动引入的复杂性而面临更多挑战。这些挑战主要源自运动的引入所带来的复杂性。时间连贯性是视频生成中的关键要素&#xff0c;模型必须确保视频中的运动在时间上是连贯和平滑的&#xff0c;避免出现不自然的跳…...

MySQL:MySQL的EXPLAIN各字段含义详解

在MySQL中&#xff0c;EXPLAIN是一个强大的工具&#xff0c;用于获取关于SELECT语句执行计划的信息。当你对查询性能有疑问时&#xff0c;使用EXPLAIN可以帮助你理解MySQL如何执行你的查询&#xff0c;并可能揭示性能瓶颈。 以下是EXPLAIN输出中各个列的详细解释&#xff1a; …...

域内路由选择协议——RIP

例题 RIP&#xff08;Routing Information Protocol&#xff09;是一种基于距离向量的路由协议&#xff0c;使用跳数作为度量标准来决定最优路径。下面我们详细分析为什么RIP协议要这样设计。 RIP协议的基本工作原理 距离向量算法&#xff1a; 每个路由器维护一张路由表&…...

JVM学习-MAT

MAT(Memory Analyzer Tool) 基本概述 Java堆内存分析器&#xff0c;可以用于查找内存泄漏以及查看内存消耗情况MAT是基于Eclipse开发的&#xff0c;不仅可以单独使用&#xff0c;还能以插件方式嵌入Eclipse中使用&#xff0c;是一款免费的性能分析工具 获取堆dump文件 dump…...

高通Android 12/13实现USB拔出关机功能

思路流程 1、监听广播->接受USB断开或者USB不充电广播->执行关机逻辑 涉及类 UsbManager/UsbDeviceManager \frameworks\base\services\usb\java\com\android\server\usb\UsbDeviceManager.java \frameworks\base\services\com\android\hardware\usb\UsbManager.java 2…...

用Python打造你的微博热搜追踪器

简介 在当今信息爆炸的时代&#xff0c;获取最新、最热门的信息成为了许多人的日常需求。微博热搜榜作为反映社会热点和公众关注焦点的重要窗口&#xff0c;其信息价值不言而喻。本文将介绍一个实用的Python爬虫程序&#xff0c;它能够自动爬取微博热搜榜的信息&#xff0c;并…...

TypeScript 在前端开发中的应用

TypeScript 在前端开发中的应用非常广泛。以下是一些常见的应用场景&#xff1a; 类型检查&#xff1a;TypeScript 是 JavaScript 的超集&#xff0c;它引入了静态类型检查。在开发过程中&#xff0c;TypeScript 编译器可以帮助开发者捕捉潜在的类型错误&#xff0c;提前发现并…...

【ArcGIS微课1000例】0115:字段数据类型案例详解

文章目录 一、ArcGIS数据类型概述二、案例1. 数字2. 文本3. 日期4. BLOB5. 对象标识符6. 全局标识符一、ArcGIS数据类型概述 创建要素类和表时,需要为各字段选择数据类型。可用的类型包括多种数字类型、文本类型、日期类型、二进制大对象 (BLOB) 或全局唯一标识符 (GUID)。选…...

ABC318-D

问题陈述 给你一个加权无向完整图&#xff0c;图中有 &#x1d441;N 个顶点&#xff0c;编号从 11 到 &#x1d441;N 。连接顶点 &#x1d456;i 和 &#x1d457;j 的边 (&#x1d456;<&#x1d457;)(i<j) 的边的长度与 (&#x1d456;<&#x1d457;)(i<j) …...

Java实现线程安全的单例模式

单例模式&#xff1a;保证某个类在程序中只存在唯⼀⼀份实例&#xff0c;而不会创建出多个实例&#xff0c;单例模式的类一般是构造器私有&#xff0c;通过一个方法返回唯一实例&#xff1b; 点这里查看线程安全的详细讲解&#xff1b; 常见的单例模式分为饿汉式和懒汉式 一…...

osg库的下载和安装

下载 下载地址:https://github.com/openscenegraph/OpenSceneGraph 安装 打开Cmake.exe,将上述下载的osg文件下的CMakeLists.txt文件拖入Cmake界面中。 在其路径下新建一个build文件 并配置cmake,点击Configure 修改如下几个选项 ACTUAL_3RDPARTY_DIR BUILD_OSG_EXAM…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...