MoEar¶
概览¶
部署说明¶
本项目实现了基于 Docker 的容器部署方式,如果您对 Docker 足够熟悉,相信您会感受到丝般顺滑。
如果您不是很了解 Docker ,强烈建议您学习一下,真的找不到比这个更赞的部署方案了(安利脸~~
环境搭建¶
唯一需要的环境就是 Docker 以及 docker-compose ,关于 Docker 我曾经参考官方文档编写过一个搭建教程,如果您是 Ubuntu 系统,可以参考一下 《Ubuntu安装部署Docker》 , 但是仍然更推荐您阅读 docker官方安装文档
docker-compose 的安装方法很多,您可以参考 docker-compose官方安装文档
部署文件¶
项目部署文件路径如下:
.
├── docker-compose.yml
├── env
│ └── moear.env
└── volumes
└── web
└── config
├── db
│ └── mysql.conf
└── nginx
└── nginx.conf
下面将逐一介绍相应文件的配置方式,以及用例
docker-compose.yml¶
该文件为 docker
的装配文件,基本不需要修改,直接在目标服务器中的项目路径下创建即可。
创建路径:
$ mkdir -p path/to/project
$ touch docker-compose.yml
将下列内容写入到 docker-compose.yml
文件中:
version: '2'
services:
moear:
image: littlemo/moear
container_name: moear-server
hostname: moear-server
restart: unless-stopped
ports:
- "8888:8000"
networks:
- frontend
- backend
volumes:
# 挂载运行时路径(其中包含日志、归集的静态文件)
- ./volumes/runtime:/app/runtime:rw
- ./volumes/runtime/log/nginx:/var/log/nginx:rw
# 挂载扩展插件路径,仅支持 wheels 格式的 Python 包
- ./volumes/plugin:/app/requirements/wheels:ro
# 挂载配置文件
- ./volumes/web/config/db/mysql.conf:/app/server/server/config/db/mysql.conf:ro
- ./volumes/web/config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
env_file:
- env/moear.env
depends_on:
- mysql
- redis
redis:
image: redis:alpine
container_name: moear-redis
hostname: moear-redis
restart: unless-stopped
networks:
- backend
volumes:
# 数据库数据文件路径
- ./volumes/redis/data:/data
mysql:
image: mysql
container_name: mysql
restart: unless-stopped
volumes:
- ./volumes/conf.d:/etc/mysql/conf.d:ro # my.cnf 之后,额外的配置文件,用于覆盖 my.cnf 中的配置项
- ./volumes/initdb:/docker-entrypoint-initdb.d # 用于初始化数据库时执行的 .sh, .sql & .sql.gz
- ./volumes/datadir:/var/lib/mysql # 数据库数据文件路径
networks:
- backend
environment:
MYSQL_ROOT_PASSWORD: root_pwd
MYSQL_DATABASE: moear
MYSQL_USER: moear
MYSQL_PASSWORD: moear_pwd
character-set-server: utf8mb4
collation-server: utf8mb4_unicode_ci
TZ: Asia/Shanghai
entrypoint: docker-entrypoint.sh
networks:
frontend:
backend:
注意
该配置文件会在启动时创建一个 MySQL
实例,并创建指定的数据库、用户、密码,
如果您有需要可以自行修改数据库配置
moear.env¶
此文件为 docker 具体容器实例中的环境变量,配置如下:
# General
SERVER_SETTINGS=server.settings
SECRET_KEY=adb7t$a%t_sxb5lji=lxr&%q$3)@1rk_%wi#t!@7zy^17k7iua
ALLOWED_HOSTS=localhost,127.0.0.1
# Tips: 该逻辑会在安装时执行创建超级管理员用户,若目标用户已存在,则仅执行密码修改操作
ADMIN_USERNAME=admin
ADMIN_EMAIL=
ADMIN_PASSWORD=whoisyourdaddy
# EMAIL
EMAIL_HOST=
EMAIL_PORT=
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
EMAIL_USE_SSL=
EMAIL_TIME_LIMIT=30
DEFAULT_FROM_EMAIL=
# Switch
DEBUG=False
PRODUCTION=True
# Celery
CELERY_BROKER_URL=redis://moear-redis:6379/0
CELERY_RESULT_BACKEND=redis://moear-redis:6379/0
CELERY_WORKER_CONCURRENCY=2
CELERY_WORKER_CONCURRENCY_EMAIL=1
CELERY_WORKER_CONCURRENCY_CRAWL=1
CELERY_WORKER_PREFETCH_MULTIPLIER=1
CELERY_BEAT_LOG_LEVEL=INFO
CELERY_BEAT_LOG_FILE=/app/runtime/log/celery/celeryd.log
CELERY_WORKER_LOG_LEVEL=INFO
CELERY_WORKER_LOG_FILE=/app/runtime/log/celery/%n%I.log
留空的配置需要您填入,另外需重点关注的配置项说明如下
- SECRET_KEY
- 需修改为一个随机值,如果您不修改,站点安全性将大大下降
- ALLOWED_HOSTS
- 如果您需要使用域名访问的话,需要将其添加到此处,多个允许值可使用
,
连接 - ADMIN_USERNAME / ADMIN_EMAIL / ADMIN_PASSWORD
- 管理员账户配置,用户名&密码可按您需求修改
- EMAIL_HOST / EMAIL_PORT / EMAIL_HOST_USER / EMAIL_HOST_PASSWORD / EMAIL_USE_SSL / DEFAULT_FROM_EMAIL
- 邮件服务器配置,这是必须的,不然启动后服务器无法向您的管理员账户发送验证邮件, 且无法向您的 Kindle 发送投递邮件
mysql.conf¶
数据库配置文件如下:
[client]
host = mysql
database = moear
user = moear
password = moear_pwd
default-character-set = utf8mb4
注意
若您在之前的 docker-compose.yml
的 MySQL 配置中修改了数据库配置,
此处需做相应修改,若未修改,则可直接使用
nginx.conf¶
此文件是最应该被优化掉得,由于我没有找到一个好的低成本设置 Nginx.conf
中 server_name
字段值的方式,故此处为保证 Nginx
可以正常处理外部请求中的 host 需添加配置如下:
worker_processes 3;
user root root;
# 'user nobody nobody;' for systems with 'nobody' as a group instead
pid /tmp/nginx.pid;
error_log /app/runtime/log/nginx/nginx.error.log;
events {
worker_connections 1024; # increase if you have lots of clients
accept_mutex on; # set to 'on' if nginx worker_processes > 1
use epoll; # to enable for Linux 2.6+
# 'use kqueue;' to enable for FreeBSD, OSX
}
http {
include mime.types;
default_type application/octet-stream;
access_log /app/runtime/log/nginx/nginx.access.log combined;
sendfile on;
upstream app_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
# for UNIX domain socket setups
# server unix:/tmp/gunicorn.sock fail_timeout=0;
# for a TCP configuration
server 127.0.0.1:8000 fail_timeout=0;
}
server {
listen 80 default_server;
return 444;
}
server {
listen 80;
client_max_body_size 4G;
# set the correct host(s) for your site
server_name localhost;
keepalive_timeout 5;
# path for static files
location /static/ {
root /;
rewrite ^/static/(.*)$ /app/runtime/static/$1 break;
access_log off;
}
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
}
将 server_name localhost;
修改为您的相应域名即可,多值可通过空格间隔
待处理
此处配置极度不够优雅,一定要找到更优雅的解决方案把这步毙掉!哼(ˉ(∞)ˉ)唧
构建容器¶
完成上述准备工作后,构建容器就很简单了, docker-compose
的基础操作:
$ cd path/to/project
$ docker-compose up -d
另外, docker-compose
还支持很多实用的运维工具,您可以自行了解学习
剩下的就是用浏览器访问站点( http://127.0.0.1:8888
),完成账号的邮箱认证,执行文章订阅,
以及配置 Kindle 收件地址等操作了,此处不再一一赘述
提示
列出几个常用命令:
$ docker-compose stop # 停止服务
$ docker-compose start # 启动服务
$ docker-compose down # 销毁容器
$ docker-compose up # 构建容器
系统设计¶
提示
下图中除了 deliver
其他实体都是可点击的哦,会在新标签页中打开相应的包文档页。
系统架构设计图¶
提示
抓取与打包功能均以插件形式实现,便于扩展和替换,投递系统由于比较固定,于是实现在了主服务中。
待处理
关于投递系统,为实现节省流量的目的,实现时做了合并投递,即多人订阅了同一个文章源, 会在该文章当日爬取后合并为一封邮件,加入多个收件地址的形式进行投递。小规模情况下测试正常, 没有问题,但作者在网上(非官网)看到了一些 Kindle 的投递限制,由于不便测试,故先记录在下:
- 一份邮件超过15个不同的【发送至Kindle】电子邮箱,会被认定为垃圾邮件而被Amazon拒绝接收
- 附加大于50MB会投递失败
以上两点未经确认,故暂不为其做应对处理
其实第二点是可以测试的,但一般情况下应该遇不到这么大的文章,而且吧。懒。。懒。。。(溜了
模型设计¶
提示
下图为 SVG
的矢量图,点击可放大查看
提示
具体数据模型字段信息,可查看相应应用 models
中的定义,此处不再赘述
注解
从模型 ER 图中您也可以看出,原本设计的功能很多,但考虑到开发周期,目前只实现了最核心的功能。 关于文章管理、分类系统等,会在之后版本中陆续实现,但愿不会烂尾(羞~
插件开发¶
为保证足够的松耦合设计,本项目采用了基于 stevedore 的扩展插件实现方式。
现支持两种插件,entry_points
列出如下:
- 爬虫插件:
moear.spider
- 打包插件:
moear.package
两种插件均提供了默认参考实现,下面分章节进行简要说明
爬虫插件¶
爬虫插件作为文章来源的提供者,主要责任为抓取某一特定文章源中的文章数据,并返回规定的数据结构。
具体协议与接口定义,可参考 moear-api-common
另外我还实现了系统默认安装的文章源,知乎日报,已开源到 GitHub 上,可为您开发文章源插件提供参考 moear-spider-zhihudaily
提示
作为提供文章来源的插件,欢迎有能力的小伙伴儿实现自己喜欢的文章源爬虫插件, 如果您这样做了请联系我将其加入官方插件列表,让大家看到您的贡献
打包插件¶
打包插件作为书籍文件的生成者,主要责任为将传入的文章数据结构处理后,本地化文章中的图片, 同时对文件进行压缩、灰度化等操作,最终打包生成书籍文件字节串返回给调用者。
具体协议与接口定义,可参考 moear-api-common
另外我事先了系统默认安装的打包工具,mobi打包,已开源道 Github 上,可为您开发打包插件提供参考 moear-package-mobi
注解
该 mobi 打包工具为基于 Amazon 官方打包工具 KindleGen 的实现。
提示
一般情况来说该插件已经足够完善,除非需要支持新的书籍格式,否则不需要实现额外的打包插件
高级部署¶
除了 部署说明 中描述的基础部署,为了更靠的监控 Celery
异步消息队列的运行情况,您可以额外部署一个监控容器 docker-celery-flower 。
在已有的 docker-compose.yml
文件中增加内容如下:
version: '2'
services:
flower:
image: littlemo/docker-celery-flower
container_name: moear-flower
hostname: moear-flower
restart: unless-stopped
mem_limit: 1G
ports:
- "8889:5555"
networks:
- frontend
- backend
volumes:
- ./volumes/runtime/flower:/app/runtime:rw
environment:
- CELERY_BROKER_URL=redis://moear-redis:6379/0
- FLOWER_BASIC_AUTH=用户名:密码
- FLOWER_PERSISTENT=True
depends_on:
- redis
- moear
注意
前两行语句主要为了让您清楚层级,从第三行开始将容器配置添加到 docker-compose.yml
中即可
注意
环境变量中的 FLOWER_BASIC_AUTH
需要您替换为您的账户验证信息。
重新执行 docker-compose up -d
命令完成容器构建,部署完成后,您可以通过浏览器访问(
http://127.0.0.1:8889
)来查看 Celery
的运行状况
碎碎念¶
前言¶
最初需求来源于对Kindle推送工具 狗耳朵 / KindleEar 的使用,以及对类似 Pocket 的文章归档、分类的需求。
在使用上述服务时遇到了痛点如下,狗耳朵收费了,而且界面不好看((。•ˇ‸ˇ•。)哼唧~)。。。KindleEar只能GAE部署,但是国内访问Google。。。你懂的,虽然FQ部署好后就不用管了,但总归不方便,使用过程中经常遇到漏推送的情况(不确定是项目本身问题还是由于跨洋网络问题造成),而且界面不好看((。•ˇ‸ˇ•。)哼唧~)。最后,Pocket虽然很nice,但是除非氪金否则只保存链接,不保存文章本身,而知乎日报经常会遇到次日文章由于各种原因(原作者要求等)被删除的情况,强迫症不能忍。
于是在16年底的时候便着手开始 MoEar 的开发,然而不自量力如我,最初只是实现了一个基于 Scrapy 的爬虫。对于前端知识的匮乏使得 Web 管理页完全无处下手,虽然可以借用 Django 提供的 admin site 作为管理站点使用,但终归觉得不尽如人意,因此便搁置了下来。
一晃一年过去,转眼来到18年初,俨然 MoEar 已经是腹死胎中的状态(虽然我也并没有把它发布出去, 死了也没人知道),但总归是一个遗憾。好在路漫漫其修远兮,吾时刻未忘于求索。一年的时间里, 已经对在前端部分有了长足的进步。猛然发现不知不觉间已码了五年代码,然而却未给开源世界留下丝毫有价值的东西, 实是不该。故决定将之前烂尾的 MoEar 拉出来鞭鞭尸。
于春节期间开始思考架构与实现,从数据表设计、整体架构、插件系统,到业务流程。边思考边实现, 虽然小弯路不断,但还算顺利。开发该项目的时候,深刻的意识到了现在工作的无趣,虽名为研发工程师, 然实际做得确实运维的工作,故此毅然辞职,专心完成此项目。
截止行文之时,已离职月余。虽然很多早先设计要实现的功能都还未实现,但好在核心功能与架构已经构建完成。 到了可以发布的水平,总算对自己有个交代。剩下的功能待洒家找到饭辙后再慢慢维护吧 (毕竟还是要生活的/(ㄒoㄒ)/~~),目前底层的功能已经算是比较完善了可做的事情已然不会很多, 但 Web 端还有很多可发挥的地方,毕竟是跟用户直接接触的部分,有很多 Feature 可以实现, 现在的 Web 管理站点还只是很基础的配置功能。
以上,废话结束
感谢¶
感谢家父家母对我任性的决定给予的支持,身处帝都,肩负房贷,骤然离职,还是需要一定勇气的 (ノへ ̄、)。
感谢我还未曾出现的女票,是你的迟迟不现,才让我有了如此多的时间&精力,不断学习与重构自己(大雾。
重要
理工科钢铁直男,情商低于智商,穿特步的那种,有没有小姐姐愿意领走 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
代办事项¶
待处理
此处配置极度不够优雅,一定要找到更优雅的解决方案把这步毙掉!哼(ˉ(∞)ˉ)唧
(原始记录 见 /home/docs/checkouts/readthedocs.org/user_builds/moear/checkouts/stable/docs/source/intro/overview.rst,第 316 行。)
待处理
关于投递系统,为实现节省流量的目的,实现时做了合并投递,即多人订阅了同一个文章源, 会在该文章当日爬取后合并为一封邮件,加入多个收件地址的形式进行投递。小规模情况下测试正常, 没有问题,但作者在网上(非官网)看到了一些 Kindle 的投递限制,由于不便测试,故先记录在下:
- 一份邮件超过15个不同的【发送至Kindle】电子邮箱,会被认定为垃圾邮件而被Amazon拒绝接收
- 附加大于50MB会投递失败
以上两点未经确认,故暂不为其做应对处理
其实第二点是可以测试的,但一般情况下应该遇不到这么大的文章,而且吧。懒。。懒。。。(溜了
(原始记录 见 /home/docs/checkouts/readthedocs.org/user_builds/moear/checkouts/stable/docs/source/intro/overview.rst,第 381 行。)
待处理
考虑是否添加一个小工具插件(widget),用以提供如:去除文章中的链接、 文章末尾插入原文链接二维码、文章首页加入字数统计与阅读时间预估等小工具功能。
如果添加,其调用点如何设计,应尽量避免与现有插件间的耦合,而将耦合设计在 MoEar 主服务中
(原始记录 见 /home/docs/checkouts/readthedocs.org/user_builds/moear/checkouts/stable/docs/source/topics/plugin.rst,第 60 行。)
发布说明¶
v1.0.1 (2018-05-01 21:57:53)¶
Bugfix¶
- 投递设置 WebAPI 接口调用权限错误
- 创建&更新超级管理员
CLI
命令,修改超级管理员密码后,未保存到 DB - 用户从未设置收件地址,造成
get
结果错误 - 修复过晚设置投递记录关联用户,造成投递失败触发时记录还未有关联的 Bug
Optimize¶
- 投递书籍前对收件地址进行清洗,避免重复投递
- 应用版本号自动生成&更新显示
- 优化
Docker
编译流程 - 优化
fabric
自动化脚本工具
v1.0.0 (2018-04-12 22:03:29)¶
- 实现定时、抓取、打包、投递业务
- 实现基础功能的 Web 管理站点
- 构建 Docker 镜像
- 编写项目说明文档