四、注册Docker账号
注册一个账号(可选项),地址:Docker Hub ,可以在上面建自己的仓库。
五、创建一个ASP.NET Core 项目,生成并运行Docker镜像
新建一个名为DockerComposeDemo的API项目,直接发布,拷贝发布的文件到CentOS系统中,例如/home/aspcore目录。并在该目录新建一个文本文件名为Dockerfile,内容如下:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base WORKDIR /app EXPOSE 80 COPY . . ENTRYPOINT ["dotnet", "DockerComposeDemo.dll"]
含义是:引用包含3.0运行时的镜像,这个镜像在远程仓库中,若本地没有提前pull下来,会先执行pull操作获取到本地。然后将工作目录设为/app , 拷贝发布的项目文件,设置进程的入口是通过dotnet运行DockerComposeDemo.dll。
执行如下命令:
cd /home/aspcore docker build -t dockertest .
注意第二行后后面有个'.'不能少。 含义就是按照Dockerfile文件中设置的规则生成名为dockertest的镜像。
此时执行docker images命令可以看到本地镜像中已经有了 mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim 和 dockertest 两个镜像。
运行这个镜像生成容器:
docker run --name aspdocker -p 8080:80 -d dockertest
生成一个名为aspdocker 的容器,并将容器的80端口映射到主机的8080端口。访问项目默认提供的controller:http://192.168.183.230:8080/WeatherForecast
可以看到能正常访问。
六:使用docker-compose
因为一个Docker容器只建议运行一个应用,那么一个项目就可能会存在多个容器被运行,可能包含多个项目、数据库等,这时候就需要对这些容器进行统一的管理,从构建运行开始到运行后状态的监控等。
这时候有个简易的方法就是docker-compose,它可以完成多个Docker的统一管理,包括Docker镜像构建、容器运行、相关配置以及Docker之间的依赖关系等。
下面举个简单例子,这个DockerComposeDemo项目需要搭配一个MongoDB数据库,这样除了该项目外还需要一个Docker容器运行MongoDB数据库。
这时候用docker-compose就方便多了。docker-compose的核心是docker-compose.yml文件,看一下对应这个例子的文件内容:
version: '3.4' services: demomvc: image: thisdemoimage build: context: . dockerfile: Dockerfile environment: - ASPNETCORE_DBCONN=mongodb://192.168.183.230:27089 - ASPNETCORE_DBNAME=dockerdb ports: - "5103:80" depends_on: - mongodocker mongodocker: image: mongo ports: - "27089:27017"
在services节点下定义了demomvc和mongodocker两个服务,一个是ASP.NET Core的项目,一个是MongoDB数据库。
每个节点下的image参数指定了采用的镜像名称,ports指定端口映射。此处的MongoDB设置未涉及持久化,实际使用时要注意设置。
ASP.NET Core的项目的thisdemoimage镜像是不存在的,下面指定了build方法。当然也可以先创建好镜像然后在这里使用就像mongo服务的设置一样。
depends_on表示本服务对另一个服务的依赖,本例中就是ASP.NET Core项目依赖MongoDB项目。
environment用于设置环境变量,作用是什么呢?
有一些设置,比如本例中的数据库连接,如果将连接字符串写在了项目中的appsettings.json中,而这个文件被“固化”到镜像中了,是不能修改的,除非重新生成镜像,非常麻烦。
所以可以通过这样的环境变量在外面设置。
将项目引用NuGet包MongoDB.Driver, 修改WeatherForecastController的get方法:
[HttpGet] public IEnumerable<WeatherForecast> Get() { var rng = new Random(); _mongoHelper.InsertOne(new WeatherForecast { Date = DateTime.Now.AddDays(1), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }); return _mongoHelper.FindList<WeatherForecast>(); }
每次都是先插入一条,然后返回所有记录。这里简要的写了一个mongoHelper:
public class MongoHelper { private readonly IMongoDatabase database; public MongoHelper(IConfiguration configuration) : this(configuration["ASPNETCORE_DBCONN"], configuration.GetSection("ASPNETCORE_DBNAME").Value) { } public MongoHelper(string ConnectionString,string DBName) { MongoClient mongoClient = new MongoClient(ConnectionString); database = mongoClient.GetDatabase(DBName); } public List<T> FindList<T>(FilterDefinition<T> filter = null, string collectionName = null) { collectionName ??= typeof(T).Name; filter ??= new BsonDocument(); var collection = database.GetCollection<T>(collectionName); return collection.Find(filter).ToList(); } public void InsertOne<T>(T model, string collectionName = null) { collectionName ??= typeof(T).Name; var collection = database.GetCollection<T>(collectionName); collection.InsertOne(model); } }
连接字符串采用 IConfiguration中的设置。
这里有个不算技巧的技巧,为了方便在非Docker的情况下测试,依然可以在appsettings.json文件中设置MongoDB的连接字符串,当部署到Docker中的时候,通过Docker环境变量配置的连接字符串会覆盖appsettings.json中的配置。
这是因为在讲述IConfiguration的文章中说过,系统是先加载appsettings.json中的设置,后加载环境变量中的设置的,二者的key相同,所以最终会以环境变量中的配置为准。
重新发布项目并将文件拷贝到/home/aspcore目录,其中的dockerfile文件不变,添加本例中的docker-compose.yml文件。
docker-compose是需要单独下载安装的, 执行命令:
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
如果提示权限错误,需执行如下命令:
sudo chmod +x /usr/local/bin/docker-compose
安装好之后执行 docker-compose --version 验证是否安装成功。
都准备好了,执行如下命令:
cd /home/aspcore
docker-compose up
执行成功后访问 http://192.168.183.230:5103/WeatherForecast