.Net 6.0 Web API 项目生成镜像并上传到私有仓库 Harbor
〇、前言
本文首先简单介绍了 Dockerfile 内容和常用命令;
然后是在 Windows 环境 Docker desktop 的安装和配置;
最后创建了 Web API 示例项目,并简单说明了从构建到推送至 Harbor 镜像仓库的步骤。
一、关于 Dockerfile
1.1 Dockerfile 文件示例
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app # EXPOSE 811 # EXPOSE 443 # EXPOSE 可以注释掉,以环境变量 ASPNETCORE_URLS 配置为准 ENV ASPNETCORE_URLS=http://+:811 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src COPY ["Test.WebApplication1.ImgTest6.0.csproj", "."] RUN dotnet restore "./Test.WebApplication1.ImgTest6.0.csproj" COPY . . WORKDIR "/src/." RUN dotnet build "Test.WebApplication1.ImgTest6.0.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "Test.WebApplication1.ImgTest6.0.csproj" -c Release -o /app/publish /p:UseAppHost=false # 设置时间为中国上海 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 设置环境为开发环境 ENV ASPNETCORE_ENVIRONMENT=Development FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "Test.WebApplication1.ImgTest6.0.dll"]
1.2 常见命令
1.2.1 FROM 指定基础镜像或创建新的镜像阶段
// 格式 FROM <image> # 没有 tag 或 digest 时,默认使用 latest 版本 FROM <image>:<tag> # tag 标签 FROM <image>:<digest> # digest 摘要(通常是一个SHA256哈希值) // 例如 FROM nginx FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build FROM ubuntu:18.04@sha256:3c7f9d4a8b1f3e4e8b1f3e4e8b1f3e4e8b1f3e4e8b1f3e4e8b1f3e4e8b1f3e4
Dockerfile 文件首行命令一定是 FROM 指令。当同时需要多个进出镜像时,可重复使用。
FROM 还有另外一个用途,为镜像创建一个副本,标识一个镜像阶段。
例如下面示例中的第二行命令:
# 【构建阶段】 # 使用 dotnet build 命令编译项目,此阶段的目的是编译源代码,准备用于发布 RUN dotnet build "Test.WebApplication1.ImgTest6.0.csproj" -c Release -o /app/build # 【准备发布】 # “publish”阶段是通过本命令创建的,这一阶段从“build”阶段继承了编译好的代码,然后准备发布 FROM build AS publish # 【发布阶段】 # 使用 dotnet publish 命令将应用程序发布到 /app/publish 目录 # 发布操作包括优化应用程序以减少其大小、生成运行时依赖项等 RUN dotnet publish "Test.WebApplication1.ImgTest6.0.csproj" -c Release -o /app/publish /p:UseAppHost=false
1.2.2 WORKDIR 设定工作目录
类似命令行中的 cd 命令,设定之后后续的命令相当于在工作目录中运行
# 格式 WORKDIR /usr/workdir # 示例 WORKDIR /a # (这时工作目录为:/a) WORKDIR b # (这时工作目录为:/a/b) WORKDIR /c # (这时工作目录为:/c)
1.2.3 EXPOSE 指定与外界交互的端口
# 格式 EXPOSE 80 EXPOSE 443
此命令只是声明容器打算使用什么端口,它并不会实际改变容器的网络设置。
也可以不配置 EXPOSE 参数来指定暴露的端口,可以通过配置环境变量的方式指定容器端口,例如:ENV ASPNETCORE_URLS=http://+:81
。
1.2.4 ENV 设置环境变量
这个命令非常简单,就是用于设置环境变量而已,无论是接下来的指令,还是在容器中运行的程序,都可以使用这里定义的环境变量。
# 格式 ENV <key>=<value> # 示例,这个环境变量通常用于指定应用程序监听的 URL ENV ASPNETCORE_URLS=http://+:81 # 表示应用程序将接受来自任何 IP 地址(由 + 表示)的连接请求,并使用端口 81 进行通信
1.2.5 COPY 拷贝文件
这个命令可以拷贝当前宿主机的文件,也可以拷贝当前文件夹中编译后的文件到当前镜像。
# 第一个参数指的是源文件路径,【.】表示当前文件夹 # 第二个参数指的是目标路径,【.】表示将宿主机当前文件夹中的全部文件进行拷贝 COPY . . # 使用【--from=publish】表示,从 publish 的镜像中拷贝文件,这里的 publish 是引入镜像时指定的别名 # 【/app/publish】是 publish 镜像的文件路径 # 最后这个【.】是指要拷贝到当前镜像来的目录,.表示当前路径,一般也是配合WORKDIR使用 COPY --from=publish /app/publish .
1.2.6 RUN 构建镜像
构建镜像的时候需要安装其他软件或者编译文件的命令都可以通过 RUN 命令执行。
# 格式 RUN <command> # shell 执行 RUN ["executable", "param1", "param2"] # exec 执行
多条命令可以用 && 来连接,以发布 ASP.NET Core 项目为例,将代码拷贝到镜像之后,需要进行 restore、build、publish,就可以在这里使用,例如:
RUN dotnet restore "./Test.WebApplication1.ImgTest6.0.csproj" && dotnet build "./Test.WebApplication1.ImgTest6.0.csproj" -c Release -o /app/build && dotnet publish "./Test.WebApplication1.ImgTest6.0.csproj" -c Release -o /app/publish /p:UseAppHost=false
1.2.7 ENTRYPOINT 容器启动命令
指定容器启动的要运行的命令,可以追加命令
# 格式 ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2 # shell 内部命令 # 示例 ENTRYPOINT ["dotnet", "Test.WebApplication1.ImgTest6.0.dll"] # 相当于在命令行执行 dotnet Test.WebApplication1.ImgTest6.0.dll 这个命令
注意:只允许有一个 ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的 ENTRYPOINT 指令。
1.2.8 VOLUME 指定持久化目录
用于创建一个数据卷(volume),它允许将容器内的目录或文件与宿主机进行共享,卷会一直存在,直到没有任何容器在使用它。
通过使用数据卷,可以在容器之间共享数据,或者在容器重启时保留数据。对卷的修改会立即生效,但不会对镜像产生影响。
# 格式 VOLUME ["/path/to/dir"] # 示例 VOLUME ["/data"] # 创建了一个名为/data的数据卷 VOLUME ["/var/www", "/var/log/apache2"] # 同时创建两个数据卷
注意:VOLUME 指令只是声明了数据卷的位置,并不会实际创建它们。数据卷的创建是在容器运行时进行的,通常是通过 docker run 命令或 Docker Compose 等工具来完成。
参考: https://blog.csdn.net/WuLex/article/details/113730475 https://blog.csdn.net/guojiaqi_/article/details/135909376
二、构建镜像并推送到 Harbor
2.1 Docker 安装
2.1.1 环境准备
- 启用相关 Windows 功能
打开“控制面板”,进入“程序和功能”,勾选“Hyper-V”和“适用于 Linux 的 Windows 子系统”:
安装完成后,按照提示需要重启。
- 安装 wsl
WSL(Windows Subsystem for Linux)是 Windows 10 的一个子系统,它允许用户在 Windows 上运行 Linux 发行版。
通过 WSL,用户可以在 Windows 上安装和运行 Linux 命令行工具、应用程序和环境,而无需使用传统的虚拟机或双启动设置。
wsl --install
检查是否安装成功
如下图运行wsl --list --verbose
或简化为wsl -l -v
,列出所有已安装的WSL分发版及其版本号,以及如何进入 wsl 命令模式:
另外,如何实现 WSL 和 Windows 文件系统互相访问?
在 WSL 中,你可以通过/mnt/
目录访问 Windows 文件系统。例如,要在 WSL 中访问 C 盘的某个文件,可以使用以下路径:
/mnt/c/path/to/your/file.txt
在Windows中,你可以通过\\wsl$\
路径访问WSL文件系统。例如,要在Windows中访问WSL的某个文件,可以使用以下路径:
\\wsl$\your_linux_distro\home\your_username\path\to\your\file.txt
2.1.2 环境准备中遇到的问题
1/3)安装 wsl 过程中出现如下报错,输出全是 ????? 报错提示不明确
C:\WINDOWS\system32>wsl --install 正在安装: Ubuntu 已安装 Ubuntu。 正在启动 Ubuntu... Installing, this may take a few minutes... WslRegisterDistribution failed with error: 0x80370114 Error: 0x80370114 ?????????????????? Press any key to continue... 分发“Ubuntu”的安装过程失败,退出代码: 1。 Error code: Wsl/InstallDistro/WSL_E_INSTALL_PROCESS_FAILED
解决步骤如下:
在 win10 搜索框搜索“应用和浏览器控制”,进入该界面 点击“Exploit Protection设置” 切换到"程序设置" 下拉找到“C:\WINDOWS\System32\vmcompute.exe”,点击编辑 找到“控制流保护(CFG)”,取消下面的“替代系统设置”。 打开 windows 命令行 ,输入“net start vmcompute”
参考:https://blog.csdn.net/gyjjj12/article/details/115531298
2/3)上边最后一部重启 vmcompute 时提示系统错误 1058
C:\WINDOWS\system32>net start vmcompute 发生系统错误 1058。 无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动。
解决方法:
服务【Hyper-V 主机计算服务】被禁用了或没有运行,开启即可。
3/3)检查下 Hyper-V 相关服务开启情况
2.1.3 下载和安装
官网下载 Docker Desktop Installer.exe:https://www.docker.com/products/docker-desktop/
双击下载安装包(Docker Desktop Installer.exe)进行安装,如下图,第一项建议勾选:
然后点击 OK 按钮,完成安装。
另外,关于 WSL 2 和 Hyper-V:
WSL 2 相较于 Hyper-V 有更低的资源占用; WSL 2 允许用户在不启动完整虚拟机的情况下运行容器,这简化了操作并减少了系统的复杂性; 对于仅需要运行 Docker 容器的用例,WSL 2 提供了足够且优化过的支持; 如果需要使用其他虚拟机或需要精细控制 Docker 资源分配,则可能需要依赖 Hyper-V; 当使用 WSL 2 作为后端时,Docker 镜像和容器无法在不同的 Windows 用户账户之间共享。
验证是否安装成功
直接打开或以管理员身份运行 Docker Desktop。
启动后 Docker 是 running 状态,如下图:
如下简单操作测试 Docker 是否安装成功:
# 查看版本 C:\WINDOWS\system32>docker -v Docker version 27.1.1, build 6312585 # 尝试拉取测试镜像 hello-world C:\WINDOWS\system32>docker pull hello-world Using default tag: latest latest: Pulling from library/hello-world c1ec31eb5944: Pull complete Digest: sha256:1408fec50309afee38f3535383f5b09419e6dc0925bc69891e79d84cc4cdcec6 Status: Downloaded newer image for hello-world:latest docker.io/library/hello-world:latest ... # 运行测试镜像 hello-world,成功输出:Hello from Docker! C:\WINDOWS\system32>docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. # 查看当前全部镜像 C:\WINDOWS\system32>docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest d2c94e258dcb 15 months ago 13.3kB
2.1.4 Docker 必要的配置
- 国内镜像仓库配置
在 Docker-->Setting-->Docker Engine 模块的配置中,新增配置项"registry-mirrors":(推荐使用阿里云的镜像地址,后边有详解如何获取)
{ "builder": { "gc": { "defaultKeepStorage": "20GB", "enabled": true } }, "experimental": false, "registry-mirrors": [ "http://hub-mirror.c.163.com", "https://docker.mirrors.ustc.edu.cn" ] }
其中,"http://hub-mirror.c.163.com"为网易云镜像地址;"https://docker.mirrors.ustc.edu.cn"为中国科学大学镜像地址。
最后点击“apply & restart”会自动重启 Docker,使新配置项生效。也可以通过命令docker info
来查看当前的全部配置项。
推荐使用个人阿里云镜像地址,需要单独申请,方法:登录地址【https://cr.console.aliyun.com】,然后如下图操作,没有申请过的话需要申请下:
具体的配置,可以参考对应系统的操作文档,来更新配置。
2.2 创建 Web API 项目
在编辑器里创建新的项目,如下图勾选配置:
项目创建以后,会自动生成一个 Dockerfile 文件,需要对此文件做相应修改,详见本文 1.1 Dockerfile 文件示例。
如下示例文件目录:
2.3 镜像编译并推送到 Harbor 镜像库
首先在项目文件夹,打开命令行工具,Shift+鼠标右键,选择“在此处打开 Powershell 窗口”,打开后,输入 cmd,进入命令行模式。
第一步:镜像构建
通过 build 语句,构建项目:
docker build -t test-dotnet/testwebapplication1imgtest60:stage_v1.0 .
其中,test-dotnet 表示项目名称,test-dotnet/testwebapplication1imgtest60 表示镜像名称,冒号后边的 stage_v1.0 是给镜像打的标签。
第二步:打标签
将本地的镜像对应到私有 Harbor 仓库中的镜像:(harbor.xxxx.com 为仓库的域名,需要更换成自己的)
docker tag test-dotnet/testwebapplication1imgtest60:stage_v1.0 harbor.xxxx.com/test-dotnet/testwebapplication1imgtest60:stage_v1.0
随后一步:将本地镜像推送到远程仓库
// 先登录 docker login harbor.xxxx.com // 登录成功后,再推送 docker push harbor.xxxx.com/test-dotnet/testwebapplication1imgtest60:stage_v1.0
最后再登录 Harbor 进行仓库,查看对应标签的镜像是否已经上传成功。
确认推送成功后,接口通过镜像地址来拉取。例如:
// 域名+项目名称+Tag,拉取指定版本 docker pull harbor.xxxx.com/test-dotnet/testwebapplication1imgtest60:stage_v1.0
2.4 镜像构建和推送过程中遇到的问题
2.4.1 Program does not contain a static 'Main' method suitable for an entry point
解决方法:解决方案文件(.sln)需要和项目文件(.csproj、Dockerfile)在同一目录下。
根据提示内容,确认无法判断问题原因,实际上项目中就不包含 Main 这个方法。
2.4.2 Docker 运行异常导致的 Error 提示
ERROR: request returned Internal Server Error for API route and version http://%2F%2F.%2Fpipe%2FdockerDesktopLinuxEngine/_ping, check if the server supports the requested API version
重启下 Docker Desktop 即可。

本文来自博客园,作者:橙子家,欢迎微信扫码关注博主【橙子家czzj】,有任何疑问欢迎沟通,共同成长!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2023-08-02 Builder 生成器模式简介与 C# 示例【创建型2】【设计模式来了_2】