前置条件

  1. 安装 supervisor:
    参见:服务、进程监控 – supervisor

  2. 安装 gitlab:
    参见:版本控制 – gitlab16.0.0

  3. 安装 jenkins:
    参见:持续集成 – jenkins2.385

  4. 安装 efk:
    参见:docker 安装 EFK6.4.3

  5. 安装 golang:
    参见:源码安装 golang

gitlab 项目代码

  1. 目录结构:

    |—— myproject/   // 根目录
    ****|—— config/
    ********|—— config.yaml  // 配置文件
    ****|—— log/
    ********|—— info.log  // 日志文件(自动生成)
    ****|—— utils/  // 工具目录(go test 目录)
    ********|—— utils.go
    ********|—— utils_test.go
    ****|—— .gitignore  // git 配置忽略文件
    ****|—— go.mod.example  // go.mod 模板文件
    ****|—— main.go  // 入口文件
    ****|—— Makefile  // makefile 文件
  2. 编写 myproject/config/config.yaml:
    port: 8999

  3. 编写 myproject/utils/utils.go:

     package utils
    
     func Add(a, b int) int {
         return a + b
     }
  4. 编写 myproject/utils/utils_test.go:

     package utils
    
     import (
         "testing"
     )
    
     func TestUtils(t *testing.T) {
         c := Add(1, 2)
         if c != 3 {
             t.Errorf("%d + %d != %d", 1, 2, 3)
         }
         t.Log("测试通过")
     }
  5. 编写 myproject/.gitignore:

    log/info.log
    go.sum
    go.mod
  6. 编写 myproject/go.mod.example:
    module myproject

  7. 编写 myproject/main.go:

     package main
    
     import (
         "fmt"
         "github.com/sirupsen/logrus"
         "github.com/spf13/viper"
         "myproject/utils"
         "net/http"
         "os"
         "strconv"
     )
    
     func init() {
         // 初始化 logrus
         logrus.SetReportCaller(true)
         logrus.SetFormatter(&logrus.TextFormatter{
             TimestampFormat: "2006-01-02 15:03:04",
         })
         file, err := os.OpenFile("./log/info.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
         if err == nil {
             logrus.SetOutput(file)
         } else {
             logrus.Fatalf("输出到日志文件失败:%s \n", err)
         }
         logrus.SetLevel(logrus.TraceLevel)
         // 初始化 viper
         viper.SetConfigName("config.yaml")
         viper.SetConfigType("yaml")
         viper.AddConfigPath("./config")
         err = viper.ReadInConfig()
         if err != nil {
             logrus.Fatalf("获取配置文件失败: %s \n", err)
         }
     }
    
     func myHandler(w http.ResponseWriter, r *http.Request) {
         r.ParseForm()
         var a, b string
         params := r.Form
         if len(params["a"]) > 0 {
             a = params["a"][0]
         }
         if len(params["b"]) > 0 {
             b = params["b"][0]
         }
         aInt, _ := strconv.Atoi(a) // 参数 a
         bInt, _ := strconv.Atoi(b) // 参数 b
         res := utils.Add(aInt, bInt)
         output := fmt.Sprintf("%d + %d = %d", aInt, bInt, res)
         logrus.WithFields(logrus.Fields{
             "a": aInt,
             "b": bInt,
         }).Info(output)
         fmt.Fprintln(w, output)
     }
    
     func main() {
         port := viper.GetString("port")
         addr := fmt.Sprintf(":%s", port)
         http.HandleFunc("/", myHandler)
         svc := http.Server{
             Addr:    addr,
             Handler: http.DefaultServeMux,
         }
         fmt.Printf("http 服务器启动成功,访问地址为:%s \n", addr)
         if err := svc.ListenAndServe(); err != nil {
             logrus.Fatalf("启动 http 服务失败:%s \n", err)
         }
     }
  8. 编写 myproject/Makefile:

     # 所有自定义步骤列表
     .PHONY: all test build deploy help
    
     # 自定义变量
     OUTPUT_FILE=myapp
    
     # 直接运行 make 命令调用的步骤
     all: test build deploy
    
     # 测试
     test:
         cd utils && \
         go test
    
     # 构建
     build:
         CGO_ENABLED=0 && \
         GOOS=darwin && \
         GOARCH=amd64 && \
         go build -v -ldflags "-w" -o ${OUTPUT_FILE} main.go
    
     # 部署(运行)
     deploy:
         supervisorctl restart ${OUTPUT_FILE}
    
     # 帮助信息("@"屏蔽输出)
     help:
         @echo "【make】 -- 测试、构建、部署"
         @echo "【make test】 -- 测试"
         @echo "【make build】 -- 构建"
         @echo "【make deploy】 -- 部署"
         @echo "【make help】 -- 查看帮助"

配置文件:

  1. jenkins pipeline:

    pipeline{
     //agent any
     agent {
         label 'master'  // 指定在 master 节点运行
     }
     stages{
         stage("pull"){
             steps{
                 sh """
                     cd /path/to/myproject
                     git checkout .
                     git reset --hard
                     git stash
                     git pull
                 """
             }
         }
         stage("tidy"){
             steps{
                 sh """
                     go env -w GO111MODULE=on
                     go env -w GOPROXY=https://goproxy.cn,direct
                     cd /path/to/myproject
                     cp go.mod.example go.mod
                     go mod tidy
                 """
             }
         }
         stage("deploy"){
             steps{
                 sh """
                     cd /path/to/myproject
                     make
                 """
             }
         }
     }
    }
  2. supervisor:
    cat /etc/supervisord.d/myproject.ini

    [program: myproject]
    directory=/path/to/myproject
    command=/path/to/myproject/myapp
    user=root
    stderr_logfile=/path/to/log/myproject/err.log
    stdout_logfile=/path/to/log/myproject/info.log
    autorestart=true
    autostart=true
    stopsignal=INT
    startsecs=10
    startretries=5
    stopasgroup=true
  3. efk:
    cat /path/to/filebeat/config/filebeat.yml

     filebeat.inputs:
         -   type: log
             enabled: true
             paths:
                 - /var/myproject/log/*.log
             fields:
                 log_topics: "myproject"
    
     setup.template.settings:
         index.number_of_shards: 3
    
     setup.template.name: "filebeat*"
     setup.template.pattern: "filebeat*"
    
     output.elasticsearch:
         hosts: [ "elasticsearch643:9200" ]
         index: "project-other"
         indices:
             -   index: "myproject"
                 when.contains:
                     fields:
                         log_topics: "myproject"

各服务器访问地址

  1. gitlab:
    xx.xx.xx.xx:8888

  2. jenkins:
    xx.xx.xx.xx:9999

  3. myproject:
    xx.xx.xx.xx:8999

  4. kibana:
    xx.xx.xx.xx:5601

文档更新时间: 2024-04-20 10:57   作者:lee