golang中的热加载

热加载

一般称为hot loading,指在应用程序运行时动态加载或替换代码、配置或资源,而无需停止或重新启动应用程序。
通过热加载,可以在运行时更新应用程序的部分内容,而不会中断服务或造成停机时间。
对于开发人员来说,hot loading更多的体现在更改了文件内容之后,不需要编译实时的就能看到改变后的结果。
这种特性一般来说都是解释性语言的专利,golang作为编译型语言无法做到真正的热加载。
但是由于golang编译速度足够快,所以有一些工具通过监听文件变化,重新编译运行来实现伪热加载功能。

工具air

推荐一个自用的工具air
github官方仓库地址
工具本身没什么可说的,用起来也是极为简单

推荐使用golang的module管理工具全局安装

1
2
3
4
5
6
7
8
9
10
#安装air
go install github.com/cosmtrek/air@latest
#检查是否可用
air -v
#切换到项目文件夹
cd /path/to/your_project
#初始化配置文件
air init
#启动air
air

效果

air的效果图

图中右下角第一个ok1就是修改之前的
只要保存文件,就触发了air的自动编译,再次请求就是ok2了,非常的方便

goland多次保存的问题

有的时候goland会因为格式化或者其他原因保存多次,如果不做任何特殊配置会导致air重新编译n次(n=保存的次数)
因为几次保存几乎都是同时进行的, 所以只需要在配置文件里设置delay = 100即可有效解决问题

记录一次sshd故障

故障表现

昨天还能连的机器,今天就突然Remote side unexpectedly closed network connection

尝试使用vmvare管理平台进行登录

登录正常,基本可以确认是sshd故障

观察配置文件

配置文件打开之后没发现有什么异常,允许远程登录等选项都是正常的

观察进行是否正常

1
2
ps -e|grep sshd
>00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups

感觉好像sshd没有起来

尝试重启sshd服务

1
service sshd restart

报错 让查看详细信息
在报错信息中看到

Jul 11 11:54:05 TJnetwork sshd [13153]: Missing pr ivi lege separat ion directory: /var/empty/sshd

第一次听说/var目录下会因为缺少文件夹导致sshd启动不了

history观察之前的操作发现供应商对/var目录进行了硬盘挂载导致目录没了。。。
大无语,直接mkdir新建目录之后重启sshd服务恢复正常。

keycloak中refresh_token的相关测试

refresh_token是什么

起手先向chatgpt提问refresh_token的作用,得到的回答如下:

  1. 刷新访问令牌:访问令牌通常具有短暂的有效期,一旦过期,它就不能用于进行进一步的身份验证和授权请求。在这种情况下,客户端可以使用refresh_token向身份验证服务器发起请求,以获取一个新的有效的访问令牌。通过刷新令牌,客户端可以持续地访问受保护的资源,而无需再次要求用户进行身份验证。
  2. 提高安全性:相对于长期有效的访问令牌,refresh_token的有效期通常更长,因此可以减少访问令牌的生命周期,从而减少了黑客获取有效访问令牌的机会。如果令牌被泄露或被不法分子获取,它的有效期相对较短,限制了潜在损失。
  3. 用户交互:当访问令牌过期时,客户端可以使用refresh_token向身份验证服务器发起请求,获取新的访问令牌。这个过程通常是无需用户交互的,用户不需要再次提供他们的凭据来获取新的令牌,因此提供了更好的用户体验。

用人话来解释下chatgpt回答了一些什么

刷新访问令牌

我们都知道access_token的作用,无论是前端直接请求还是后端转发请求,当你想访问受到jwt保护的资源的时候,都要带上可爱的access_token。
根据最佳实践,一般access_token有效时间设置为30分钟。那么在用户使用网站超过30分钟的时候,会因为access_token过期而无法请求受保护的资源。
在这种情况下,使用refresh_token来获取新的access_token就是一种比较合理的选择。

为什么不直接使用较长有效期的access_token呢?

这是我的第一个疑问。仔细思考一下这个问题的本质,就是access_token里到底包含了什么。
它附带了用户的信息,比如关键的userid/username,附带了这个client能请求此用户的哪种资源(也就是scope)。
那么这些信息是否一成不变呢?答案是否定的,比如极端的情况我希望对一个名为QueryInfo的client下发一个180天有效期的access_token。
用户A同意了client-QueryInfo访问自己信息的请求,那么QueryInfo就拿到了用户A授予它的180天有效期的jwt。
在第20天的时候,用户A反悔了,他在自己的个人授权界面那里取消了对QueryInfo的授权。
但是如果管理员设置了一个180天有效期的access_token,那么QueryInfo就可以持续的拿着这个access_token来访问用户A的信息。
因为jwt的技术设计原因,此时的取消授权是无意义的。
恰巧一个懂行的管理员设置了30分钟有效期的access_token,180天有效期的refresh_token,那么QueryInfo使用refresh_token来换取access_token的时候,就会被拒绝,因为用户A他已经取消了授权。

是否维持较长时间的keycloak的session来达到同样的效果

这是我的第二个疑问,如果保持了keycloak登录的session,那么用户access_token过期之后自然就可以跳转到keycloak登录页面,
并且因为keycloak的session已经存在,自然会通过redirect_uri跳转回原页面,实际对用户是也是无感知的。
简单思考之后,发现跳转本身就需要有个过程,对keycloak本身也是一种压力,就算是不需要用户在用户名密码界面停留,也至少会造成白屏,进度条走动等问题。
所以refresh_token不能简单的被替代

keycloak中哪些参数控制了refresh_token

本文基于16.1版本的keycloak
Clients->对应的client->settings->advanced Settings 这其中有三个选项比较关键

  • Access Token Lifespan (控制access_token的有效期)
  • Client Session Idle (控制refresh_token的有效期)
  • Client Session Max (控制refresh_token有效期的最大值 一般没有特殊需求跟上一行同值即可)
    这三个值都有一个全局变量的默认值,是在realms菜单中的tokens里管理
    如果没有在此client下设置过值,那么默认就跟随全局变量走
    其中有一个需要注意的点是,全局变量中还有一个SSO Session Idle
  • SSO Session Idle代表了keycloak登录态的session最大默认登录时常。
  • Client Session Idle不能超过SSO Session Idle,max也同理。那么记得要把realms里面也改成一个比较大的值。

观察一个授权码模式的token返回

我们先把test_login这个client的配置文件按照上文所述改为1天有效期的Access Token Lifespan,180天有效期的Client Session Idle

访问授权码模式demo加上F12打开控制台可以看到
keycloak-refresh-refreshtoken.jpg
refresh有效时间已经被设置为180天,说明配置生效

使用refresh_token

判断access_token是否超过有效期,如果超过有效期则尝试使用refresh_token获取新的access_token
实际的token很长,缩短了一些

请求如下:

1
2
3
4
5
curl --location --request POST 'https://api.tongji.edu.cn/v1/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=test_login' \
--data-urlencode 'refresh_token=eyJhbGciOiJIUzI1Ni**********************UwMGUifQ.eyJleHAiOjE3OGM3Y***************hN2ZlN2MifQ.NIag08UV6j********YtOY' \
--data-urlencode 'grant_type=refresh_token'

返回如下:

1
2
3
4
5
6
7
8
9
10
11
{
"access_token": "实际的真实access_token",
"expires_in": 86400,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIwOG0wVG5rb3M0QWVyaVE2Q0hiNUt0TGNXbDN6R0MtS2ZPbG5UYjVqRTF3In0.eyJleHAiOjE2ODkxNTI0NTksImlhdCI6MTY4OTA2NjA1OSwiYXV0aF90aW1lIjoxNjg5MDY1NDM3LCJqdGkiOiJhMDk4YWZiOC1hZDA2LTQwYWMtOTJhYS1jNDcyYjljNWJhNjciLCJpc3MiOiJodHRwczovL2FwaS50b25namkuZWR1LmNuL2tleWNsb2FrL3JlYWxtcy9PcGVuUGxhdGZvcm0iLCJhdWQiOiJ0ZXN0X2xvZ2luIiwic3ViIjoiZTVkYWIxYzMtZTlkYy00MzU2LTk3YTYtMDc0Mjg3MjkwZDYzIiwidHlwIjoiSUQiLCJhenAiOiJ0ZXN0X2xvZ2luIiwibm9uY2UiOiIzMTEzMWYxZS05NTkwLTQyYjItOGJhYy1lNTNlM2RiYThlYzUiLCJzZXNzaW9uX3N0YXRlIjoiNzhjYzdmOWQtMDZmOS00OWJmLThlMDMtODc2M2QzYTdmZTdjIiwiYXRfaGFzaCI6Il9LNlQ0Mzhmb0g0UEdNc05FMjZwbGciLCJhY3IiOiIwIiwic2lkIjoiNzhjYzdmOWQtMDZmOS00OWJmLThlMDMtODc2M2QzYTdmZTdjIiwibmFtZSI6IjIwNjY2MDkzIOS6juaZqCIsInByZWZlcnJlZF91c2VybmFtZSI6IjIwNjY2MDkzIiwiZ2l2ZW5fbmFtZSI6IjIwNjY2MDkzIiwiZmFtaWx5X25hbWUiOiLkuo7mmagiLCJ1c2VyaWQiOiIyMDY2NjA5MyJ9.EP68TlPvflhHVxIr8yaBYjcmUyDClUJTaAOibWoMujFW7U7631UdvDu1Knr402GgxebbeRNJRMCEbjcq5AMQtOdocbdaOh4_a98bSiSktBrMquEGIq6LGWjMstsDirFfYcKV1uaGvq74E5DPBAUUxWjLWCFgpTC6Ge-DaevZyIiGBODteHqv7c5mQXskW_R8rPHirFOy8oJc085RIpgIp1xwIbp4IvFcLWKKpJqCXgCmPfNZRPYWWPMTuJ2rBSFFBRWGLxwGMZJBUC7M4Q8Lc5riXNGlUnHVk7mr0bdCBfMWWLQjg-wThIJt9Z200O4MGutPe4R4NDKA-DFOONeXmQ",
"not-before-policy": 0,
"refresh_expires_in": 15551378,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMDNjZjRkMi0yYjdmLTQxM2EtYjEwZC01NjJlOTQzZDUwMGUifQ.eyJleHAiOjE3MDQ2MTc0MzcsImlhdCI6MTY4OTA2NjA1OSwianRpIjoiM2YwYzI1MzYtNWE4YS00YzQ2LWI5YTItOGJkNzQyZGI5NGYwIiwiaXNzIjoiaHR0cHM6Ly9hcGkudG9uZ2ppLmVkdS5jbi9rZXljbG9hay9yZWFsbXMvT3BlblBsYXRmb3JtIiwiYXVkIjoiaHR0cHM6Ly9hcGkudG9uZ2ppLmVkdS5jbi9rZXljbG9hay9yZWFsbXMvT3BlblBsYXRmb3JtIiwic3ViIjoiZTVkYWIxYzMtZTlkYy00MzU2LTk3YTYtMDc0Mjg3MjkwZDYzIiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InRlc3RfbG9naW4iLCJub25jZSI6IjMxMTMxZjFlLTk1OTAtNDJiMi04YmFjLWU1M2UzZGJhOGVjNSIsInNlc3Npb25fc3RhdGUiOiI3OGNjN2Y5ZC0wNmY5LTQ5YmYtOGUwMy04NzYzZDNhN2ZlN2MiLCJzY29wZSI6Im9wZW5pZCBkY191c2VyX3NpbmdsZV9pbmZvIHByb2ZpbGUiLCJzaWQiOiI3OGNjN2Y5ZC0wNmY5LTQ5YmYtOGUwMy04NzYzZDNhN2ZlN2MifQ.Z2tL5f-8_x5NrgQWvwqE6iqOu4L3sBMK1jrshrgRYuU",
"scope": "openid dc_user_single_info profile",
"session_state": "78cc7f9d-06f9-49bf-8e03-8763d3a7fe7c",
"token_type": "Bearer"
}

可以看到又是一个86400s也就是24h有效期的access_token

nvm简易指南

事情起因

编译一个老的项目的时候报错Error: error:0308010C:digital envelope routines::unsupported at new Hash,简单搜索发现是新版的nodejs禁用了new Hash的一个功能
stackoverflow提供了环境变量的解决方案,set NODE_OPTIONS=--openssl-legacy-provider,非常不幸我怎么尝试都未成功

降级nodsjs版本

因为平时nodejs用的不多,所以也没准备旧版本,故使用以前的老工具nvm解决,此工具有windows版

操作流程

  1. 下载windows版nvm,并安装
  2. nvm命令测试能运行
  3. 安装nvm install 14
  4. 使用nvm use 14
  5. 检查nodejs版本,nodejs -v,发现一切正常
  6. 尝试编译程序,无报错

创建一个单节点consul

consul挂了

因为某个项目使用了consul作为服务注册发现中心
今天尝试跑测试环境的时候发现statusCode=500, statusMessage='Internal Server Error', statusContent='No cluster leader'的错误,观察了一下测试环境的consul发现只有两个节点还在运行了,一般情况consul有3-5个节点同时运行。
在尝试恢复节点的时候,发现虚拟机都无法ssh上去了。决定随便找一台空机器来做一个单节点的consul来支持测试环境。

k8s还是docker

看到linux安装教程还要去下载和配置就决定要么用k8s要么用docker版,权衡利弊因为k8s的网络配置比较复杂最后决定使用docker。
consul版本决定跟线上保持一致使用1.13.2

跟老节点产生了关系

一开始想把旧consul集群恢复所以尝试使用新建的consul里的join命令加入旧consul集群,但是因为其中一个node状态实在是诡异,所以加入失败也不清楚原因。
后续删除consul重新建立consul之后,发现老节点不断的尝试主动来建立联系,感觉一旦注册过去之后应该会反复尝试拉进自己的集群。
最后无奈通过新建了一个datacenter来解决的。

注册了私有IP地址

启动consul之后在本机跑示例程序时候发现注册的是私有地址,似乎因为装了一些虚拟网卡所以选择了虚拟网卡的地址注册给consul了。参考文章3看过之后觉得不会影响测试环境,故未处理。

最后单条命令实施如下

docker run -id --name=consul --net=host consul:1.13.3 agent -server -ui -node=n1 -bootstrap -bootstrap-expect=1 -client=0.0.0.0 -advertise=192.xxx.xxx.162 -datacenter=dctest -bind=192.xxx.xxx.162
访问192.xxx.xxx.162:8500一切正常

部署正式环境

部署正式环境时候发现又拿到私有地址了 在rancher中把网络模式改为主机解决了问题
原理跟上一条docker命令中的--net=host是一样的

参考文章:

  1. Docker consul的容器服务更新与发现的问题小结
  2. Docker部署Consul单节点或者集群教程
  3. 如何指定注册到Consul上的IP地址

利用Gitlab新建一个博客

选用Hexo

没啥原因,之前同事推荐过

本地尝试

官网

1
2
3
4
5
npm install hexo-cli -g
hexo init blog
cd blog
npm install
hexo server

浏览器打开http://localhost:4000之后看到效果

推送Gitlab

推送到同济Gitlab
官方给出了部署Gitlab-Pages的教程
里面附送了一份.gitlab-ci.yml文件

其中有两个问题

  1. image: node:10-alpine # use nodejs v10 LTS这一行有问题,最新版本的hexo至少需要node12以上
  2. 因为打包hexo需要nodejs,shell解释器的runner没装nodejs环境,所以需要用tags为docker的runner,它的解释器是docker,这里感觉将来可以优化一下

能用的.gitlab-ci.yml文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
image: node:18.5.0 # use nodejs v10 LTS
cache:
paths:
- node_modules/

before_script:
- npm install hexo-cli -g
- npm install

pages:
script:
- hexo generate
artifacts:
paths:
- public
only:
- main
tags:
- docker

更改一些配置

按照官方教程更改了_config.yml文件,标题作者什么的都不是很重要
其中url比较重要,必须填入url:http://20666093.pages.tongji.edu.cn/blog/<blog>是项目名字,如果这个url填错会导致css等静态资源加载错误

大功告成

一个拥有同济官方域名的个人博客就创建好了
这篇文章就是对这个博客网站的试用