Git Actions自动发布部署,非最完善但足够完善和上手的一篇
文章最后附带完整代码链接
GitHub Actions是一个持续集成和持续交付(CI/CD)平台,允许您自动化构建、测试和部署管道。您可以创建构建和测试存储库中的每个拉取请求的工作流,或者将合并的拉取请求部署到生产中。
- 至于什么是CI/CD?
CI全称 Continuous Integration,代表持续集成,CD则是 Continuous Delivery和 Continuous Deployment两部分,分别是持续交付和持续部署。CI/CD 是一种软件开发实践,利用自动化的手段来提高软件交付效率,让交付更简单。
以上的概念问题粗暴理解就是,比如我提交push一个代码到git,git actions可以帮助我们实现传输到远程服务器,同时让远程服务器编译,重新启动服务等等。特别是测试阶段,改动代码需要发布并重启服务器,提交git即可自动完成,代替以往的手动操作上传,关闭和重启。
- git actions怎么实现呢? 这里就不讲解太多,尽量简单过下大概流程。
通过git actions可以实现on事件监听行为(push,pull事件),然后触发事件,运行自定义的workflow工作流,workflow工作流执行自定义的job任务,可以把我们想要的行为通过job跑出来。
相关行为和事件等,都是通过yaml配置文件,入门则了解yaml配置文件中,on, workflow,job,step这几个关键字,以及格式和用法即可,其它关键字边学边上手,这里就不敞开讲,看文档
下面是一个完整的例子,监听git的push事件,触发传输到远程服务器,平滑关闭服务并重启服务的例子
第一步:github上开一个空项目
第二步:增加web服务器代码,并推送push到github
服务器代码, main.go
package main
import (
"context"
"github.com/toegg/egg_actions/test"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// 创建一个接收信号的通道,监听signal信息
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
log.Println("start server")
//启动web服务器,监听两个API行为,1个测试,1个重启
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
log.Println("Test Print:", test.Test())
w.Write([]byte("hello http HandleFunc, Result:" + test.Test()))
})
http.HandleFunc("/reload", func(w http.ResponseWriter, r *http.Request) {
quit <- syscall.SIGINT
log.Println("Server Reload")
w.Write([]byte("http HandleFunc"))
})
s := &http.Server{
Addr: ":8881",
}
go s.ListenAndServe()
// 阻塞在此,接收到关闭进程信号,继续往下走
<-quit
log.Println("Shutdown Server ...")
timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := s.Shutdown(timeoutCtx); err != nil {
log.Println(err)
}
}
增加编译的shell脚本, build.sh
,脚本为了git actions远程ssh操作执行
#!/bin/bash
# 切换到服务器工程所在目录(这里要切换到所在目录,避免不必要路径报错问题)
cd /home/tool/golearn/src/egg_actions
# 用go指令(带上安装路径),编译
/home/tool/go/go/bin/go build main.go
最后把内容推送push到github,必须推送push
第三步:启用项目git actions,直接在github项目中操作
打开github的项目,选择Actions,点击set up a workflow yourself
点击后会进入自定义yaml配置文件界面。页面右边也选择了可以提供的模板,右边可选择不同编程语言的yaml模板配置等。我们这里用我已经写好的,先贴上去。
我们自己的用到了3个任务job :
code: 测试编译go代码
restart:平滑关闭服务并重启
deply:推送文件模块到远程服务器
# 这里声明git actions的名字
name: Go
# 指定监听事件,这里监听push到git分支main的事件
on:
push:
branches: [ "main" ]
# 这里定义工作流,工作流配置对应job任务
jobs:
code: # 声明job的名字(这个job主要用来介绍,可以用做测试go test流程)
runs-on: ubuntu-latest # 使用ubuntu系统镜像运行脚本
# steps定义job的步骤,具体执行,运行xxx,-字符开头的一块则为一个步骤,可以配置多个步骤
steps:
- uses: actions/checkout@v2 # 步骤1:下载git仓库中的代码,使用官方提供,使用库用uses关键字
- name: SetUp Go # 步骤2:下载go代码
uses: actions/setup-go@v3 # 使用官方提供
with:
go-version: 1.16 # 指定go版本1.16
- name: Build Go # 步骤3:编译仓库中的代码
run: go build -v ./
restart: # 声明另一个job的名字
runs-on: ubuntu-latest
steps:
- name: Check my-json-server
uses: cross-the-world/ssh-pipeline@master # 使用别人包装好的步骤,执行远程操作的库
with:
host: ${{ secrets.REMOTE_HOST }} # 远程连接的host,引用配置
user: ${{ secrets.SSH_USERNAME }} # 远程连接的用户名,引用配置
key: ${{ secrets.ACCESS_TOKEN }} # 远程连接的ssh秘钥,引用配置
port: '22' # ssh端口
connect_timeout: 10s # 远程连接的超时时间
# 下面是执行的脚本内容,找到go服务进程,通过发送信号关闭进程,调用build.sh脚本编译代码,用nohup重启服务
script: |
echo "hello egg"
(ps aux|grep main|grep -v "grep"|head -n 1|awk '{printf $2}'|xargs kill -15) &&
(sh /home/tool/golearn/src/test_actions/build.sh) &&
(nohup /home/tool/golearn/src/test_actions/main > /home/tool/golearn/src/test_actions/error.log 2>&1 &)
echo "over"
needs: deploy # 依赖关键字,等deploy的执行完了再执行restart
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Deploy to Server # 使用别人包装好的步骤,推送文件模块到远程服务器
uses: AEnterprise/rsync-deploy@v1.0
env:
DEPLOY_KEY: ${{ secrets.ACCESS_TOKEN }} # 远程连接的ssh秘钥,引用配置
ARGS: -avz --delete # rsync参数
SERVER_PORT: '22' # ssh端口
FOLDER: ./ # 要推送的文件夹,路径相对于代码仓库的根目录
SERVER_IP: ${{ secrets.REMOTE_HOST }} # 远程连接的host,引用配置
USERNAME: ${{ secrets.SSH_USERNAME }} # 远程连接的用户名,引用配置
SERVER_DESTINATION: /home/tool/golearn/src/test_actions # 部署到目标文件的路径
needs: code # 等code完成再执行deploy
粘贴上去,点击start commit提交,会自动在项目目录创建.github/workflows/main.yaml
文件
再选择Actions,会看到我们新增的actions的Create main.yaml,但是失败了,点击其中一个进去
进入之后可以看到我们三个job为线性关系,有前后依赖(因为用到了needs关键字)。
可以看到在code任务成功了,但是deploy报错停住了,点击deploy查看具体原因
这里面会显示具体的任务job执行步骤,查看报错原因,原来是由于我们用到了引用配置,但是还没配,导致执行远程推送服务器失败。
第四步:配置github项目的配置变量,提供引用
进入项目主页,选中settings,点击actions,添加对应的key=》val配置变量
分别添加以下3个我们会用到的变量
REMOTE_HOST :远程连接的host
SSH_USERNAME : 远程连接的用户名
ACCESS_TOKEN : 远程连接的ssh秘钥
添加完毕后,则如图
第五步:编译go程序可执行文件,手动上传服务器,启动web服务
因为我们为了测试重启,所以先手动上传服务器并启动web服务。
第六步:重新跑actions,测试结果
点击回第三步最后的actions页面,重新跑工作流,测试,选中右上角的Re-run all jobs会自动执行。
出现以下结果,测试通过
进入服务器查看,文件是否推送同步过来,并且编译了main.go,存在main可执行程序
打开浏览器,访问web服务器链接,出现如图,说明部署成功了
第七步:本地修改代码,push推送git,查看是否自动发布,远程传输,重启
修改test/test.go
模块的代码为
func Test() string {
return "Hello TestActions Change Push"
}
提交push到github,跟着上github项目查看actions执行结果,看到正在执行
待执行完毕,显示成功
打开浏览器,访问web服务器链接,已经生效,说明改动代码,直接提交git,会自动发布部署了