该篇文章记录的是这个博客的整个搭建流程.
Hugo + PaperMod + Drone
目标
Logseq 用来日常记录使用,不对外开放
使用博客作为日常分享以及知识产出的对外平台
第一目标是轻量
其次是自动化
随后是美观
方案选型
简单调研了几个平台:
WordPress:不够轻量,放弃
Typecho:不够轻量,放弃(主要是提供的有后台编辑工具,我用不到,性价比就很低了,并且也就导致不够轻量)
Solo:强制加入社区,导出还需要积分,不是我想要的,放弃
Holo:与上面类似吧,没仔细研究
Hugo:目前使用的,够轻量,没有多余的内容,没有平台,只是静态资源生成工具
可以看到,个人的博客目前是比较小的,暂时是不考虑做的很大,因此轻量
是当前的一个重要因素
希望的是所有的数据在自己手里,以写 Markdown
的方式记录博客,Hugo
就刚好满足
关于 Hugo
不做过多介绍,贴一个官网:https://gohugo.io/
关于主题
看了一些之后,考虑了两个:
PaperMod
LoveIt
LoveIt 还是比较丰富的,看起来漂亮一点儿,甚至我当时都考虑在主题上面放弃 “轻量”,但后来发现开源协议是,放弃了GPL3
,也就是版权和许可声明必须保留
在此声明一下:刚才又去看了下,看着是 MIT
的,不知道是不是我之前看错了,不过也因为此吧,放弃了,正好也感觉有点儿重
PaperMod 整体看着还是很干净简约的,目前我就是要这种风格吧
开发工具
就 Typora
吧,不需要系统性的
生成新的博客的时候,直接使用 Hugo 命令:hugo new posts/first-blog/index.md
随后用 Typora 打开编写
关于图片
可以看到我上面的命令里面新建文章的时候,用的是 /first-blog/index.md
,这种是为了解决引入本地文件的问题
也就是假如我们想直接使用项目中的图片或者文件采用如下方法:
新建博客时候中间多一层目录,实际的 md 文件放在这个目录中,叫做
index.md
,该目录中定义资源目录,如 pics 用于存放图片,files 用来存放可以下载的附件index.md
中引用到图片或者文件的时候,直接写相对路径
整体的目录结构:
themes
static
...
assets
content:
posts:
first-blog:
files
pics:
test.png
index.md
参考了该博客:
另外,这个博主的风格挺好看的,这个字体我也去查了,附上链接,后续也会改成这个 霞鹜文楷
网站部署
emm,这个这次不打算过多介绍,每个人都有自己的办法,本质上就只是在服务器上部署一个静态目录即可
因为 Hugo 生成的页面是静态的,直接放到服务器上即可
我这边直接采用的是 “宝塔”,直接创建网站即可,https
就去用 letsencrypt
,现在这个网站有点儿限制了,不过也还是目前最简单可用的证书
附上链接:
宝塔:
加密证书:
最终,我的博客地址就是:
自动化 CI
有了上面的网站之后,其实就可以手动发布部署了,操作流程如下:
- 本地建文章并编写
- 本地
hugo server
查看 - 本地执行
hugo
生成静态资源文件,网站根目录的 public 目录下 - sftp 工具将生成的静态资源放到服务器网站目录
当然了,能用程序去做的事情,肯定不要自己去做,不然买的服务器闲着不动不就亏死了
提到自动化,肯定第一想到的就是 jenkins
,但是最近贯穿整个生活的都是“轻量”,因此,jenkins
首先被排除了
去 Google 搜,多搜几个,就找到了 drone
,随后去 github
上找,一看 star 很多,基本就确定了用这个了
发现呢,这个需要用到 docker,虽说 docker 都用过,但一直都是浅尝辄止,仅会 docker run 至于后续的 docker-compose 等根本不会,怎么办?
学呗
于是,去学习了 Docker 的基本使用、基本构建镜像、docker-compose 的基本使用
可以看到,全是基本使用,因为我现在的重心不在这个上面,能用 docker 正常运行并且启动 CI 执行流程即可
Drone
还是简单介绍一下这个吧,不然没有实际内容了
Drone is a self-service Continuous Integration platform for busy development teams.
【Drone 是为繁忙的开发团队提供的自助式持续集成平台。】
可以看到,就是简单好用
截几张官网特性图
总结一下
- 流水线都是配置出来的,配置文件还是 .yml 的,易懂易学习
- 基于 docker,不会有什么脏数据,用完即销毁
- 后台页面运行起来很快,轻量(自己使用感受)
本人使用场景
嗯对,就是这么个流程
一些基本的使用我这里不多写,可以参考一些官方的或者其他博客的,我给个路标:
我只解释一些关键点
Drone 服务
Drone 需要有台服务器去运行它,所以我们要有一台可以运行的服务器,如上图就是 drone 服务器
运行的方式可以是 docker,使用官方的就行,对照我的解释一下:
version: '3'
services:
drone-server:
image: drone/drone:2.3.1
ports:
- "8088:80"
volumes:
- drone-data:/data:rw
- ./ssl:/etc/certs
restart: always
command:
- git config --global core.autocrlf input
environment:
- DRONE_SERVER_HOST=${DRONE_SERVER_HOST:-https://drone.yeasy.com}
- DRONE_SERVER_PROTO=${DRONE_SERVER_PROTO:-https}
- DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret}
- DRONE_GITHUB_SERVER=https://github.com
- DRONE_GITHUB_CLIENT_ID=${DRONE_GITHUB_CLIENT_ID}
- DRONE_GITHUB_CLIENT_SECRET=${DRONE_GITHUB_CLIENT_SECRET}
- DRONE_USER_CREATE=username:xiaohanqing,admin:true
drone-agent:
image: drone/drone-runner-docker:1
restart: always
depends_on:
- drone-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock:rw
command:
- git config --global core.autocrlf input
environment:
- DRONE_RPC_PROTO=http
- DRONE_RPC_HOST=drone-server
- DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret}
- DRONE_RUNNER_NAME=${HOSTNAME:-demo}
- DRONE_RUNNER_CAPACITY=2
dns: 114.114.114.114
volumes:
drone-data:
首先,这是一个 docker-compose 的配置文件
里面定义了两个 docker服务,也就是这个启动之后,会启动两个 docker
分别是 drone-server
和 drone-agent
,看名字也能看出来,大概就是 Drone 的一个主服务,一个守护服务
image 没什么好说的,docker 镜像
ports:端口映射,上面意思是把 docker 中的 80 端口映射到我主机的 8088 端口
volumes:目录映射,上面意思就是把 docker 中的 /data 目录映射到主机上的 ./drone-data,后面跟了个 rw 意思就是读写权限都有
command:指的是跟着执行的命令,后面解释为什么要加个这一行,官方上面是没有的
environment:就是一些环境变量,照着来就行了,反正数据都有。哦对了,这里面有一行叫这个:
- DRONE_USER_CREATE=username:xiaohanqing,admin:true
这个是要自己加上的,username 后面的值 xiaohanqing
是我的 github
账号,改成自己的,运行起来之后 drone 后台管理页面需要用 github 授权,这样配置之后,登录到后台之后,自己就是管理员,可以进行一些操作。不然的话,有些功能受限
最后启动时候,就是 docker-compose up -d
后台启动,启动就会把上面两个 docker 运行起来
可以通过 docker ps
查看运行中的容器
到这一步的时候,后台页面就可以打开了,安全期间,这里就不暴露我的域名了,反正用 NG 反代之后,大概就是
drone.xxx.xxx
页面长这样:
点 Continue,就会让去 github 授权,授权之后就好使了
可以看到我上面已经部署了 75 次了,有成功有失败,就是各种尝试
配置文件
kind: pipeline
type: docker
name: blog-publish
steps:
- name: build
image: hugo-base:alpine-v1.2
volumes:
- name: blog
path: /data
commands:
- hugo
- cp -r public/* /data
- name: scp
image: appleboy/drone-scp
volumes:
- name: blog
path: /blog.chunxiao.site
settings:
host: xxx.xxx.xxx.xxx
username: drone-scp
password: aaaaaa
port: 22
target: /www/wwwroot
source: /blog.chunxiao.site
overwrite: false
debug: true
volumes:
- name: blog
host:
path: /data/blogs_host
kind:照着写就行,意思是流水线类型
type:意思就是用 docker,drone 支持的有其他的
name:起个名
steps:流水线的每一步
volumes:目录映射
name:起个名字,这个名字就是一个标识,可以在 step 中使用
host.path:指的是这个名字在主机中的目录
step 中:
name:起个名
image:选个镜像(hugo-base:alpine-v1.2
大家不要用啊,这是我本地自己整的)
volumes:
name:对应上面说的最外层的那个 volumes 中的 name
path:docker 中的目录
commands:可以执行的命令
settings:镜像提供的一些配置,用到哪个镜像去找对应的文档
几个注意点:
- 这个是基于 docker 的,流水线中的每一步都是一个 docker,因此,我们需要用到 volumes 来把每一步中产生的数据存起来,也就是第二步中是没有任何第一步的数据的,除非使用 volumes 做映射。比如 A(第一个 step) 中 /data 目录映射到主机的 /data/common 中,A运行过程中产生的一些数据就可以放到 /data 中,同时主机的 /data/common 中也就有了这些数据,这时候 B(第二个 step) 中也配置了 /data 映射到主机的 /data/common,那么 B 在启动一开始 /data 中就有 A 的产出数据
- 配置的 step 中不用写拉取 git 的操作,实际上在自定义的 step 执行之前,drone 会先进行一次拉取操作
- 当前目录就是 git 项目的根目录
解释一下两个 step
build流程
目的就是让 hugo 生成静态资源,因此需要一个带有 hugo 应用的镜像
之前一直有问题,于是考虑自己弄一个(其实后来找到根本原因后发现跟这个没关系)
既然要弄,就得搞一个轻量的,于是去搜了下轻量相关的 docker,发现排的靠前的有这个:alpine(https://hub.docker.com/_/alpine
)
并且刚好发现,alpine 这个系统也可以直接软件库中按照 hugo,于是自己基于 alpine 整了个 hugo-base 镜像
DockerFile 贴上:
FROM alpine
RUN apk update && \
apk add hugo && \
hugo version
随后使用 docker 构建命令生成自己的本地镜像:docker build -t hugo-base:alpine-v1.2 .
这个建议直接用 docker hub 里面别人做好的就行,不建议自己搞一个,我是之前遇到的一些问题,我怀疑跟 hugo 版本或者什么有关,才自己搞的,最后发现其实没关系的
可以看到, volumes 里面配置了: docker 中的 /data
映射到主机上的 /data/blogs-host
随后执行了两个命令:
- 执行 hugo 生成静态资源
- 把静态资源复制到
/data
目录,也就是主机的/data/blogs_host
目录
注意:
git 忽略文件中记得把 public 目录忽略
scp流程
由于我这个 drone 服务器与博客服务器不在一块儿(没办法,服务器多)
因此需要再多一个 scp 的操作,把生成的静态资源部署到博客所在的服务器目录中
参考 drone 官方文档:https://plugins.drone.io/plugins/scp
注意点:
需要用到 ssh 登录远程机器,所以需要提供远程服务器的账号密码,这个还是比较危险的,并且这个还需要放到 github 上,切记把项目改成私有的,但是为了安全期间,还是要做一层基本的拦截。因此这里一定不要使用 root 账号,单独建一个账号,给这个账号有限的权限
关于目录的问题,整了很久,都没有达到我要的效果,比如我是想把 ./*
放到远程的 /www/wwwroot/blog.chunxiao.site/
下,但是怎么搞都不行,都会多一层目录,尝试用文档是的 tar_exec 参数,但并没有效果。后来实在没办法了,就搞成了上面那种方式,大家可以试一试,有更好的方式可以留言告知我一下,谢谢(当然了,现在还没有接入评论系统,晚些天接入)
这个很基本啊,并且肯定是有安全问题的,正常应该是去做一些脚本处理逻辑的
并且使用了几次后就发现问题了,这个时间太长,因为是全量的,所以不符合要求,正在看 rsync 的,rsync 的好了之后就会放弃这种方式
遇到问题整理
其实挺多的,后来逐渐找到了根本原因,总结之后是两个
发布到服务器上后样式丢失
本地没问题,本地执行 hugo 后直接手动上传到博客服务器网站目录中没问题,但是走了 drone 自动化就没样式了
F12
看了之后发现报错:
Failed to Find a Valid Digest in the 'Integrity' Attribute
就这种类似错误吧,是加载一个 css 时候异常,导致样式没了
当时也找了好久不知道啥原因,一直以为是服务器上的配置问题,毕竟所有的都是新的
后来实在不行了,去找了前端大哥(感谢林叔儿),果然是大哥,没一会儿让我去掉一个东西试试,发现去掉就好使;后来又帮我找到了两篇相关内容:
https://blog.51cto.com/MyIO/5096208
https://yqc.im/hugo-failed-to-find-a-valid-digest-in-the-integrity-attribute/
终于弄明白是怎么一回事了:
应该是 hugo 或者 paperMod 使用到了一个 Blazor
的工具,这个工具呢会做这样一件事:
会检查文件的SHA-256哈希值,确保不会出现加载不一致文件的风险
但是,git 在 windows 下会自动将文件中的换行符 CRLF 转成 LF ,这样就造成文件的哈希值变化,就被拦住了
所以,这个问题的原因就找到了,解决方案基本也确定了,就是统一这个换行符
统一换行符
我这样做了之后是好使的:
清空博客服务器中网站的内容(记得先做备份)
本地 git 配置(windows):
git config --global core.autocrlf true
意思是:提交时自动地把行结束符 CRLF 转换成 LF ,而在签出代码时把 LF 转换成 CRLF
drone 服务器上(做拉取操作的机器,Linux)配置:[开始时候的配置就是干这个用的]
git config --global core.autocrlf input
意思是:在提交时把 CRLF 转换成 LF,签出时不转换
重新提交一次代码,push,执行上面的流水线任务
Hugo 生成的文件少
遇到过几次,之前因为一直有上面的那个大问题,没怎么解决这个。但上面问题解决之后,发现我在服务器上执行 hugo 后,生成的文件比较少,观察了之后发现是没有生成 HTML
后来无意中取看了下 themes/PaperMod 目录,发现是空目录,才发现,原来在服务器上 git 下来的数据中没有主题信息。
原因是:之前主题的时候使用的是这种 git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
这种就导致单独的这个 PaperMod 目录也是一个 git 项目,需要单独去克隆拉取出来(应该不太准确,但是肯定是跟 Git 有关),放弃这种方式,让这个主题就是我们项目中的一些文件就行了
最新变动
以上流程用了几次之后就发现了问题,使用 scp 的话每次需要的时间太长了
所以就考虑放弃之前那台服务器,博客也放在了这台drone服务器上,目前原域名是重定向过来的,随后就可以直接打到这台机器了
最新配置文件
Drone 服务器与博客服务器合成一个的话,就简单多了,贴上最新的配置:
kind: pipeline
type: docker
name: blog-publish
steps:
- name: build
image: hugo-base:alpine-rsync
volumes:
- name: blog
path: /data
commands:
- hugo
- rsync -a --delete --exclude '.user.ini' public/ /data
volumes:
- name: blog
host:
path: /www/wwwroot/blog.x-r.cc
当然了,那个 hugo-base:alpine-rsync
是我自己本地打的镜像,就是 alpine 安装了 hugo 和 rsync 的
hugo-base alpine-rsync afcf7f89ce5e 2 hours ago 76MB
可以看到,还是有点儿大的,不过也还能接受,比官方提供的 hugo 镜像小多了,下面是官方的
plugins/hugo latest 5343f140bc4b 4 months ago 119MB
写在最后
写的还是有点多的
最后列举出来一些 Todo 项,后续完成一个勾一个
- 访问统计 Hugo使用自定义字体
- 字体 Hugo使用自定义字体
- 评论系统
- 标签页整理
- 归档时间轴
Bye ~