使用 Jenkins 和 Gitee 自动部署静态博客

本文介绍如何在自建服务器上使用 Jenkins 和 Gitee 自动部署博客。

最近给域名备了个案,于是花了点时间把博客从 Vercel 迁移到了国内服务器上。之前用的 Vercel 是能够在 Git 仓库发生变更后自动部署的,但迁到自建服务器上后这个功能就得自己实现了,搜索了一下实现方案,最后选用了 Jenkins

 环境信息

环境 版本
操作系统 CentOS 7
Jenkins 2.277.4
JDK 1.8.0_282
Nginx 1.18.0
Git Host Gitee

 配置 Jenkins

 安装 Jenkins

参考 官方文档 安装即可, CentOS 的步骤如下 :

1
2
3
4
5
6
# 添加 Yum 源
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
# 导入密钥
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key

sudo yum install -y jenkins
 

(可选)Jenkins 默认端口为 8080,可以在配置文件里修改:

1
2
vim /etc/sysconfig/jenkins
# 修改 JENKINS_PORT=xxx 即可
 

最后添加开机启动:

1
2
3
4
5
6
7
8
9
# 重载服务(由于前面修改了 Jenkins 启动脚本)
sudo systemctl daemon-reload

# 启动 Jenkins 服务
sudo systemctl start jenkins

# 将 Jenkins 服务设置为开机启动
# 由于 Jenkins 不是 Native Service,所以需要用 chkconfig 命令而不是 systemctl 命令
sudo /sbin/chkconfig jenkins on
 

 Jenkins 初始化

确保之前设置的端口在防火墙里已开放,然后浏览器访问 <ip>:<port>,按照向导一步步完成初始化。

 安装插件

 安装配置 NodeJS Plugin

登录 Dashboard,选择 Manage Jenkins > Manage Plugins,点击 Available,安装 NodeJS Plugin

然后在 Dashboard > Manage Jenkins > Global Tool Configuration 里下滑找到 NodeJS ,点击 NodeJS installations …,配置如下:

选择 Node 版本,在 Global npm packages to install 里填入 Hexo 和 Yarn 依赖:

1
hexo-cli@4.2.0 yarn --registry https://registry.npm.taobao.org/ 
 

点 Save 保存。

 安装 Gitee Plugin

由于 Github 在国内网络几乎不可用,这里把 Host 换成了 Gitee,因此还需要安装一个 Gitee Plugin

Gitee 的配置参考 Gitee 的官方 帮助中心

简单来说,在 Jenkins -> Manage Jenkins -> Configure System -> Gitee Configuration -> Gitee connections 里,按照文档配置如下:

 添加 CI 任务

 配置密钥(可跳过)

由于我博客项目设置为了私人仓库,所以需要额外生成密钥对并把公钥添加到 Gitee 里,如果你的仓库是公开状态,这一步可以跳过:

切换到 Jenkins 用户:

1
sudo su -s /bin/bash jenkins
 

生成密钥对:

1
ssh-keygen -o
 

查看公钥并复制:

1
cat ~/.ssh/id_rsa.pub
 

然后在 Gitee 网站右上角 个人头像 > 设置 > SSH 公钥 里粘贴公钥,点确定保存。

 新建任务

 新建任务

接下来就可以在 Jenkins 里新建构建博客的 CI 任务了!

打开 Dashboard,点击 New Item。输入 Item name,类型选择 Freestyle project。配置页里 Gitee connection 选择之前配置的 connection。

在 Source Code Management 里选择 Git,Repository URL 里填入仓库链接,如果这个时候显示权限失败,请返回上一小节配置密钥。

在 Build Triggers 里选择 Build when a change is pushed to Gitee. Gitee webhook URL: http://81.70.155.173:8089/gitee-project/blog ,注意复制这里的 webhook url,之后会用到。

然后再 Enabled Gitee triggers 里选中 Push EventsSecret Token for Gitee WebHook 里点击 Generate,同样保存备用。

 Gitee 配置 Webhook

之前配置的 Webhook 需要在 Gitee 上同样配置一下才能正常工作:

登陆 Gitee 后在仓库主页点击 管理 > WebHooks > 添加 WebHooks,然后填入刚刚保存的 url 和 token,保存即可。

 编写构建脚本

回到任务配置页,继续添加自动构建脚本:

在 Build 里点击 Add build step,选择 Execute shell,根据网站和博客的具体情况编写构建部署命令如下:

1
2
3
4
5
6
7
8
9
10
# 不安装 devDependences
yarn install --prod --registry https://registry.npm.taobao.org/

# Hexo 生成脚本
hexo clean
hexo generate

# 部署脚本
rm -rf /www/wwwroot/mysite/*
cp -a ./public/. /www/wwwroot/mysite/
 

2021 年 5 月 28 日 更新,部署 mkdocs 的脚本如下:

1
2
3
4
5
/usr/bin/pip3.6 install -i https://pypi.tuna.tsinghua.edu.cn/simple mkdocs-material --user
/usr/bin/python3 -m mkdocs build

rm -rf /www/wwwroot/mymkdocssite/*
cp -a ./site/. /www/wwwroot/mymkdocssite/
 

 测试部署

完成 CI 任务的创建后,回到 Project 页面,点击 Build now,观察是否一切正常。然后通过 Git 更改后 push,测试 WebHook 是否正常。

如果部署时提示权限不足,可以把网址所在的目录 owner 改为 jenkins 来解决。

1
sudo chown -R jenkins:jenkins mysite/
 

 其他

 推送

原来用 Vercel 的时候,每次构建完毕,Vercel Bot 就会给我的仓库的 Commit 评论一下,然后会收到 Github 发来的邮件,提醒我构建完成,非常好用。当然,现在这个功能也只能自己写了。因为是国内服务器,直接排除了用 Telegram 推送。搜索了一下,发现了一个通过 QQ 推送消息的网站 Qmsg 酱 ,按照 文档  注册配置后可以获得一个 Qmsg Key,然后就可以调用 RESTful 接口发起推送了!

配置非常简单,在构建脚本的最后添加如下命令即可:

1
2
3
curl --location --request POST 'https://qmsg.zendee.cn/send/< 你的 qmsgKey>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'msg=itiandong.com 部署成功 '
 

这样每次部署完成,你会收到一条 QQ 消息:

 国内网络的坑

这次迁移的过程中也遇到了一些坑。最开始本来打算沿用 Github 的,但测试发现 Clone 总是出错,于是被迫改成国内的 Gitee。可以在原仓库上额外添加 Gitee 远程仓库地址,让 Github 和 Gitee 并存:

1
git remote add gitee <url>
 

然后提交时,分别执行:

1
2
git push origin master
git push gitee master
 

就可以分别提交到两个仓库里了。

另外,博客用到的一个插件 hexo-all-minifier 也遇到了类似的问题。这个插件的安装脚本 install.js 会从 githubusercontent.com 里下载文件,而国内这个域名直接被 ban 了… 无语…于是我暂时去掉了这个插件,如果想解决可能需要重打包一下了…

刚尝试重打包了一下,太麻烦了,怕了怕了,还是换个包吧。

from 

https://web.archive.org/web/20221206035548/https://itiandong.com/2021/automating-blog-deployment-with-jenkins-and-gitee/

-----------------------------------------------------

jenkis概述与安装

 

install

 
  • on mac install
$ brew install jenkins
$ jenkins
 

浏览器访问 http://localhost:8080 进入配置页面。 数据存储目录:~/.jenkins 包括插件,日志和Jobs等。

初始化

 
  • 第一次需 Unlock: ~/.jenkins/secrets/initialAdminPassword 系统把密码生成到这个文件,只有能访问这个文件的人才说明是管理员

  • 设置代理:代理服务器,认证账号密码和 no_proxy 设置。

如需重新初始化,请直接删除 ~/.jenkins 又可以重头开始配置。

plugins

 

官方推荐插件

 

点击:系统管理>管理插件>可选插件

  • git plugin (新版本或默认安装)
  • Publish Over SSH / SSH Credentials Plugin
  • Email Extension Plugin (邮件通知)

下载插件的时候,往往需要用到代理(往往需海外代理)。可以在启动jenkins时,设置http_proxy环境变量。后期设置代理的路径是:系统管理>管理插件>高级 Jenkins Plugin Center: https://updates.jenkins-ci.org/download/plugins/https://plugins.jenkins.io/

既然有插件,那就有生态:(1)插件仓库;(2)发布插件;(3)自动安装插件;(4)自动更新插件;(5)安装量/受欢迎程度统计;(6)Plugin之间的依赖管理。

安装Locale插件

 

安装完jenkins时,默认它的语言会跟浏览器设置的语言一致。但是为了跟国际接轨,我们尽可能强制用英文。需要下载Locale插件。

  • 安装Locale插件
系统设置 (Manage Jenkins) -> 插件管理 (Manage Plugins) -> 可选插件 (Available)
然后搜索:Locale
 
  • 设置为英文
http://localhost:8080/configure
Locale -> Default Language	-> en_US.UTF-8  或者 zh_CN.UTF-8
 

账号体系

 

Jenkins 可以有自己的账号体系,也可以跟公司的域账号LADP集成。只需要在Jenkins -> Configure Global Security中设置:

调用 API

 

Jenkins 支持RESTful API,但需要认证,难道我们模拟登陆?当然不是,现在主流的做法是用户通过界面登陆Jenkins的Web管理界面,然后通过界面生成一个token,后期调用只要携带这个token即可。本质上跟普通Web登陆,输入用户名+密码,然后服务端生成一个session_id,浏览器通过COOKIE来承载这个session_id是一样的。只不过两者的生命周期不一样而已。

生成 API Token

  • 点击 Jenkins -> People -> admin (选择进入admin账户,以便以admin账户的名义)
  • admin账户页面 的左侧栏,点击 Configure -> API Token 选项卡

jenkins-cli

 

大家都知道Jenkins的界面是出了名的丑陋。但是作为一个后端程序员,有点想法,发明了一个Jenkins,前期找不到前端程序员合作,能搞出这样的界面也算是不容易了。当你不会做漂亮的界面,又想搞点事的时候,你怎么办呢?RESTful API + cli 呀。

比如,我们直接通过命令行,查询job列表:

$ jenkins-cli -s  http://localhost:8080/ list-jobs
java.io.IOException: Server returned HTTP response code: 403 for URL: http://localhost:8080/jenkins/cli?remoting=false
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1840)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
	at hudson.cli.FullDuplexHttpStream.<init>(FullDuplexHttpStream.java:99)
	at hudson.cli.CLI.plainHttpConnection(CLI.java:652)
	at hudson.cli.CLI._main(CLI.java:612)
	at hudson.cli.CLI.main(CLI.java:426)

$ export JENKINS_URL=http://localhost:8080/

$ jenkins-cli list-jobs
java.io.IOException: Server returned HTTP response code: 403 for URL: http://localhost:8080/jenkins/cli?remoting=false

$ jenkins-cli -auth admin:e6c630e01fce4191a2be2b602ca69874 list-jobs
hello-world-jresty
 

其中:

  • -s选项: 表示服务器地址。如果我们不想每次命令都输入,可以保存到 $JENKINS_URL 环境变量中。
  • API地址:JENKINS_URL=http://localhost:8080/ 而不是有些教程里面的 JENKINS_URL=http://localhost:8080/jenkins/ (本教程jenkins版本是 2.73)
  • 账号密码:通过-auth admin:e6c630e01fce4191a2be2b602ca69874指定账号和密码。
  • 帮助信息:在Web页面上,点击 jenkins -> Manage Jenkins -> Jenkins-Cli,也就是 http://localhost:8080/cli/ 会有帮助信息。

认证方式

 

除了上文直接输入Web页面一样的用户名+密码的方式(这种用在RESTful API上,实质表现为HTTP Basic Auth形式),它还支持:API token认证 和 SSH Key 方式。

API Token 形式

 

按前文说的步骤,生成 API Token

  • 点击 Jenkins -> People -> admin (选择进入admin账户,以便以admin账户的名义)
  • admin账户页面 的左侧栏,点击 Configure -> API Token 选项卡
$ jenkins-cli -auth admin:f69552d7a187b8a8944ab3f88b38ad76 list-jobs

hello-world-jresty
 

注意:形式跟账号密码是一样的?对!官方帮助是这么写的:

-auth [ USER:SECRET | @FILE ] : specify username and either password or API token (or load from them both from a file);

也可以把账号+API Token保存到文件,然后:

$ echo "admin:f69552d7a187b8a8944ab3f88b38ad76" > token.txt
$ jenkins-cli -auth @token.txt list-jobs
hello-world-jresty

from

mdblog/devops/jenkis概述与安装.md at master · tenebaul/mdblog · GitHub

 

SSH Key 方式

 

Jenkins可以类似github.com一样,支持SSH Key方式认证:1)在本地生成秘钥对:~/.ssh/id_rsa~/.ssh/id_rsa.pub;2) 把~/.ssh/id_rsa.pub粘贴到Jenkins Web

按下列步骤填写SSH Public Key: http://localhost:8080/me/configure

  • 点击 Jenkins -> People -> admin (选择进入admin账户,以便以admin账户的名义)
  • admin账户页面 的左侧栏,点击 Configure -> SSH Public Keys 选项卡

接着直接使用命令行,它自己会用~/.ssh/id_rsa去签名的:

$ jenkins-cli list-jobs

ERROR: anonymous is missing the Overall/Read permission

$ jenkins-cli -i ~/.ssh/id_rsa list-jobs

ERROR: anonymous is missing the Overall/Read permission
 

报错了,我们还需要在服务端 Configure Global Security 打开一个选项开关。如下图勾选上 Allow anonymous read access即可:

$ jenkins-cli list-jobs

hello-world-jresty
 

参考资料