一、Hexo 安装 Hexo 安装根据官方文档直接操作即可,安装前提是需要先安装 Nodejs(这里不再阐述直接略过)
Hexo 命令行工具安装完成后可以直接初始化一个样例项目,init 过程会 clone https://github.com/hexojs/hexo-starter.git
到本地,同时自动安装好相关依赖
进入目录启动样例站点
1 2 3 4 cd mritd.com hexo serve
二、主题设置 基本的样例博客启动完成后就需要选择一个主题,主题实质上才决定博客功能,这里目前使用了 Fluid 主题,这个主题目前兼具了个人博客所需的所有功能,而且作者提交比较活跃,文档也比较全面。
1 2 3 4 git clone https://github.com/fluid-dev/hexo-theme-fluid.git themes/fluid (cd themes/fluid && git checkout -b v1.8.3 v1.8.3)
接下来修改 _config.yml
配置切换主题即可
然后重新启动博客进行预览: hexo cl && hexo s
关于主题其他配置可自行阅读 官方文档 ,文档有时可能更新不及时,可同时参考仓库内的 _config.yml
配置。
三、文章导入 关于 jekyll 博客的文章如何导入到 Hexo 中网上有很多脚本;但是实际上两个静态博客框架都是支持标准的 Markdown 语法书写的文章进行渲染,唯一区别就是每篇文章上的 “头”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 --- catalog: true categories: - [Kubernetes] - [Golang] date: 2018-11-25 11:11:28 excerpt: 最近在看 kubeadm 的源码,不过有些东西光看代码还是没法太清楚,还是需要实际运行才能看到具体代码怎么跑的,还得打断点 debug;无奈的是本机是 mac,debug 得在 Linux 下,so 研究了一下 remote debug keywords: kubeadm,debug multilingual: false tags: - Golang - Kubernetes title: 远程 Debug kubeadmindex_img: img/remote_ debug.jpg --- 具体文章内容......
所以直接复制 jekyll 的 md 文件到 source/_posts
目录,并修改文档头部即可。
四、自动更新 目前博客部署在自己的 VPS 上,以前都是将博客生成的静态直接使用 nginx 发布出去的;但是面临的问题就是每次博客更新都要手动去 VPS 更新,虽然可以写一些 CI 脚本但是并不算智能;得益于 Golang 官方完善的标准库支持,这次直接几行代码写一个静态服务器,同时拦截特定 URL 来更新博客:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 package mainimport ( "fmt" "net/http" "os" "os/exec" "path" )func main () { http.Handle("/" , fileServerWithCustom404(http.Dir("/data" ))) http.HandleFunc("/update" , update) fmt.Println("Updating WebSite..." ) _, err := gitPull() if err != nil { fmt.Printf("WebSite update failed: %s" , err) } fmt.Println("HTTP Server Listen at [:8080]..." ) _ = http.ListenAndServe(":8080" , nil ) }func update (w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte ("only support POST method.\n" )) return } bs, err := gitPull() if err != nil { w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte (err.Error())) return } w.WriteHeader(http.StatusOK) _, _ = w.Write(bs) }func fileServerWithCustom404 (fs http.FileSystem) http.Handler { fsh := http.FileServer(fs) return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) { _, err := fs.Open(path.Clean(r.URL.Path)) if os.IsNotExist(err) { r.URL.Path = "/404.html" } fsh.ServeHTTP(w, r) }) }func gitPull () (msg []byte , err error ) { cmd := exec.Command("git" , "pull" ) cmd.Dir = "/data" return cmd.CombinedOutput() }
五、Docker 化 有了上面的静态服务器,写个 Dockerfile 将 Hexo 生成的静态文件打包即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 FROM golang:1.15 -alpine3.12 AS builderENV GO111MODULE onCOPY goserver /go/src/github.com/mritd/hexo/goserver WORKDIR /go/src/github.com/mritd/hexo/goserver RUN set -e \ && go install FROM alpine:3.12 AS distLABEL maintainer="mritd <mritd@linux.com>" ENV TZ Asia/ShanghaiENV REPO https://github.com/mritd/mritd.com.gitCOPY --from=builder /go/bin/goserver /usr/local/bin/goserver RUN set -e \ && apk upgrade \ && apk add bash tzdata git \ && git clone ${REPO} /data \ && ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime \ && echo ${TZ} > /etc/timezone \ && rm -rf /var/cache/apk/* WORKDIR /data CMD ["goserver" ]
镜像运行后将使用 /data
目录最为静态文件目录进行发布,Hexo 生成的静态文件(public 目录)也会完整的 clone 到当前目录,此后使用 POST 请求访问 /update
即可触发从 Github 更新博客内容。
六、Travis CI 集成 所有就绪以后在主仓库增加 .travis.yml
配置来联动 travis ci;由于每次 push 到 Github 的内容实际上已经是本地生成的 public 目录,所以 CI 只需要通知服务器更新即可;强迫症又加了一个 Telegram 通知,每次触发更新完成后 Telegram 再给自己推送一下:
1 2 3 4 5 6 7 8 9 10 language: go git: quiet: true script: - curl -X POST ${CALLBACK} after_script: - curl -X POST https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage -d chat_id=${TELEGRAM_CHAT_ID} -d "text=mritd.com deployed."
七、gulp 优化 由于目前一些配图啥的还是存储在服务器本地,所以图片等比较大的静态文件仍然是访问瓶颈,这时候可以借助 gulp 来压缩并进行优化:
1 2 3 4 5 6 npm install -g gulp npm install gulp-htmlclean gulp-htmlmin gulp-minify-css gulp-uglify-es gulp-imagemin --save npm link gulp
接下来编写 gulpfile.js
指定相关的优化任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 var gulp = require ('gulp' );var minifycss = require ('gulp-minify-css' );var uglify = require ('gulp-uglify-es' ).default ;var htmlmin = require ('gulp-htmlmin' );var htmlclean = require ('gulp-htmlclean' );var imagemin = require ('gulp-imagemin' ); gulp.task ('minify-html' , function ( ) { return gulp.src ('./public/**/*.html' ) .pipe (htmlclean ()) .pipe (htmlmin ({ removeComments : true , minifyJS : true , minifyCSS : true , minifyURLs : true , })) .pipe (gulp.dest ('./public' )) }); gulp.task ('minify-css' , function ( ) { return gulp.src ('./public/css/*.css' ) .pipe (minifycss ({ compatibility : '*' })) .pipe (gulp.dest ('./public/css' )); }); gulp.task ('minify-js' , function ( ) { return gulp.src ('./public/js/*.js' , '!./public/js/*.min.js' ) .pipe (uglify ()) .pipe (gulp.dest ('./public/js' )); }); gulp.task ('minify-images' , function ( ) { return gulp.src ('./public/img/*.*' ) .pipe (imagemin ( [imagemin.gifsicle ({'optimizationLevel' : 3 }), imagemin.mozjpeg ({'progressive' : true }), imagemin.optipng ({'optimizationLevel' : 7 }), imagemin.svgo ()], {'verbose' : true })) .pipe (gulp.dest ('./public/img' )) }); gulp.task ('default' , gulp.parallel ( 'minify-html' ,'minify-css' ,'minify-images' ));
最后在每次部署时执行一下 gulp
命令即可完成优化: hexo cl && hexo g && gulp