点击上方蓝字关注“汪宇杰博客”

导语

我的博客(https://edi.wang)所使用的博客系统 Moonglade 开源已经一年多了。目前已有至少4位社区朋友使用此系统在 Azure、阿里云上部署了自己的博客。可惜长久以来该系统一直缺乏 Docker 支持,而 .NET Core 必须结合 Docker 才是当今世界的政治正确。我作为一名20年的老软粉,虽然嘴上说着很不情愿用 Linux、Docker这种非微软的东西,但也只能假装抱着批判的态度,向 Linux 和 Docker 伸出了魔爪,让我的博客系统能够容器化运行。

Docker 环境安装

我作为一个20多年的老软粉,怎么可以在自己纯洁的 Windows 电脑上装 Docker 呢?装完以后:Docker 真香。

为了最大限度的避免 Windows 被污染(尽管它已经是咖喱拌饭了),我的 Docker 编译和发布环境都配置在云端,采用 Azure DevOps + Docker Hub + Azure App Service Linux Plan 的方式去编译运行。

Dockerfile

Visual Studio 可以直接右键一个 ASP.NET Core 项目添加 Docker 支持,这种方式可以让你很方便的在本地调试 Docker 中的 ASP.NET Core 程序。VS除了向工程目录添加一个 Dockerfile 以外,还会修改你的 csproj 工程文件,好让工具链整合你的容器。而其实对于单纯编译和运行 ASP.NET Core 网站而言,单独一个 Dockerfile 就够了,Docker 会根据这个 Dockerfile 编译出应用的容器镜像。

最初我博客的 Dockerfile 内容如下:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base

WORKDIR /app

EXPOSE 80

EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build

WORKDIR /src

COPY ["Moonglade.Web/Moonglade.Web.csproj", "Moonglade.Web/"]

# COPY 其余的工程文件,篇幅关系省略

RUN dotnet restore "Moonglade.Web/Moonglade.Web.csproj"

COPY . .

WORKDIR "/src/Moonglade.Web"

RUN dotnet build "Moonglade.Web.csproj" -p:Version=10.2.0-docker -c Release -o /app/build

FROM build AS publish

RUN dotnet publish "Moonglade.Web.csproj" -p:Version=10.2.0-docker -c Release -o /app/publish

FROM base AS final

WORKDIR /app

COPY --from=publish /app/publish .

ENTRYPOINT ["dotnet", "Moonglade.Web.dll"]

这份 Dockerfile 和 Visual Studio 自动生成的没太大区别。其中,我指定编译版本号参数为 -p:Version=10.2.0-docker,以便于直接从博客网站的界面分辨部署类型是 Docker 还是传统的 Code。

YAML

在 Azure DevOps 上,我使用 YAML 方式编译和部署我的博客项目,其中 Docker 的编译步骤定义如下:

- job: Docker

pool:

vmImage: 'ubuntu-latest'

steps:

- task: Docker@2

displayName: 'Build and Push'

inputs:

containerRegistry: 'ediwang_dockerhub'

repository: ediwang/moonglade

tags: latest

由于VM镜像选的是 Ubuntu,因此这个 Docker 镜像编译出来为 Linux/x64 架构。如果你需要其他架构,可以自行添加其他类型的VM镜像。

ediwang_dockerhub 是预先在 Azure DevOps 授权配置好的针对 Docker Hub 的连接名称。编译完成后,Azure DevOps 会使用其中的授权向 Docker Hub 发布镜像。

福报#1:路径问题

当我兴高采烈的测试我的 Docker 容器时,我惊喜的发现,博客的博主头像、RSS订阅、OPML等全部都404了。根据之前我修过的Linux福报,我立即明白这是路径写法的问题。

在 Windows 系统中,表示一个文件或文件夹的路径通常用反斜杠分割目录,如:

C:\Fubao\996.icu

而 Linux 系统中,路径得用斜杠来分割目录,如:

/use/dotnet/work/955

像我这样的老牌软狗,很容易按照习惯把代码写成 Windows 的形式,毕竟微软曾经说好的 Linux 是毒瘤, .NET 只能在 Windows 上跑:

var fallbackImageFile = $@"{AppDomain.CurrentDomain.GetData(Constants.AppBaseDirectory)}\wwwroot\images\default-avatar.png";

其实 .NET 自古以来都有个API:Path.Combine(),用来拼路径,它在 .NET Core 里遇到 Linux 环境可以正确使用斜杠,于是软狗以为这样写就没事了:

var cssPath = Path.Combine(webRootPath, "css", "theme", currentTheme);

大部分情况确实是好的,然而我们来看个会爆的例子:

var p1 = "/dotnet";

var p2 = "/fubao/996.icu";

Path.Combine(p1, p2);

猜猜结果变成什么?

/dotnet 被丢掉了,只能996,进ICU。

好在微软为了不让我们进ICU,在.NET Standard 2.1里引入了 Path.Join() 方法,可以输出我们想要的结果:

因此,我把博客代码里用到路径的地方全部都用 Path.Join() 改了一遍,终于恢复了博主头像、RSS等资源的正常访问。

Path.Join() 参考文档:https://docs.microsoft.com/en-us/dotnet/api/system.io.path.join?view=netcore-3.1

福报#2:libgdiplus

博客程序运行期间,还报了另一个错,日志如下:

2020-03-31T12:02:53.405115468Z System.TypeInitializationException: The type initializer for 'Gdip' threw an exception.
2020-03-31T12:02:53.405359877Z  ---> System.DllNotFoundException: Unable to load shared library 'libgdiplus' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: liblibgdiplus: cannot open shared object file: No such file or directory
2020-03-31T12:02:53.405375177Z    at System.Drawing.SafeNativeMethods.Gdip.GdiplusStartup(IntPtr& token, StartupInput& input, StartupOutput& output)
2020-03-31T12:02:53.405390778Z    at System.Drawing.SafeNativeMethods.Gdip..cctor()
2020-03-31T12:02:53.405397878Z    --- End of inner exception stack trace ---

这是由于博客代码用到了一些 .NET Core 的绘图 API,而这些 API 的底层需要 Linux 系统上装一个叫做 libgdiplus 的库。可是 Azure App Service 的 Linux 容器主机对用户来说无法直接操作,不可能 SSH 进去给它装个库,怎么办呢?

Bing 了一番之后发现,Dockerfile 里面居然可以直接定义 Linux 安装包的命令,把依赖性搞定。直接加入一条RUN命令的步骤即可:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base

RUN apt-get update && apt-get install -y libgdiplus

WORKDIR /app

EXPOSE 80

EXPOSE 443

...

配置默认值

使用 Docker 容器部署应用的体验我希望是一键部署以后啥都不用干,直接能跑。而以前版本的博客系统,必须要求用户先手工配置一堆环境变量或是配置文件才能跑,非常996。

这个问题非常好办,只要在 appsettings.json 中留配置的默认值,保证程序能先跑起来即可。至于自定义的配置,可以让用户通过环境变量传给 Docker 容器。即保证了一键部署的方便性,又保留了自定义配置的灵活性。

小结

让 .NET Core 程序支持 Docker 并不麻烦。麻烦的是老一代 .NET 程序员会被根深蒂固的 Windows 设计所牵绊。在新的时代,我们必须学习新的实践,不要想着吃老本。.NET Framework 已经日薄西山,及时删库跑路,上 .NET Core + Docker 的船,才能保证在新的时代还能继续用 C# 释放生产力!我的 Docker 之旅刚刚起步,肯定还有很多我没遇到过的情况。欢迎读者在留言中补充和建议!

让我的 .NET Core 博客系统支持 Docker相关推荐

  1. 一个基于Microsoft Azure、ASP.NET Core和Docker的博客系统

    2008年11月,我在博客园开通了个人帐号,并在博客园发表了自己的第一篇博客.当然,我写博客也不是从2008年才开始的,在更早时候,也在CSDN和系统分析员协会(之后名为"希赛网" ...

  2. 个人博客系统的测试报告

    目录 1.项目背景 2.项目功能 3.测试计划 3.1功能测试 3.1.1 测试用例设计 3.1.2 实际执行测试的部分操作步骤 3.2自动化测试 3.2.1 脑图 3.2.2 代码编写 1.项目背景 ...

  3. 博客系统知多少:揭秘那些不为人知的学问(四)

       点击上方关注"汪宇杰博客" ^_^ 上篇<博客系统知多少:揭秘那些不为人知的学问(三)>介绍了博客协议或标准.本篇终章介绍设计博客系统有哪些知识点. 1.&quo ...

  4. 博客系统知多少:揭秘那些不为人知的学问(二)

    点击上方关注"汪宇杰博客" 上篇<博客系统知多少:揭秘那些不为人知的学问(一)>介绍了博客的历史.我的博客故事及博客的受众来源.本篇精彩继续,介绍博客基本功能设计要点. ...

  5. 博客系统知多少:揭秘那些不为人知的学问(三)

    点击上方关注"汪宇杰博客" 上篇<博客系统知多少:揭秘那些不为人知的学问(二)>介绍了博客的基本功能设计要点,本篇介绍博客的协议或标准. 1."博客" ...

  6. 我的 .NET Core 博客性能优化经验补充

    点击上方蓝字关注"汪宇杰博客" 导语 去年年底我写了一篇<我的 .NET Core 博客性能优化经验总结>,但后来还发现有一处遗漏需要补充.我们一起来看看~ 牺牲空间换 ...

  7. 我的 .NET Core 博客性能优化经验总结

    点击上方蓝字关注"汪宇杰博客" 导语 去年8月,我用 .NET Core 重写了我的博客系统.经过一年多的优化,服务器响应速度从上线时候的 80ms 提高到了现在的 8ms,十倍提 ...

  8. mac wordpress php7,Mac 下基于 wordpress 搭建个人博客系统

    一.前言 这里说的是自己从 wordpress 源码开始搭建一个个人博客系统.当然,很多云端已经直接提供了在线安装的方式,这个就不在本文的讨论范围之内了. 二.关于 wordpress wordpre ...

  9. 基于Django的博客系统

    代码地址如下: http://www.demodashi.com/demo/14445.html 基于django的博客系统, 界面展示 首页前端界面如下: 文章页面: 后台页面: 文章页面: ##项 ...

最新文章

  1. hdu 1724 Ellipse——辛普森积分
  2. 没有数学何来计算机:论计算机起源的数学思想
  3. luvit 被忽视的lua 高性能框架(仿nodejs)
  4. hive中删除表的错误Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException
  5. 1周第1课 Linux 认知、安装 Centos7
  6. 在 WSL2.0 的 Ubuntu 18 里使用 Docker
  7. JBoss类加载机制 ClassLoadingConfiguration
  8. 更新无限无线连接更新服务器,02-H3C WBC560多业务无线控制器软件升级操作指导...
  9. C++03:论容器的使用
  10. 最近完成的一个可伸缩性的WEB开发框架
  11. 【名额有限】腾讯技术工程-运维技术沙龙
  12. php 费率计算_如何计算您的小时费率
  13. Android AAB增量安装
  14. dell电脑如何安装ubuntu系统_如何在 Dell PC 上安装 Ubuntu Linux
  15. 全国各主要省市经纬度
  16. android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明
  17. 世界最高山峰是珠穆朗玛峰(8844.43米=8844430毫米),假如我有一张足够大的纸,它的厚度是0.1毫米。请问,我折叠多少次,可以折成珠穆朗玛峰的高度?
  18. 如何用PHP判断一个网址是否被百度搜索引擎收录,判断的原理是什么?
  19. 8个有用的表单构建工具,你一定要使用并收藏好
  20. 最新IOS xcode12真机调试步骤

热门文章

  1. 【Java基础】Java中的持久属性集Properties
  2. UVa 12100 - Printer Queue
  3. Yii框架里用grid.CGridView调用pager扩展不显示最后一页按钮的解决
  4. (转载)9个主流的开源许可协议[整理]
  5. POJ1269 Intersecting Lines 计算几何 C语言
  6. 在VSCode Remote环境下开发Teams Bot
  7. 本地服务器下的局域网安全吗_本地安全认证服务器
  8. 在Ubuntu 11.10中将窗口按钮移回右侧
  9. 如何停止Internet Explorer 11的建议站点?
  10. t-mobile频段_T-Mobile再次被黑客入侵:超过200万个帐号和地址可能泄漏