Docker - Docker重启!机器宕机!容器能自己恢复吗?

能!

启动容器的时候,可以指定容器在某些可预测(docker engine重启)与不可预测(机器宕机重启)时的重启行为,利用这个功能,我们可以放心当重启docker engine,也不用担心机器重启导致应用不可用。

这个神奇的功能是“restart polices”,定义了当容器因为某种原因停掉之后的行为,有四种police:

Docker - Docker重启!机器宕机!容器能自己恢复吗?_第1张图片 四种重启策略
  • no,无论什么时候容器因为什么原因宕掉,都不重启;
  • on-failure,如果容器因为某种错误宕掉,就重启;
  • always,与no相反,无论什么时候容器因为什么原因宕掉,都会尝试重启;
  • unless-stopped,除了执行过docker stop,否则都会重启。

咋用啊

很简单,可以在docker run中指定,也可以在compose文件中指定:

如我启动一个nginx:docker run -d nginx:1.17.2-alpine,那么其restart policy就是默认值no,不会重启;如果:docker run -d --restart always nginx:1.17.2,那么其restart policy就是always。

如果是compose中,也很简单:

nginx:
    container_name: nginx
    image: nginx:1.17.2-alpine
    ports:
      - "80:80"
    networks:
      - my_bridge
    restart: always

原理(涉及读源码,可能引起不适)

看moby的源码,restartmanager/restartmanager.go的ShouldRestart函数中有这样的逻辑:根据restart参数的设置值确定在各种情况下是否应该重启,并返回判断结果:

var restart bool
switch {
case rm.policy.IsAlways():
	restart = true
case rm.policy.IsUnlessStopped() && !hasBeenManuallyStopped:
	restart = true
case rm.policy.IsOnFailure():
	// the default value of 0 for MaximumRetryCount means that we will not enforce a maximum count
	if max := rm.policy.MaximumRetryCount; max == 0 || rm.restartCount < max {
		restart = exitCode != 0
	}
}

而在daemon/monitor.go的ProcessEvent函数中使用了ShouldRestart的逻辑。docker的daemon进程会监听各个容器生命周期中各种事件,而对应的行为是通过调用ProcessEvent来处理的,只要有事件触发,那么libcontainerd就会调用ProcessEvent函数生成行为。当判断事件是容器退出事件时,就会根据传入的restart police来处理这个事件:

case libcontainerdtypes.EventExit:
    if int(ei.Pid) == c.Pid {
        // ... 此处省略15行
        restart, wait, err := c.RestartManager().ShouldRestart(ei.ExitCode, daemon.IsShuttingDown() || c.HasBeenManuallyStopped, time.Since(c.StartedAt))
		if err == nil && restart {
			c.RestartCount++
			c.SetRestarting(&exitStatus)
		} else {
			if ei.Error != nil {
				c.SetError(ei.Error)
			}
			c.SetStopped(&exitStatus)
			defer daemon.autoRemove(c)
		}

而具体moby定义了哪些事件呢?在libcontainerd/types/types.go中定义了如下事件:

// Event constants used when reporting events
const (
	EventUnknown     EventType = "unknown"
	EventExit        EventType = "exit"
	EventOOM         EventType = "oom"
	EventCreate      EventType = "create"
	EventStart       EventType = "start"
	EventExecAdded   EventType = "exec-added"
	EventExecStarted EventType = "exec-started"
	EventPaused      EventType = "paused"
	EventResumed     EventType = "resumed"
)

每一个事件信息量都是一个复合变量struct,包含了容器ID、容器进程ID、Pid、退出代码、退出时间、是否OOM掉了,以及详细的err对象。这里包含的信息足够使docker engine对涉事容器进行操作了。

// EventInfo contains the event info
type EventInfo struct {
	ContainerID string
	ProcessID   string
	Pid         uint32
	ExitCode    uint32
	ExitedAt    time.Time
	OOMKilled   bool
	Error       error
}

事件监听怎么实现的呢?

 

 

你可能感兴趣的:(docker,云计算,kubernetes,容器云)