把Web Api OData移植到Asp.Net Core(4)-docker MySQL

Asp.Net Core支持跨平台开发服务端软件,可以采用docker部署到Linux。以前开发基于Windows Server的服务端软件,配套的数据库通常采用SQL Server Express。虽然微软也发布了SQL Server的Linux版本,但是考虑到成熟度,还是优先采用在Linux平台上已经广泛使用了很多年的MySQL数据库,并且全部采用docker部署。
把这个大目标拆分为以下几个小目标:

  • Asp.Net Core采用MySQL数据库;
  • 在docker中运行MySQL数据库;
  • Asp.Net Core网站访问MySQL docker数据库;

1.Asp.Net Core采用MySQL数据库

首先在Windows系统安装MySQL,百度上就可以找到安装包。MySQL可以全部采用默认安装,数据库密码设置为xxx。Asp.Net Core在执行添加控制器、Update Database等操作的时候,都要连接到MySQL,如果连不上会报错。

Asp.Net Core已经支持MySQL数据库,并且数据库驱动不止一种,先采用官方的驱动。NuGet安装MySql.Data.EntityFrameworkCore 6.10.5。

然后修改ODataWeb网站代码。
注意,初始化数据库的时候,一定要调用EnsureCreated(),可以在首次运行的时候自动创建数据库,否则要采用非常麻烦的方法去导入数据库。
注意:数据表全部采用小写名字,避免后续因为大小写问题造成BUG。

public class BookDbContext : DbContext
    {
        public BookDbContext(DbContextOptions<BookDbContext> options)
            : base(options)
        {
        }

        //MySql默认定义的数据表全部小写!并且大小写敏感!
        public DbSet<Book> books { get; set; }
    }

    public static class SeedData
    {
        public static void SeedDB(BookDbContext context)
        {
            //重要:如果数据库完全为空,可以自动创建数据库!
            context.Database.EnsureCreated();

            // DB has been seeded
            if (context.books.Any())
                return;

            context.books.AddRange(
                  new Book() { Name = "射雕英雄传", Publish = new DateTime(1964, 1, 1), Author = "金庸", Price = 9.5f, },
                  new Book() { Name = "神雕侠侣", Publish = new DateTime(1965, 3, 1), Author = "金庸", Price = 10.5f, },
                  new Book() { Name = "倚天屠龙记", Publish = new DateTime(1968, 12, 1), Author = "金庸", Price = 12, }
                  );

            context.SaveChanges();
        }
    }

在Startup.cs中注册MySQL数据库服务。

public void ConfigureServices(IServiceCollection services)
        {
            //开发阶段使用内存数据库调试代码
            //services.AddDbContext<BookDbContext>(opt => opt.UseInMemoryDatabase("bookdb"));
            //注册MySQL数据库服务
            services.AddDbContext<BookDbContext>(options =>
                options.UseMySQL(Configuration.GetConnectionString("MySQLConnection")));

            services.AddMvc();

            //支持OData
            services.AddOData();
        }

然后在appsettings.json定义数据库连接字符串。注意SslMode=None。

 "ConnectionStrings": {
    "MySQLConnection": "Data Source=localhost;port=3306;Initial Catalog=bookdb;user id=root;password=xxx;SslMode=None"
  },

然后调试运行网站,浏览http://localhost:5000/odata/Books,检查结果。

2. 在docker中运行MySQL数据库

如果打算自己做一个MySQL镜像,那是相当之麻烦的。不过docker官网上已经有MySQL镜像,直接拉下来用就可以了。这就是docker的好处,如果我们想用什么软件,就去拉什么镜像,根本不用关心这个软件怎么安装的,大大节省了我们宝贵的时间。

编写docker-compose.yml,把ODataWeb、MySQL、nginx联合起来。
注意:
1,设置MySQL数据库root的密码是xxx。
2,挂载宿主机当前目录下面的data目录到MySQL容器的/var/lib/mysql目录。这样MySQL启动后创建的全部数据库文件都可以在宿主机dbdata目录保留下来。否则,当容器被删除的时候,数据库也全没了,这是绝对不允许的。
3,对外暴露端口3306。当容器运行后,我们可以在外网直接通过3306访问到容器内部的MySQL,这样做便于管理,但是也存在安全风险。
4,设置ODataWeb容器depends_on依赖于MySQL容器。实际测试发现有点问题,后面再说。

version: '3'

services:
  mysql-service:
    container_name: mysqlservice
    image: mysql
    ports:
      - "3306:3306"
    environment:
     - MYSQL_ROOT_PASSWORD=xxx
    volumes:
      - ./data:/var/lib/mysql
    restart: always

  odataweb-service:
    container_name: odatawebservice
    image: odatawebimage
    build:
      context: ./odataweb
      dockerfile: Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    restart: always
    depends_on:
      - mysql-service
    links:
      - mysql-service

  nginx-proxy:
    container_name: nginxproxy
    image: nginx    
    ports:
      - "9000:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    restart: always
    links:
      - odataweb-service

3. Asp.Net Core网站访问MySQL docker数据库

ODataWeb网站的数据库连接字符串也要改一下,因为ODataWeb在容器里运行的时候,MySQL运行在另外一个容器中,localhost是无法访问MySQL的。如果指定MySQL容器IP,则以上的配置文件需要按照静态IP的方式去配置,比较麻烦。经过试验,发现可以直接写容器的名称mysqlservice,就跟nginx配置文件类似。

"MySQLConnection": "Data Source=mysqlservice;port=3306;Initial Catalog=bookdb;user id=root;password=xxx;SslMode=None"

删除宿主机之前创建的odataweb镜像,然后编译,发布网站,更新宿主机的docker-compose.yml、odataweb目录,执行docker-compose up重新创建镜像,运行容器。
然后可以看到提示了一大堆错误信息,但是最后网站运行起来了。
……
odatawebservice | Unhandled Exception: System.AggregateException: One or more errors occurred. (Unable to connect to any of the specified MySQL hosts.) —> MySql.Data.MySqlClient.MySqlException: Unable to connect to any of the specified MySQL hosts. —> System.AggregateException: One or more errors occurred. (Connection refused 172.18.0.2:3306) —> System.Net.Internals.SocketExceptionFactory+ExtendedSocketException: Connection refused 172.18.0.2:3306
……
mysqlservice | 2018-01-07T08:44:26.502907Z 0 [Note] mysqld: Shutdown complete
mysqlservice |
mysqlservice |
mysqlservice | MySQL init process done. Ready for start up.
mysqlservice |
……
mysqlservice | 2018-01-07T08:44:27.011975Z 0 [Note] End of list of non-natively partitioned tables
odatawebservice | Hosting environment: Development
odatawebservice | Content root path: /app
odatawebservice | Now listening on: http://[::]:5000
odatawebservice | Application started. Press Ctrl+C to shut down.

问题的原因在于MySQL首次启动比较慢,需要初始化一大堆东西,虽然设置了ODataWeb容器依赖于MSQL容器,但是MySQL启动之后,ODataWeb就可以顺理成章地启动了,其实这时候MySQL还在执行初始化工作。因为只有首次运行会报错,所以无所谓,不再深究。
访问http://192.168.80.134:9000/odata/Books,检查结果。
可以看一下宿主机挂载目录,数据库文件都在这里了。
这里写图片描述

4. 其他初始化MySQL数据库的方法

以上方法是经过了多次试验最终确定的最简便的方法,单纯通过网站的代码去创建数据库,完全没有手动操作。
如果不通过网站的代码去初始化数据库,可以采用MySQL导入数据库的方法。

方法一:远程导入

首先,在本地的MySQL数据库中导出数据库结构和数据。前提条件是,在本地Windows中运行过ODataWeb网站,已经创建了bookdb数据库,这个只要在VS2017中按一下F5就有了。
在控制台进入MySQL的bin目录:在Windows文件资源管理器打开C:\Program Files\MySQL\MySQL Server 5.7\bin,在地址栏输入cmd,进入控制台。输入以下命令登录到MySQL系统。

mysql -h127.0.0.1 -uroot -pxxx -t -P3306

可以确认一下boodb是否已经存在。

show databases;
use bookdb;
show tables;
select * from books;

这里写图片描述
最后一定要exit退出MySQL系统,才能执行下面的命令导出数据库。

mysqldump -h localhost -u root -p bookdb > d:\temp\bookdb.sql

然后输入密码xxx,就可以导出数据库文件bookdb.sql。

然后改一下ODataWeb代码,注解EnsureCreated(),取消自动初始化数据库功能,重新发布网站。修改docker-compose.yml,让MySQL初始化的时候自动创建一个bookdb数据库,如果没有的话,后面无法远程导入数据库。

    environment:
     - MYSQL_DATABASE=bookdb
     - MYSQL_ROOT_PASSWORD=xxx

用rm-rf data删除Linux宿主机的数据库文件挂载目录。重新创建镜像、运行容器,会发现反复提示大量错误,因为ODataWeb网站无法连接到数据库。
在控制台进入MySQL的bin目录,执行以下命令,把bookdb.sql远程导入到Linux宿主机的MySQL系统。这里的192.168.80.134是VMWare虚拟机的IP。

mysql -h 192.168. 80.134 -P 3306 -u root -p bookdb < d:\temp\bookdb.sql

然后输入密码xxx,然后ODataWeb网站终于成功运行起来了。
访问http://192.168.80.134:9000/odata/Books,检查结果。

方法二:容器内部导入

但是远程操作容器内部的MySQL,不是很安全。所以,一般运行容器的时候,是不对外网开放3306端口的,我们把docker-compose.yml中mysql容器的配置再改一下:

mysql-service:
    container_name: mysqlservice
    image: mysql
    environment:
     - MYSQL_DATABASE=bookdb
     - MYSQL_ROOT_PASSWORD=xxx
    volumes:
      - ./dbdata:/var/lib/mysql
    restart: always

用rm-rf data删除Linux宿主机的数据库文件挂载目录。重新创建镜像、运行容器,再次执行远程导入,报错:
ERROR 2003 (HY000): Can’t connect to MySQL server on ‘192.168.80.134’ (10060)
我们必须换一种方法,把bookdb.sql拖到Linux宿主机的数据库文件挂载目录data下面,然后进入MySQL容器内部,导入数据库。
在MySQL容器运行起来以后,新开一个SSH命令行窗口,输入以下命令进入容器:

docker exec -it mysqlservice /bin/bash

然后登录到容器内部的MySQL系统:

mysql -h127.0.0.1 -uroot -pxxx -t -P3306

然后导入数据库。注意bookdb.sql在容器内部的路径,跟docker-compose.yml中定义的挂载目录对应:

use bookdb;
source /var/lib/mysql/bookdb.sql;

看一下控制台的信息:
[root@localhost ~]# docker exec -it mysqlservice /bin/bash
root@c1f6b2849657:/# mysql -h127.0.0.1 -uroot -pxxx -t -P3306
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 5.7.20 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> use bookdb;
Database changed
mysql> source /var/lib/mysql/bookdb.sql;
Query OK, 0 rows affected (0.00 sec)
……
访问http://192.168.80.134:9000/odata/Books,检查结果。

从以上操作可以看出,手工导入数据库的方法是很麻烦的,所以最好的办法就是使用代码EnsureCreated()自动创建数据库。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值