天天看點

Docker - Docker重新開機!機器當機!容器能自己恢複嗎?

能!

啟動容器的時候,可以指定容器在某些可預測(docker engine重新開機)與不可預測(機器當機重新開機)時的重新開機行為,利用這個功能,我們可以放心當重新開機docker engine,也不用擔心機器重新開機導緻應用不可用。

這個神奇的功能是“restart polices”,定義了當容器因為某種原因停掉之後的行為,有四種police:

Docker - Docker重新開機!機器當機!容器能自己恢複嗎?

四種重新開機政策

  • 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
}
           

事件監聽怎麼實作的呢?

繼續閱讀