asp.net core+mysql+nginx容器化部署

使用docker进行容器化部署和运维近两年时间了,有必要做个总结记录。这里从零开始由浅入深,最终完成asp.net core+mysql+nginx的容器化部署。

一、常用基础命令

查看镜像

docker images

查看容器

docker ps -a

查看容器内部详细信息

docker inspect <容器id/名称>

查看容器的ip

docker inspect <容器id/名称> | grep IPAddress

启停容器

docker start/stop/restart <容器id/名称>

删除容器

docker rm <容器id/名称>

删除所有容器

docker rm $(docker ps -qa)

删除镜像

docker rmi <镜像id/名称>

docker image rm <镜像id/名称>

查看容器日志

docker logs -f -t --tail 30 <容器id/名称>

-t,加入时间戳
-f,跟随最新的日志打印
--tail 数字n,显示最后n行

进入容器

docker exec -it <容器id/名称> /bin/bash

打包镜像。
如将当前目录打包成镜像,并命名为hello

docker build -t <镜像名称> <路径> 

docker build -t hello .

运行镜像。
如运行hello镜像,创建并运行容器hello-1

docker run --name <容器名称> -d -p 80:5000 <镜像名称>

docker run --name hello-1 -d -p 80:5000 hello 

-d,为后台任务形式运行,
-p,指定端口映射,本地端口:容器端口

修改容器后,提交生成一个新的镜像。
如将id:9a0c3f的容器提交为新的镜像hello:v1.0.1

docker commit <容器id/名称> <新的镜像名称[:tag]>

docker commit 9a0c3f hello:v1.0.1

查询默认镜像站点的镜像。
比如查询mysql相关镜像。
docker search <镜像名称> 

docker search mysql 

查询mysql镜像历史版本

curl https://registry.hub.docker.com/v1/repositories/mysql/tags | tr -d '[[]" ]' | tr '}' ' ' | awk -F: -v image='mysql' '{if(NR!=NF && $3 != ""){printf("%s:%s ",image,$3)}}'

二、Docker工具、镜像、Demo项目 

2.1 Docker工具

这里用到docker和docker-compose两个工具,安装过程不做赘述,仅展示测试的版本。

[app@test /]$ docker --version
Docker version 19.03.4, build 9013bf583a
[app@test /]$ docker-compose --version
docker-compose version 1.22.0, build f46880fe

2.2 镜像

这里用到mysql,nginx,asp.net core三个镜像。 

其中的mysql和nginx镜像直接通过命令 docker pull mysql和 docker pull nginx,从默认的docker镜像站点registry.hub.docker.com下载最新版本即可。 

asp.net core的镜像获取方式则略有不同,2018 年5月之后,微软将所有docker image都推送到了 MCR(Miscrosoft Container Registry),官方地址https://github.com/microsoft/containerregistry。按照官方说法,目前已经对全球多区域进行负载均衡以提供对MCR目录的可靠一致性访问,换句话说,不需要设置docker仓库地址等从各种国内镜像加速去下载了,我试验了下速度的确很快。

mcr仓库列表地址:https://mcr.microsoft.com/v2/_catalog,找到asp.net core的仓库为 dotnet/core/aspnet 

某个仓库内tags查询方式:
https://mcr.microsoft.com/v2/{namespace/repo}/tags/list
对应我们要查找的tag地址为:
https://mcr.microsoft.com/v2/dotnet/core/aspnet/tags/list

而mcr镜像下载的命令格式为:
docker pull mcr.microsoft.com/<namespace/repo>:<tag> 

相应的我们下载asp.net core v3.1.1镜像的命令最终就是:
docker pull mcr.microsoft.com/dotnet/core/aspnet:3.1.1 

当然,我们也可以直接在dockerhub进行搜索asp.net,直接获得下载命令。搜索链接为
https://hub.docker.com/search?q=asp.net&type=image

 可以看到主要有三个镜像,分别为

ASP.NET,对应dotnet framework的版本镜像
docker pull mcr.microsoft.com/dotnet/framework/aspnet
docker pull mcr.microsoft.com/dotnet/framework/aspnet:4.8
docker pull mcr.microsoft.com/dotnet/framework/aspnet:3.5

ASP.NET Core Runtime,对应dotnet core的版本镜像
docker pull mcr.microsoft.com/dotnet/aspnet
docker pull mcr.microsoft.com/dotnet/aspnet:5.0
docker pull mcr.microsoft.com/dotnet/aspnet:3.1

ASP.NET Core 3.1 Runtime属于ASP.NET Core Runtime的一个版本

 最后查看我们的镜像列表,其中 mcr.microsoft.com/dotnet/aspnet:3.1 就是我们要使用的镜像了,它与上面的 mcr.microsoft.com/dotnet/core/aspnet:3.1.1 都是.NET Core runtime,都不包括.NET Core SDK,仅仅版本有微小差别。

[app@test /]$ docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
nginx                                  latest              ad4c705f24d3        10 days ago         133MB
mysql                                  latest              0716d6ebcc1a        2 weeks ago         514MB
mcr.microsoft.com/dotnet/core/aspnet   3.1.1               e28362768eed        19 months ago       207MB
mcr.microsoft.com/dotnet/aspnet        3.1                 5d1ca8ae6edb        6 days ago          208MB
#mcr.microsoft.com/dotnet/core/aspnet:3.1.1镜像的容器内查看dotnet版本
root@490d942232fd:/app# dotnet --info It was not possible to find any installed .NET Core SDKs Did you mean to run .NET Core SDK commands? Install a .NET Core SDK from: https://aka.ms/dotnet-download Host (useful for support): Version: 3.1.1 Commit: a1388f194c .NET Core SDKs installed: No SDKs were found. .NET Core runtimes installed: Microsoft.AspNetCore.App 3.1.1 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 3.1.1 [/usr/share/dotnet/shared/Microsoft.NETCore.App] To install additional .NET Core runtimes or SDKs: https://aka.ms/dotnet-download
#mcr.microsoft.com/dotnet/aspnet:3.1镜像的容器内查看dotnet版本
root@cc2dad7798b3:/app# dotnet --info It was not possible to find any installed .NET Core SDKs Did you mean to run .NET Core SDK commands? Install a .NET Core SDK from: https://aka.ms/dotnet-download Host (useful for support): Version: 3.1.19 Commit: aae002469c .NET Core SDKs installed: No SDKs were found. .NET Core runtimes installed: Microsoft.AspNetCore.App 3.1.19 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 3.1.19 [/usr/share/dotnet/shared/Microsoft.NETCore.App] To install additional .NET Core runtimes or SDKs: https://aka.ms/dotnet-download

镜像仅仅包括runtime,不包括sdk,这样体积会比较小,当然  dotnet restore,dotnet run,dotnet publish 等sdk命令也就无法使用了,我们应在容器外进行 dotnet publish ,并将发布目录挂载共享到容器中构建运行。

2.3 Demo项目 

编写了简单的asp.net core mvc+mysql 的测试项目,已提交https://github.com/gitsongs/docker-demo,可以直接下载使用。

git clone https://github.com/gitsongs/docker-demo.git 

三、通过Dockerfile打包镜像

3.1 共享挂载卷

docker容器内部与宿主机是隔离的,如果我们运行asp.net core容器,并且每次进入容器里面部署源代码,这样很不方便,再者每次提交更新部署还要反复生成新的镜像也比较麻烦和耗时,如不提交镜像,容器一旦销毁那么容器内做的工作和数据就会丢失。而docker提供了挂载卷共享的功能,可以很好的应对这一问题。而且对于挂载卷目录或文件,对宿主机的文件修改会反应到容器内,反之对于容器内共享目录的文件修改不会影响到宿主机上,这体现了容器的隔离特性。这一功能在运维部署时可以用来持续构建(CI),基本思路是,首先通过git更新源码到宿主机上进行编译发布,然后将发布同步到挂载卷目录,最后在容器中构建运行,针对这个后续会单独写一篇文章进行详细介绍。

可以通过docker run命令中增加  -v <host目录:容器目录>  参数挂载共享卷。
docker run -it -v $HOME/docker-demo:/app mcr.microsoft.com/dotnet/core/aspnet:3.1.1 

这样容器内的/app目录就对应的是宿主机的 $HOME/docker-demo 目录了。

也可以通过后续的Dockerfile 或 docker-compose.yml 进行指定。

3.2 数据挂载卷

除了上述的共享宿主机目录的挂载卷,还有数据卷。比如mysql容器,一旦容器销毁,那么我们的数据库数据就会丢失,为了应对这种情形,可以创建数据卷,然后挂载到容器中以进行容器数据的持久化,这样即便容器销毁,数据卷可以保留。

#创建数据卷
$ docker volume create --name demo.db
#查找数据卷文件
$ find / -name "demo.db"
/var/lib/docker/volumes/demo.db
#查看数据卷信息
$ docker volume inspect demo.db
[
    {
        "Name": "demo.db",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/demo.db/_data",
        "Labels": {},
        "Scope": "local"
    }
]
# 挂载数据卷启动MySql实例
$ docker run --name docker-mysql -v demo.db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql

3.3 编辑Dockerfile

通过Dockerfile可以指定很多参数,用于打包镜像。比如可以通过挂载共享卷,将代码程序这一变量目录共享到容器中,而容器本质只是提供一个隔离的特定运行环境(下面的例子未采用这种做法)。

$cd ~/test
$git clone https://github.com/gitsongs/docker-demo.git
$cd docker-demo/docker-demo
$dotnet publish -c Release -o ./publish
$vim Dockerfile
$cat Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:3.1 WORKDIR /app COPY . /app ENV ASPNETCORE_URLS http://*:8881 ENV ASPNETCORE_ENVIRONMENT Production EXPOSE 8881 ENTRYPOINT /app/docker-netcore.start.sh
$cat docker-netcore.start.sh
#!/bin/bash
echo $(pwd)
dotnet /app/publish/docker-demo.dll 

int=1
while(( $int<=100 ))
do
    echo $int
    sleep 10s
    let "int++"
done

这里的Dockerfile,我们指定容器使用镜像 mcr.microsoft.com/dotnet/aspnet:3.1 ,容器工作目录为/app,并将当前上下文目录即宿主机的~/test/docker-demo/docker-demo复制到容器/app目录下,指定了相关环境变量,最后指定容器入口程序为 docker-netcore.start.sh ,文件内容也很简单,就是运行docker-demo程序,在最后面还增加了一段100*10s的耗时程序,是因为入口程序执行完毕后容器就会自动停止运行,这里的耗时程序就是为了在测试过程中,避免一些因素导致docker-demo程序启动失败,容器自动停止,这样我们可以有时间通过交互模式进入容器进行一些排查操作,比如进入容器查看 dotnet --info 或者ping一下其它容器以测试是否联通。

完成以上工作后,就可以打包镜像了,这里将我们的镜像命名为 docker-netcore-image 。
docker build -t docker-netcore-image . 

3.4 启动容器

接下来我们通过上面的镜像 docker-netcore-image 创建一个容器 docker-netcore 。查看项目docker-demo文件 appsettings.json ,可知项目依赖访问mysql数据库 docker-mysql ,所以要先创建一个mysql镜像的容器 docker-mysql ,而且两个容器要联通。

$ cat appsettings.json 
...
  "ConnectionStrings": {
    "MySql": "server=docker-mysql;database=DemoDb;uid=root;pwd=123456;"
  }
...

具体操作过程如下:

# 创建容器网络,以联通两个容器
$ docker network create -d bridge docker-net-test
# 查看容器网络
$ docker network ls
# 创建容器docker-mysql
$ docker run --name docker-mysql -d --network docker-net-test -e MYSQL_ROOT_PASSWORD=123456 mysql
# 创建容器
$ docker run --name docker-netcore -d --network docker-net-test docker-netcore-image
# 查看容器
$ docker ps -a
# 进入容器
$ docker exec -it docker-netcore /bin/bash
# 安装ping
$ apt-get update
$ apt install iputils-ping
# 测试与docker-mysql是联通的
$ ping docker-mysql
# 一切正常,测试项目,返回json结果
$ curl localhost:8881/home/test
[{"id":1,"name":"u5F20u4E09","sex":"u7537","birthday":"2000-08...}]

 四、通过docker-compose完成asp.net core+mysql+nginx容器化部署

docker-compose就像是容器的管家,用于定义和运行多容器。其使用yml文件来配置所有容器,最后使用一个命令就可以根据yml文件配置创建并启动所有容器服务。

我们的最终目的就是运行三个容器服务,使用docker-compose就会非常方便快捷,没有必要打包镜像再去运行。

配置docker-compose内容如下:

version: '2.2'
services:
  docker-mysql-service:
    container_name: docker-mysql
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    volumes:
      - ./mysql:/var/lib/mysql

  docker-netcore-service:
    container_name: docker-netcore
    build: .
    working_dir: /app
    depends_on:
      - docker-mysql-service
    links:
      - docker-mysql-service
    environment:
      - ASPNETCORE_URLS=http://0.0.0.0:8881
      - ASPNETCORE_ENVIRONMENT='Production'
    image: mcr.microsoft.com/dotnet/aspnet:3.1
    ports:
      - "127.0.0.1:8881:8881"
    volumes:
      - ~/test/docker-demo/docker-demo:/app
      - /etc/localtime:/etc/localtime
    entrypoint: /app/docker-netcore.start.sh
  
  reverse-proxy-service:
    container_name: docker-nginx
    image: nginx
    depends_on:
      - docker-netcore-service
    ports:
      - "5050:8080"
    volumes:
      - ./proxy.conf:/etc/nginx/conf.d/default.conf

配置nginx的proxy.conf内容如下:

server {
    listen 8080;
    location / {
      proxy_pass http://docker-netcore-service:8881;
    }
}

最终操作过程:

$ docker-compose up -d
Creating network "docker-demo_default" with the default driver
Creating docker-mysql ... done
Creating docker-netcore ... done
Creating docker-nginx   ... done
$ docker ps -a
CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS              PORTS                            NAMES
10be2df533b0        nginx                                 "/docker-entrypoint.…"   15 seconds ago      Up 14 seconds       80/tcp, 0.0.0.0:5050->8080/tcp   docker-nginx
d2699558111a        mcr.microsoft.com/dotnet/aspnet:3.1   "/app/docker-netcore…"   16 seconds ago      Up 15 seconds       127.0.0.1:8881->8881/tcp         docker-netcore
d907b9c112af        mysql                                 "docker-entrypoint.s…"   17 seconds ago      Up 16 seconds       3306/tcp, 33060/tcp              docker-mysql
$ curl localhost:5050/home/test [{"id":1,"name":"u5F20u4E09","sex":"u7537","birthday":"2000-08-15..."}]
原文地址:https://www.cnblogs.com/jiujiduilie/p/15310659.html