一. gitlab-runner四大過程
注冊runner
首先注冊runner壳坪,輸入url、token、tag等信息眯牧,注冊時(shí)會向GitLab發(fā)送一個(gè)請求。
GitLab接收到請求后會返回一個(gè)token給runner赖草,runner之后和GitLab的請求通訊都會帶上這個(gè)token学少。查詢job
注冊成功后runner會向GitLab輪詢請求,查看是否要執(zhí)行任務(wù)秧骑。查詢到j(luò)ob后構(gòu)建執(zhí)行
某位開發(fā)者push了代碼版确,代碼更新了扣囊,這時(shí)候流水線pipeline啟動,并將第一個(gè)stage設(shè)置為pending狀態(tài)绒疗。
在步驟3完成沒多久侵歇,runner的下一次請求已經(jīng)到達(dá)了,這時(shí)候會把pending狀態(tài)的stage發(fā)送到runner處吓蘑,之后runner開始干活惕虑,執(zhí)行g(shù)itlab-ci.yml中的腳本。Job Trace日志信息發(fā)送給GitLab Server
當(dāng)執(zhí)行完了腳本后磨镶,runner會發(fā)送最終的執(zhí)行結(jié)果溃蔫,如果完成則為passed,失敗則為failed
其中涉及到與gitlab-ci交互的部分
common/network.go
type Network interface {
RegisterRunner(config RunnerCredentials, parameters RegisterRunnerParameters) *RegisterRunnerResponse
VerifyRunner(config RunnerCredentials) bool
UnregisterRunner(config RunnerCredentials) bool
RequestJob(config RunnerConfig, sessionInfo *SessionInfo) (*JobResponse, bool)
UpdateJob(config RunnerConfig, jobCredentials *JobCredentials, jobInfo UpdateJobInfo) UpdateState
PatchTrace(config RunnerConfig, jobCredentials *JobCredentials, content []byte, startOffset int) (int, UpdateState)
DownloadArtifacts(config JobCredentials, artifactsFile string) DownloadState
UploadRawArtifacts(config JobCredentials, reader io.Reader, options ArtifactsOptions) UploadState
ProcessJob(config RunnerConfig, buildCredentials *JobCredentials) (JobTrace, error)
}
二 注冊runner的核心步驟
- commands/register.go#init()
func init() {
common.RegisterCommand2("register", "register a new runner", newRegisterCommand())
}
備注: newRegisterCommand()生成RegisterCommand的實(shí)例,中有Execute()方法
- commands/register.go#Execute()
s.askRunner() //詢問url token description tags
s.askExecutor()
s.askExecutorOptions()//詢問用那個(gè)類型的Executor
s.mergeTemplate()
s.addRunner(&s.RunnerConfig)
s.saveConfig() //將配置保存到config.toml
備注:完成配置.
3.network/gitlab.go#RegisterRunner
request := common.RegisterRunnerRequest{
RegisterRunnerParameters: parameters,
Token: runner.Token,
Info: n.getRunnerVersion(common.RunnerConfig{}),
}
var response common.RegisterRunnerResponse
result, statusText, _, _ := n.doJSON(&runner, "POST", "runners", http.StatusCreated, &request, &response)
備注:向server去注冊
三 .查詢job的核心步驟
commands/multi.go#Run
func (mr *RunCommand) Run() {
//忽略不重要代碼
go mr.feedRunners(runners)
//忽略不重要代碼
go mr.startWorkers(startWorker, stopWorker, runners)
}
備注:
第一個(gè)方法會判斷是否在可用的runners琳猫,若存在伟叛,則遍歷所有可用的 runner,并周期性地(CheckInterval / len(runners))往runners 通道中壓入runner脐嫂。
第二個(gè)方法中的mr.processRunners方法通過select case結(jié)構(gòu)從runners取前面壓入的runner實(shí)例统刮,一旦取出成功則執(zhí)行processRunner方法調(diào)用鏈最終調(diào)用network/gitlab.go#RequestJob方法,去請求.
三、四. 查詢到j(luò)ob后構(gòu)建執(zhí)行并返回日志信息
network/gitlab.go#ProcessJob
func (n *GitLabClient) ProcessJob(config common.RunnerConfig, jobCredentials *common.JobCredentials) (common.JobTrace, error) {
trace, err := newJobTrace(n, config, jobCredentials)
//開啟 Job Trace 輸出
trace.start()
return trace, nil
}
備注:
trace.start方法來調(diào)用trace.watch以周期性地patch Job trace
具體patch Job代碼還未來的及看,后面更新.
附上:gitlab-runner 與自己程序交互的demo(只有注冊runner部分)
package runners
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type RegisterResp struct {
Id string `json:"id"`
Token string `json:"token"`
}
func InitServer(port string) error {
mux := &http.ServeMux{}
srv := http.Server{
Addr: ":" + port,
Handler: mux,
}
mux.HandleFunc("/api/v4/runners", func(w http.ResponseWriter, req *http.Request) {
//var closeFlag bool = true
con, _ := ioutil.ReadAll(req.Body) //獲取post的數(shù)據(jù)
fmt.Println(string(con))
resp := RegisterResp{
Id: "55",
Token: "ft7eVVzxa6NrT3XfcKgk",
}
respData, _ := json.Marshal(resp)
//w.Header()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(201)
fmt.Println(string(respData))
if _, err := w.Write(respData); err != nil {
fmt.Println(err.Error())
}
})
return srv.ListenAndServe()
}
啟動
runners.InitServer("80")
查看通信情況抓取http包數(shù)據(jù)命令:
sudo tcpdump -i vnic0 -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'