使用Docker Compose快捷部署WEB服务、分布式任务队列项目实践

项目地址:GItHub

介绍

Docker 容器技术解决了项目部署时开发、测试、预演、生产环境差异的影响。
可以为项目的不同服务创建独立的容器,使项目模块化,降低了耦合性。
当同一宿主机中存在多个容器时,容器的统一管理便显得很必要。
Docker Compose具有管理多个容器的功能,Docker Compose通过调用Docker的接口,从 yaml 文件中读取容器配置,对容器进行统一管理。

项目架构 HaProxy + Django + Celery + MySQL + Redis

  • HaProxy,作为项目的代理程序,将请求转发至web服务器,并可以实现负载均衡;

  • Django,提供web服务,在接口中调用Celery创建任务,作为生产者,在任务函数中执行任务,作为消费者;

  • Celery,提供分布式任务队列服务;

  • MySQL,为web服务提供数据库服务,存储Celery的处理结果;

  • Redis,作为Celery的消息中间件,也可作为web的缓存服务器。

分析 docker-compose.yaml

Redis

项目中用到了Redis作为web缓存与Celery的消息中间件,此处使用redis镜像创建redis-server容器。
如果使用外部的redis-server可注释掉Redis容器配置。

MySQL

项目的数据库使用MySQL,为web服务于Celery任务队列提供存储。此处使用mysql/mysql-server:5.7镜像创建容器(查看原因?)。
如果使用外部的mysql-server可注释掉MySQL容器配置。

Web

web容器负责提供web服务,使用的web框架是Django,镜像是基于Ubuntu,安装PythonMysql-Client等系统软件与DjangoCeleryRedisUwsgiPython第三方库的自定义镜像。
可以查看我自定义镜像的Dockerfile,镜像的配置确实完整,但Ubuntu:18.04在配置时区时不能自动通过,与Ubuntu:16.04有区别。
所以不能根据这个Dockerfile打包镜像。我是创建Ubuntu:18.04的容器,安装软件后,根据容器打包镜像。

指定镜像后,使用volumes参数将项目的web目录挂在到容器内,并使用working_dir参数设置工作目录。
由于项目中HaProxy进行了负载均衡代理,所以并不需要暴露端口,如需映射端口到宿主机可以将ports参数设置为8000:8000。

在web容器中需要链接mysql容器与redis容器中的服务,所以用depends_on制定依赖的容器,这样会先启动mysql容器与redis容器,再启动web容器,并且在web中使用’mysql’、’redis’即可连接到对应的服务。

在web项目中有一些关键的配置参数,我们可以通过环境变量传入,这样通过docker-compose.yml文件即可管理项目配置。此处我们传入了,Django项目秘钥,MySQL的服务主机地址即’mysql’字符串,与mysql容器一致的root用户密码,创建好的数据库名称,Redis服务主机地址即’redis’字符串。

最后是容器启动后执行的命令:

1
sh ./run.sh

因为将web目录挂在到了容器内,并且工作目录与项目目录相同,所以run.sh脚本在容器的当前目录下。我们来看下次脚本:

1
2
3
4
python3 manage.py makemigrations
python3 manage.py migrate
uwsgi --ini /usr/src/app/web/uwsgi.ini
tail -f /usr/src/app/logs/uwsgi.log

因为不知道是否是第一次运行容器,所以加了迁移命令,第一次运行时会在数据库中创建所需的表。之后运行也不会引起错误。

然后使用uwsgi启动项目。最后监听uwsgi日志文件,并输出到终端,这样才不会使容器退出。

Celery

celery任务队列的代码是写在Django项目中的,使用了web容器相同的环境与配置。唯一的区别是容器启动后的运行命令。

HaProxy

haproxy是一个性能极高的代理软件,我们在这里用作负载均衡的转发工作。这里使用了dockercloud/haproxy镜像,将容器80端口映射至宿主机的80端口,并指定连接的容器名web,更多用法可以查阅dockercloud/haproxy镜像页面描述。

启动项目

初始化MySQL

这里会创建一个MySQL数据库,方便Django服务端连接。

1
2
3
docker-compose -f docker-compose-mysql.yaml up -d

mysql -u root -h 0.0.0.0 -p

执行SQL,创建数据库,修改时区。

1
2
CREATE DATABASE mydb CHARACTER SET utf8 COLLATE utf8_general_ci;
SET time_zone = 'Asia/Shanghai';

如果你有一个远程的MySQL服务器,可将docker-compose.yaml中mysql容器及对mysql容器的依赖注释掉,并在docker-compose.yaml中将web容器与celery容器环境变量参数environmentMYSQL_HOST的数值修改为远程MySQL的IP。

启动项目

这里会为 mysql、web、redis、haproxy创建容器。

1
docker-compose up -d

因为Haproxy的存在,可以开启多个web容器,支持负载均衡。

1
docker-compose up -d --scale web=2

访问页面

打开浏览器,访问 http://0.0.0.0/ ,创建一个运算任务、任务执行结束后,页面会刷新任务列表。

删除所有容器

1
docker-compose down