当红炸子鸡traefik,配合nginx,完成hugo博客的高效部署,如何做到?
今天通过使用traefik
加上nginx
这两种技术,部署了我现在使用的这个博客。过程中稍遇到一些问题,但是由于之前自己已有网站通过traefik
加上docker
的swarm
模式完成了部署,所以对于traefik
配置的过程并不陌生。这篇文章主要分为三部分,第一部分讲hugo博客部署的一些注意的点。第二种方式就是使用k8s或者docker-swarm模式部署应该是如果出错应该怎样高效定位问题。第三部分主要讲一下可能遗留的问题以及自己对这些遗留问题的规划
部署hugo博客的注意点
由于hugo是基于go语言开发的,所以它本身的性能已经挺高了,go语言之所以性能高让我脑海马上浮现了那幅图,GMP模型中Goroutine一个个协程都把自己准备好到可以干活的状态,被放到了全局队列或者局部队列内。调度器看着系统有资源闲置了马上就拿过一个Goroutine来自己线程内执行,如果全局取完了就取局部队列的,总之不让自己有闲置下来,真的没Goroutine可拿了,就停了,不像很多进程模型,要切换环增context,要做线程间的通信,交给操作系统去做事,操作系统针对线程通信间要做许多兼容所以会在性能上有所损失。所以,即使你直接运行hugo的服务性能也是不低的,和所有能够独立提供的服务架构一样,如nodejs
、SpringCloud
,虽然你觉得它简单,容易上手,但实际上它已经帮你做了不限于服务发现、不限于发布订阅、不限于通信协议的支持、不限于通信方式上异步非阻塞等等等等的实现。简化到,它暴露出接口给了你,让你按着文档操作规范就能实现什么操作,但是底层的运行原理还是很复杂的。
我在部署hugo的时候,特别是单独以hugo就来做nginx的事情时候,记得要把自动重载给禁了,当然本地开发倒没太大关系。因为如果你部署服务器配置本身不高,这个热加载还是挺耗费性能的,而且对于这种博客程序,不更新文章,也没有什么需要随时刷新的,要禁用,用下面的方式。
command: server --baseUrl="这里指定你的域名" --appendPort=false --watch=false --disableLiveReload=true --buildDrafts
- baseUrl看双引号中就知道啥意思了,注意你自己应用服务的配置文件,通常路径在
config/_default/config.yaml
或者直接根目录下config.yaml
里了参数baseUrl
也要对应上 - appendPort 如果用docker或者k8s部署,hugo服务通常运行1313端口,如果你不指定它会在访问的时候形如
*:1313
,这不太美观,hugo应该帮你做了类似于vue
中devServer
中proxy
同含义的事情 - disableLiveReload,就是字面意思了,哪次提交了文章更新,记得去服务器上(
宿主机直接安装
)或者容器里(或docker或k8s模式部署
)执行一下命令hugo -D
- buildDrafts,
draft=false
说明把文章从草稿改成了发布状态,draft=true
就是草稿状态,所以它的含义就是草稿状态也编译,让你能预览效果。
这里还要注意,这里都是针对的内容,也就是你创建于根目录下content
中的东西,如果你改了模板,用hugo new widget
创建了小组件,用hugo new section
创建了展示区块,你都要重新编译整个应用程序,同时,针对于css、js
的修改通常要先清了resource目录下的缓存,还要记得把config
中的build->useResourceCacheWhen
从always
改成fallback
,不然会报错。
在提一下nginx
引入的问题,通常来说用nginx来代理资源目录,因为hugo
应该编译完了,所有界面的东西都会生成到public
目录下,直接用nginx
接管这些资源就是最高性能的。但是我部署中遇到了一些问题,在下一条中说。
k8s或者docker-swarm模式部署应用报错了要怎样定位问题
由于我采用的是traefik
加nginx
做为负载均衡层,如果只用生成的静态资源做反向代理,需要修改的东西比较多,我也懒得折腾了,所以就暂时用hugo
直接来做服务了。部署的时候,本地一共8个服务,很顺利的就起来了,但是部署到线上之后,hugo
服务一直报错,我百思不得姐。常用的方式docker/kubectl logs xxx | tail -100
、docker/kubectl logs xxx | cat | grep "xx"
之类的,对于应用组成比较简单的还好说,应用组成部分比较复杂的,比如说gitlab
部署的时候报错,我查error,说的什么驴球马蛋,根本不知道哪句直指问题核心,很鸡贼。后面发现这个命令超好用kubectl get services --all-namespaces
用在k8s中查看所有的服务,docker service ls
用在docker中,这个时候无论k8s还是dockerSwarm模式下,你都能看到你运行了几个服务,服务有几个replicat是否运行正常,就类似于(1/1)这种就是1个服务运行正常,(0/1)就说明一个服务但是有问题。再用命令docker|kubectl service ps --no-trunc xxx
就能把报错原因完整的展示出来,我hugo
刚部署腾讯云始终起不来,后来定位问题是macOS
在有效的配置:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
在centos
上volumnMount
映射无效,注释后就正常启动了。
这就牵扯到另外一个问题,就是监控系统的重要性,如果你用过prometheus
配合grafana
的可视化界面监控服务运行状态,收集dubbo
服务运行的网关日志有多么的香,这是另一个话题,有机会再分享。
部署完成后还遗留了哪些问题及未来展望
最开始用kubesphere部署了整套k8s集群服务来支持hugo连同一同上线的7个服务。创建应用,创建持久卷,创建配置文件,创建各种密钥玩的那叫一个溜。后面又尝试启用了devOps
服务功能,这里还是得感慨一下,像kubesphere
这种可视操作的k8s工具真是入门的首选了,能帮你厘清很多你之间傻傻分不清楚存在功用许多文件的问题。比如我本地纯手工部署k8s的时候,搞清楚ingress
和deployment
和DaemonSet
之间到底是个啥关系,就大费了一翻周章。而kubesphere每一步操作完成之后,会有对应的.yaml
文件生成,你对应自己操作,再看这个文件,基本就知道哪个声明是做什么的了。“兴起一时爽,玩脱背大锅”由于我服务器性能不太行,所以devOps
部署以后,直接把服务拖死了,我ssh
登录都上不去。最后不得不重装了系统。后面觉得单机确实k8s
意义也不大,就用了docker swarm
模式进行了部署,你还别说,依旧还是挺香的。我创新性的把边缘路由traefik加反向代理nginx、有状态服务、应用服务给分开了。创建了三个不同的docker-compose-*.yml
文件,这样初始化的时候,先运行边缘路由+nginx
,这样所有请求就都能有流量入口,nginx也知道该转发到哪个应用做具体处理了。有状态服务mysql、redis、rocketmq
这些应用运行所需依赖的前提条件也就满足了。最后运行应用,什么基于java springCloud
的订单微服务系统、基于golang
的hugo
,基于python
的django
,基于php
的yaf
通通都能正常启动了。当然,这个配置的过程还是有些烦琐的,各自各有针对性,比如说java
中镜像文件Dockerfile
要分层编译,不然一个应用做成镜像很大,生成的中间层文件没意义还打到镜像里既浪费带宽,也影响容器性能。比如说django
部署的时候,可以原生直接运行,可以用uwsgi
来协助运行,也可以用gunicorn
来运行,性能是完全不同的,而它们运行的配置参数的含义,及如何保证容器编排领域端口概念之下真正把这些应用跟反向代理串起来是个非常细碎、很耗费时间、但不践行你又理解不了它们间连通真正底层原理的很复杂的一门行为学了,这个以后有机会再分享。现在的经验就是k8s如果你服务体量不大,没必要,还是挺复杂的,一个不注意就把自己玩蒙圈了。而对于中小型服务,用docker swarm
模式就很香,支持动态扩展节点,支持往相同的overlay
网络上加服务,也具有一定的灵活性,常玩对你理解k8s
的运行原理也颇有裨益。
最后,对这篇文章进行一下总结。容器化服务是个大趋势,现在想想自己工作之初,一步一步在笔记本上搭lump
环境,搭tomcat
环境,再反观现在docker、k8s
的出现,真是一种解脱。本地跑的好好的,上线报错业务过来招,起身大声呵斥:”我本地跑的好好的,怎么你一验就出问题,一定是你操作流程有问题,快演示演示,我给你板正板正“,docker、k8s
的出现这种问题也一去不复返了。但是进步总有成本,你在容器概念没出现前,看怎么编译安装环境,解决编码问题,解决版本问题是成本,现在容器时代了,你要懂什么是容器,你要知道怎么操作容器,你要对容器使用融会贯通甚至能举一返三,随手撸出一个名噪一时的中间件这也是成本。成本永远都存在,成本付出都有价值,或多或少而已,但看你是愿还是非愿。