研究目的

當程式委外開發,程式碼部署是由公司內部進行,這時候外包公司如果想要相關日誌時,通常都會由公司內部進行日誌匯出後,再交給外包商。這樣的流程缺點是日誌不即時與需要每次耗費人力進行匯出,但如果有一個工具,可以讓外包商在不登入公司主機狀況下,可即時觀看到日誌,將會加快外包商快速除錯與節省公司內部匯出處理成本。

實作方法

  • 透過Rabbimq架設MQTT Broker。
  • 透過Bash script監測伺服器裡的Docker容器即時日誌。
  • 透過Golang實作一個client端的應用程式。Golang因為可以編譯各種平台執行檔。

服務器監測腳本

  • 首先先安裝mosquitto client工具,透過工具可直接發送訊息到MQTT Broker。

    1
    apt install mosquitto-clients
  • 建立一個腳本為monitor_docker_log.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #!/bin/bash

    CONTAINER_NAME="監測的容器名稱"
    MQTT_BROKER="你的mqtt broker網址或IP"
    MQTT_TOPIC="訂閱標題"
    MQTT_USERNAME="驗證帳號"
    MQTT_PASSWORD="驗證密碼"

    # 透過while迴圈,將docker logs的輸出,一行一行的送到mosquitto_pub
    docker logs -f "$CONTAINER_NAME" | while read -r log_line; do
    # echo $log_line
    mosquitto_pub \
    -h "$MQTT_BROKER" \
    -p 1883 \
    -u "$MQTT_USERNAME" \
    -P "$MQTT_PASSWORD" \
    -t "$MQTT_TOPIC" \
    -m "$log_line"

    done
  • 執行腳本

    1
    2
    chmod +x monitor_docker_log.sh
    bash monitor_docker_log.sh

Client端程式

  • 新增mqtt_sub.go

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    package main

    import (
    "fmt"
    "log"
    "os"
    "os/signal"

    MQTT "github.com/eclipse/paho.mqtt.golang"
    )

    func main() {
    // MQTT 连接参数
    broker := "tcp://你的MQTT Broker網址或IP:1883"
    username := "驗證帳號"
    password := "驗證密碼"
    topic := "訂閱標題"
    println("版本: 1.0.0")
    fmt.Println("功能: 訂閱xx專案Django後端日誌")
    println("主題:", topic)


    // 创建 MQTT 连接选项
    opts := MQTT.NewClientOptions()
    opts.AddBroker(broker)
    opts.SetUsername(username)
    opts.SetPassword(password)

    // 创建 MQTT 客户端
    client := MQTT.NewClient(opts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
    log.Fatal(token.Error())
    }

    // 订阅指定主题
    if token := client.Subscribe(topic, 0, messageHandler); token.Wait() && token.Error() != nil {
    log.Fatal(token.Error())
    }

    fmt.Printf("\033[32m主題訂閱中...\n\033[0m")

    // 等待 Ctrl+C 以退出程序
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)
    <-c

    // 断开 MQTT 连接
    client.Disconnect(250)
    fmt.Println("Disconnected from MQTT broker")
    }

    func messageHandler(client MQTT.Client, msg MQTT.Message) {
    fmt.Printf("%s\n", msg.Payload())
    }

  • 編譯成可執行檔

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #先在.profile定義下列自訂指令
    alias gobuildlunux64="GOOS=linux GPARCH=amd64 go build"
    alias gobuildarm="GOOS=linux GOARM=5 GPARCH=arm go build"
    alias gobuildarm64="GOOS=linux GOARM=5 GPARCH=arm64 go build"
    alias gobuildmacos64="GOOS=darwin GPARCH=amd64 go build"
    alias gobuildwin64="GOOS=windows GPARCH=amd64 go build"
    alias gobuildpi="GOOS=linux GOARCH=arm GOARM=7 go build"


    # 載入.profile
    source ~/.profile

    # 編譯windows可執行檔案,將會自動產生一份mqtt_sub.exe執行檔
    gobuildwin64 mqtt_sub.go

Keyword

1