ログパイロットソースコードの簡単な分析

log-pilotは、動的スケーリングや動的構成などの機能を備えた、Alibabaのオープンソースコンテナログ収集プロジェクトです。そのコア原則は次のとおりです。Dockerイベントを監視し、filebeat / fluentdを自動的に構成および再ロードして、コンテナーの動的スケジューリングによるログ収集と自動スケーリングの効果を実現します。

プロジェクト全体の中核は次のとおりです。

  • 政治構造

  • Politerインターフェース

政治

主にDockerコンテナイベントを監視し、コンテナログマウントディレクトリ、タグ、環境変数などの情報を取得しfilebeat / fluentd構成ファイルを動的に生成します

type Pilot struct { 
    piloter Piloter //パイロット関連の
    mutexsync.Mutex //同時ロック、複数のコンテナーイベントがトリガーされ、最初にロックを取得した人、
    テンプレートを処理した人* template.Template //ログコレクションクライアント構成ファイルテンプレート、log -pilot golangのテキスト/テン​​プレートモジュールを使用して、構成ファイル
    クライアントをレンダリングします* k8s.Client // dockerコンテナクライアント、
    dockerイベントインターフェイスを介して関連するコンテナ情報を取得しますapi lastReload time.Time //最後の構成ファイルのリロード時間
    reloadChanchan bool //リロード通知chan 
    stopChan chan bool //通知を停止し
    ますchanbaseDir string //ホスト上の
    dockerlogPrefix [] string //環境変数が始まる文字を定義して、アプリケーションログが配置されているディレクトリを示し。log-pilotはで始まります環境変数を構成して、各コンテナー内のアプリケーションのログパスの場所を構成します
    Dockerデータの保存場所createSymlinkbool //収集するログファイルを関連付けるハードリンクを作成するかどうか
}


ポリター

Politerは、収集ツールが操作する必要のあるいくつかのメソッドを定義し、主に収集ツールの有効化停止、および再読み込みの特定の操作を担当します。

type Piloter interface { 
    Name()string // "filebeat"と "fluentd"は、それぞれ異なる収集ツール
 
    を示しますStart()エラー//収集ツールを開始します
    Reload()エラー//構成ファイルをリロードします
    Stop()エラー//収集を停止しますtool 
 
    GetBaseConf()string // filebeatの/ etc / filebeatなどのログコレクションクライアント構成ファイルの場所
    GetConfHome()string // filebeatのprospectors.dの場所などのログコレクションクライアント統合構成ファイルディレクトリ
    GetConfPath(container string)string //特定の構成ファイルパス
 
    OnDestroyEvent(container string)エラー//コンテナ停止イベントをリッスンします
}

メイン機能

プログラムエントリ、コマンドライン処理:ログ収集構成テンプレートの指定、ログパイロットログレベル構成など。 

Plot.Run

  • Politデータを初期化します。Politには、対応するfilebeat / fluentd構成テンプレート、dokcerクライアント、同時実行ロック、パイロットオブジェクトなどが含まれます。
  • コンテナイベントモニタリングをオンにする
func Run(templ string, baseDir string) error {
p, err := New(templ, baseDir)
....
return p.watch()
}

Pilot.watch

  • 使用 docker api 连接 docker,并watch docker 事件
func (p *Pilot) watch() error {
    ....
     
    err := p.piloter.Start()            // 启动收集工具
    ....
     
    msgs, errs := p.client.Events(ctx, options)  // 接受 docker 事件,返回 chan
 
    go func() {
        ....
 
        for {           // 无限循环获取事件
            select {
            case msg := <-msgs:
                if err := p.processEvent(msg); err != nil {     // 处理 docker 事件
                    log.Errorf("fail to process event: %v,  %v", msg, err)
                }
            ........
        }
    }()
    ....
}

Pilot.processEvent

  docker event 的handler函数

func (p *Pilot) processEvent(msg events.Message) error {
	....
	switch msg.Action {
	case "start", "restart":
            ....
            return p.newContainer(&containerJSON)
	case "destroy", "die":
            ....
	    err := p.delContainer(containerId)
	return nil
}

Pilot.newContainer

  • 处理环境变量/tag标签/mount

  • 渲染配置文键模板,生成新的配置文件并reload生效 

func (p *Pilot) newContainer(containerJSON *types.ContainerJSON) error {
    ....
    // containerJSON 是 docker接口 Client.ContainerInspect 返回的数据类型
 
    container := container(containerJSON)
 
    for _, e := range env {         // 处理环境变量, env由containerJSON 得到
        .....
    }
    // 获取配置文件模板数据
    logConfigs, err := p.getLogConfigs(jsonLogPath, mounts, labels)
    if err != nil {
        return err
    }
    
 
    ....
 
    // 关联 docker 容器中应用日志文件或目录
    p.createVolumeSymlink(containerJSON)
    
 
    // 渲染配置文件模板数据,生成具体的配置文件
    logConfig, err := p.render(id, container, logConfigs)
    if err != nil {
        return err
    }
    //TODO validate config before save
    //log.Debugf("container %s log config: %s", id, logConfig)
    if err = ioutil.WriteFile(p.piloter.GetConfPath(id), []byte(logConfig), os.FileMode(0644)); err != nil {
        return err
    }
    // 重载配置文件
    p.tryReload()
    return nil
}

Pilot.delContainer

  • 渲染配置文键模板,删除配置文件
  • reload 配置文件

func (p *Pilot) delContainer(id string) error {
	p.removeVolumeSymlink(id)

	//fixme refactor in the future
	if p.piloter.Name() == PILOT_FLUENTD {
		clean := func() {
			log.Infof("Try removing log config %s", id)
			if err := os.Remove(p.piloter.GetConfPath(id)); err != nil {
				log.Warnf("removing %s log config failure", id)
				return
			}
			p.tryReload()
		}
		time.AfterFunc(15*time.Minute, clean)
		return nil
	}

	return p.piloter.OnDestroyEvent(id)
}

LogConfig

动态渲染配置文件模板数据集

type LogConfig struct {
    Name         string                 // 日志名
    HostDir      string                 // 日志文件在宿主机上的目录
    ContainerDir string                 // 容器应用日志目录
    Format       string
    FormatConfig map[string]string     
    File         string                 // 具体的日志文件名
    Tags         map[string]string      // 标签数据
    Target       string                 // 索引或者kafka主题
    EstimateTime bool
    Stdout       bool
 
    CustomFields  map[string]string     // 自定义添加日志字段
    CustomConfigs map[string]string     // 自定义配置文件项
}

getLogConfigs

  • 获取配置文件模板渲染数据

parseLogConfig

  • 接续容器数据获得配置文件模板渲染数据

最终生成的filebeat 配置文件

- type: log
  enabled: true
  paths:
      - /host/var/lib/docker/containers/b61b94c9f38eec70df32d45df408ea09ad05987bf4ff92d5d5f2eae3fd9e503d/b61b94c9f38eec70df32d45df408ea09ad05987bf4ff92d5d5f2eae3fd9e503d-json.log*
  scan_frequency: 10s
  fields_under_root: true
 
  docker-json: true
  
  fields:
 
      index: aaa-test
 
      topic: aaa-test
  
      docker_container: k8s_tomcat_tomcat_default_6cc39a2f-2a2b-45a2-94d8-a51faf68dd14_0
 
      k8s_container_name: tomcat
 
      k8s_node_name: cn-hangzhou.172.16.179.195
 
      k8s_pod: tomcat
 
      k8s_pod_namespace: default
 
  tail_files: false
  close_inactive: 2h
  close_eof: false
  close_removed: true
  clean_removed: true
  close_renamed: false

おすすめ

転載: blog.51cto.com/3379770/2641663