devops-自动化部署自己的博客 Nov 25, 2021 · devops · 分享到: 自动化部署自己的博客 思路汇总 选定需要git管理的内容 gitignore添加忽略文件失效的处理方法 在云服务器上搭建git服务器 创建Git用户和库文件 添加ssh公钥 本地库设置远程库的地址 远程仓库的工作区更新方法 推送给裸仓库的情形 推送给普通远程仓库的情形 设置post-receive hook完成内容自动更新 裸仓库的更新 普通远程仓库的更新脚本 使用HUGO作为博客生成工具 修改Hugo博客的clarity主题 上传修改好的Hugo博客 使用Jenkins自动化部署网站 推送到Github并生成Gitpages 思路汇总 我自己分几个文件夹写了一些笔记和资料,现在想用Hugo部署到自己的云主机上同时同步到github上,利用gitpage在生成一个blog,也就是自动生成两个同步的blog,初步体验一下DevOps流程。目前本地使用win10,带有git;云主机是Debian 10,有golang 1.15.14环境。主要使用了git hooks和jenkins,以及rsync作为补充。 总体思路: 由于本地文件夹都放在一起,首先通过编辑.gitignore文件,指定需要git管理的几个文件。 将自己的云服务器作为一个git remote仓库,管理自己的这些资料和笔记 在云服务器的git repo中设置hook,将这些本来在不同文件夹中笔记和资料复制到特定文件夹中。注:用hook复制的方法并不好,因为当文件名称修改或被删除时,就无法实现文件的同步。 改成在远程主机上再设置一个git仓库,设置post-receive hook通知jenkins将提交的内容pull到云主机新的仓库中 建立hugo文件到git仓库的软链接,不能使用软链接的用rsync同步过去,当hugo编译的时候实际使用的是git仓库中的文件 使用jenkins自动构建部署云服务器上的Hugo blog 将完整的编译好的Hugo blog推送到GitHub,利用GitPages生成网站。 为什么不设置两个remote repo分别推送?怕自己疏忽,造成大量的冲突处理问题。 为什么不先推送到GitHub再用Github Actions推送到云上?自己觉得在云上折腾比较方便,就当云是测试环境,GitHub是发布环境吧。 选定需要git管理的内容 我们在有很多文件/文件夹的地方执行git init .时,会有大量不需要的文件也被放入待添加空间,我们需要先创建一个.gitignore文件筛选出我们需要的文件。比如,我们需要保留images,学习笔记,工程笔记,网页资料四个文件夹,其他全部不要,则.gitignore文件可以写成: 1# 先忽略跟文件下所有文件,开头使用/防止递归 2/* 3# 取反所有需要git管理的文件 4# images图片文件夹 5!/images 6# 笔记文件夹:学习笔记,工程笔记 7!/学习笔记 8!/工程笔记 9# 资料文件夹,已提前都转为网页格式 10!/网页资料 11# .gitignore本身 12!.gitignore 然后查看目前状态: 1$ git status 2On branch master 3No commits yet 4Untracked files: 5 (use "git add <file>..." to include in what will be committed) 6 .gitignore 7 images/ 8 学习笔记/ 9 工程笔记/ 10 网页资料/ 11nothing added to commit but untracked files present (use "git add" to track) 没有问题,接下来正常流程,添加进git本地库。 1$ git add . 2...... 3$ git commit -m "首次将images,学习笔记,工程笔记,网页资料四个文件夹添加进repo" 4...... 如果是初次使用git,还要先配置用户信息,这一点很重要,因为每一个Git提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改。比如: 1$ git config --global user.name "John Doe" 2$ git config --global user.email johndoe@example.com 3# 然后查看现有的全局信息,已有用户信息 4$ git config --list gitignore添加忽略文件失效的处理方法 如果项目开始的时候没有将一些无关文件配置进.gitignore里面,导致文件已经进行跟踪了,但是目前想把这些文件添加到.gitignore文件中,但是发现没有效果。这是因为.gitignore对已被git管理的文件无效。在这种情况下,必须使用git rm --cached < file name >这个命令来移除对这个文件的跟踪,然后将不想被跟踪的文件添加到.gitignore文件里面就可以了。 在云服务器上搭建git服务器 由于git是完全分布式设计,本质上,各个git库之间是没有主次之分的(各个库之间实际上都可以互相pull/push)。因此,在云服务器上搭建一个git服务器和客户端安装git过程上没有区别。在win 10 上安装git安装包(包括git bash,它有一个奇葩设计之后再说),在Debian 10上使用sudo apt install git安装。我们“人为决定”让云服务器上的git repo作为“公共库”,本地主机上的作为工作环境。 创建Git用户和库文件 在云服务器上,我们最好再添加一个专用git用户(不添加也可以,URL中git@domain.com:port或git@ip:port就是git作为用户名,如果你用的是别的用户,比如jack,那么就用jack@domain.com:port) 1# 在云服务器上 2$ sudo adduser git 3......... # 这里会设定git的密码,要记住 4......... 5......... 6$ cd /srv && sudo mkdir gitblogs.git # 未来把/srv/gitblogs.git作为库位置,一般git库都以.git作为结尾 7$ sudo chown -R git:git gitblogs.git # 把所属用户从root改成git 8$ su - git # 带 - 符号表示环境变量也跟着切换 9# 如果把git设置成非登录用户,则以下操作用root执行,再把文件拥有者和组改成git 10.......... # 输入git用户密码 11$ id # 实际id号码可能有区别 12uid=1001(git) gid=1001(git) groups=1001(git) 有的用useradd git创建新用户,这样只是创建了一个最小用户结构,里面很多设置、环境变量得自己弄,比较麻烦。自己也没那么多安全性讲究(包括但不限于nonlogin设置),就不那么麻烦了,直接sudo adduser git搞定。下面我们要在云端建立存储内容的仓库,有两种方式:一是建立裸库,二是建立普通库来实现同步。建立裸库之后,里面什么都没有,即使push内容之后也不会显示到工作区,也无法进行操作,只是单纯的一个存储仓库,需要在云端建立一个中转普通仓库来读取内容;建立普通库可以不用再在云端建立中转库,但是需要post-receive钩子来实现内容更新。我这里更推荐第一种。 下面是初始化裸库: 1$ cd /srv/gitblogs.git 2# 远程服务器初始化仓库 3$ git init . --bare 下面是初始化普通库 1$ cd /srv/gitblogs.git 2# 远程服务器初始化仓库 3$ git init . 4# 允许向普通库push 5$ git config receive.denyCurrentBranch ignore 详细说明如下: (1)我们可以用git init .建立一个普通库,而非裸库。当你创建一个普通库时,在工作目录下,除了.git目录之外,你还可以看到库中所包含的所有源文件。你拥有了一个可以进行浏览和修改(add, commit, delete等)的本地库。当你创建一个裸库时,在工作目录下,只有一个.git目录,裸库是没有工作区的!库仅包含记录着版本历史的文件。如果建立的是普通库,由于有工作区,可以直接把hugo博客内容的软连接建立到普通库的文件中,但是git不鼓励直接操作远程仓库的内容,所以我推荐在云上建立裸库后,在建立第二个普通库作为中转。 (2)自Git 1.6.2版以来,Git默认不会让你推送到非裸库。这是因为git push命令仅更新远程存储库上的分支和HEAD引用。它不会更新非裸机中的工作区副本、暂存区和版本指针。因此我们让git需要忽略这个要求,即git config receive.denyCurrentBranch ignore。此外,由于工作区也不会自动更新,我们后面会使用post-receive hook来更新工作区内容。 添加ssh公钥 首先,保证服务端是允许通过公钥登陆,在/etc/ssh/sshd_config中,去掉公钥登录相关的注释符。 1# 通过公钥登录,如果需要就去掉前面的注释符 2PubkeyAuthentication yes 3# 指定存放客户端ssh公钥的文件的位置 4# Expect .ssh/authorized_keys2 to be disregarded by default in future. 5AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 其次,在客户端生成公私钥对,win 10可以用cmd或git bash生成: 1# 生成公私钥对,下面一路回车即可 2$ ssh-keygen -t rsa 3Generating public/private rsa key pair. 4Enter file in which to save the key (++++++++++): 5Created directory '++++++++++'. 6Enter passphrase (empty for no passphrase): 7Enter same passphrase again: 8Your identification has been saved in ++++++++++/id_rsa. 9Your public key has been saved in ++++++++++/id_rsa.pub. '++++++++++'指的是公私钥对存放的位置(Windows用户在C:\用户\“用户名”\.ssh目录下可以看到系统的.ssh公钥id_rsa.pub),打开该位置,然后将id_rsa.pub文件中的内容复制出来,放到服务端的.ssh/authorized_keys文件中(没有就在此位置新建一个),即可通过公钥进行clone、push和pull操作。 也可不添加公钥,每次使用git用户的密码进行clone、push和pull操作。 本地库设置远程库的地址 由于为了平衡简单和安全,我们不用HTTP和Git协议(没装git-daemon),而选用SSH协议作为本地端和云服务器段的传输。SSH协议用于为Git提供远程读写操作,是远程写操作的标准服务,在智能HTTP协议出现之前,甚至是写操作的唯一标准服务。 对于拥有shell登录权限的用户帐号,可以用下面的语法访问Git版本库: 1#语法1: 2$ ssh://[<username>@]<server>[:<port>]/path/to/repos/myrepo.git 3#语法2: 4$ [<username>@]<server>:/path/to/repos/myrepo.git 第一种是使用ssh://开头的SSH协议标准URL写法,另外一种是SCP格式的写法。 两种写法均可,SSH协议标准URL写法稍嫌复杂,但是对于非标准SSH端口(非22端口),可以通过URL给出端口号。由于我使用5122作为ssh端口号,所以我使用第一种语法。 在本地git库添加远程仓库地址 1# 添加远程地址 2$ git remote add origin ssh://git@"your IP or domain":"port number"/srv/gitblogs.git 3# 推送本地仓库到远程仓库 4$ git push -u origin master 下面要要体现一个git bash的骚操作了! 由于,我的云服务器上的git用户是新创建的,因此其ssh公钥也是新添加的,首次登陆git用户也是通过root用户su过去的,之后就没有尝试登陆。我通过git push -u origin master推送的时候,git bash跳出了让我输密码的框框,如下图: 我觉得有些不对劲,因为我已经添加了公钥,理论上不应该再需要密码。我还是尝试输入了云服务器git用户的密码,显示不对,我有输入本地电脑的密码也不对,我就很奇怪。查了查资料,也没有我这个情况。 接下来,我尝试直接用VS code的git插件push,居然等了10多分钟还push不上去。最后,我使用windows自带的cmd执行git push -u origin master,跳出来一行通知: 1Microsoft Windows [版本 10.0.18363.1916] 2(c) 2019 Microsoft Corporation。保留所有权利。 3> git push -u origin master 4The authenticity of host '[xxx.xxx.xxx.xxx]:xxxx ([xxx.xxx.xxx.xxx]:xxxx)' can't be established. 5ECDSA key fingerprint is SHA256:8KEtnlH6cLQlFGYgDZgK12qDiiElEgX3PDV+X9xaiYY. 6Are you sure you want to continue connecting (yes/no)? 额,发现了没有?首次登陆ssh服务端首要确认key fingerprint的!也就是说,我们在git bash跳出的密码框里输入的不是什么密码,而是“yes”!!! 我重置了环境,在git bash跳出的密码框输了“yes”,不出所料,通过了…………🤣🤣🤣所以,git bash为什么要跳出密码框啊!误导人啊!之后,VS Code的git插件也能自动push上去了,这里也算发现VS Code git插件的一个小小问题,希望以后能改正吧。 远程仓库的工作区更新方法 无论是使用裸仓库还是使用普通仓库,我们都要读取最新更新的内容,裸仓库可以被正常clone和push更新,但是裸仓库不包含工作区,所以并不会存在在裸仓库上直接出现可用文件,需要建立一个普通中转仓库读取最新内容;而普通仓库存在工作区不自动更新问题,也需要用户自己更新。 推送给裸仓库的情形 如果之前建立的是裸仓库,里面是不会显示出任何用户内容的,需要建立一个中转普通仓库。这个中转普通仓库从裸仓库中pull最新的内容,提供给hugo blog。 我们在云端裸仓库同一文件夹中,新建一个中转仓库: 1$ cd /srv && sudo mkdir blogtransfer.git # /srv/blogtransfer.git作为中转仓库,一般git库都以.git作为结尾 2$ sudo chown -R git:git blogtransfer.git # 把所属用户从root改成git 3$ su - git # 带 - 符号表示环境变量也跟着切换 4# 将裸仓库内容clone到中转仓库,使用git的本地协议 5$ git clone /srv/gitblogs.git/ /srv/blogtransfer.git 6Cloning into '/srv/blogtransfer.git'... 7done. 8$ ls /srv/blogtransfer.git 9images 学习笔记 工程笔记 网页资料 初次git clone后,每当我们从本地提交新的内容,可以在/srv/blogtransfer.git文件夹中,使用git pull更新。 1$ cd /srv/blogtransfer.git/ 2$ git pull # 我做了一个修改,来进行测试 3remote: Counting objects: 7, done. 4remote: Compressing objects: 100% (4/4), done. 5remote: Total 4 (delta 3), reused 0 (delta 0) 6Unpacking objects: 100% (4/4), done. 7From /srv/gitblogs 8 f9e0b20..a33731d master -> origin/master 9Updating f9e0b20..a33731d 10Fast-forward 11 ...s-\350\207\252\345\212\250\345\214\226\351\203\250\347\275\262\350\207\252\345\267\261\347\232\204\345\215\232\345\256\242.md" | 105 ++++++++++++++++++++++++++++++++++++++++++++++---------------------- 12 1 file changed, 71 insertions(+), 34 deletions(-) 这样,我们就可以从中转仓库读取内容。 推送给普通远程仓库的情形 如果之前建立的是普通库,当我们在本地完成第一次远程仓库推送后,登录到服务器的/srv/gitblogs.git目录会发现,该目录里还是什么都没有啊,那和裸库有什么区别?!我们之前说了: git push命令仅更新远程存储库上的分支和HEAD信息。它不会更新非裸机中的工作区副本、暂存区和版本指针。 如果我们用git status查看,会发现多了大量的修改记录,因此我们需要手动把版本库的“指针”指向最新的地方。 1# 把工作区回退到git库的版本(此情况下等同于更新) 2$ git reset --hard 这样再查看/srv/gitblogs.git目录就有最新的内容了。需要注意的是,每一次push推送后,普通仓库都要用git reset --hard手动更新工作区。 设置post-receive hook完成内容自动更新 上面一章就已经提到过push裸仓库需要中转仓库来更新内容和push到非裸库,工作区不更新的这两方面问题,大多数人都是用post-receive hook来处理的。 Hook就是钩子,本质是一种触发器,代表在某种情况触发某种操作。Git的钩子脚本位于版本库.git/hooks目录下,当Git执行特定操作时会调用特定的钩子脚本。当版本库通过git init或者git clone创建时,会在hooks目录下创建示例脚本,用户可以参照示例脚本的写法开发适合的钩子脚本。 钩子脚本要设置为可运行,并使用特定的名称。Git提供的示例脚本都带有.sample扩展名,是为了防止被意外运行。如果需要启用相应的钩子脚本,需要对其重命名(去掉.sample扩展名)。 1$ ls 2applypatch-msg.sample fsmonitor-watchman.sample pre-applypatch.sample prepare-commit-msg.sample pre-rebase.sample update.sample 3commit-msg.sample post-update.sample pre-commit.sample pre-push.sample pre-receive.sample 其中,pre-commit、post-update、pre-receive、update等等代表着钩子被触发的情况。我们要的post-receive这里恰好没有,没关系,自己创建一个就行。 需要指出:裸仓库内直接可以看到hooks目录,而非裸仓库需要在隐藏目录.git/hooks下查看。 裸仓库 1# 新建post-receive构造,这是一个shell文件 2$ touch /srv/gitblogs.git/hooks/post-receive 3# 增加可执行权限 4$ chmod +x /srv/gitblogs.git/hooks/post-receive 普通仓库 1# 新建post-receive构造,这是一个shell文件 2$ touch /srv/gitblogs.git/.git/hooks/post-receive 3# 增加可执行权限 4$ chmod +x /srv/gitblogs.git/.git/hooks/post-receive 裸仓库的更新 复制以下脚本到post-receive文件来实现中转仓库的更新。 注意:这个脚本要复制到gitblogs.git这个裸库的hooks/post-receive文件中,而不是中转库的! 1#!/bin/bash 2git --work-tree=/srv/blogtransfer.git/ --git-dir=/srv/blogtransfer.git/.git pull 普通远程仓库的更新脚本 我们将下面这个脚本复制到post-receive文件来完成普通远程仓库的更新工作区。 1#!/bin/bash 2# 几个地址变量 3GITBLOGS_PATH=/srv/gitblogs.git/ 4# 下面是自己记录的日志,方便查询记录用 5LOG_PATH=/tmp/gitblogs-post-receive-log 6 7echo "Here is the post-receive hook to update work tree by 'git reset --hard'" >> $LOG_PATH 8 9# 输入时间等信息用于方便记录 10date >> $LOG_PATH 11echo "git reset --hard" >> $LOG_PATH 12# 回复工作区到最新版本库 13git --work-tree=$GITBLOGS_PATH --git-dir=$GITBLOGS_PATH/.git reset --hard >> $LOG_PATH 使用HUGO作为博客生成工具 我们这里这里使用Hugo作为生成博客的工具。我们根据自身需求,要做以下修改: 我的笔记是分类放在多个文件夹中,希望Hugo能够从多个目录中读取markdown 博客文章,这样我就不需要对本地文件结构做调整。 我有一个网页资料的文件夹,希望把它单独设置一个目录页面,而不出把它算成博客文章。我需要一个能生成文件夹目录txt文章的工具,然后此目录页面通过js读取并生成链接。 我的在本地写markdown的时候,使用图片的相对路径,且所有图片相对于博客文章的路径都是../images/,而Hugo默认的图片路径都是根目录的绝对路径。 希望能把内容条件给百度等搜索引擎,github page其实不需要这个功能。 增加安全的评论功能,应该需要生成永久链接。 处理yaml front matter与一级目录重复的问题。 文章中遇到太多公式的时候。hugo自带的编译器渲染出来的公式效果很差,有大量无法编译的公式。 问题1解决:我将文章目录都放到了hugo的content目录,hugo会自动读取content下所有的目录和文件,并根据目录结构生成这也是选择hugo框架的一个优势。 问题2解决:由于hugo在content文件中不支持编译纯html文件,我将网页资料的文件夹放在/static/目录下,然后在主题的lib_webpages模板中用hugo的readDir函数读取文件夹中的内容,然后拼接成链接,不需要能生成文件夹目录txt文章的工具等步骤。目录则使用/content/library/webpages.html生成,其调用了主题中的lib_webpages模板。有个小缺点,即URL的层级关系被破坏。 问题3解决:在本地我用的是VS Code写markdown,我发现它是支持打开的文件作为根目录来索引文件的,即支持以打开的目录为"/"索引。因此,我把我所有本地的markdown文件中的../images/改成了/images/。其实用绝对路径对本地写markdown也是有好处的,就是主要打开的文件夹不变,就可以用多层文件结构编写文档,而不用总记相对路径;对网站的SEO也有利。此外,hugo对相对路径的支持也是有很多问题的,不值得花太多精力处理。 问题4TODO:参考https://www.kyfws.com/post/kyfws-hugo-baidu-seo/ 问题5解决:可以通过hugo内置的_internal/disqus.html完成评论功能,但是感觉我目前不太需要。 问题6解决:为了不让vscode 的markdownlint报错,我们首先将其多个一级标题警告“MD025/single-title/single-h1: Multiple top-level headings in the same document”取消。因为,VS Code的markdownlint插件会把yaml元标题当成是一级标题,因此需要在本地编辑环境目录中设置.markdownlint.json文件 1{ 2 "MD025":false 3} 4 然后,我们为了让文章看起来更美观,采用以下形式: 1--- 2yaml meta info 3title : "TITLE" 4date : "2020-02-02" 5--- 6 7目录/table of contents 8 9## H1 title<!-- omit in toc --> 这样在渲染成网页的时候,两个大标题会夹着目录,因此会美观一些。如果hugo能提供自动把一级标题当元信息,或者VS Code能够markdown能够渲染yaml头信息就不同这么麻烦。此外,我将H1 title前面变成二级标题,可以在不改变.markdownlint.json文件的情况下在VS Code中不报错。 问题7解决:在有大量公式的文章中,不要使用hugo自带的golden编译器,替换成pandoc。pandoc的安装方法可在网上查到。我们还需要在该文章的头部信息中加入markup: pandoc这一条。 修改Hugo博客的clarity主题 我的博客是基于clarity主题修改而来,基本改动有 在头部导航添加了归档和分类两项,添加了二者的模板、功能和archive type; 在头部导航添加了资料库->资料web版,基于readDir实现了网页信息遍历的post,网页资料存放在/static/网页资料 在头部导航添加了资料库->书签地址,书签位置/content/library; 在头部导航添加了专栏项,基于原来的series修改而来; 删除了多语言支持,因为总是出bug; 修改了侧边栏的内容显示顺序,取消了个人信息阅读更多按钮,将链接移植到了名字上; 精简了分享链接,由于外国大多社交网站不可访问和国内社交网站的封闭性,只保留了复制网页链接的功能,删除了多余的社交网站链接; 简化了默认的archetypes; 修改了主题配色、链接、404页面等样式 现在只要将我的markdown文章的文件夹放入content目录,网页资料的内容放到/static/网页资料,images中的图片文件夹放到/static/images中,即可自动生成静态网站。 上传修改好的Hugo博客 首先,我们把改好的网站主题上传到云主机,路径为/opt/blogtheme,并把/opt/blogtheme的拥有者改为git。然后将其中content的内容建立软链接,连接到git工作区的相应目录。 1# 将/opt/blogtheme的拥有者改为git 2$ sudo chown git:git -R /opt/blogtheme 如果使用裸仓库,需要从中转仓库提取需要的文件,路径为/srv/blogtransfer.git。我们建立目录的软链接: 1# 如果主题中已经有了/opt/blogtheme/static/projectnotes,则删除 2$ ln -s /srv/blogtransfer.git/工程笔记 /opt/blogtheme/content/projectnotes 3# 如果主题中已经有了/opt/blogtheme/static/studynotes,则删除 4$ ln -s /srv/blogtransfer.git/学习笔记 /opt/blogtheme/content/studynotes 在hugo 0.62以后,不在支持static的软链接复制(说是因为存在可能导致循环链接),因此hugo主题的static文件夹中无法直接使用ln,退一步,我使用rsync同步文件夹。我们把下面两命令加到之前的post-receive脚本中。 1# rsync -a source destination 2# 图片同步 3rsync -a /srv/blogtransfer.git/images/ /opt/blogtheme/static/images 4# 网页同步 5rsync -a /srv/blogtransfer.git/网页资料/ /opt/blogtheme/static/网页资料 如果使用普通仓库,路径为/srv/gitblogs.git/。我们建立目录的软链接: 1# 如果主题中已经有了/opt/blogtheme/static/projectnotes,则删除 2$ ln -s /srv/gitblogs.git/工程笔记 /opt/blogtheme/content/projectnotes 3# 如果主题中已经有了/opt/blogtheme/static/studynotes,则删除 4$ ln -s /srv/gitblogs.git/学习笔记 /opt/blogtheme/content/studynotes 在hugo 0.62以后,不在支持static的软链接复制(说是因为存在可能导致循环链接),因此hugo主题的static文件夹中无法直接使用ln,退一步,我使用rsync同步文件夹。我们把下面两命令加到之前的post-receive脚本中。 1# 在hugo0.62以后,不在支持static的软链接复制(说是因为存在可能导致循环链接),因此static文件中 2# 无法直接使用ln,退一步,我用rsync同步。 3# rsync -a source destination 4# 图片同步 5$ rsync -a /srv/gitblogs.git/images/ /opt/blogtheme/static/images 6# 网页同步 7$ rsync -a /srv/gitblogs.git/网页资料/ /opt/blogtheme/static/网页资料 这样,我们也实现了内容和格式的分离,/opt/blogtheme做为存放格式的位置,基本不用动,每次只要git更新内容即可。 使用Jenkins自动化部署网站 经过上述准备,我们已经准备好了所需的内容,下面就是使用jenkins将它们构建成网站。我们首先新建网站的目录文件夹/opt/public/: 1$ sudo mkdir /opt/public 2# 将/opt/public的拥有者改为git 3$ sudo chown git:git /opt/public 如果直接从shell手动输入构建命令,就一句指令很简单。 1$ hugo --minify -s /opt/blogtheme -d /opt/public/ 2Start building sites … 3hugo v0.89.4-AB01BA6E+extended linux/amd64 BuildDate=2021-11-17T08:24:09Z VendorInfo=gohugoio 4 5 | ZH-CN 6-------------------+-------- 7 Pages | 335 8 Paginator pages | 54 9 Non-page files | 0 10 Static files | 361 11 Processed images | 0 12 Aliases | 80 13 Sitemaps | 1 14 Cleaned | 0 15 16Total in 18050 ms 不过,我们希望在git完成push后自动执行。这里我们使用jenkins来完成自动构建命令。 首先,为了解决jenkins的权限和环境变量问题,安装好jenkins后,我们需要先进行以下配置: 防止jenkins出现command not found的错误,我们要为jenkins添加PATH环境变量。在系统管理->系统配置->全局属性对话框中选中“环境变量”,添加键值对“PATH”和PATH对应值。PATH对应值在系统中使用echo $PATH获取,复制粘贴到这里即可。 防止jenkins出现Permission denied权限不够的问题,我们要重新以git用户启动jenkins,以git用户启动是因为我们之前文件拥有者都是git。 1$ sudo vim /etc/sysconfig/jenkins 2...... 3 ## Type: string 4 22 ## Default: "jenkins" 5 23 ## ServiceRestart: jenkins 6 24 # 7 25 # Unix user account that runs the Jenkins daemon 8 26 # Be careful when you change this, as you need to update 9 27 # permissions of $JENKINS_HOME and /var/log/jenkins. 10 28 # 11 29 JENKINS_USER="git" # 由默认值jenkins改为git 12...... 13# 修改jenkins对应文件拥有者 14$ sudo chown -R git:git /var/lib/jenkins 15$ sudo chown -R git:git /var/cache/jenkins 16$ sudo chown -R git:git /var/log/jenkins 17# 重启jenkins 18$ sudo systemctl restart jenkins 接下来,我们打开jenkins网站界面,默认是8080端口。首先按照页面提示进行初始化(因为我的jenkins早就安装了,这里就不介绍初始化流程了),然后点击左边菜单栏的“新建任务”,输入任务名称,选择构建一个自由风格的软件项目。 按照如下配置,设置构建流程。我们不需要源码,因此也没有工作区,在构建一栏中加上需要执行的命令。构建触发器接下来再设置。 设置好后,我们点击保存,然后点击左侧菜单栏的“立即构建”,就可通过jenkins执行构建命令。目前为止,我们做的以上的工作,只不过是把在命令行做的工作放到jenkins里完成而已,若需要自动触发构建,还需要构建触发器,如下图所示: 构建的触发器种类选择“触发远程构建”,然后在身份验证令牌中输入一串随机数作为验证码,接下面,我们只需要访问一个网址http://127.0.0.1:8080/job/hugoblog/build?token=TOKEN_NAME,就能触发这个构建。由于我们的git库和jenkins在同一台主机上,所以IP写127.0.0.1就行,端口8080是jenkins的默认端口,后面的url是固定的,最后在“TOKEN_NAME”处用我们刚在身份验证令牌中输入的随机替代。我们在浏览器中输入这个URL,就可以发现jenkins启动了一个新的构建。 一般这样就没什么问若发生403错误:Error 403 No valid crumb was included in the request,则考虑jenkins关闭全局安全设置中的“跨站请求伪造保护”;若真心为了安全考虑,则增加获取crumb值,具体步骤自行搜索。 接下来我们要把触发网址的工作交给git的hook脚本,我们在post-receive脚本的最后添加如下命令: 1# 触发jenkins编译新网站 2# -X 表示请求类型,用post;-u 表示认证信息,填写登录jenkins的用户名密码;-v表示显示详细过程 3# URL触发远程构建所用的URL 4curl -X post -u 'username:password' -v http://127.0.0.1:8080/job/hugoblog/build?token=TOKEN_NAME 到此,我们已经完成了本地git push后,自动完成内容更新、网站构建的工作。 推送到Github并生成Gitpages 如果要使用GitPages,我们需要将hugo编译好的网站,而非原始数据推送到GitHub。 首先,我们要在GitHub新建一个库,库名比较特殊,必须是:用户名.github.io,且所有字母必须小写。选择public类型,然后下面的README、证书、.gitignore都不用添加。如下图所示: 由于我们自己云服务和GitHub的域名不一样,所以不能直接把云上编译好的网站直接push到GitHub。我们需要改变baseUrl参数,重新编译。为了公式完整,我们之前在markdown编译时用了pandoc编译速度慢,同时国内连接github网络不稳定,所以我在jenkins中单独为Github的推送流程新建了一个任务,以免拖累本地编译过程。 我们先做一些准备工作。 第一步,我们为了能让云服务器有权限把内容推送给GitHub的库,因此要将自己的公钥存放到GitHub上。我们存放的是云服务器上git用户的公钥,查看git用户的公钥cat /home/git/.ssh/id_rsa.pub,若没有此文件则使用git用户的ssh-keygen -t rsa创建。将公钥放到GitHub右上角图像->settings->SSH and GPG keys->New SSH key,然后把公钥复制粘贴过来。 第二步,我们为推送到github的库做一些初始化工作。 1# 为GitHub新建库文件夹,并将所有者改为git 2$ sudo mkdir cd /opt/surprisedcat.github.io 3$ sudo chown git:git /opt/surprisedcat.github.io 4# 切换到git用户执行以下操作 5$ su - git 6# 重新编译网站,注意baseUrl是不同的 7$ hugo --minify --baseUrl=https://surprisedcat.github.io -s /opt/blogtheme -d /opt/surprisedcat.github.io/ 8Start building sites … 9hugo v0.89.4-AB01BA6E+extended linux/amd64 BuildDate=2021-11-17T08:24:09Z VendorInfo=gohugoio 10 11 | ZH-CN 12-------------------+-------- 13 Pages | 335 14 Paginator pages | 54 15 Non-page files | 0 16 Static files | 364 17 Processed images | 0 18 Aliases | 80 19 Sitemaps | 1 20 Cleaned | 0 21 22Total in 18596 ms 23# 初始化git库 24$ cd /opt/surprisedcat.github.io 25$ git init . 26# 第一次commit和添加远程库,commit带上日期 27$ git add . 28$ git commit -m "`date` commit" 29# 将主分支重命名为main 30$ git branch -M main 31$ git remote add origin git@github.com:SurprisedCat/surprisedcat.github.io.git 32$ git push -u origin main 第三步,在jenkins中新建构建任务。源码管理选择“无”,构建触发器选择如下图: 我们建立两个触发器,一是传统远程触发器,二是在云构建完成后,自动构建推送到github的流程。 在构建栏目下,选择“执行shell”,并填入以下命令: 1hugo --minify --baseUrl=https://surprisedcat.github.io -s /opt/blogtheme -d /opt/surprisedcat.github.io/ 2cd /opt/surprisedcat.github.io 3git add . 4git commit -m "`date` commit" 5git push -u origin main 点击保存。 一整套配置完成。 接下来,为了安全起见,我们不再允许git使用shell登录(过河拆桥啦),我们修改/etc/passwd下git用户的最后一项,将/bin/bash改为/usr/bin/git-shell,这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。