TL;DR: docker 서비스가 시작하면 modprobe overlay를 진행한다. modprobe는 dockerd.service의 의존성 서비스인 containerd.service에서 진행한다.

현재 이 위키는 ODROID-U2로 실행중이다. 옛날에 나온 작은 보드라서 몇 가지 문제가 있었는데, 어찌어찌 커널 플래그 주고 간신히 컴파일해서 왠만한 문제는 해결하였다. 문제 중 하나였던 docker도 잘 실행되서 쓰고 있다.

잘 돌아가고 있으니 신경 안쓰고 업데이트도 하지 않았는데, 최근 리눅스 패키지를 전체 업데이트 했더니 도커 대몬이 실행되지 않는다. 그래서 systemd 로그를 살펴 보았다.

$ journalctl -xe
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit docker.service has begun starting up.
11월 09 16:00:37 cublr-odroidu2 modprobe[3420]: modprobe: FATAL: Module overlay not found in directory /lib/modules/3.14.0-rc3
11월 09 16:00:37 cublr-odroidu2 systemd[1]: containerd.service: Control process exited, code=exited status=1
11월 09 16:00:37 cublr-odroidu2 systemd[1]: Failed to start containerd container runtime.
-- Subject: Unit containerd.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit containerd.service has failed.
-- 
-- The result is failed.
11월 09 16:00:37 cublr-odroidu2 systemd[1]: Dependency failed for Docker Application Container Engine.
-- Subject: Unit docker.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit docker.service has failed.
-- 
-- The result is dependency.
11월 09 16:00:37 cublr-odroidu2 systemd[1]: docker.service: Job docker.service/start failed with result 'dependency'.
11월 09 16:00:37 cublr-odroidu2 systemd[1]: containerd.service: Unit entered failed state.
11월 09 16:00:37 cublr-odroidu2 systemd[1]: containerd.service: Failed with result 'exit-code'.
11월 09 16:00:37 cublr-odroidu2 systemd[1]: Stopped Docker Application Container Engine.
-- Subject: Unit docker.service has finished shutting down
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit docker.service has finished shutting down.

최근 도커 버전은 기본 스토리지 드라이버가 overlay이므로, 업데이트 하면서 overlay를 찾으려 해서 생기는 문제라고 생각했다. 기본 스토리지 드라이버를 aufs로 변경해 보자.

$ cat /etc/docker/daemon.json
{
	"dns": ["8.8.8.8"],
	"dns-opts": ["8.8.8.8"],
	"bridge": "none",
	"experimental": true,
	"storage-driver": "aufs"
}

aufs를 기본적으로 사용하도록 변경하였으므로 overlay를 찾는 문제는 없을 것이다. 그럴 것이라 생각했는데 실제로는 에러가 그대로 출력되는 것이었다. 어디서 지금 overlay를 modprobe하고 있는데 그걸 지우지 않으면 앞으로도 실행이 안된다는 뜻.

우선 원인을 찾기 전에 dockerd를 직접 실행해 보았다.

$ /usr/bin/dockerd
WARN[0000] Running experimental build                   
INFO[2018-11-09T16:05:36.224035214Z] libcontainerd: started new containerd process  pid=3488
INFO[2018-11-09T16:05:36.225087001Z] parsed scheme: "unix"                         module=grpc
INFO[2018-11-09T16:05:36.225285791Z] scheme "unix" not registered, fallback to default scheme  module=grpc
INFO[2018-11-09T16:05:36.225909455Z] ccResolverWrapper: sending new addresses to cc: [{unix:///var/run/docker/containerd/containerd.sock 0  <nil>}]  module=grpc
INFO[2018-11-09T16:05:36.226182912Z] ClientConn switching balancer to "pick_first"  module=grpc
INFO[2018-11-09T16:05:36.226649910Z] pickfirstBalancer: HandleSubConnStateChange: 0x9546a0f0, CONNECTING  module=grpc
INFO[2018-11-09T16:05:36.403721025Z] starting containerd                           revision=c4446665cb9c30056f4998ed953e6d4ff22c7c39 version=1.2.0

...

INFO[2018-11-09T16:05:36.652862188Z] Loading containers: start.                   
INFO[2018-11-09T16:05:37.865763991Z] Removing stale sandbox 038d3d7fa4fc358c22cbd8137566c5b7e2eb5fcd609635d155158faae52fcf34 (b40675347479fcba98e68c1a8a73277b34833930a794a0a05aedaab06507e06b) 
INFO[2018-11-09T16:05:37.920301325Z] Loading containers: done.                    
INFO[2018-11-09T16:05:38.035146632Z] Docker daemon                                 commit=4d60db4 graphdriver(s)=aufs version=18.09.0
INFO[2018-11-09T16:05:38.035965754Z] Daemon has completed initialization          
INFO[2018-11-09T16:05:38.097783635Z] API listen on /var/run/docker.sock           
^CINFO[2018-11-09T16:05:44.822252837Z] Processing signal 'interrupt'                
INFO[2018-11-09T16:05:44.834203292Z] stopping event stream following graceful shutdown  error="<nil>" module=libcontainerd namespace=moby
INFO[2018-11-09T16:05:44.835993367Z] stopping healthcheck following graceful shutdown  module=libcontainerd
INFO[2018-11-09T16:05:44.836240782Z] stopping event stream following graceful shutdown  error="context canceled" module=libcontainerd namespace=plugins.moby
INFO[2018-11-09T16:05:44.838064148Z] pickfirstBalancer: HandleSubConnStateChange: 0x9585c7d0, TRANSIENT_FAILURE  module=grpc
INFO[2018-11-09T16:05:44.838379855Z] pickfirstBalancer: HandleSubConnStateChange: 0x9585c7d0, CONNECTING  module=grpc

실행은 잘 된다. 즉 dockerd를 직접 실행하면 daemon.json을 읽고 정상적으로 실행된다는 것이다.

docker info
Containers: 1
 Running: 0
 Paused: 0
 Stopped: 1
Images: 30
Server Version: 18.09.0
Storage Driver: aufs
 ...
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 ...
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
...
Experimental: true
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine

정리해 보면 다음과 같다.

  1. 직접 실행하면 원하는 대로 실행 가능하다.
  2. systemd를 쓰면 modprobe를 시도하다 실패한다.
  3. modprobe를 하는 곳을 찾아서 없애야 한다.

systemd 서비스 파일을 찾아보자.

$ systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since 금 2018-11-09 16:16:06 UTC; 7min ago
     Docs: https://docs.docker.com
  Process: 4138 ExecStart=/usr/bin/dockerd -H unix:// (code=killed, signal=TERM)
 Main PID: 4138 (code=killed, signal=TERM)

이 메시지에 적혀 있는 /lib/systemd/system/docker.service를 열어 보면

$ cat /lib/systemd/system/docker.service 
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
BindsTo=containerd.service
After=network-online.target firewalld.service
Wants=network-online.target

...

BindsTo로 containerd.service에 연결되어 있는 것이다. 그걸 다시 열어 보면

[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/usr/bin/containerd
...

그렇다. systemd 서비스로 등록된 dockerd는 dependency로 containerd.service 서비스를 가지고 있고, 여기서 modprobe overlay를 진행하는 것. 기본 도커 스토리지가 overlay이므로 이렇게 서비스 파일을 만든 것이라고 생각되는데 이게 이렇게 되면 aufs를 기본으로 쓰는 사람은 조금 헤맬 수 있겠다는 생각이 든다.