使用 Flask 和 Bootstrap 构建的轻量博客,基于 Git 存储博客内容。支持自动更新、全文检索、Docker 部署。
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
blog
conf
.dockerignore
.gitignore
Dockerfile
LICENSE
Pipfile
Pipfile.lock
README.md
config.py
docker-compose.yaml
gunicorn.py
manage.py

README.md

MrChiBlog

使用 Flask 和 Bootstrap 构建的轻量博客,基于 Git Repo 存储博客内容。

项目缘起于在前司工作期间,需要搭建一个团队技术博客,需要支持团队多人发布文章,并放在公网访问。彼时团队代码托管在 Coding,刚好也不想增加新的一套账号体系,因此想到了 Coding repo 作为文章来源,使用 Coding API 来获取内容并展示的方案。不巧的是,在职期间一直没时间实现,离职后终于动手实现了基本功能。

特性

  • 使用 Git Repo 管理 markdown 文章,支持扩展 markdown 语法;
  • 通过 webhook 自动更新文章内容(目前支持 Coding 和 GitHub);
  • 支持文章拥有以下元数据:分类和标签,另外通过跟踪 commit 记录获取文章创建时间和更新时间;
  • 支持按分类和标签查看文章;
  • 支持全文检索文章标题和内容;
  • 支持自动生成文章目录,并显示当前阅读位置;
  • Docker 快速部署;
  • 通过钉钉接收 HTTP 500 告警;

使用的技术和库

前端

  • Bootstrap
  • jQuery
  • Moment.js
  • Font Awesome

后端

  • Flask
  • RQ
  • Gunicorn
  • Flask-SQLAlchemy
  • Flask-WhooshAlchemyPlus
  • Flask-RQ2
  • Whoosh
  • Jieba
  • python-markdown
  • Pygments
  • requests
  • PyMySQL
  • GitPython

使用方法

普通部署

安装 redis 和 mysql,并创建 mysql 数据库(建议使用 utf8mb4 编码以兼容 emoji 表情等字符)。

拉取代码:

git clone https://github.com/chiqj/MrChiBlog.git

安装依赖:

cd MrChiBlog
pipenv install --deploy

在项目根目录创建 .env 环境变量文件,示例如下:

# 生产环境 mysql 数据库
PROD_DATABASE_URI=mysql+pymysql://test:test123@127.0.0.1:3306/mrchiblog?charset=utf8mb4

# 指定 Flask app
FLASK_APP=manage:app
# 指定 Flask 在 production 模式
FLASK_ENV=production

# Git 仓库配置,依次为 Repo 目录,Repo 部署公钥(用于拉代码)对应的私钥
REPO_DIR=$HOME/notes/
REPO_SSHKEY=$HOME/.ssh/id_rsa

# Coding 上该 repo 的 webhook token,用于接收 push 代码消息,触发更新
WEBHOOK_TOKEN=1234567890

# 生成文章固定链接的密钥
HMAC_KEY=foobar

# 钉钉 robot token,用于接收 HTTP 500 消息
PROD_DINGTALK_TOKEN=123456789000000

# 生产环境 redis 数据库
PROD_REDIS_URI=redis://127.0.0.1:6379/0

# 生产环境 whoosh 索引目录配置
PROD_WHOOSH_BASE=./prod_whoosh_idx

# 生产环境 rq 配置
PROD_RQ_REDIS_URI=redis://127.0.0.1:6379/1

初始化文章 Repo:

cd $REPO_DIR
git init
git remote add origin <git ssh url>

初始化数据库:

pipenv run flask deploy

运行:

pipenv run gunicorn -c gunicorn.py -b 0.0.0.0:5000 manage:app

启动 rq worker:

pipenv run flask rq worker update
pipenv run flask rq worker notify

访问 5000 端口即可。

Docker 部署

拉取代码:

git clone https://github.com/chiqj/MrChiBlog.git

在项目根目录创建 .env 环境变量文件。与普通部署时略有不同:

  • 需要分别指定 mysql 数据库用户名、密码、数据库名;
  • redis 和 rq redis url 中的主机部分都使用容器名。

示例如下:

# 生产环境 mysql 数据库
MYSQL_USER=test
MYSQL_PASSWORD=test123
MYSQL_DATABASE=mrchiblog

# 指定 Flask app
FLASK_APP=manage:app
# 指定 Flask 在 production 模式
FLASK_ENV=production

# Coding 上该 repo 的 webhook token,用于接收 push 代码消息,触发更新
WEBHOOK_TOKEN=1234567890

# 生成文章固定链接的密钥
HMAC_KEY=foobar

# 钉钉 robot token,用于接收 HTTP 500 消息
PROD_DINGTALK_TOKEN=123456789000000

# 生产环境 redis 数据库
PROD_REDIS_URI=redis://redis:6379/0

# 生产环境 whoosh 索引目录配置
PROD_WHOOSH_BASE=./prod_whoosh_idx

# 生产环境 rq 配置
PROD_RQ_REDIS_URI=redis://127.0.0.1:6379/1

构建镜像

docker-compose build

初始化文章 Repo:

cd $REPO_DIR
git init
git remote add origin <git ssh url>

复制 ssh_key(私钥):

cp $HOME/.ssh/id_rsa /mrchiblog/sshkey/id_rsa
chmod 600 /mrchiblog/sshkey/id_rsa

运行

docker-compose up -d

初始化数据库:

docker-compose exec web flask deploy

在宿主机上访问 127.0.0.1:5000 即可。

在 markdown 中包含元数据

目前我是将一些元数据直接放到了 markdown 文档中, python-markdown 库在转换为 html 时,通过 Meta-data 扩展读取这些元数据并存入数据库,而转换得到的 html 中不会包含这些元数据。这种方式,无疑给写文档的人增加了一定工作量,但好处是,所有信息都在 Coding repo 中,任何时候都可以删库重建而不会造成数据丢失。

在 markdown 中包含的元数据包括:分类(category)和标签(labels)。示例如下:

---
category: Docker
labels: Docker
        Dockerfile
---

这是 markdown 正文第一句话。Good luck, have fun.

元数据写在 markdown 文档的开头,以 --- 行开头(L1)和结尾(L6),并与 markdown 正文之间有一个空行(上面的 L7)。元数据采用 yaml 语法,分类和创建时间只能有一个,标签可以有多个。多个标签分别写在不同行,并保证从第二个标签开始,缩进大于 2 个空格。

上面的示例中,该文章分类为 “Docker”,标签为 “Docker” 和 “Dockerfile”。

开发

开发时,Flask 应被设置为 development 模式。相比普通部署的 .env 文件,部分环境变量需要调整,包括:

# flask 应用工作在 development 模式,开启 debug 和 auto_reload
FLASK_ENV = "development"

# 开发环境 mysql 数据库
DEV_DATABASE_URI

# 开发环境 redis 数据库
DEV_REDIS_URI

# 开发环境 whoosh 索引目录
DEV_WHOOSH_BASE

# 开发环境 dingtalk robot token
DEV_DINGTALK_TOKEN

初始化:

flask deploy

运行:

flask run

访问 http://127.0.0.1:5000 即可。

感谢

  • 感谢“学长”在 Docker 方面的技术指导,帮助了我很多。
  • 感谢不愿透露姓名的“菜鸡”同学帮我解决前端 bug。
  • 由于我前端水平不够高,博客页面样式和配色大量借鉴了 SegmentFault,在此对 SegmentFault 表示感谢。

Todo

  1. 增加测试用例并实现 TDD;
  2. [DONE]使用“操作 Git 仓库”方式替代“使用 Coding API”方式获得内容和数据(可兼容任意 Git 托管平台);
  3. 文章支持多作者,并增加按作者展示文章内容;
  4. 增加后台管理;
  5. 增加评论;
  6. 前后端分离 + Restful 接口;