通过docker的API或者docker event命令,我们都可以获取到容器生命周期内发生了那些事情。首先把结论放出来,然后在看实现过程。
这里写图片描述
这个是实验的结论,那我怎么获取到这些状态和事件的呢?很简单,就是通过上面的api watch。
通过docker go client很容易实现

func (w *watcher) watch() {
    filters := filters.NewArgs()
    filters.Add("type", "container")

    options := types.EventsOptions{
        Since:   fmt.Sprintf("%d", w.lastValidTimestamp),
        Filters: filters,
    }

    for {
        events, errors := w.client.Events(w.ctx, options)

    WATCH:
        for {
            select {
            case event := <-events:
            fmt.Printf("get event %v action %v \n",event.Actor.Attributes["name"],event.Action)
                logp.Debug("docker", "Got a new docker event: %v", event)
                w.lastValidTimestamp = event.Time

                // Add / update
                if event.Action == "create" || event.Action == "update" {
                    name := event.Actor.Attributes["name"]
                    image := event.Actor.Attributes["image"]
                    delete(event.Actor.Attributes, "name")
                    delete(event.Actor.Attributes, "image")
                    container := &Container{
                        ID:     event.Actor.ID,
                        Name:   name,
                        Image:  image,
                        Labels: event.Actor.Attributes,
                        Env:    make(map[string]string),
                    }
                    info, err := w.client.ContainerInspect(w.ctx, event.Actor.ID)
                    if err == nil {
                        for _, env := range info.Config.Env {
                            kv := strings.SplitN(env, "=", 2)
                            if len(kv) >= 2 {
                                container.Env[kv[0]] = kv[1]
                            }
                        }
                    }
                    w.containers[container.ID] = container
                    w.containers[container.Name] = container
                }

                // Delete
                if event.Action == "die" || event.Action == "kill" {
                    delete(w.containers, event.Actor.ID)
                    delete(w.containers, event.Actor.Attributes["name"])
                }

            case err := <-errors:
                // Restart watch call
                logp.Err("Error watching for docker events: %v", err)
                time.Sleep(1 * time.Second)
                break WATCH

            case <-w.ctx.Done():
                logp.Debug("docker", "Watcher stopped")
                return
            }
        }
    }
}

这样当我们操作docker上的时候就能顺利的获取到它的状态,譬如一次docker run操作,

get event big_meninsky action create 
get event big_meninsky action start

相应的一次stop操作就可以获取到

get event big_meninsky action kill 
get event big_meninsky action kill 
get event big_meninsky action die 
get event big_meninsky action stop 

这里有个很有意思的事,就是怎么会有两次kill操作呢!那是因为,docker stop命令的玩法

docker stop: Stop a running container (send SIGTERM, and then SIGKILL after grace period)

就是先发现TERM信号(为了让容器优雅关闭),再发送KILL信号。所以收到两次kill event命令。这个和kill最大的区别,它是直接发送KILL信号,所以不会有两次kill event。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐