通过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。