本文主要介绍一下如何在Docker中发布.NET Core 3.x 并对整个过程所遇到的问题加以记录和分析.
环境、工具、准备工作
- 服务器: VM中安装CentOS, 内核版本3.10.x;
- 客户端: Windows 10;
- IDE: VS2019
- SFTP客户端: FileZilla; 用来进行文件传输;
- SSH工具: Putty; 用来在Windows 上远程访问CentOS;
- 本文示例均为Root权限;
- 因为是本地环境,所以防火墙是关闭状态,如果没有关闭防火墙,端口映射的时候记得处理.
Docker安装 (如已安装可忽略)
参考官方文档
1. 卸载删除旧Docker版本,使用如下命令;
yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
2. 安装 yum-config-manager ,DeviceMapper(了解D
eviceMapper
) 和 lvm2(了解lvm2); 使用如下命令:
yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
3. 设置仓库地址; 使用如下命令:
//官方地址: yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo //阿里云(建议): yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4. 安装社区版Docker, 使用如下命令: (如需安装指定版本请参考官方文档)
yum install docker-ce docker-ce-cli containerd.io
5. 启动Docker, 使用如下命令:
//设置开机自动启动docker systemctl enable docker //启动docker systemctl start docker
6. 运行测试, 使用如下命令:
docker version
Docker发布.NET Core MVC
1. 使用VS2019创建.NET Core MVC, 选不选择Docker 支持都无所谓,重要的是Dockerfile. (Dockerfile学习)
2. 编写Dockerfile, 并设置始终复制到目录; Dockerfile内容如下:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 WORKDIR /app COPY . . EXPOSE 80 ENTRYPOINT ["dotnet", "TestMVC.dll"]
说明:
2.1 如果创建项目时选择了Docker支持, 请将内容修改为上面内容(主要为方便理解);
2.2 Dockerfile 路径默认先放置在Project 下,并设置始终复制到目录; 文件路径并非一定要在Project下,但是这样对初学者好理解;
2.3 着重说明下EXPOSE选项:
可以不设置,该选项只是告诉镜像使用者容器准备以什么协议暴露哪个端口号,实际运行是不发布端口的;相当于描述信息(Docker Run -p);
Docker Run -P 命令会使用到该选项,后面介绍;
2.4 官方基础镜像库 https://hub.docker.com/_/microsoft-dotnet-core 根据自己需要选择
3. 发布项目并上传到CentOS;
4. 使用命令构建镜像: (Build命令学习)
进入项目发布目录:
cd /home/publish
构建镜像:
docker build -t testmvc:v1 .
注意: . 号不能丢失, 表示当前目录
查看镜像信息:
docker images
5. 使用命令运行容器: (Run命令学习)
docker run -d -p 5000:5000 --name testmvc testmvc:v1
查看容器:
docker ps -a
容器启动, 这个时候我们的.NET Core MVC就算发布完了, 在浏览器输入http://你的服务器地址:5000 访问程序, 你会惊喜的发现,无论怎么访问你都访问不到, 是不是很意外?
为什么会访问不到呢? 这也是初学者踩的最多的坑, 目前网上大部分博文的部署都是上面的流程, 你部署下来会发现无论如何都访问不到, 很少有讲解为什么, 其实原因很简单,我们使用命令来看看为什么:
docker logs testmvc
根据log我们发现我们的程序是正常运行了, 但是仔细看内容, .NET Core 程序默认监听的是localhost:5000 和 localhost:5001 而localhost 是回环网络地址, 而我们的容器和宿主机是隔离的, 所以即便我们将容器端口和宿主机端口进行了映射绑定, 宿主机依然无法访问容器内的应用.
解决方案有以下四种(顺序既是优先级,任选一种即可)
(1) 在程序Program.cs修改程序端口监听配置;
(2) 修改Dockerfile的ENTRYPOINT参数;
(3) 启动容器设置应用监听端口;
docker run -d -p 5000:5000 -e ASPNETCORE_URLS=http://+:5000 --name testmvc testmvc:v1
(4)设置Dockerfile的环境变量;
以上四种方式都可以重新设置应用程序端口监听,四种情况共存的话1最优先,4最后;一般建议使用3, 方便各种容器编排工具进行动态管理;
停止之前运行的容器,并删除;
//停止运行的镜像 docker stop testmvc //删除已经创建的容器 docker rm testmvc
使用第三者方案重新创建运行容器, 并测试, 你会发现我们的应用程序已经可以正常的访问了.
最后我们再来解析下Dockerfile的EXPOSE的作用;
使用命令来查看我们的容器配置信息:
docker inspect testmvc
我们会看到以下配置信息:
使用查看容器命令来看容器启动信息:
docker ps
从以上内容来看,EXPOSE定义的端口,并未暴露给宿主机, 这也是我们上面说的EXPOSE实际并不发布端口,仅相当于描述信息;
我们在启动容器时使用了-p 5000:5000 意义是将容器的5000端口和宿主机5000端口进行绑定;
但是 docker run还有一个参数 -P ,我们使用以下命令:
docker run -d -P --name testmvc1 testmvc:v1
你会发现有一个随机的端口和EXPOSE暴露的80端口进行了绑定,如果这个时候你的应用程序默认监听了80端口, 则就可以使用http://服务器地址:32768进行程序访问了
这就是EXPOSE的作用;