去招聘网站做顾问,广州哪家公司做网站好,梁平网站建设,小加工厂做网站上个月15日#xff0c;上海MVP做了一次线下的技术分享活动#xff0c;我分享的主题是《快速构建容器化的ASP.NET Core应用程序》#xff0c;有关这次活动的简报#xff0c;可以参考这里。另外#xff0c;我的主题分享的PPT也可以点击这里下载。由于线下活动时间紧迫#… 上个月15日上海MVP做了一次线下的技术分享活动我分享的主题是《快速构建容器化的ASP.NET Core应用程序》有关这次活动的简报可以参考这里。另外我的主题分享的PPT也可以点击这里下载。由于线下活动时间紧迫没有办法把所有的内容完全仔细地讲解一遍最后使用一个小时左右的时间做了一个tasklist的案例演示但也是走马观花很多细节没有覆盖到。因此特撰此文将之前分享的内容再细化一下希望能够给关注这方面内容的读者带来帮助。我会尽量将细节问题解释清楚于是文章篇幅会比较长因此我会分三个部分进行介绍ASP.NET Core应用程序容器化需要注意的内容持续集成、持续部署与Azure DevOpsAzure Kubernetes Service介绍ASP.NET Core应用程序的构建构建ASP.NET Core应用程序的方式有很多种你可以使用Visual Studio 2017的项目模板直接创建也可以在安装了.NET Core SDK之后使用dotnet new命令创建具体步骤在此也就不再细表我仍然使用Visual Studio 2017的ASP.NET Core项目模板进行创建。在新建项目对话框中我们可以选择启用Docker容器支持这样的话Visual Studio会在新建的ASP.NET Core项目中添加Dockerfile文件同时会在解决方案中增加一个Docker Compose的项目用以实现容器编排。然而我并不太喜欢使用这一功能虽然它能够带来很多方便原因主要有二。首先一个复杂的应用程序解决方案项目往往不止一个各项目的运行环境和配置都会有所不同使用项目模板创建的Dockerfile和Docker Compose文件有可能还是需要进行修改甚至重写其次我们需要对IDE自动生成的代码了如指掌这样才能理解并在实际项目中正确使用与其如此不如自己根据实际需要自己编写这样可以让自己对整个项目的各个技术细节都有着深刻的理解和认识。新建ASP.NET Core项目之后就可以开始编写代码来实现我们的业务逻辑了。有关Visual Studio 2017开发ASP.NET Core应用程序的详细步骤在这里就不多介绍了作为这次线下活动的演示案例我开发了一个简单的Apptasklist这个App使用Angular 6作为前端框架TypeScript进行前端编程后端使用ASP.NET Core Web API构建基于MongoDB数据库完整的代码可以在https://github.com/daxnet/tasklist找到。该案例项目使用MIT许可协议开源。Tasklist的业务非常简单就是允许用户能够增加、删除任务项目它的界面如下在这个界面中用户可以在文本框中输入需要完成的任务项目点击“新增”按钮可以将任务项目添加到列表也可以在列表中点击“删除”按钮删除指定的项目文本框下方列出了所有已添加的任务项目。整个后端ASP.NET Core Web API解决方案中各项目的依赖关系如下具体的代码实现部分就不多介绍了这里重点介绍一下ASP.NET Core应用程序容器化时需要注意的几点问题。ASP.NET Core应用程序容器化所需注意的问题应用程序的配置信息容器化的应用程序往往都是在容器启动的过程中将所需的配置信息通过环境变量注入容器此时运行于容器中的应用就可以读取环境变量来获得运行参数。比如使用docker run命令启动容器时就可以使用-e参数来指定环境变量。因此理解ASP.NET Core应用程序的配置系统是非常重要的它有助于应用程序配置体系的设计。在《ASP.NET Core应用程序的参数配置及使用》一文中我已经简要介绍过ASP.NET Core应用程序的配置系统可供参考。在此需要注意的一点是ASP.NET Core配置系统通常使用冒号:来分隔配置数据模型中不同层次的名称。比如有如下配置数据模型1234567mongo: { server: { host: localhost, port: 27017 }, database: tasklist}如果在C#代码中要访问host那么就需要使用下面的代码1var mongoServerHost Configuration[mongo:server:host]然而如果应用程序需要运行在容器中这个配置就需要写在容器的编排文件里比如docker-compose.yml文件。但是有些容器的编排系统例如Kubernetes就不支持在环境变量设置时出现冒号这样的“非法字符”为此ASP.NET Core的配置也支持使用双下划线分隔。比如这样的话不仅ASP.NET Core应用程序在容器中能够获得环境变量的配置而且诸如Kubernetes这样的系统也能在启动容器时将配置信息设置到环境变量中。端口侦听ASP.NET Core应用程序的端口侦听设置也是一个在容器化过程中非常重要的内容。通常在开发阶段我们偏向于在Main方法中通过代码的方式指定应用程序所侦听的端口号比如1234public static IWebHostBuilder CreateWebHostBuilder(string[] args) WebHost.CreateDefaultBuilder(args) .UseUrls(http://*:8087) .UseStartupStartup();但是这种方法缺点是很明显的我们无法在部署应用程序的时候动态设置需要侦听的端口。对于ASP.NET Core应用程序而言常见的做法有两种通过命令行参数指定侦听端口或者使用环境变量。通过命令行参数只需要在启动应用程序时指定—server.urls参数即可或者如果是使用环境变量只需要配置ASPNETCORE_URLS变量即可如下因此事实上我们并不需要在Main函数中去显式地指定侦听端口只需要在最终部署的时候设置ASPNETCORE_URLS环境变量即可。现在让我们看看tasklist代码库中docker-compose.yml文件中有关后端服务的环境变量配置123456789101112131415161718service: image: daxnet/tasklist-service build: context: service/tasklist dockerfile: TaskList.Service/Dockerfile links: - db depends_on: - db ports: - 9020:9020 environment: - ASPNETCORE_ENVIRONMENTProduction - ASPNETCORE_URLShttp://*:9020 - mongo__server__hosttasklist-db - mongo__server__port27017 - mongo__databasetasklist container_name: tasklist-service在上面的配置中ASPNETCORE_ENVIRONMENT指定ASP.NET Core应用程序运行环境该参数将决定应用程序配置信息的读取方式ASPNETCORE_URLS指定ASP.NET Core应用程序的侦听端口mongo__server__hostMongoDB的服务器名称mongo__server__portMongoDB的侦听端口mongo__databaseMongoDB的数据库名称ASP.NET Core的容器版本微软官方发布了.NET Core/ASP.NET Core的docker容器镜像可以在https://hub.docker.com/r/microsoft/dotnet/中找到。开发人员需要根据不同的场景来选用不同的tag。比如2.1-sdk包含了.NET Core 2.1 SDK2.1-aspnetcore-runtime包含了ASP.NET Core 2.1的运行库2.1-runtime包含了.NET Core 2.1的运行库此外在这个repo下还有一些预览版的tag可以在https://hub.docker.com/r/microsoft/dotnet/tags/页面找到所有的tag。就ASP.NET Core而言在2.0含之前需要使用microsoft/aspnetcore这个docker容器镜像而从2.1开始则需要使用上面提到的microsoft/dotnet这个容器镜像。总之对于容器镜像和tag的选择需要慎重否则有可能出现一些奇奇怪怪的问题。docker镜像构建上下文Build Context与Dockerfile的配套使用在上面的docker-compose.yml片段中我们指定了ASP.NET Core应用程序的docker镜像构建上下文为service/tasklist目录于是接下来所有与构建docker镜像相关的操作都会基于这个构建上下文来执行。首先通过dockerfile指定了Dockerfile的位置是service/tasklist/TaskList.Service/Dockerfile注意这里已经将构建上下文路径带入进来然后我们了解一下Dockerfile的具体内容123456789101112131415FROM microsoft/dotnet:2.1-aspnetcore-runtime AS baseWORKDIR /appEXPOSE 9020FROM microsoft/dotnet:2.1-sdk AS publishWORKDIR /srcCOPY . .RUN dotnet restoreWORKDIR /src/TaskList.ServiceRUN dotnet publish TaskList.Service.csproj -c Release -o /appFROM base AS finalWORKDIR /appCOPY --frompublish /app .CMD [dotnet, TaskList.Service.dll]这个Dockerfile分成三个部分第一部分指定运行时会采用microsoft/dotnet:2.1-aspnetcore-runtime这个tag运行目录为/app目录并会向外界暴露9020端口第二部分就是应用程序的编译部分这里采用microsoft/dotnet:2.1-sdk作为编译环境先设置容器中的工作目录为/src然后将service/tasklist目录下的所有内容全部复制到容器中的/src目录注意虽然COPY指令后面是两个点号但由于我们已经指定了镜像构建上下文因此第一个点号就表示service/tasklist目录第二个点号就表示容器中的当前目录也就是/src目录接着就是标准的dotnet restore命令然后就是进入到/src/TaskList.Service目录执行dotnet publish指令从而编译整个项目并将编译结果输出到/app目录到了第三部分将第二部分的输出结果复制到第一部分容器中的/app目录也就是最后那个点号所指定的目录然后执行dotnet命令启动服务。事实上如果你在创建ASP.NET Core应用程序时启用了docker支持那么Visual Studio会在你的项目中添加一个Dockerfile内容与上面的Dockerfile类似不过需要注意的是使用这个自动生成的Dockerfile之前需要弄清楚镜像构建上下文否则直接通过docker build命令是无法正常完成镜像构建的。在容器化ASP.NET Core应用程序方面我暂时先介绍这些内容接下来看看前端部分需要做些什么。前端应用nginx的反向代理在tasklist案例中前端我采用的是Angular 6框架使用TypeScript编写。由于是一个单页面应用因此我没有选择相对比较重的Jetty、Tomcat、IIS等Web容器而是选择使用了比较轻量的nginx。当然前端通过http请求访问ASP.NET Core Web API应用程序所提供的RESTful API接口那么这里就有一个访问URL的问题。使用过Angular框架的开发者都知道通过environment.ts或者environment.prod.ts代码文件可以针对不同的运行环境Development, Staging或者Production来选择设置不同的配置数据那么后端服务的URL地址又该如何设置呢使用绝对路径这不是个好的做法这就要求将后端API的全路径都写死Hard Code在environment.prod.ts里显然不是一种合理的做法使用相对路径这种做法会使得前端App调用后端API时产生一个错误的URL。比如假设前端运行在localhost:80而后端是localhost:9020那么如果我们指定API的URL是相对路径/api/service那么当前端程序运行时它请求的API地址就成了http://localhost/api/service而不是http://localhost:9020/api/service在tasklist中我选择了使用相对路径然后更改nginx的配置设置了一条反向代理规则1234567891011121314151617181920212223242526events { worker_connections 4096;}http { server { listen 80; server_name localhost; include /etc/nginx/mime.types; location / { root /usr/share/nginx/html; index index.html index.htm; } location /api { proxy_pass http://tasklist-service; } } upstream tasklist-service { server tasklist-service:9020; }}在这里当前端页面请求/api路径时nginx会自动重定向到http://tasklist-service:9020/api此时就能正确完成RESTful API调用。注意这里的tasklist-service是ASP.NET Core应用程序的运行机器名请参考docker-compose.yml文件中service配置部分的container_name设置。同样基于docker镜像构建上下文我们可以使用容器来编译和运行前端代码123456789101112131415161718192021# 基于node 8容器作为编译环境FROM node:8 AS build# 首先安装Angular CLIRUN npm install -g angular/cli6.1.5# 然后将源代码复制到容器中WORKDIR /srcCOPY . .# 执行npm install以及Angular的编译RUN npm installRUN ng build --prod# 基于nginx容器作为运行环境FROM nginx AS final# 将nginx.conf配置文件复制到容器指定目录COPY nginx.conf /etc/nginx/nginx.conf# 将Angular编译输出复制到nginx的指定目录COPY --frombuild /src/dist/tasklist /usr/share/nginx/html在容器中运行整个应用程序在此我选择使用Docker for Windows来运行整个tasklist应用程序。首先启动Docker for Windows然后打开Windows命令行工具进入到tasklist目录执行1docker-compose up --build经过一段漫长时间的构建过程之后所有的服务都会启动在浏览器中打开我们的应用总结本文为ASP.NET Core应用程序容器化、持续集成、持续部署话题的第一部分重点介绍了ASP.NET Core应用程序容器化时需要注意的地方并展示了整个案例的运行效果。下文会接着讨论基于Azure DevOps的持续集成看看如何使用Azure DevOps的服务来完成项目的自动编译。原文地址: http://sunnycoding.cn/2018/10/07/dockerize-aspnetcore-cicd-with-azure-devops-and-kubernetes-part1.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com