真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

golang 應(yīng)用自升級

概要

最近遇到一個需求,golang應(yīng)用部署在遠程機器,遠程機器在內(nèi)網(wǎng),部署之后不方便再次登錄此遠程機器去升級。

站在用戶的角度思考問題,與客戶深入溝通,找到連城網(wǎng)站設(shè)計與連城網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、空間域名、網(wǎng)站空間、企業(yè)郵箱。業(yè)務(wù)覆蓋連城地區(qū)。

因此,需要golang應(yīng)用自動檢查是否需要升級,如果需要升級,則下載二進制后自升級。

自升級庫

golang自升級的庫有好幾個,比較之后決定采用: https://github.com/jpillora/overseer
此庫不是最全面的,但是實現(xiàn)原理和提供的接口比較簡單,代碼量也不大,便于定制。

overseer 庫簡介

overseer 將升級的程序啟動在主協(xié)程上,真正完成功能的部分作為 Program(這個可以當(dāng)做實際程序的 main 函數(shù))運行。
其中最重要的2個部分是 **Config **和 Fetcher。

Config

overseer 通過 Config 結(jié)構(gòu)提供了一些參數(shù)來控制自更新。

// Config defines overseer's run-time configuration
type Config struct {
	//Required will prevent overseer from fallback to running
	//running the program in the main process on failure.
	Required bool
	//Program's main function
	Program func(state State)
	//Program's zero-downtime socket listening address (set this or Addresses)
	Address string
	//Program's zero-downtime socket listening addresses (set this or Address)
	Addresses []string
	//RestartSignal will manually trigger a graceful restart. Defaults to SIGUSR2.
	RestartSignal os.Signal
	//TerminateTimeout controls how long overseer should
	//wait for the program to terminate itself. After this
	//timeout, overseer will issue a SIGKILL.
	TerminateTimeout time.Duration
	//MinFetchInterval defines the smallest duration between Fetch()s.
	//This helps to prevent unwieldy fetch.Interfaces from hogging
	//too many resources. Defaults to 1 second.
	MinFetchInterval time.Duration
	//PreUpgrade runs after a binary has been retrieved, user defined checks
	//can be run here and returning an error will cancel the upgrade.
	PreUpgrade func(tempBinaryPath string) error
	//Debug enables all [overseer] logs.
	Debug bool
	//NoWarn disables warning [overseer] logs.
	NoWarn bool
	//NoRestart disables all restarts, this option essentially converts
	//the RestartSignal into a "ShutdownSignal".
	NoRestart bool
	//NoRestartAfterFetch disables automatic restarts after each upgrade.
	//Though manual restarts using the RestartSignal can still be performed.
	NoRestartAfterFetch bool
	//Fetcher will be used to fetch binaries.
	Fetcher fetcher.Interface
}

一般用不到這么多參數(shù),核心的是:

  • Program
  • Fetcher

常用有:

  • Address
  • Addresses
  • MinFetchInterval
  • PreUpgrade

Fetcher

除了 Config,overseer 中另一個重要的接口就是 Fetcher。
Fetcher 接口定義了程序如何初始化和更新

package fetcher

import "io"

// Interface defines the required fetcher functions
type Interface interface {
	//Init should perform validation on fields. For
	//example, ensure the appropriate URLs or keys
	//are defined or ensure there is connectivity
	//to the appropriate web service.
	Init() error
	//Fetch should check if there is an updated
	//binary to fetch, and then stream it back the
	//form of an io.Reader. If io.Reader is nil,
	//then it is assumed there are no updates. Fetch
	//will be run repeatedly and forever. It is up the
	//implementation to throttle the fetch frequency.
	Fetch() (io.Reader, error)
}

overseer 只帶了幾個實現(xiàn)好了的 Fetcher,可以滿足大部分需求,也可以自己繼承 Fetcher 接口實現(xiàn)自己的 Fetcher。

簡單的自升級示例

演示自動升級,我們需要編譯2個版本的程序。

示例如下:

package main

import (
	"fmt"
	"time"

	"github.com/jpillora/overseer"
	"github.com/jpillora/overseer/fetcher"
)

const version = "v0.1"

// 控制自升級
func main() {
	overseer.Run(overseer.Config{
		Program:          actualMain,
		TerminateTimeout: 10 * time.Second,
		Fetcher: &fetcher.HTTP{
			URL:      "http://localhost:9000/selfupgrade",
			Interval: 1 * time.Second,
		},
		PreUpgrade: preUpgrade,
	})
	// mainWithSelfUpdate()
}

// 升級前的動作,參數(shù)是下載的程序的臨時位置,如果返回 error,則不升級
func preUpgrade(tempBinaryPath string) error {
	fmt.Printf("download binary path: %s\n", tempBinaryPath)
	return nil
}

// 這里一般寫是實際的業(yè)務(wù),此示例是不斷打印 version
func actualMain(state overseer.State) {
	for {
		fmt.Printf("%s: current version: %s\n", time.Now().Format("2006-01-02 15:04:05"), version)
		time.Sleep(3 * time.Second)
	}
}

上面的程序編譯后啟動。

$ go build -o selfupgrade

$ ./selfupgrade 
2022-05-21 00:46:52: current version: v0.1
2022-05-21 00:46:55: current version: v0.1
2022-05-21 00:46:58: current version: v0.1
2022-05-21 00:47:01: current version: v0.1
2022-05-21 00:47:04: current version: v0.1

啟動之后開始不斷的打印版本號(間隔3秒)。不要停止此程序。

然后我們修改 version,并且將 actualMain 中的間隔修改為5秒。

const version = "v0.2"  // v0.1 => v0.2

// 。。。 省略。。。

// 這里一般寫是實際的業(yè)務(wù),此示例是不斷打印 version
func actualMain(state overseer.State) {
	for {
		fmt.Printf("%s: current version: %s\n", time.Now().Format("2006-01-02 15:04:05"), version)
		time.Sleep(5 * time.Second)
	}
}

修改之后,再編譯一個版本到 ~/tmp 目錄(如果不存在提前創(chuàng)建)。
然后啟動一個文件服務(wù),我用python自帶的方法啟動了一個服務(wù),服務(wù)端口對應(yīng)代碼中的升級URL("http://localhost:9000/selfupgrade")

$ go build -o ~/tmp/selfupgrade 
$ cd ~/tmp
$ python -m http.server 9000

過一會兒之后,就能看到之前啟動程序已經(jīng)更新。
更新之后版本號變成 v0.2,時間間隔變成了5秒

2022-05-21 01:27:22: current version: v0.1
2022-05-21 01:27:25: current version: v0.1
download binary path: /tmp/overseer-5c0eb0f83a
2022-05-21 01:27:28: current version: v0.1
2022-05-21 01:27:31: current version: v0.1
2022-05-21 01:27:34: current version: v0.1
2022-05-21 01:27:37: current version: v0.1
2022-05-21 01:27:37: current version: v0.2
2022-05-21 01:27:42: current version: v0.2
2022-05-21 01:27:47: current version: v0.2

Web服務(wù)自升級示例

web服務(wù)與之類似,比如:

func actualMainServer(state overseer.State) {
	http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "%s: current version: %s\n", time.Now().Format("2006-01-02 15:04:05"), version)
	}))
	http.ListenAndServe(":8000", nil)
}

將上面函數(shù)替換 overseer.Config 的Program即可。

通過觀察進程的變化,可以看出升級之后就是將子進程重啟,主進程沒變。

升級前:

$ ps -ef | ag self
wangyub+    8058    4443  1 09:58 pts/12   00:00:00 ./selfupgrade
wangyub+    8067    8058  0 09:58 pts/12   00:00:00 ./selfupgrade
wangyub+    8130    3548  0 09:59 pts/11   00:00:00 ag self

升級后:

$ ps -ef | ag self
wangyub+    8058    4443  0 09:58 pts/12   00:00:00 ./selfupgrade
wangyub+    8196    8058  0 09:59 pts/12   00:00:00 ./selfupgrade
wangyub+    8266    3548  0 09:59 pts/11   00:00:00 ag self

上面的寫法,會導(dǎo)致端口的服務(wù)中斷一會兒,如果要保持端口持續(xù)暢通,可以用官方示例中的寫法。

overseer.Run(overseer.Config{
		// 。。。省略。。。
		Address:          ":8000",  // 服務(wù)的端口
	})

實際的server中使用 state 中的 Listener。

func actualMainServer(state overseer.State) {
	http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "%s: current version: %s\n", time.Now().Format("2006-01-02 15:04:05"), version)
	}))
	http.Serve(state.Listener, nil)  // 這里使用 state 中的 Listener,也就是 Config中的 Address
}

總結(jié)

總的來說,overseer 滿足了自升級的各種需求。
但是自帶的Fetcher功能比較簡單,比如HTTP的Fetcher,升級的過程可能只有一個URL還不夠,還有更加復(fù)雜的版本檢查和比較。
實際場景下可能需要定制一個適合自己應(yīng)用的Fetcher。


網(wǎng)頁題目:golang 應(yīng)用自升級
URL網(wǎng)址:http://weahome.cn/article/dsoisoo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部