1

研究背景

go程序部署时,直接将编译好的文件在服务器上运行即可,一般无需安装所依赖的第三方库。

Linux下部署分为以下几种方式:

  • 使用nohup 命令

  • 使用 Supervisord管理

  • 使用systemd管理

windows下部署方式:

  • 注册成windows服务,方便进行管理

其实golang自己也可以实现以服务的形式常驻后台。

现在介绍一个包 github.com/kardianos/service ,它可以让 go 程序支持在不同系统上作为服务:注册,卸载,启动,停止。

2

安装部署

go get github.com/kardianos/service

3

使用方法

通过两个例子,我们来了解其用法。

3.1 示例程序: simple

package mainimport ("log""github.com/kardianos/service"
)var logger service.Logger //service的日志对象type program struct{} //定义结构体,并实现service.Interface的start和stop接口func (p *program) Start(s service.Service) error {// Start should not block. Do the actual work async.go p.run()return nil
}
func (p *program) run() {// Do work here
}
func (p *program) Stop(s service.Service) error {// Stop should not block. Return with a few seconds.return nil
}func main() {svcConfig := &service.Config{Name:        "GoServiceExampleSimple",DisplayName: "Go Service Example",Description: "This is an example Go service.",}prg := &program{}s, err := service.New(prg, svcConfig)if err != nil {log.Fatal(err)}logger, err = s.Logger(nil)if err != nil {log.Fatal(err)}err = s.Run()if err != nil {logger.Error(err)}
}

套路如下:

一、定义结构体program,并实现service的接口函数Start和Stop

需要实现的service接口Interface如下:

type Interface interface {// Start provides a place to initiate the service. The service doesn't// signal a completed start until after this function returns, so the// Start function must not take more then a few seconds at most.Start(s Service) error// Stop provides a place to clean up program execution before it is terminated.// It should not take more then a few seconds to execute.// Stop should not call os.Exit directly in the function.Stop(s Service) error
}

二、初始化service.Config结构体,并调用service.New创建service对象

三、为service对象设置日志Logger

四、调用service的Run方法来运行程序

3.2 示例程序2

package mainimport ("encoding/json""flag""fmt""log""os""os/exec""path/filepath""github.com/kardianos/service"
)// Config is the runner app config structure.
type Config struct {Name, DisplayName, Description stringDir  stringExec stringArgs []stringEnv  []stringStderr, Stdout string
}var logger service.Loggertype program struct {exit    chan struct{}service service.Service*Configcmd *exec.Cmd
}func (p *program) Start(s service.Service) error {// Look for exec.// Verify home directory.fullExec, err := exec.LookPath(p.Exec)if err != nil {return fmt.Errorf("Failed to find executable %q: %v", p.Exec, err)}p.cmd = exec.Command(fullExec, p.Args...)p.cmd.Dir = p.Dirp.cmd.Env = append(os.Environ(), p.Env...)go p.run()return nil
}
func (p *program) run() {logger.Info("Starting ", p.DisplayName)defer func() {if service.Interactive() {p.Stop(p.service)} else {p.service.Stop()}}()if p.Stderr != "" {f, err := os.OpenFile(p.Stderr, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777)if err != nil {logger.Warningf("Failed to open std err %q: %v", p.Stderr, err)return}defer f.Close()p.cmd.Stderr = f}if p.Stdout != "" {f, err := os.OpenFile(p.Stdout, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777)if err != nil {logger.Warningf("Failed to open std out %q: %v", p.Stdout, err)return}defer f.Close()p.cmd.Stdout = f}err := p.cmd.Run()if err != nil {logger.Warningf("Error running: %v", err)}return
}
func (p *program) Stop(s service.Service) error {close(p.exit)logger.Info("Stopping ", p.DisplayName)if p.cmd.Process != nil {p.cmd.Process.Kill()}if service.Interactive() {os.Exit(0)}return nil
}func getConfigPath() (string, error) {fullexecpath, err := os.Executable()if err != nil {return "", err}dir, execname := filepath.Split(fullexecpath)ext := filepath.Ext(execname)name := execname[:len(execname)-len(ext)]return filepath.Join(dir, name+".json"), nil
}func getConfig(path string) (*Config, error) {f, err := os.Open(path)if err != nil {return nil, err}defer f.Close()conf := &Config{}r := json.NewDecoder(f)err = r.Decode(&conf) //将json字符串转为Config对象if err != nil {return nil, err}return conf, nil
}func main() {svcFlag := flag.String("service", "", "Control the system service.")flag.Parse()configPath, err := getConfigPath() //获取配置文件路径if err != nil {log.Fatal(err)}config, err := getConfig(configPath) //获取配置if err != nil {log.Fatal(err)}//初始化service配置属性svcConfig := &service.Config{Name:        config.Name,DisplayName: config.DisplayName,Description: config.Description,}prg := &program{exit: make(chan struct{}),Config: config,}s, err := service.New(prg, svcConfig)if err != nil {log.Fatal(err)}prg.service = serrs := make(chan error, 5)logger, err = s.Logger(errs)if err != nil {log.Fatal(err)}go func() {for {err := <-errsif err != nil {log.Print(err)}}}()if len(*svcFlag) != 0 {//通过命令行参数来控制服务err := service.Control(s, *svcFlag)if err != nil {log.Printf("Valid actions: %q\n", service.ControlAction)log.Fatal(err)}return}err = s.Run()if err != nil {logger.Error(err)}
}

其配置文件runner.json如下

{"Name": "builder","DisplayName": "Go Builder","Description": "Run the Go Builder","Dir": "C:\\dev\\go\\src","Exec": "C:\\windows\\system32\\cmd.exe","Args": ["/C","C:\\dev\\go\\src\\all.bat"],"Env": ["PATH=C:\\TDM-GCC-64\\bin;C:\\Program Files (x86)\\Git\\cmd","GOROOT_BOOTSTRAP=C:\\dev\\go_ready","HOMEDRIVE=C:","HOMEPATH=\\Documents and Settings\\Administrator"],"Stderr": "C:\\builder_err.log","Stdout": "C:\\builder_out.log"
}

可将service相关的配置信息存储到配置文件中。通过读取配置文件中的配置信息来生成service。

4

接口定义(源码剖析)

这个库有两个接口

4.1 Service接口

其中Service接口有Run、Start、Stop、Restart、Install、Uninstall等核心方法可实现,以对应服务的运行、启动、停止、重启、安装、卸载操作。

type Service interface {// Run should be called shortly after the program entry point.// After Interface.Stop has finished running, Run will stop blocking.// After Run stops blocking, the program must exit shortly after.Run() error// Start signals to the OS service manager the given service should start.Start() error// Stop signals to the OS service manager the given service should stop.Stop() error// Restart signals to the OS service manager the given service should stop then start.Restart() error// Install setups up the given service in the OS service manager. This may require// greater rights. Will return an error if it is already installed.Install() error// Uninstall removes the given service from the OS service manager. This may require// greater rights. Will return an error if the service is not present.Uninstall() error// Opens and returns a system logger. If the user program is running// interactively rather then as a service, the returned logger will write to// os.Stderr. If errs is non-nil errors will be sent on errs as well as// returned from Logger's functions.Logger(errs chan<- error) (Logger, error)// SystemLogger opens and returns a system logger. If errs is non-nil errors// will be sent on errs as well as returned from Logger's functions.SystemLogger(errs chan<- error) (Logger, error)// String displays the name of the service. The display name if present,// otherwise the name.String() string
}
image-20210910150157094

其中aixService、freebsdService、solarisService、systemd、sysv、upstart、windowsService分别对应不同的操作系统aix,freebsd,solaris,linux,windows操作系统上的服务。

4.2 Interface接口

Interface接口中有Start和Stop

type Interface interface {// Start provides a place to initiate the service. The service doesn't not// signal a completed start until after this function returns, so the// Start function must not take more then a few seconds at most.Start(s Service) error// Stop provides a place to clean up program execution before it is terminated.// It should not take more then a few seconds to execute.// Stop should not call os.Exit directly in the function.Stop(s Service) error
}

《酷Go推荐》招募:

各位Gopher同学,最近我们社区打算推出一个类似GoCN每日新闻的新栏目《酷Go推荐》,主要是每周推荐一个库或者好的项目,然后写一点这个库使用方法或者优点之类的,这样可以真正的帮助到大家能够学习到

新的库,并且知道怎么用。

大概规则和每日新闻类似,如果报名人多的话每个人一个月轮到一次,欢迎大家报名!戳「阅读原文」,即可报名

扫码也可以加入 GoCN 的大家族哟~

「GoCN酷Go推荐」golang 跨平台部署利器相关推荐

  1. 「GoCN酷Go推荐」Golang轻量级桌面程序wails2教学

    01 推荐理由 不依赖cgo!不依赖cgo!不依赖cgo!真的不依赖cgo,且跨平台,原生渲染 无嵌入式浏览器,轻量级,生成的文件很小,而且只有一个可执行文件就可运行. 02 功能介绍 后端使用标准 ...

  2. 「GoCN酷Go推荐」Golang的Ealstic链接库

    背景介绍 Elasticsearch是一个分布式.高扩展.高实时的搜索与数据分析引擎,用于海量文档的搜索.有些项目会将Elasticsearch当做存储海量数据的数据库使用,可见其查询性能之高效.作为 ...

  3. 「GoCN酷Go推荐」后现代时代远程办公网络问题的golang开源解决方案 —— PairMesh...

    PairMesh是什么? Pairmesh是一款先进的虚拟局域网(VPN)工具,用来搭建与访问安全,易用,高性能的点对点的软件定义虚拟局域网,为远程办公的网络连接问题提供了开箱即用的解决方案. 拥抱开 ...

  4. 「GoCN酷Go推荐」​QQ机器人 go-cqhttp

    什么是 go-cqhttp?✦ QQ机器人,可以做的事儿太多了,比如一个UP主需要群发多个QQ群,以便通知粉丝们开播:再比如可以检测群内或发给自己的消息,而通过代码直接回复做的简单回复.比如检测群内有 ...

  5. 「GoCN酷Go推荐」高性能内存缓存 ristretto

    背景 ristretto 是 dgraph 团队开源的一款高性能内存缓存库,旨在解决高并发场景下的缓存性能和吞吐瓶颈.dgraph 专攻的方向是高性能图数据库,ristretto 就是其图数据库和 K ...

  6. 「GoCN酷Go推荐」快速搭建私有云服务 go-btfs

    # 1. go-btfs 是什么?# go-btfs 是一个去中心化的文件存储平台,无论图片.文件.视频等等各类文件.每个人都可以在自己电脑上安装部署 BTFS 节点,然后大家的节点相互连接,构成一个 ...

  7. 「GoCN酷Go推荐」JSON 数据获取器 JID

    01 推荐理由   JSON 格式数据适用范围非常广泛,一个内容丰富的json数据可能很大,使用 JID 可以让你非常舒服的获取到想要到数据. 02 简介 JID 是一个过滤JSON格式数据 cli ...

  8. 「GoCN酷Go推荐」简单易用的性能分析工具——nitro

    #1 推荐理由 Golang官方在程序性能分析方面提供了用来分析cpu/内存等采样信息的pprof,以及用来追踪和分析运行时事件的trace,这两个工具对于分析程序的性能瓶颈可以说是得心应手.但是,对 ...

  9. 「GoCN酷Go推荐」漏桶限流库 — uber-go/ratelimit

    上次有同学分享了 单机限流器 time/rate 库,讲了 Golang 标准库中基于令牌桶实现限流组件的 time/rate 使用,同时也讲了一些限流算法原理. 这里分享一个 uber 开源的一套基 ...

最新文章

  1. 计算两个日期相差几年几个月
  2. tar/gzip/zip文件打包、压缩命令
  3. python中deepcopy函数_python – copy.deepcopy使用自定义的__new __()方法在对象上引发TypeError...
  4. 如何使用Serilog.AspNetCore记录ASP.NET Core3.0的MVC属性
  5. 解决 LaTeX Error: File `.sty‘ not found.,直接进行本地导入就好了,暂时解决而已
  6. Windows Mobile开发的一些小技巧(持续更新)
  7. div显示在上层_将某个div层显示在最上面(总结)
  8. 令人超赞的ButterKnife8.8.1—快捷、方面、好用!你还在等什么
  9. Django登录并使用LDAP认证
  10. Xcode Message from debugger: Terminated due to memory issue
  11. 人人网主页登录_人人网回归,你的前任和全部黑历史将被翻开!买账吗?
  12. 智能鱼塘远程检测控制系统
  13. 千兆路由器怎么设置网速最快_安装了千兆路由器,为什么下载速度很慢?
  14. 电脑版微信多开,只需要三步
  15. python-华三防火墙过期策略统计
  16. Android——TextView指定字符串颜色高亮,实现类似微信、支付宝搜索结果中搜索字段高亮的效果
  17. 阿里云飞天技术总架构师唐洪:飞天技术与应用
  18. 何恺明新作来了!更快更有效的训练FLIP
  19. P1719 最大加权矩形(二维前缀和Java)
  20. (附源码)python电影院信息管理系统 毕业设计 021844

热门文章

  1. chrome打印自动分页_在Google Chrome中启用自动分页功能
  2. python发送正文带统计表格的邮件
  3. VS2019分开头文件和源文件
  4. centos7中设置防火墙
  5. 【笔记】在win10安装界面,更改磁盘格式为GPT
  6. java中bean是_JavaBean简介
  7. 基于RFID的学生一卡通管理系统的设计与实现
  8. nodejs 爬取动态网页
  9. html5 上传图片模板,HTML5实现图片文件异步上传
  10. Win7游戏全屏设置