用 docker-compose 启动 WebApi 和 SQL Server
本系列文章所要做出的演示架構(gòu)基于 .NET Core Web Api、MSSQL、Skywalking 和 nginx ,這些都會通過docker-compose一鍵創(chuàng)建/啟動容器,然后用?Azure DevOps?發(fā)布上線。
所以本系列文章重點并不是如何寫好.NET Core,而是圍繞著 .NET Core 的容器化架構(gòu)加上一部分 DevOps 的實踐。
系列大綱
本系列文章會分為四個部分,大家可以通過大綱大概了解一下我們會涉及到哪些內(nèi)容,是不是你想了解想學(xué)習(xí)的東西。
用?docker-compose?啟動WebApi和SQL Server
在容器中集成SkywalkingAPM
通過nginx-proxy對?ES、Skywalking、WebApi實現(xiàn)自動反向代理和HTTPS
通過Azure DevOps進行CI/CD和藍綠發(fā)布
前提條件
本系列文章不會對.NET Core、Docker等做零基礎(chǔ)講解,如果遇到不會建項目,不懂某條命令一類的問題需要你多谷歌一下,遇到問題可以先看文章結(jié)尾的幫助信息,會寫一些對排錯有幫助的內(nèi)容。
然后?Azure DevOps?部分會要求你有一個 Linux 服務(wù)器,沒有的可以用信用卡去 Google Cloud Platform、Azure、AWS 等自己免費擼一個,我推薦 Google Cloud Platform。
環(huán)境條件
NET Core 2.2 SDK
Docker 最新版(目前是 18.09.2)
SQL Server
接下來我們開始系列第一篇。
創(chuàng)建 .NET Core WebApi 項目
首先我們創(chuàng)建一個.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" }...然后點擊這里運行看一下效果:
接下來,為了讓W(xué)ebApi在容器中被順利訪問,我們需要讓Kestrel監(jiān)聽外網(wǎng)流量,修改Program.cs的CreateWebHostBuilder方法:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseUrls("http://0.0.0.0:5000");創(chuàng)建 Dockerfile
找到我們的解決方案文件夾,創(chuàng)建一個名為Dockerfile的文件。
然后將以下內(nèi)容復(fù)制進去:
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 用戶名,當然如果你沒有登錄的話,你需要先執(zhí)行docker login登錄一下,然后依次執(zhí)行下列命令:
docker build -t [yourusername]/coreapi .docker run -p 5000:5000 -it --rm --name coreapi [yourusername]/coreapi不出意外等一段時間你應(yīng)該會發(fā)現(xiàn)自己的 API 在容器里活潑地蹦達了起來,我們這次訪問http://localhost:5000/api/values/5這個 Url,你應(yīng)該能看到跟之前一樣的結(jié)果。
好,我們按下Ctrl+C讓它冷靜下來,繼續(xù)教程。
配置 Entityframework Core
一個標準的應(yīng)用當然不能少了數(shù)據(jù)庫,一個簡明扼要的教程就需要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,作為我們的數(shù)據(jù)庫上下文:
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傾情奉獻??", "感謝大家關(guān)注~", "博客地址為 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`的項目依賴,然后在程序包控制臺執(zhí)行以下命令:add-migration initialupdate-database它會創(chuàng)建你的初始遷移文件,然后將其更新到數(shù)據(jù)庫中。如果報錯了,檢查一下`appsettings.Development.json`中的鏈接字符串是否正確。接下來,我們需要在`Startup.cs`的`ConfigureServices`和`Configure`方法中進行一些修改,并設(shè)置`EFCore`在發(fā)現(xiàn)沒有數(shù)據(jù)庫或數(shù)據(jù)庫過期時自動遷移。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,好讓其獲取我們想要的數(shù)據(jù):
[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); }}我們再次運行看下是否能夠正確獲取了。
創(chuàng)建 docker-compose 文件
接下來,我們要用docker-compose在容其中將webapi跟SQL Server一并運行起來。
在解決方案文件夾下創(chuàng)建?docker-compose.yml?文件:
粘貼以下內(nèi)容:
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然后在當前目錄執(zhí)行docker-compose up -d
這時候再看下是不是正常運行了。
但此時SQL Server的數(shù)據(jù)也是只在容器中的,意味著容器被移除后數(shù)據(jù)就會丟失,所以我們要通過掛載volume的方式持久化數(shù)據(jù)。
在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的遷移日志就知道數(shù)據(jù)有沒有被持久化了。
幫助信息
實用的 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文件
因為編碼問題帶中文注釋的不太容易被識別,所以沒有放進源碼中
案例參考
這是我正在開發(fā)的一個開源博客系統(tǒng),該系列文章的這套架構(gòu)就出自這個項目,覺得不錯的話希望可以幫我點顆星鼓勵一下;如果你是從 https://siegrain.wang 看見這篇文章的,那么你現(xiàn)在所看見的就是這個項目: )
https://github.com/siegrainwong/ancorazor
項目源代碼
https://github.com/Seanwong933/.NET-Core-with-Docker/tree/master/Part1
本篇到此為止,下一篇文章將帶領(lǐng)大家在容器中集成skywalking監(jiān)控webapi,不了解的同學(xué)可以先去了解一下skywalking是什么,能做什么。
原文地址:https://siegrain.wang/article/2019/06/24/launch-netcore-webapi-and-sqlserver-by-docker-compose
總結(jié)
以上是生活随笔為你收集整理的用 docker-compose 启动 WebApi 和 SQL Server的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#中await/async闲说
- 下一篇: 一个通用数据库操作组件DBUtil(c#