本系列文章所要做出的演示架构基于 .NET Core Web Api、MSSQL、Skywalking 和 nginx ,这些都会通过docker-compose
一键创建/启动容器,然后用 Azure DevOps
发布上线。
所以本系列文章重点并不是如何写好.NET Core
,而是围绕着 .NET Core 的容器化架构加上一部分 DevOps 的实践。
系列大纲
本系列文章会分为四个部分,大家可以通过大纲大概了解一下我们会涉及到哪些内容,是不是你想了解想学习的东西。
用
docker-compose
启动WebApi
和SQL Server
在容器中集成
Skywalking
APM通过
nginx-proxy
对ES
、Skywalking
、WebApi
实现自动反向代理和HTTPS
通过
Azure DevOps
进行CI/CD
和蓝绿发布
前提条件
本系列文章不会对.NET Core
、Docker
等做零基础讲解,如果遇到不会建项目,不懂某条命令一类的问题需要你多谷歌一下,遇到问题可以先看文章结尾的帮助信息,会写一些对排错有帮助的内容。
然后 Azure DevOps
部分会要求你有一个 Linux 服务器,没有的可以用信用卡去 Google Cloud Platform、Azure、AWS 等自己免费撸一个,我推荐 Google Cloud Platform。
环境条件
NET Core 2.2 SDK
Docker 最新版(目前是 18.09.2)
SQL Server
接下来我们开始系列第一篇。
创建 .NET Core WebApi 项目
首先我们创建一个.NET Core WebApi
项目,将其命名为Core.API
,然后为了演示方便,我们修改一下ValuesController
的Get
方法。
[HttpGet("{id}")]public ActionResult<string> Get(int id){ return "您输入的是:" + id;}
然后修改一下launchSettings.json
,将https
的Url
移除掉:
... "Core.API": { "commandName": "Project", "launchBrowser": true, "launchUrl": "api/values", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, //"applicationUrl": "https://localhost:5001;http://localhost:5000" "applicationUrl": "http://localhost:5000" }...
然后点击这里运行看一下效果:
接下来,为了让WebApi
在容器中被顺利访问,我们需要让Kestrel
监听外网流量,修改Program.cs
的CreateWebHostBuilder
方法:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseUrls("http://0.0.0.0:5000");
创建 Dockerfile
找到我们的解决方案文件夹,创建一个名为Dockerfile
的文件。
然后将以下内容复制进去:
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS publishWORKDIR /srcCOPY . .RUN dotnet publish "/src/Core.API/Core.API.csproj" -c Release -o /appFROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slimEXPOSE 5000WORKDIR /appCOPY --from=publish /app .ENTRYPOINT ["dotnet", "Core.API.dll"]
开启你的命令行工具,指向到 API 项目中,将下列命令中的[yourusername]
替换为你的 Docker 用户名,当然如果你没有登录的话,你需要先执行docker login
登录一下,然后依次执行下列命令:
docker build -t [yourusername]/coreapi .docker run -p 5000:5000 -it --rm --name coreapi [yourusername]/coreapi
不出意外等一段时间你应该会发现自己的 API 在容器里活泼地蹦达了起来,我们这次访问http://localhost:5000/api/values/5这个 Url,你应该能看到跟之前一样的结果。
好,我们按下Ctrl+C
让它冷静下来,继续教程。
配置 Entityframework Core
一个标准的应用当然不能少了数据库,一个简明扼要的教程就需要EFCore
的Code First
。
我们新建一个名为Core.Entity
的.NET Standard
类库,打开你的程序包管理控制台,将默认项目指向Core.Entity
,安装以下依赖:
Install-Package Microsoft.EntityFrameworkCore -Version 2.2.4Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 2.2.4Install-Package Microsoft.EntityFrameworkCore.Design -Version 2.2.4Install-Package Microsoft.Extensions.Configuration.Json -Version 2.2.0Install-Package Microsoft.Extensions.Configuration.FileExtensions -Version 2.2.0
新建两个类文件,一个叫CoreContext
,作为我们的数据库上下文:
using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.Configuration;using System;using System.IO;namespace Core.Entity{ public class CoreContext : DbContext { public CoreContext() { } public CoreContext(DbContextOptions<CoreContext> options) : base(options) { } public virtual DbSet<Post> Post { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { var config = new ConfigurationBuilder() .SetBasePath(Path.Combine(Directory.GetCurrentDirectory())) .AddJsonFile("appsettings.Development.json", optional: false).Build(); optionsBuilder.UseSqlServer(config["ConnectionString"]); } } protected override void OnModelCreating(ModelBuilder builder) { builder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687"); #region Seeds string[] titles = new string[] { "本教程由Siegrain倾情奉献?️", "感谢大家关注~", "博客地址为 http://siegrain.wang", "本教程Github地址为 https://github.com/Seanwong933/.NET-Core-with-Docker" }; for (var i = 0; i < titles.Length; i++) { builder.Entity<Post>().HasData(new Post { Id = i + 1, Title = titles[i], Content = Guid.NewGuid().ToString() }); } #endregion } }}
一个叫Post
,作为我们的示例实体:
using System.ComponentModel.DataAnnotations;using System.ComponentModel.DataAnnotations.Schema;namespace Core.Entity{ public class Post { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] public string Title { get; set; } public string Content { get; set; } }}接下来在`Core.API`中添加`Core.Entity`的项目依赖,然后在程序包控制台执行以下命令:add-migration initialupdate-database它会创建你的初始迁移文件,然后将其更新到数据库中。![](Untitled-c6fc13c0-281f-434a-a86b-9dcc4a2059cd.png)如果报错了,检查一下`appsettings.Development.json`中的链接字符串是否正确。接下来,我们需要在`Startup.cs`的`ConfigureServices`和`Configure`方法中进行一些修改,并设置`EFCore`在发现没有数据库或数据库过期时自动迁移。public void ConfigureServices(IServiceCollection services){ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddScoped<CoreContext, CoreContext>(); services.AddDbContext<CoreContext>(options => { options.UseSqlServer(Configuration["ConnectionString"]); });}public void Configure(IApplicationBuilder app, IHostingEnvironment env){ if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope()) { var context = serviceScope.ServiceProvider.GetRequiredService<CoreContext>(); context.Database.Migrate(); } app.UseHttpsRedirection(); app.UseMvc();}
然后修改一下ValuesController
,好让其获取我们想要的数据:
[Route("api/[controller]")][ApiController]public class ValuesController : ControllerBase{ private readonly CoreContext _context; public ValuesController(CoreContext context) { _context = context; } [HttpGet] public IActionResult Get() { return Ok(_context.Post.ToList()); } [HttpGet("{id}")] public IActionResult Get(int id) { var entity = _context.Post.Find(id); if (entity == null) return NotFound(); return Ok(entity); }}
我们再次运行看下是否能够正确获取了。
创建 docker-compose 文件
接下来,我们要用docker-compose
在容其中将webapi
跟SQL Server
一并运行起来。
在解决方案文件夹下创建 docker-compose.yml
文件:
粘贴以下内容:
version: '3.3'services: coreapi: container_name: coreapi image: siegrainwong/coreapi:latest ports: - 5000:5000 depends_on: - sqlserver links: - sqlserver volumes: - ./Core.API/appsettings.docker.json:/app/appsettings.json:ro restart: always sqlserver: image: mcr.microsoft.com/mssql/server:2017-latest container_name: sqlserver restart: always environment: ACCEPT_EULA: Y MSSQL_PID: Developer SA_PASSWORD: 'NetCore123!@#' ports: - 1433
然后在当前目录执行docker-compose up -d
这时候再看下是不是正常运行了。
但此时SQL Server
的数据也是只在容器中的,意味着容器被移除后数据就会丢失,所以我们要通过挂载volume
的方式持久化数据。
在docker-compose
文件中添加箭头处的代码:
version: '3.3'services: coreapi: container_name: coreapi image: siegrainwong/coreapi:latest ports: - 5000:5000 depends_on: - sqlserver links: - sqlserver volumes: - ./Core.API/appsettings.docker.json:/app/appsettings.json:ro restart: always sqlserver: image: mcr.microsoft.com/mssql/server:2017-latest container_name: sqlserver restart: always environment: ACCEPT_EULA: Y MSSQL_PID: Developer SA_PASSWORD: 'NetCore123!@#' volumes: - coredata:/var/opt/mssql # <-- ports: - 1433volumes: coredata: # <--
此时我们可以先将容器用docker rm -f coreapi
移除,再跑起来后用docker logs coreapi
命令看看有没有EFCore
的迁移日志就知道数据有没有被持久化了。
帮助信息
实用的 docker 命令
docker psdocker imagesdocker rm -f [container_name]docker exec [container_name] [commands]docker exec -it [container_name] bashdocker logs [container_name]
带注释的docker-compose.yml
文件
因为编码问题带中文注释的不太容易被识别,所以没有放进源码中
案例参考
这是我正在开发的一个开源博客系统,该系列文章的这套架构就出自这个项目,觉得不错的话希望可以帮我点颗星鼓励一下;如果你是从 https://siegrain.wang 看见这篇文章的,那么你现在所看见的就是这个项目: )
https://github.com/siegrainwong/ancorazor
项目源代码
https://github.com/Seanwong933/.NET-Core-with-Docker/tree/master/Part1
本篇到此为止,下一篇文章将带领大家在容器中集成skywalking
监控webapi
,不了解的同学可以先去了解一下skywalking
是什么,能做什么。
原文地址:https://siegrain.wang/article/2019/06/24/launch-netcore-webapi-and-sqlserver-by-docker-compose