【ASP.NET Core分布式项目实战】(五)Docker制作dotnet core控制台程序镜像

Docker制作dotnet core控制台程序镜像

基于dotnet SDK

  1. 新建控制台程序
    mkdir /home/console
    cd /home/console
    dotnet new console
    dotnet restore
  2. 创建 Dockerfile 文件,参考https://github.com/dotnet/dotnet-docker/blob/master/samples/aspnetapp/Dockerfile
    vim /home/console/Dockerfile
    
    # ------
    
    FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
    WORKDIR /app
    
    COPY . /app
    
    RUN dotnet run

     

  3. 构建镜像

    docker build -t wyt/console:dev .
  4. 运行容器
    dotnet run --name console-dev wyt/console

基于dotnet Runtime

  1. 新建控制台程序
    mkdir /home/console
    cd /home/console
    dotnet new console
    dotnet restore
    using System;
    using System.Threading;
    
    namespace console
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hello World from docker!");
    
                Thread.Sleep(Timeout.Infinite);
            }
        }
    }
    View Code
  2. 创建 Dockerfile 文件
    FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
    WORKDIR /code
    
    COPY *.csproj /code
    RUN dotnet restore
    
    COPY . /code
    RUN dotnet publish -c Release -o out
    
    FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
    WORKDIR /app
    COPY --from=build /code/out /app
    ENTRYPOINT ["dotnet", "console.dll"]
  3. 构建镜像
    docker build -t wyt/console:prod .
  4. 运行容器
    docker run --name=console-prod wyt/console:prod

镜像大小对比

docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
wyt/console                            prod                d2c683338197        3 minutes ago       260MB
wyt/console                            dev                 93b346366bc5        20 minutes ago      1.74GB
mcr.microsoft.com/dotnet/core/sdk      2.2                 155911c343f3        11 days ago         1.74GB
mcr.microsoft.com/dotnet/core/aspnet   2.2                 c56aab97bc42        11 days ago         260MB

Mysql EF Core 快速构建 web api

  1. 新建文件夹beta,创建WebAPI项目User.API,添加EFCore引用
    Install-Package MySql.Data.EntityFrameworkCore
  2. 新建文件夹Data、Models 
    新建 AppUser.cs 
    namespace User.API.Models
    {
        public class AppUser
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Company { get; set; }
            public string Title { get; set; }
        }
    }
    View Code

    新建 UserContext.cs 

    namespace User.API.Data
    {
        public class UserContext:DbContext
        {
            public UserContext(DbContextOptions options) : base(options)
            { }
            
            public DbSet Users { get; set; }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity().ToTable(nameof(Users)).HasKey(t => t.Id);
    
                base.OnModelCreating(modelBuilder);
            }
        }
    }
    View Code
  3. 修改 Startup.cs 
    namespace User.API
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddDbContext(options =>
                {
                    options.UseMySQL(Configuration.GetConnectionString("MysqlUser"));
                });
    
    
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseMvc();
    
                InitDatabase(app);
            }
    
            public void InitDatabase(IApplicationBuilder app)
            {
                using (var scope=app.ApplicationServices.CreateScope())
                {
                    var userContext = scope.ServiceProvider.GetRequiredService();
                    //userContext.Database.Migrate();
                    if (userContext.Users.Count()==0)
                    {
                        userContext.Users.Add(new AppUser()
                        {
                            Name = "wyt"
                        });
                        userContext.SaveChanges();
                    }
                }
            }
        }
    }
    View Code
  4. 修改 appsettings.json 添加数据库配置
    "ConnectionStrings": {
      "MysqlUser": "Server=192.168.103.240;Port=3306;Database=beta_user;Uid=root;Pwd=pwd123456"
    }
  5. 生成数据库

    Add-Migration init
    Update-Database
  6. 修改 ValuesController.cs 加入依赖注入
    namespace User.API.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class ValuesController : Controller
        {
            private UserContext _userContext;
    
            public ValuesController(UserContext userContext)
            {
                _userContext = userContext;
            }
    
            // GET api/values
            [HttpGet]
            public async  Task Get()
            {
                return Json(await _userContext.Users.FirstOrDefaultAsync(u => u.Name == "wyt"));
            }
        }
    }
    View Code
  7. 访问api

    【ASP.NET Core分布式项目实战】(五)Docker制作dotnet core控制台程序镜像_第1张图片

ASPNETCORE WEB API与MYSQL互联

  • 修改 appsettings.json 与 appsettings.Development.json ,采用不同配置
    //appsettings.json
    
    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
        "MysqlUser": "Server=db;Port=3306;Database=beta_user;Uid=root;Pwd=pwd123456"
      }
    }
    
    //appsettings.Development.json
    
    {
      "Logging": {
        "LogLevel": {
          "Default": "Debug",
          "System": "Information",
          "Microsoft": "Information"
        }
      },
      "ConnectionStrings": {
        "MysqlUser": "Server=47.111.84.191;Port=3306;Database=beta_user;Uid=root;Pwd=pwd123456"
      }
    }

     

  • 修改 Program.cs 设置80端口

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseUrls("http://*:80")
            .UseStartup();

     

  • 创建 Dockerfile 

    FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
    WORKDIR /code
    COPY *.csproj ./
    RUN dotnet restore
    
    COPY . ./
    RUN dotnet publish -c Release -o out
    
    FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
    WORKDIR /app
    COPY --from=build /code/out ./
    
    EXPOSE 80
    
    ENTRYPOINT ["dotnet", "User.API.dll"]

     

  • 拷贝到Linux服务器上,并执行下方命令创建镜像

    docker build -t wyt/aspnetcore:pred .
    [root@localhost User.API]# docker build -t wyt/aspnetcore:pred .
    Sending build context to Docker daemon  1.265MB
    Step 1/11 : FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
     ---> 155911c343f3
    Step 2/11 : WORKDIR /code
     ---> Using cache
     ---> 3e2cb7223b3b
    Step 3/11 : COPY *.csproj ./
     ---> 6f6d88b83c75
    Step 4/11 : RUN dotnet restore
     ---> Running in c538c0a59636
      Restore completed in 3.85 sec for /code/User.API.csproj.
    Removing intermediate container c538c0a59636
     ---> 6e45bd786a9c
    Step 5/11 : COPY . ./
     ---> 50ac66ac3f97
    Step 6/11 : RUN dotnet publish -c Release -o out
     ---> Running in 9febf9972a3d
    Microsoft (R) Build Engine version 16.1.76+g14b0a930a7 for .NET Core
    Copyright (C) Microsoft Corporation. All rights reserved.
    
      Restore completed in 667.65 ms for /code/User.API.csproj.
      User.API -> /code/bin/Release/netcoreapp2.2/User.API.dll
      User.API -> /code/out/
    Removing intermediate container 9febf9972a3d
     ---> a7c92c3fd98b
    Step 7/11 : FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
     ---> c56aab97bc42
    Step 8/11 : WORKDIR /app
     ---> Using cache
     ---> 12d1df98dc50
    Step 9/11 : COPY --from=build /code/out ./
     ---> Using cache
     ---> b901e53b64f8
    Step 10/11 : EXPOSE 80
     ---> Using cache
     ---> c61ad551fa76
    Step 11/11 : ENTRYPOINT ["dotnet", "User.API.dll"]
     ---> Running in 36c66859c548
    Removing intermediate container 36c66859c548
     ---> 063fc4fe64ed
    Successfully built 063fc4fe64ed
    Successfully tagged wyt/aspnetcore:pred
    View Code

     

  • 运行容器,进行端口映射和容器关联

    docker run -d -p 8002:80 --name aspnetcore --link mysql01:db wyt/aspnetcore:pred

     

  • 成功访问
    【ASP.NET Core分布式项目实战】(五)Docker制作dotnet core控制台程序镜像_第2张图片 

Docker Network

  1. 创建新的桥接网段
    # 创建mybridge桥接网段
    docker network create -d bridge mybridge
    # 显示网络信息
    docker network ls
  2. 通过桥接网络创建新的 aspnetcore 容器
    # 删除之前创建的容器
    docker rm aspnetcore -f
    # 使用mybridge桥接网段创建新的容器
    docker run -d -p 8002:80 --net mybridge --name aspnetcore wyt/aspnetcore:pred
    我们可以通过命令查看容器 aspnetcore 的ip信息,为172.17.0.4
    docker inspect aspnetcore
  3. 将 mybridge 桥接网段与 mysql01 进行桥接
    # 将mybridge网段与mysql01所在网段进行桥接
    docker network connect mybridge mysql01

    这时可以查看 mysql01 的ip,然后进入 aspnetcore 容器内尝试是否可以ping通

    docker exec -it aspnetcore bash
    apt-get update -y
    apt-get install iputils-ping -y
    apt-get install net-tools -y
    ping 172.18.0.3

     

  4. 由于我们没有进行数据卷映射,所以配置文件无法更改,备注: appsettings.json 中使用的数据库为db,所以我们只能将 mysql01 改为 db 

    # 容器重命名
    docker rename mysql01 db

     方法二

    # 进入容器
    docker exec -it aspnetcore bash
    ls
    apt-get install vim -y
    # 修改配置
    vim appsettings.json
    exit
    # 重启容器
    docker restart aspnetcore

     

  5. 完成
    curl http://47.111.84.191:8002/api/values

    或者访问

    【ASP.NET Core分布式项目实战】(五)Docker制作dotnet core控制台程序镜像_第3张图片

     

制作 docker compose

  1. 修改User.API项目
    # Startup.cs
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseMvc();
    
        UserContextSeed.SeedAsync(app,loggerFactory);
    }
    
    
    # /Data/UserContextSeed.cs
    public class UserContextSeed
    {
    
        private ILogger _logger;
        public UserContextSeed(ILogger logger)
        {
            _logger = logger;
        }
    
        public static async Task SeedAsync(IApplicationBuilder app, ILoggerFactory loggerFactory)
        {
            using (var scope = app.ApplicationServices.CreateScope())
            {
                var userContext = scope.ServiceProvider.GetRequiredService();
                var logger = (ILogger)scope.ServiceProvider.GetService(typeof(ILogger));
                logger.LogDebug("Begin UserContextSeed SeedAsync");
    
                userContext.Database.Migrate();
    
                if (userContext.Users.Count() == 0)
                {
                    userContext.Users.Add(new AppUser()
                    {
                        Name = "wyt"
                    });
                    userContext.SaveChanges();
                }
            }
        }
    }
    View Code
  2. 安装docker-compose
    # 下载Docker Compose的当前稳定版本
    sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    # https://github.com/docker/compose/releases/download/1.24.1/docker-compose-Linux-x86_64
    # 建议迅雷下载后进行重命名,这样速度快
    # 对二进制文件应用可执行权限
    sudo chmod +x /usr/local/bin/docker-compose
    # 测试安装
    docker-compose --version
  3. 新建文件 docker-compose.yml 
    version: '3'
    
    services: 
      db: 
        image: mysql/mysql-server
        container_name: db
        command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci
        restart: always
        ports:
          - '3306:3306'  #host物理直接映射端口为3306
        environment:
          MYSQL_ROOT_PASSWORD: pwd123456 #root管理员用户密码
          MYSQL_USER: jeese   #创建jeese用户
          MYSQL_PASSWORD: pwd123456  #设置jeese用户的密码
          MYSQL_ROOT_HOST: '%'
        volumes:
          - "/home/wyt/beta/mysql-init:/docker-entrypoint-initdb.d"  #设置数据库自动执行脚本目录,目录要存在
    
      web: 
        build: .
        container_name: aspnetcore
        ports:
          - '8003:80'  #host物理直接映射端口为3306
        depends_on: 
          - db
    # 初始化脚本mysql-init/init.sql
    use mysql;
    ALTER USER 'jeese'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd123456';
    ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd123456';
    FLUSH PRIVILEGES;

     

  4. docker-compose构建

    docker-compose build
    [root@localhost User.API]# docker-compose build
    db uses an image, skipping
    Building web
    Step 1/11 : FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
     ---> 155911c343f3
    Step 2/11 : WORKDIR /code
     ---> Using cache
     ---> 7525de38c042
    Step 3/11 : COPY *.csproj ./
     ---> Using cache
     ---> 397affedf1a6
    Step 4/11 : RUN dotnet restore
     ---> Using cache
     ---> 964ce7a0de36
    Step 5/11 : COPY . ./
     ---> Using cache
     ---> 5d18774ff1df
    Step 6/11 : RUN dotnet publish -c Release -o out
     ---> Using cache
     ---> 3353849a8dd8
    Step 7/11 : FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
     ---> c56aab97bc42
    Step 8/11 : WORKDIR /app
     ---> Using cache
     ---> 12d1df98dc50
    Step 9/11 : COPY --from=build /code/out ./
     ---> Using cache
     ---> 4e6819b010fe
    Step 10/11 : EXPOSE 80
     ---> Using cache
     ---> 2ee374887860
    Step 11/11 : ENTRYPOINT ["dotnet", "User.API.dll"]
     ---> Using cache
     ---> 2b06acc1b707
    Successfully built 2b06acc1b707
    Successfully tagged userapi_web:latest
    View Code
    docker-compose up
    [root@localhost User.API]# docker-compose up
    Creating network "userapi_default" with the default driver
    Creating db ... done
    Creating aspnetcore ... done
    Attaching to db, aspnetcore
    db     | [Entrypoint] MySQL Docker Image 8.0.16-1.1.11
    db     | [Entrypoint] Initializing database
    aspnetcore | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
    aspnetcore |       No XML encryptor configured. Key {67f35cc4-a4c3-4224-ba07-7a0753ed0d09} may be persisted to storage in unencrypted form.
    aspnetcore | Hosting environment: Production
    aspnetcore | Content root path: /app
    aspnetcore | Now listening on: http://[::]:80
    aspnetcore | Application started. Press Ctrl+C to shut down.
    db     | 2019-07-05T09:27:43.358708Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.16) initializing of server in progress as process 20
    db     | 2019-07-05T09:27:43.360043Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
    db     | 2019-07-05T09:27:43.360052Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' is a collation of the deprecated character set UTF8MB3. Please consider using UTF8MB4 with an appropriate collation instead.
    db     | 2019-07-05T09:27:46.943704Z 5 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
    db     | 2019-07-05T09:27:48.131450Z 0 [System] [MY-013170] [Server] /usr/sbin/mysqld (mysqld 8.0.16) initializing of server has completed
    db     | [Entrypoint] Database initialized
    db     | 2019-07-05T09:27:49.902213Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.16) starting as process 66
    db     | 2019-07-05T09:27:49.903376Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
    db     | 2019-07-05T09:27:49.903389Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' is a collation of the deprecated character set UTF8MB3. Please consider using UTF8MB4 with an appropriate collation instead.
    db     | 2019-07-05T09:27:50.456492Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
    db     | 2019-07-05T09:27:50.477501Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.16'  socket: '/var/lib/mysql/mysql.sock'  port: 0  MySQL Community Server - GPL.
    db     | 2019-07-05T09:27:50.558190Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/var/run/mysqld/mysqlx.sock'
    db     | Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
    db     | Warning: Unable to load '/usr/share/zoneinfo/leapseconds' as time zone. Skipping it.
    db     | Warning: Unable to load '/usr/share/zoneinfo/tzdata.zi' as time zone. Skipping it.
    db     | Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
    db     | Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
    db     | 
    db     | [Entrypoint] running /docker-entrypoint-initdb.d/init.sql
    db     | 
    db     | 
    db     | 2019-07-05T09:27:52.092496Z 12 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 8.0.16).
    db     | 2019-07-05T09:27:54.191280Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.16)  MySQL Community Server - GPL.
    db     | [Entrypoint] Server shut down
    db     | 
    db     | [Entrypoint] MySQL init process done. Ready for start up.
    db     | 
    db     | [Entrypoint] Starting MySQL 8.0.16-1.1.11
    db     | 2019-07-05T09:27:55.417600Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.16) starting as process 1
    db     | 2019-07-05T09:27:55.419490Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
    db     | 2019-07-05T09:27:55.419504Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' is a collation of the deprecated character set UTF8MB3. Please consider using UTF8MB4 with an appropriate collation instead.
    db     | 2019-07-05T09:27:55.858661Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
    db     | 2019-07-05T09:27:55.880107Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.16'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MySQL Community Server - GPL.
    db     | 2019-07-05T09:27:56.066024Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/var/run/mysqld/mysqlx.sock' bind-address: '::' port: 33060
    aspnetcore | Application is shutting down...
    aspnetcore exited with code 0
    aspnetcore | Hosting environment: Production
    aspnetcore | Content root path: /app
    aspnetcore | Now listening on: http://[::]:80
    aspnetcore | Application started. Press Ctrl+C to shut down.
    View Code
    # 停止docker-compose
    # docker-compose down

启动问题解决方式:由于docker-compose.yml文件中存在db依赖,所以要修改/Data/UserContextSeed.cs进行延迟数据库自动初始化

public static async Task SeedAsync(IApplicationBuilder app, ILoggerFactory loggerFactory,int? retry=0)
{
    var retryForAvaiability = retry.Value;
    try
    {
        using (var scope = app.ApplicationServices.CreateScope())
        {
            var userContext = scope.ServiceProvider.GetRequiredService();
            var logger = (ILogger)scope.ServiceProvider.GetService(typeof(ILogger));
            logger.LogDebug("Begin UserContextSeed SeedAsync");

            userContext.Database.Migrate();

            if (userContext.Users.Count() == 0)
            {
                userContext.Users.Add(new AppUser()
                {
                    Name = "wyt"
                });
                userContext.SaveChanges();
            }
        }
    }
    catch (Exception ex)
    {
        if (retryForAvaiability<10)
        {
            retryForAvaiability++;
            var logger = loggerFactory.CreateLogger(typeof(UserContextSeed));
            logger.LogError(ex.ToString());
            await Task.Delay(TimeSpan.FromSeconds(2));
            await SeedAsync(app, loggerFactory, retryForAvaiability);
        }
    }
}
View Code

 

你可能感兴趣的:(【ASP.NET Core分布式项目实战】(五)Docker制作dotnet core控制台程序镜像)