部署Hugo
这个项目是在今年夏天完成的,该设想在全年年底就已经形成了,迫于工作上总是有别的事情要忙而迟迟没有开始。前期的我一直在完善Rapid.Space 使用手册和Rapid.Space 学习进程,对于部署软件在SlapOS上的实际操作总是手痒。好在法国的夏天,工作没有这么紧迫,我终于在夏天快要结束的时候完成了这个小项目。虽然里尔的夏天其实并没有来,今年一直都好冷。
目前在网页端IDE(Theia)运行Hugo的教程已经在Rapid.Space 用户使用手册上发布了:
该项目的主旨也是在Theia环境中进行网站的修改,并以此为云平台和服务器进行网站的发布和运行。当然我还添加了Nginx服务,或许可以在未来作为产品网站的服务器,但在本次版本中还未得到区分。本次开发过程,我也是在Theia上完成的。Theia已经在SlapOS上发布并处于测试阶段。
附:项目的Merge Request源码:software/hugo: Add Hugo software in slapos
添加组件(Component)
众所周知,Hugo是一款由go语言编写的静态网站生成工具,所以我们首先要确认的是,SlapOS架构中是否已经有go的存在,这将为我们省去不少麻烦。Golang 确实已经实现了,那我们就可以直接开始写hugo的组件了。
根据Hugo的github仓库的提示:
Build and Install the Binaries from Source (Advanced Install)
Prerequisite Tools
- Git
- Go (we test it with the last 2 major versions; but note that Hugo 0.81.0 only builds with >= Go 1.16.)
Fetch from GitHub
Since Hugo 0.48, Hugo uses the Go Modules support built into Go 1.11 to build. The easiest is to clone Hugo in a directory outside of
GOPATH
, as in the following example:mkdir $HOME/src cd $HOME/src git clone https://github.com/gohugoio/hugo.git cd hugo go install
我们的实现过程主要就是获取仓库内容以及用go安装。
我们可以先通过[hugo-get]
实现下拉仓库的功能:
[hugo-get]
<= go-git-package
go.importpath = github.com/gohugoio/hugo
repository = https://github.com/gohugoio/hugo.git
revision = f6821b88abbc1237af0e28cefbc624e6cda3305a
在产品端的revision
,我们一般还是更倾向于固定commit,方便管理。
接着就是go install
的部分:
[gowork]
install =
${hugo-get:location}:./...
environment =
CGO_ENABLED = 1
buildflags = --tags extended
[gowork.goinstall]
depends_gitfetch =
${hugo-get:recipe}
command = set -e
. ${gowork:env.sh}
cd ${hugo-get:location}
go build ${gowork:buildflags} -o ${gowork:bin}/hugo
具体的参数设置可以在hugo的文档中找到,并对应在buildout中设置。
最后通过[hugo]
进行打包,该组件便可以实现快速复用。
[hugo]
<= gowork.goinstall
添加Hugo软件
software.cfg
让我们先从software.cfg
看起:
extends =
...
../../component/hugo/buildout.cfg
...
parts =
...
hugo
...
首先在extends
中添加刚才写的hugo组件,并提供上文中提到的打包好的hugo
。如此一来,我们就拥有了hugo的工作环境,
在[profile-common]
,我定义了一些必要的路径变量:
[profile-common]
nginx_location = ${nginx:location}
dash_location = ${dash:location}
go_environment = ${gowork:env.sh}
openssl_location = ${openssl:location}
template_nginx_conf = ${template_nginx_conf:target}
template_mime_types = ${template_mime_types:target}
template_index_html = ${template_index_html:target}
template_monitor = ${monitor-template:rendered}
接下来是必要的模版[template-cfg]
,它具体对应的就是下文会详细展开的instance.cfg.in
:
[template-cfg]
recipe = slapos.recipe.template:jinja2
rendered = ${buildout:directory}/template.cfg
template = ${:_profile_base_location_}/${:filename}
mode = 0644
context =
section buildout buildout
section parameter_list profile-common
可以在content
部分看到,我将profile-common
定义给了parameter_list
,parameter_list
就可以代表profile-common
在instance.cfg.in
被使用了。
接下来是使用download
菜谱,并通过<=
复用:
[download-base]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:_update_hash_filename_}
mode = 0644
[template_nginx_conf]
<= download-base
[template_mime_types]
<= download-base
[template_index_html]
<= download-base
复用的含义,举个例子:
[template_nginx_conf]
<= download-base
其实就相当于:
[template_nginx_conf]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:_update_hash_filename_}
mode = 0644
为了减少代码的赘余,而将下载菜谱模块化。而下载菜谱的意义就是使用template_nginx_conf
,template_mime_types
,template_index_html
这几个模版。
instance.cfg.in
接下来,我们来看看hugo的实例instance.cfg.in是如何完成的:
定义参数:
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration
computer = ${slap-connection:computer-id}
partition = ${slap-connection:partition-id}
url = ${slap-connection:server-url}
key = ${slap-connection:key-file}
cert = ${slap-connection:cert-file}
configuration.hugo-monitor-httpd-port = 8196
configuration.nginx-monitor-httpd-port = 8197
configuration.site = default
创建需要的路径:
[directory]
...
[basedirectory]
...
[tempdirectory]
...
定义端口:
[hugo-frontend-port]
recipe = slapos.cookbook:free_port
minimum = 1313
maximum = 1323
ip = ${slap-configuration:ipv6-random}
[nginx-frontend-port]
recipe = slapos.cookbook:free_port
minimum = 1324
maximum = 1334
ip = ${slap-configuration:ipv6-random}
当然,我们也可以直接在[slap-configuration]
中直接定义,但是我还是用了free_port
的烹饪书进行空余端口的筛选,这样可以保证不管是hugo的服务器也好,还是nginx的服务器也好,都可以顺利地启动而不受冲突端口的干扰。
接下来的[hugo]
模块同样也主要是一些参数的设置,包括hugo/nginx服务器的后端地址及其端口,一些路径等。
[hugo]
nb-workers = 2
go-environment = {{ parameter_list['go_environment'] }}
ip = ${slap-configuration:ipv6-random}
hugo-port = ${hugo-frontend-port:port}
nginx-port = ${nginx-frontend-port:port}
hugo-access-url = http://[${:ip}]:${:hugo-port}
nginx-access-url = https://[${:ip}]:${:nginx-port}
path-pid = ${basedirectory:run}/nginx.pid
path-log = ${basedirectory:log}/nginx.log
path-access-log = ${basedirectory:log}/nginx.access.log
path-error-log = ${basedirectory:log}/nginx.error.log
path-tmp = ${tempdirectory:tmp}
path-nginx-conf = ${directory:etc}/nginx.conf
path-mime-types = ${directory:etc}/mime_types
path-nginx = {{ parameter_list['nginx_location'] }}/sbin/nginx
# Docroot
docroot = ${basedirectory:data}/${slap-configuration:configuration.site}/public
其中Nginx的设置也主要是参考Nginx的官方资料,比如其log、配置文件的路径。
这里我也定义了go环境,在使用hugo之前,我们总是需要先source
go环境,
go-environment = {{ parameter_list['go_environment'] }}
如果你还记得的话,你会发现,parameter_list
是来自software.cfg
中的[profile-common]
模块。
接下来是一个Hugo服务器的实现。
[hugo-server]
recipe = slapos.recipe.template:jinja2
rendered = ${directory:bin}/hugo-server
mode = 0700
template =
inline:#!/bin/sh
. ${hugo:go-environment}
cd ${basedirectory:data}/${slap-configuration:configuration.site}
if [ -d "public" ]; then rm -Rf public; fi
hugo && hugo server --bind=${hugo:ip} --port=${hugo:hugo-port} --baseURL=${hugo-frontend:connection-secure_access} --appendPort=false
${directory:bin}
路径下的程序可以一直运行,这正符合了我们对hugo服务器的要求。
template =
inline:#!/bin/sh
用这种方法,我们可以简便地将bash语句放入模版中。具体的hugo命令需参考Hugo官方文档。我这里主要是保证public
文件为最新,因为它会被放在在Ngnix服务器上。另外就是一些端口和IP地址的配置。
剩余部分,则可以参考HTML5AS教程。
Templates
模版部分,我最后只留下了3个比较冗长的内容。其他我都尽量以template =
形式写在software.cfg
中。
index.html.in
很明显就是一个主页html。但其中也免不了一些来自software.cfg
和instance.cfg.in
中的参数:
<pre><code>$ cd {{ data }}</code></pre>
nginx.conf.in
也很熟悉,是nginx服务器配置的必要文件。
测试
最后是必不可少的测试部分。可参考How To Test Your Software Release。
为了快点结束,~~因为夏天要过去了,~~我只进行了几项简单内容的测试。
未完成的工作
这个软件的开发其实十分粗糙,因为一开始我把自己局限在了HTML5AS的教程里,试图依葫芦画瓢地将Hugo做出来。这让后期设计上的改动变得无比困难,也就是费时间。我可以大致罗列一下问题:
- 为了运行
hugo
,命令行是必须的。也就是一个像Theia一样的IDE是必不可少的。如果能把Hugo嵌入Theia,那么用户在使用的时候就可以一步到位,并且有一个标准化的生产环境。 - 这一版Hugo中,我我留下了两个web服务器:Hugo和nginx。本意是Hugo将作为调试服务器,而nginx则变成生产服务器。但是目前这两个服务器的作用是一样的,如果后期能改进,希望可以进行明确区分。比如对于Nginx服务器,可以直接通过一个git仓库的URL的参数而运行。
- 测试方面还有很多没有涵盖到的地方。
纸上读来终觉浅,绝知此事要躬行。
另外,我想起来为什么自己之前都不怎么用中文写了:为了打Markdown符号需要中英文转换。。。