在上一part《把AspDotNetCoreMvc程序运行在Docker上-part4:实现负载均衡》中,咱们经过几个比较复杂的步骤在docker平台上实现了对网站程序的负载均衡,配置步骤比较多。若是实际的站点较少,整个架构比较简单的状况下,这么作没有太大问题,若是应用较多的时候,会容易出错。那么这时候咱们可能会想到本身写一些脚原本实现自动化,固然这是可行的。然而docker已为咱们着想好,给咱们提供了docker-compose功能,利用它咱们能够实现对复杂应用的管理,包括容器、网络、volume等。html
准备工做node
先删除上一part咱们建立的容器、网络和volume(不用以为惋惜,后面用上docker-compose能够轻易实现)mysql
docker rm -f $(docker ps -aq)
docker network rm $(docker network ls -q)
docker volume rm $(docker volume ls -q)linux
安装docker-composegit
在linux平台上须要手动执行以下命令安装github
sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-composesql
sudo chmod +x /usr/local/bin/docker-composedocker
(最新版本能够从这里https://github.com/docker/compose/releases获知)数据库
安装以后,运行docker-compose –version检查是否成功npm
准备MVC站点程序
能够从这里下载
https://github.com/shenba2014/AspDotNetCoreMvcDocker/tree/docker-compose
而后执行
dotnet restore
bower install
一会用到这个站点程序建立一个镜像以及对应的容器
建立docker-compose配置文件
新建docker-compose.yml文件(在docker所在宿主服务器直接建立也能够)
version: "3"
volumes:
productdata:
networks:
frontend:
backend:
services:
mysql:
image: "mysql:8.0.0"
volumes:
- productdata:/var/lib/mysql
networks:
- backend
environment:
- MYSQL_ROOT_PASSWORD=password
- bind-address=0.0.0.0
这个文件足够的自描述,把上一节咱们用到的内容都做出了定义,仍是简单解释一下
version:版本号,目前最新的是3.0
volumes:以前的《把AspDotNetCoreMvc程序运行在Docker上-part3:使用独立的存储容器》里面有介绍过,用于在docker容器外存储数据
networks:在上一part说过,定义了两个网络:frontend和backend
services:定义将要用到的容器,这里只定义了mysql容器,这些参数跟使用docker create命令建立容器的参数一致。具体可参考上一part《把AspDotNetCoreMvc程序运行在Docker上-part4:实现负载均衡》。
docker-compose执行构建
执行以下构建命令
docker-compose –f docker-compose.yml build
输出结果
WARNING: Some networks were defined but are not used by any service: frontend, backend
mysql uses an image, skipping
这里的警告信息意思是咱们定义的两个网络还没被任何服务组件使用。
运行了这个命令只是定义,并无真正的建立volume、network或者容器。
接下来运行docker-compose.yml定义的应用,才会真正的建立内容
docker-compose -f docker-compose.yml up
能够理解为启动刚才咱们定义的组件,而后会有一堆的输出内容
WARNING: Some networks were defined but are not used by any service: frontend
Creating network "dockertemp_backend" with the default driver
Creating dockertemp_mysql_1 ...
Creating dockertemp_mysql_1 ... done
Attaching to dockertemp_mysql_1
很明显docker-compose在依次建立network、容器实例。
名字看起来比较奇怪,都带了dockertemp_前缀。由于docker-compose.yml所在的目录命令是dockertemp,因此最终提供的名称有这个前缀,避免了命名冲突。
而为何是mysql_1,带有_1后缀,后续会用到,这里是为了用于横向扩展作集群的时候用到。
进一步经过以下命令验证volume、network和容器是建立成功的
docker volume ls
docker netowrk ls
docker ps –a
使用docker-compose –f docker-compose.yml down -v可删除network、容器和volume,全自动完成(保存在volume的数据也会删除,若是要保留volume把-v去掉便可)。
如今docker-compose文件里只定义了一个service,接下来继续添加MVC站点容器以及负载均衡容器。
添加MVC站点容器以及负载均衡容器
首先从如下路径下载代码
https://github.com/shenba2014/AspDotNetCoreMvcDocker/tree/docker-compose
这个分支跟以前的不同,增长了对支持docker-compose的一些改动。
代码拉下来以后执行以下命令
dotnet restore
dotnet publish --framework netcoreapp2.0 --configuration Release --output dist
cd dist | npm install
dist文件夹里的内容就是咱们后续要用到的MVC站点内容。
从源代码查看完整的docker和docker-compose.yml文件
先看看docker文件的更新内容
FROM microsoft/aspnetcore:2.0.0
COPY dist /app
COPY dist/node_modules/wait-for-it.sh/bin/wait-for-it /app/wait-for-it.sh
RUN chmod +x /app/wait-for-it.sh
WORKDIR /app
EXPOSE 80/tcp
ENV WAITHOST=mysql WAITPORT=3306
ENTRYPOINT ./wait-for-it.sh $WAITHOST:$WAITPORT --timeout=0 && exec dotnet AspDotNetCoreMvcDocker.dll
红色部分是新增的内容,这里拷贝了一个wait-for-it的脚本到了容器内部,而且在ENTRYPOINT里设置了等待mysql启动以后再启动MVC容器。
简单解释一下,由于使用了docker-compose启动容器以后,咱们不能确保mysql容器服务是否已正常启动,若是mysql没有启动,那么站点也无法使用。因此容器必须在mysql容器启动以后执行,这里就引入了一个npm的package:wait-for-it,这个只能在Linux平台下使用。
接下打开完整的docker-compose.yml文件,这里只列出新增的service(完整文件内容不列出,可查看代码)
dbinit:
build:
context: .
dockerfile: Dockerfile
networks:
- backend
environment:
- INITDB=true
- DBHOST=mysql
- DBPASSWORD=password
depends_on:
- mysql
mvc:
build:
context: .
dockerfile: Dockerfile
networks:
- backend
- frontend
environment:
- DBHOST=mysql
- DBPASSWORD=password
depends_on:
- mysql
loadbalancer:
image: dockercloud/haproxy
ports:
- 3000:80
links:
- mvc
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- frontend
这里才原来的基础上增长了dbinit,mvc和loadbalancer三个service,分别描述以下
dbinit:主要是用于初始化数据库,这里是把它当作一个容器来执行,实际在完成了数据库初始化自后就会退出。
mvc:这里就是MVC站点的容器,跟咱们上一part定义MVC的参数相似。主要是增长了depends_on参数,指明mvc容器依赖于mysql容器。
loadbalancer:顾名思义,就是负载均衡服务器容器,经过links参数指向了其代理的站点是MVC容器,而且经过volumes参数配置了/var/run/docker.sock文件映射为主机的文件,具体做用不描述,主要是为了在扩容的时候通知到负载均衡服务器。
启动站点
把上一步的dist文件夹docker、docker-compose.yml文件拷贝到docker服务器(若是开发机就是docker服务器能够忽略),而后在这些文件的所在目录执行以下命令
docker-compose -f docker-compose.yml build
这个命令以前提到过,相似于编译,检查是否有错误,实际上不会建立容器
接着运行
docker-compose -f docker-compose.yml up dbinit
开启dbinit容器,以前咱们提到,这个dbinit也是个MVC容器,可是只是负责数据库初始化,完成以后会自动关闭,这是这个命令的output
Creating network "dockertemp_frontend" with the default driver
Creating network "dockertemp_backend" with the default driver
Creating volume "dockertemp_productdata" with default driver
Creating dockertemp_mysql_1 ...
Creating dockertemp_mysql_1 ... done
Creating dockertemp_dbinit_1 ...
Creating dockertemp_dbinit_1 ... done
Attaching to dockertemp_dbinit_1
dbinit_1 | wait-for-it.sh: waiting for mysql:3306 without a timeout
dbinit_1 | wait-for-it.sh: mysql:3306 is available after 16 seconds
dbinit_1 | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
dbinit_1 | No XML encryptor configured. Key {1b1e827d-d1d0-4d0c-a92d-8632ee0791ef} may be persisted to storage in unencrypted form.
dbinit_1 | Preparing Database...
dbinit_1 | Applying Migrations...
dbinit_1 | Creating Seed Data...
dbinit_1 | Database Preparation Complete
dockertemp_dbinit_1 exited with code 0
从output能够看到有一个等待mysql启动的步骤,等待了16秒。而后是执行了数据库初始化,建立表以及插入一些种子数据。最后一个行输出代表该容器自动退出。
好了数据库准备好以后,就能够启动MVC和负载均衡容器,仍是经过docker-compose命令
docker-compose -f docker-compose.yml up mvc loadbalancer
执行完成以后,就能够访问咱们的MVC站点了,这里咱们只启用了一个MVC站点,试试从浏览器打开http://192.168.115.136:3000/,一切正常的话就能看到网站和数据了
作了这么多步骤,就是为了实现负载均衡,接下来一行命令让他当即扩容到4个MVC站点
docker-compose -f docker-compose.yml scale mvc=4
秒级扩容就是这简单,不信的话运行docker ps看看下面是否是有4个MVC站点容器,还不相信的话手动多刷几回http://192.168.115.136:3000/,会发现from server的值是会发生变化的。
好了,若是这时候要实现优雅降级怎么办,没问题,仍是一行命令
docker-compose -f docker-compose.yml scale mvc=1
系统自动移除了三个MVC站点容器,固然也是秒级的。
最后关闭全部服务的命令是
docker-compose -f docker-compose.yml stop
写了这么多就是为了描述docker-compose的使用方法,对比上一part,实际上就是把以前的工做都放到一个批处理文件里执行,将全部服务当作一个总体来管理,同时也提供了遍历站点扩容和降级的方式。看起来已经很方便了,固然还没完,后续还有大招。