『CI/CD』使用Webhook通知服务器
在前面的 Github Actions 工作流中,我们最后都是直接使用 SSH 连接在服务器上执行命令,但是这样很不优雅,而且会被认为是服务器被异常登录
所以可以尝试使用 webhook
简单地说,就是先在服务器准备一个部署脚本,然后一直运行一个守护进程监听请求,触发 GitHub Actions 时发送请求,守护进程被收到后自动执行部署脚本
准备部署脚本
准备 redeploy.sh
12345678#!/bin/bashsudo docker login --username=***** registry.cn-hangzhou.aliyuncs.com --password "******"sudo docker-compose pullsudo docker-compose up -d
这个很容易理解,在写完之后记得测试一下能不能成功运行
编写 webhook
这里为了方便,就直接使用一个库:https://github.com/adnanh/webhook
这东西看文档直接 apt 就能安装了
1sudo apt install webhook
使用方法就是编写配置文件,然后运行时带上配置文件,就能根据规则监听请求
新建一个 webhook.json
1234567891011121314151617181920[ { "id": "webhook", "execute-command": "/home/admin/projects/g ...
『CI/CD』结合GitHub Actions+Docker实现自动化部署
上一篇 『CI/CD』使用GitHub Actions实现简单的自动化部署 中实现了简单的自动化部署,本篇来介绍一下使用 docker 的做法 (NX 整整折腾了两天呢)
基本流程
首先要明确一下最终的运行流程,一共有4个步骤
更新代码,提交至GitHub
GitHub 触发 Actions,自动 build 镜像,并推送至镜像仓库
服务器拉取最新镜像
重新启动容器
因为今天时间有点紧我就不画图了(明天赶回家,要收拾东西)
本地原生运行测试
首先第一步要介绍一下我们的项目,还是上次的仓库:https://github.com/NX-Official/github-actions-test ,当然啦,现在是 v3 分支
为了方便我本次使用一个 go-zero 的 demo,因为它来生成 Dockerfile 比较方便
首先和文档一样创建一个 hello 服务
1goctl api new hello
为了模拟可能的业务场景,我现在给这个 demo 增加两个要求:
我这个项目需要使用 mysql 和 redis 等服务,但是 docker 中的 mysql 会对性能造成影响,我可能需要直接使用宿主机上的端口与服务
本地测试环境和实际环境有不同,我希望到时候能从宿主机的某个目录读取配置文件,而不是打包在一起
所以我在这个 dome 中连接了 127.0.0.1 的 mysql 和 redis 服务,并从文件中读取配置,你可以在项目中看见
现在,我在 hello 目录下原生运行本项目,没有问题
1go run hello.go
本地打包&运行测试
接下来,用 ...
『Docker』Docker内程序如何访问宿主机的端口
好家伙,折腾了这个问题折腾了一天,刚才终于搞定了,简直不要太高兴
事情是这样的,我现在要折腾基于 Docker 的自动化部署,然后我的项目已经打包好了,但是运行起来有问题,一直说连不上 mysql
然后呢? 就递归折腾(不是) 我就感觉肯定是网络的事情
然后就想是不是要折腾容器间通信,但是把 mysql 跑在 docker 里面肯定有不少损耗吧,问了下助手里面的大佬,结论也是这样
那么,现在的问题就是,如何让 Docker内程序如何访问宿主机的端口
然后我就去搜哇,看各种文章博客去各种平台,还看了些项目,看他们是怎么解决的
但是助手的项目自然都是读服务器上的配置文件,我也看不见
去看 docker 相关的教程,但都感觉好像没遇见这个问题一样,提都不提
去网上查这个问题,有的说就 docker 启动的时候有个网卡,然后直接连它的 ip 就行,但是我没搞定
有的说启动的时候指定 host 模式,这个在 Linux 上的确可以(当然是后面发现的),但是我在 Mac 上不行,也没报错,就这样又折腾了好久
然后去翻官方文档这是个什么玩意,然后我就看见了
没事了,人麻了
然后我在服务器上尝试,的确这个 host 是可以的,但是我不相信 Windows和Mac就没有好的方法
最后去谷歌一趟,奶奶的,一分钟搞定
如图所示,简直不要太简单,直接用 host.docker.internal 即可
然后看见访问的实际是 192.168.65.2 ,我就想到了这篇
的确,貌似和我的 192.168.65.0 一个网段,但是并不和它说的一样
国内什么垃圾互联网啊🤔(迫真
PS:如果遇到 ...
设置在使用 SSH key 时不用再输入密码
今早发生了非常尴尬的事情,我在群里抱怨怎样才能在 git ssh 的时候不用密码
然后群u们居然告诉我:你在生成的时候不输密码就可以了!
好家伙,这么多年每天多输了这么多密码(
那要怎样重置密码为空呢?使用下面的命令
1ssh-keygen -p -f ~/.ssh/id_rsa
『CI/CD』使用GitHub Actions实现简单的自动化部署
本篇是一个 GitHub Actions 使用示例,实现在每次提交代码时自动更新你的远端服务器正在运行的项目
但是我并不会从头开始向你介绍 GitHub Actions 是什么,而要求你事先对它有所了解
你可以去看官方文档,去 B 站找视频看,网上有很多高质量的参考资料
简单地说就是 GitHub 可以在你更新代码或合并分支的时候开一个虚拟机帮你完成一些事情
又或者,你也可以去问 ChatGPT,哈哈😄
那为什么说是“简单的”呢?因为本篇只会举一个很简单的例子,不会涉及 docker ,也没有 k3s 集群
本篇的例子可以在我的仓库找到:https://github.com/NX-Official/github-actions-test
为了将重点放在部署上,我以下面的 main.go 为例,它只显示一个简单的 hello world
12345678910111213141516package mainimport ( "github.com/gin-gonic/gin")func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.String(200, "Hello World") }) r.Run(":8080")}
目前的项目结构如下:
1234./├── go.mod├── go.sum└── main.go
我该如何部署?
现在来思 ...
『C/C++』一文初识Makefile与CMake
本文来源于 B 站视频,鄙人只是跟着做一下笔记:
Makefile 20分钟入门,简简单单,展示如何使用Makefile管理和编译C++代码
CMake 6分钟入门,不用再写复杂的Makefile
感觉这个老师讲的真的好 ,要是杭电也都是这样的的老师就好了(
编译链接的预备知识
在手动编译一些 C/C++ 项目时,你会经常遇到下面的命令
12cmake .make
这两个都是用来管理和编译 C/C++ 项目的工具,本文将浅浅地介绍这两个工具的使用
首先引出一个小项目作为例子,项目结构如下
12345./├── factorial.cpp├── function.h├── main.cpp└── printhello.cpp
目前共有 4 个文件,首先来看 printhello.cpp
123456789#include <iostream>#include "function.h"using namespace std;void printhello(){ int i; cout << "Hello World!" << endl;}
这是一个很简单的文件,仅有一个 printhello() 函数,功能也很简单
但请记住这个定义了但没使用 i 变量,后面会出场
接着看 factorial.cpp ,它包含一个简单的递归函数,用于求阶乘
123456789#include "function.h"int factorial(int n) ...
Golang 语法速通指南(十)函数之进阶使用
函数进阶一点的使用,就是将函数当作一个变量
函数类型
若要将函数作为变量,那自然是有类型的
那函数的类型是怎样的呢?一个函数的类型就是它的签名(名称、入参列表、出参列表)
签名一样的函数,类型就一样
例如定义一个 add 函数,然后打印它的类型
1234567func add(x, y int) int { return x + y}func main() { fmt.Printf("%T", add) // func(int, int) int}
既然函数也是一种变量,那么肯定是可以相互赋值的
123456func main() { fmt.Println(add(1, 2)) // 3 var f func(int, int) int f = add fmt.Println(f(1, 2)) // 3}
当然了,你也可以给函数类型起别名
123456type MyFuncType func(int, int) intfunc main() { var f MyFuncType f = add fmt.Println(f(1, 2)) // 3}
函数类型的零值是 nil ,你可以将函数变量与 nil 比较,但函数变量之间是不能比较的
函数作为参数或返回值
当你知道了函数也可以作为变量之后,你就能理解将函数作为参数或者返回值的做法
12345678910111213141516func add(x, y int) int { ret ...
『Go』使用 grpc 时传递错误的一种方法
折腾了一天,算是找到了一种解决方法
就是我现在需要在调用 rpc 时传递全局错误,我定义的全局错误如下
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970package rpcError// RpcError rpc 错误,参考了 https://junedayday.github.io/2021/05/07/go-tip/go-tip-3/type Code intconst ( ErrPersonNotExistCode Code = iota + 1000 ErrPersonCreateFailedCode ErrPersonUpdateFailedCode ErrPersonDeleteFailedCode ErrClassNotExistCode Code = iota + 2000 ErrClassCreateFailedCode ErrClassUpdateFailedCode ErrClassDeleteFailedCode ErrClassGetListFailedCode ErrRedisSetFailedCode Code = iota + 3000 ErrRedisGetFailedCode)var errCodeMap = map[Code]string{ ErrPersonNotExistCode: "用户不存在& ...
『k8s』创建dashboard访问token
前几天老王八蛋给了我杭助服务器的权限,让我一睹部署的细节
然后本菜鸡还没接触 k8s ,先把生成 dashboard token 的命令记一下(
1k3s kubectl -n kubernetes-dashboard create token admin-user
Golang 语法速通指南(九)函数之基础使用
Go 中的函数基本可分为普通函数、匿名函数和方法,方法可视为绑定在结构体上的函数,将在之后单独讲解
普通函数的声明
函数声明包括函数名,参数(入参,形参,随你怎么叫)列表,返回值(出参)列表以及函数体
123func 函数名([入参列表]) [返回值列表] { 函数体}
函数返回值
一个函数可以有返回值,也可以没有返回值,甚至可以有多个返回值
下面是一个简单的函数
123func sum(a, b int) int { return a + b}
你可以在返回值列表就把返回的变量给定义好,这样可以 return 的时候会自动返回对应的变量
1234func sum(a, b int) (c int) { // 这种写法以及多返回值都要加括号 c = a + b return}
多返回值的例子
123func divi(a, b int) (int, int) { return a / b, a % b}
函数参数
值传递还是引用传递
在 C++ 中,函数一般是值传递,也就是传递的是实参的拷贝,在函数中修改形参不会影响实参
在 Go 中也是如此,基本类型是值传递,但引用类型(如指针,slice、map、function、channel 等类型)传过去的可以看作是指针,实参会因为引用关系而修改
也就是说,基本类型是值传递,引用类型可以看作引用传递
可变参数
Go 的可变参数是在 [C/C++ 的版本](C/C++ 的版本) 上改进的,它解决了一些痛点,让使用更加方便
还是经典的 ...
『Go』记录一种处理大文件上传的可行方案:tus 协议
由于项目业务需要,我需要处理一些大文件的上传(比如说几百MB的视频)
然后在网上搜了一通之后是,发现都是一些零散的实现
但是我感觉这种东西一定是有人造过轮子的,于是我就到 GitHub 上搜索相关的包
然后就发现了 tus 这个项目
打开官网,我发现这是一个基于 HTTP 的开源协议(有 在线 Demo ,感觉挺不错的),还有官方的 Go 实现 tusd ,简直不要太爽
来看在 Go 项目中如何使用 tusd 包
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758package mainimport ( "fmt" "net/http" "github.com/tus/tusd/pkg/filestore" tusd "github.com/tus/tusd/pkg/handler")func main() { // Create a new FileStore instance which is responsible for // storing the uploaded file on disk in the specified directory. // This path _must_ exist before tusd will store uploads in it. // If you want to sav ...
新人如何参加面试系统后端讲解留档
前几天讲的,BB了一个小时
https://hdu-help.feishu.cn/docx/NVHqdjh00o53KIxzv9ict5AxnVh
如有不好的地方请大力敲打我
Golang 语法速通指南(八)复合数据结构之结构体
创建结构体
var
Golang 中的结构体和 C++ 中的差别不大,下面是一个例子
1234567891011type Employee struct { ID int Name string Address string DoB time.Time Position string Salary int ManagerID int}var dilbert Employee
一个最显著的区别就是在 C/C++ 中,访问指针成员必须用 -> ,但是 Go 中可以像访问普通变量一样使用点操作符 .
而且在使用结构体指针的时候,不必使用 (*p).x ,直接使用 p.x 即可,Go 会帮你处理的
而且如果你想在函数中修改结构体的话,必须传入指针
使用大写表示可导出也可以算是一个 Go 特色
扯远了,来看下一个创建方式
字面值
123type Point struct{ X, Y int }p := Point{1, 2}
这是只按顺序给出值的写法,不常用,只在简单或成员排练比较规则的时候才可能用
下面的方式才是最常用的
123456type Point struct{ X, Y int } p := Point{ X: 1, Y: 2,}
因为结构体通常通过指针处理,可以用下面的写法来创建并初始化一个结构体变量,并返回结构体的地址
1pp := &Point{1 ...
Golang 语法速通指南(七)复合数据结构之 Map
用过 C++ 的 STL 的人肯定见过 Map,或者说这东西相当于 Python 中的字典
简单地说,就是用来存储键值对的结构,键(key)必须是可比较类型,而值(value)可以是任意类型
创建 Map
var
1var m map[string]int
使用 make
1m = make(map[string]int)
使用字面值
1m = map[string]int{"one": 1, "two": 2}
当然你可以指定内容为空
1m = map[string]int{}
通过使用空接口,你可以在同一个 map 中存储不同类型的 value(就像 Python 中的字典一样)
1234m = map[string]interface{}{ "name": "张三", "age": 18,}
当然现在空接口有一个语法糖 any ,不够我还是习惯旧的写法
添加元素
直接使用索引添加
12ages["alice"] = 31ages["charlie"] = 34
访问 Map
直接使用索引访问
1fmt.Println(ages["alice"]) // "32"
如果你尝试访问一个不存在的键,会返回零值
如果你愿意接收两个返回值,那么会返回结果和是否存在的 bool
所以你会经常看见这样的写法
1if a ...
Golang 语法速通指南(六)复合数据结构之切片(Slice)
本文重构于 Go 切片(Slice)
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,容量(cap)不够时会自动扩容
切片为引用类型,从数组中得到的切片修改元素值时,原数组也会发生变化,修改原数组时,切片也会变化
创建切片
创建切片可以有四种方法
使用 var
1var s []uint32
指定字面值
这样创建的切片长度和容量都等于初始元素个数
1s := []uint32{1, 2, 3}
使用 make() 函数
可以指定长度和容量,格式为make([]type, len[, cap]),可以只指定长度,也可以长度容量同时指定
123s1 := make([]uint32)s2 := make([]uint32, 1)s3 := make([]uint32, 1, 10)
使用截取符
可以从现成的数组或切片创建
12345var arr [10]uint32s1 := arr[0:5]s2 := arr[:5]s3 := arr[5:]s4 := arr[:]
访问切片
直接使用下标
使用截取符
使用 for k,v:= range s
添加元素
使用append()函数向切片中添加元素,可以一次添加 0 个或多个元素,如果容量不够会自动扩容
1234567s := make([]uint32, 0, 4)s = append(s, 1, 2, 3)fmt.Println(len(s), cap(s)) // 3 4s = ...
写在10月的最后一天
最近有点忙,不配图了,就纯意识流,想到哪写到哪
前天刚把期中考考了,昨天杭助破冰大会,今天上午评讲期中试卷,下午阴间长跑刚跑完,累死,回来直接洗澡然后吃饭刷B站,现在状态还行,来水一篇博客
这个月
上大学的生活,平时就跟泡脚一样舒服
然后呢?等到最后的考试周,感觉就是让你把洗脚水喝下去一样
我感觉这十月,就跟一个学期一样:一开始放国庆非常舒服,到月末的考试,再折磨你一手
这个月最大的事情应该是完成了招新工作吧,国庆的录了个视频教新人怎么提交小任务,然后一起见面交流,月末团建助手生日会并一起吃饭
然后呢?国庆几天速成了 GORM 还有 go-zero 框架,然后就一直在搞面试系统(前后重构了好几次),后面就是准备大物考试和杭助节目了
对了,我还在咸鱼花 3000 整了个 iPad Air 5 ,之前一直想要的,但是举棋不定,新 iPad 发布当天全线涨价,二手必定会跟着涨,所以我就直接冲了,用到现在感觉没什么问题
学业
我能很负责地告诉你,圣光机自动化就是天坑专业
毛子讲课啥都听不懂,本来自动化东西就多,然后有些科目中文教学都挂一大堆人,何况是一堆专有名词的英文
然后呢?材料的 practice 教又不教清楚,那天我在 MATLAB 搞了一上午都没搞懂,做个 der 的作业,我还有一堆事情要做
然后呢?去找辅导员,第二天当面聊了一下,转专业是不可能的,这个合作办学情况特殊,然后课也是必须要听的,因为你要毕业
我只能说,命运真会捉弄,高考一考定终生的确不假,分数差了点被调剂到这个专业,每年交这么多钱学一堆我用不上的东西,关键是我还学不懂
如果没被调剂还好,计算机至少能学点相关的,这 ...