系列导航及源代码

需求

.NET 6 Web API应用使用最多的场景是作为后端微服务应用,在实际的项目中,我们一般都是通过将应用程序打包成docker镜像进行发布,以便更好地进行部署,包括基于Kubernetes平台的微服务项目部署。

一般来说作为微服务部署的应用程序,都是位于某个虚拟子网下的,也就是说它们不直接暴露给外部用户,请求都是走的内部网络,所以很少会有HTTPS的需求,但是作为演示,在本文中我们还是会介绍如何实现HTTPS访问docker中的应用程序。

目标

实现应用程序的docker镜像打包运行,包括实现基于HTTPS的访问。

原理与思路

应用程序docker镜像打包的实现思路很简单,准备一个正确的dockerfile,再根据需要进行HTTPS配置,最后正确构建镜像就可以了。

实现

实现Docker镜像打包

Api项目中新建dockerfile文件,一般我们构建应用程序都是通过两步构建:第一步进行编译发布,第二步将发布的文件拷贝到运行时环境中,这样可以减少镜像的大小。

如果你是使用Visual Studio或者Rider开发项目,可以在创建项目的时候就将是否使用Docker支持选上,选择容器环境为Linux即可,项目模版会为我们自动生成正确的Dockerfile。或者我们也可以在项目上右击,选择添加Docker支持

下面是我们手写的dockerfile的文件内容,对于编写dockerfile经验不多的小伙伴来说,最容易出错的地方就是路径的问题。因为我们将dockefile文件生成在了Api项目中了,所以单从文件内容里的路径来看,是有问题的,但是不要紧,我们在打包镜像的时候可以指定dockefile文件执行的上下文,只要在解决方案目录下执行docker build就没问题了。

ARG NET_IMAGE=6.0-bullseye-slim
FROM mcr.microsoft.com/dotnet/aspnet:${NET_IMAGE} AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
ENV ASPNETCORE_ENVIRONMENT=Development FROM mcr.microsoft.com/dotnet/sdk:${NET_IMAGE} AS build
WORKDIR /src
COPY ["src/TodoList.Api/TodoList.Api.csproj", "TodoList.Api/"]
COPY ["src/TodoList.Application/TodoList.Application.csproj", "TodoList.Application/"]
COPY ["src/TodoList.Domain/TodoList.Domain.csproj", "TodoList.Domain/"]
COPY ["src/TodoList.Infrastructure/TodoList.Infrastructure.csproj", "TodoList.Infrastructure/"]
RUN dotnet restore "TodoList.Api/TodoList.Api.csproj"
COPY ./src .
WORKDIR "/src/TodoList.Api"
RUN dotnet build "TodoList.Api.csproj" -c Release -o /app/build FROM build AS publish
RUN dotnet publish --no-restore "TodoList.Api.csproj" -c Release -o /app/publish FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TodoList.Api.dll"]

在构建镜像之前,有几个小坑需要注意一下:

  • 暂时删除Program中的UseHttpsRedirection中间件,因为我们还没有配置HTTPS证书;
  • Api项目的csproj文件中,将TodoList.Api.xml文件在Debug模式下的配置复制到Release中,否则会报错Could not find file '/app/TodoList.Api.xml
  • 修改对应appsettings.{env}.json中的数据库连接字符串,使用docker网络模型获取其他容器的方式,将localhost改为mssql,这个名字是在本地运行sql server docker的容器名称,我们将使用docker网络允许应用程序连接到数据库docker容器。

下面我们就来构建一下这个镜像,确保位于解决方案目录下,注意最后那.指明了当前选择的dockerfile文件执行的上下文路径,即解决方案目录:

$ docker build -t todo-list -f src/TodoList.Api/Dockerfile .

生成的镜像:

运行起来,把80端口暴露出来,使用--link参数指出需要将当前应用容器连接到数据库容器所在的网络,并使用API客户端去验证登陆请求:

$ docker run -p 80:80 --name=todo_list_in_docker --link=mssql -d todo-list
4733f35c2c9558b78e3c7b9281536d8891f19bf87b18fa0ad953e94f7b984184

请求认证:

实现HTTPS访问

接下来我们为容器添加HTTPS支持,为了实现这一点,我们当然还是需要继续使用UseHttpsRedirection中间件,然后需要添加一个证书,并在启动容器的时候添加这个证书。

dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p Test@Password
dotnet dev-certs https --trust

重新build并运行容器,这次我们使用HTTPS的5001端口去访问容器中的API,需要将HTTPS容器内的443端口暴露到host上的端口(我选择的是5001端口)并制定相关的HTTPS的环境变量,证书的指定并将host上保存证书的路径挂载到容器内可以访问到。

docker run \
-p 80:80 \
-p 5001:443 \
--name=todo_list_in_docker \
--link=mssql \
-e ASPNETCORE_URLS="https://+;http://+" \
-e ASPNETCORE_HTTPS_PORT=5001 \
-e ASPNETCORE_Kestrel__Certificates__Default__Password="Test@Password" \
-e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx \
-v ${HOME}/.aspnet/https:/https/ \
-d \
todo-list

增加docker-compose功能

到这里我们发现了一个比较麻烦的地方在于我们需要记住这些配置,并且每次需要手动分别启动数据库容器和应用容器,我们完全可以通过docker-compose来完成,所以我们先把应用容器和数据库容器都停止并删除掉,开始在解决方案目录下新建docker-compose文件:

version: '3.4'

services:
todo-list:
image: todo-list
# 配置端口转发
ports:
- "80:80"
- "5001:443"
# 配置容器环境变量
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+;http://+
- ASPNETCORE_HTTPS_PORT=5001
- ASPNETCORE_Kestrel__Certificates__Default__Password=Test@Password
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
# 挂载证书路径
volumes:
- ~/.aspnet/https:/https:ro
# 需要先启动数据库容器
depends_on:
- mssql
# todo-list通过public网络响应请求,通过private网络连接数据库容器
networks:
- private
- public mssql:
image: mcr.microsoft.com/mssql/server:2019-latest
# 配置端口转发,这是为从主机直接访问数据库需要的,如果没有从主机直接访问数据库的需求,只需要声明容器端口1433不做转发即可
ports:
- "1433:1433"
environment:
- SA_PASSWORD=StrongPwd123
- ACCEPT_EULA=Y
# 挂载数据目录实现持久化
volumes:
- mssqldata:/var/opt/mssql
networks:
- private
- public # 因为mssqldata路径之前已经创建了,所以需要在这里声明使用已有的
volumes:
mssqldata: networks:
private:
public:

运行起来以后继续请求认证:

$ docker-compose up --build
Creating network "todolist_private" with the default driver
Creating network "todolist_public" with the default driver
Recreating todolist_mssql_1 ... done
Recreating todolist_todo-list_1 ... done
Attaching to todolist_mssql_1, todolist_todo-list_1
// 省略后面的日志....

请求结果:

到此为止如何使用容器去进行应用程序打包和部署的演示就结束了,关于如何在Kubernetes和CI/CD中应用这些步骤,会在后面将微服务的系列中再次涉及到。

总结

docker打包应用程序比较容易出错的地方在于dockerfile路径,除此之外如果在容器中还需要有其他操作比如安装一些第三方的agent(比如splunk agent),也需要仔细操作,关于如何进行Docker Build的Debug,可以参考其他人写的文章,例如这篇:Debugging Docker builds

参考资料

  1. Hosting ASP.NET Core images with Docker over HTTPS
  2. Hosting ASP.NET Core images with Docker Compose over HTTPS
  3. Debugging Docker builds

使用.NET 6开发TodoList应用(30)——实现Docker打包和部署的更多相关文章

  1. 使用.NET 6开发TodoList应用(3)——引入第三方日志库

    需求 在我们项目开发的过程中,使用.NET 6自带的日志系统有时是不能满足实际需求的,比如有的时候我们需要将日志输出到第三方平台上,最典型的应用就是在各种云平台上,为了集中管理日志和查询日志,通常会选 ...

  2. 使用.NET 6开发TodoList应用(1)——系列背景

    前言 想到要写这样一个系列博客,初衷有两个:一是希望通过一个实践项目,将.NET 6 WebAPI开发的基础知识串联起来,帮助那些想要入门.NET 6服务端开发的朋友们快速上手,对使用.NET 6开发 ...

  3. 使用.NET 6开发TodoList应用(2)——项目结构搭建

    为了不影响阅读的体验,我把系列导航放到文章最后了,有需要的小伙伴可以直接通过导航跳转到对应的文章 : P TodoList需求简介 首先明确一下我们即将开发的这个TodoList应用都需要完成什么功能 ...

  4. 使用.NET 6开发TodoList应用(4)——引入数据存储

    需求 作为后端CRUD程序员(bushi,数据存储是开发后端服务一个非常重要的组件.对我们的TodoList项目来说,自然也需要配置数据存储.目前的需求很简单: 需要能持久化TodoList对象并对其 ...

  5. 使用.NET 6开发TodoList应用(5)——领域实体创建

    需求 上一篇文章中我们完成了数据存储服务的接入,从这一篇开始将正式进入业务逻辑部分的开发. 首先要定义和解决的问题是,根据TodoList项目的需求,我们应该设计怎样的数据实体,如何去进行操作? 长文 ...

  6. 使用.NET 6开发TodoList应用(5.1)——实现Repository模式

    需求 经常写CRUD程序的小伙伴们可能都经历过定义很多Repository接口,分别做对应的实现,依赖注入并使用的场景.有的时候会发现,很多分散的XXXXRepository的逻辑都是基本一致的,于是 ...

  7. 使用.NET 6开发TodoList应用(6)——使用MediatR实现POST请求

    需求 需求很简单:如何创建新的TodoList和TodoItem并持久化. 初学者按照教程去实现的话,应该分成以下几步:创建Controller并实现POST方法:实用传入的请求参数new一个数据库实 ...

  8. 使用.NET 6开发TodoList应用文章索引

    系列导航 使用.NET 6开发TodoList应用(1)--系列背景 使用.NET 6开发TodoList应用(2)--项目结构搭建 使用.NET 6开发TodoList应用(3)--引入第三方日志 ...

  9. 使用.NET 6开发TodoList应用(24)——实现基于JWT的Identity功能

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在.NET Web API开发中还有一个很重要的需求是关于身份认证和授权的,这个主题非常大,所以本文不打算面面俱到地介绍整个主 ...

随机推荐

  1. [BUUCTF]REVERSE——[BJDCTF2020]BJD hamburger competition

    [BJDCTF2020]BJD hamburger competition 附件 步骤: 例行检查,64位程序,无壳儿 由于unity是用C++开发的,这里就不用IDA了,直接用dnspy看源码 在B ...

  2. win10 linux ubuntu子系统 使用adb

    条件 本文已经默认你已经在win10系统下成功配置了ubuntu子系统,所以唯一的条件就是windows上的adb 版本和ubuntu子系统的adb版本一致. 方法 怎么来保证adb 版本一致呢?在本 ...

  3. LuoguP7859 [COCI2015-2016#2] GEPPETTO 题解

    Content 有 \(n\) 个数 \(1\sim n\).你需要在其中选若干个数.但是还有 \(m\) 个限制,第 \(i\) 个限制格式为 \(a_i\) 不能和 \(b_i\) 一起选.问你一 ...

  4. tcp十种状态;关于tcp中time_wait状态(2MSL问题)

    tcp十种状态 注意: 当一端收到一个FIN,内核让read返回0来通知应用层另一端已经终止了向本端的数据传送 发送FIN通常是应用层对socket进行关闭的结果 关于tcp中time_wait状态的 ...

  5. RPA账户和密码管理方案

    如何将登录业务系统的账户和密码"更好的,更合适"地交给RPA? 相信很多小伙伴们在做RPA的时候, 都会或多或少的遇到类似的问题. 正常情况下IT管理人员都会给真实的业务人员分配业 ...

  6. Mac下好用的“visio”之 OmniGraffle Pro

    !!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!! 作者:mohist 1.官方网站:https://www.omnigroup.com/omnigraffle/ ...

  7. 自己常用的CMake用法总结

    欢迎指正 CMake : A.download : https://cmake.org/download/ B.tutorial: https://cmake.org/cmake-tutorial/ ...

  8. 【LeetCode】974. Subarray Sums Divisible by K 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 动态规划 前缀和求余 日期 题目地址:https:/ ...

  9. 【LeetCode】3. Longest Substring Without Repeating Characters 无重复字符的最长子串

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:无重复字符,最长子串,题解,leetcode, 力扣,py ...

  10. 如何改善win10录屏时声音降噪(消除杂音)

    此文章是针对win10系统中安装Realtek声卡的麦克风出现杂音的设置办法 1. 打开win10的控制面板,找到"硬件和声音选项" 2. 进入"硬件和声音"选 ...