Docker 데몬 트러블슈팅

Docker 데몬 트러블슈팅 (Troubleshooting the Docker daemon)

이 페이지는 문제가 발생했을 때 데몬을 트러블슈팅하고 디버그하는 방법을 설명해요.

데몬의 런타임 활동을 파악하고 트러블슈팅을 돕기 위해 데몬에서 디버깅을 켤 수 있어요. 데몬이 응답하지 않으면 Docker 데몬에 SIGUSR 신호를 보내 모든 스레드의 전체 스택 트레이스를 데몬 로그에 추가하도록 강제할 수도 있어요.

출처: 문서

본문

데몬 (Daemon)

Docker 데몬에 연결할 수 없음 (Unable to connect to the Docker daemon)

Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?

이 오류는 다음을 나타낼 수 있어요:

  • 시스템에서 Docker 데몬이 실행되지 않고 있음. 데몬을 시작하고 명령을 다시 실행해 보세요.
  • Docker 클라이언트가 다른 호스트의 Docker 데몬에 연결하려고 시도 중이고, 그 호스트에 도달할 수 없음.

Docker가 실행 중인지 확인 (Check whether Docker is running)

Docker가 실행 중인지 확인하는 운영 체제에 독립적인 방법은 docker info 명령으로 Docker에게 물어보는 것이에요.

sudo systemctl is-active docker, sudo status docker, sudo service docker status 같은 운영 체제 유틸리티를 사용하거나, Windows 유틸리티로 서비스 상태를 확인할 수도 있어요.

마지막으로 pstop 같은 명령으로 프로세스 목록에서 dockerd 프로세스를 확인할 수 있어요.

클라이언트가 연결하는 호스트 확인 (Check which host your client is connecting to)

클라이언트가 연결하는 호스트를 보려면 환경의 DOCKER_HOST 변수 값을 확인해요.

$ env | grep DOCKER_HOST

이 명령이 값을 반환하면 Docker 클라이언트는 해당 호스트에서 실행되는 Docker 데몬에 연결하도록 설정된 것이에요. 설정되지 않았다면 Docker 클라이언트는 로컬 호스트에서 실행되는 Docker 데몬에 연결하도록 설정된 거예요. 잘못 설정되어 있다면 다음 명령으로 해제해요:

$ unset DOCKER_HOST

DOCKER_HOST 변수가 잘못 설정되지 않도록 ~/.bashrc~/.profile 같은 파일에서 환경을 편집해야 할 수도 있어요.

DOCKER_HOST가 의도대로 설정되었다면 원격 호스트에서 Docker 데몬이 실행 중인지, 그리고 방화벽이나 네트워크 중단이 연결을 막고 있지 않은지 확인해요.

daemon.json과 시작 스크립트 간의 충돌 트러블슈팅 (Troubleshoot conflicts between the daemon.json and startup scripts)

daemon.json 파일을 사용하고 dockerd 명령에 수동으로 또는 시작 스크립트로 옵션을 전달하며, 이 옵션들이 충돌하면 Docker는 다음과 같은 오류로 시작에 실패해요:

unable to configure the Docker daemon with file /etc/docker/daemon.json:
the following directives are specified both as a flag and in the configuration
file: hosts: (from flag: [unix:///var/run/docker.sock], from file: [tcp://127.0.0.1:2376])

이와 유사한 오류가 보이고 데몬을 플래그로 수동 시작하는 중이라면, 충돌을 제거하기 위해 플래그나 daemon.json을 조정해야 할 수도 있어요.

Note hosts에 대한 이 특정 오류 메시지가 보이면 다음 섹션으로 진행해 해결책을 확인하세요.

운영 체제의 init 스크립트로 Docker를 시작 중이라면 그 스크립트에서 운영 체제에 특화된 방식으로 기본값을 재정의해야 할 수도 있어요.

systemd로 데몬 호스트 구성 (Configure the daemon host with systemd)

트러블슈팅하기 어려운 구성 충돌의 한 가지 대표적인 예는 기본값과 다른 데몬 주소를 지정하고 싶을 때예요. Docker는 기본적으로 소켓에서 수신 대기해요. systemd를 사용하는 Debian과 Ubuntu 시스템에서 이는 dockerd를 시작할 때 호스트 플래그 -H가 항상 사용된다는 뜻이에요. daemon.jsonhosts 엔트리를 지정하면 구성 충돌이 발생하고 Docker 데몬이 시작에 실패해요.

이 문제를 해결하려면 기본적으로 데몬을 시작할 때 사용되는 -H 인자를 제거하기 위해 다음 내용으로 새 파일 /etc/systemd/system/docker.service.d/docker.conf를 만들어요.

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd

HTTP 또는 HTTPS 프록시 구성처럼 Docker로 systemd를 구성해야 하는 다른 경우도 있어요.

Note daemon.jsonhosts 엔트리를 지정하지 않거나 Docker를 수동으로 시작할 때 -H 플래그를 지정하지 않고 이 옵션을 재정의하면 Docker는 시작에 실패해요.

Docker를 시작하려 시도하기 전에 sudo systemctl daemon-reload를 실행해요. Docker가 성공적으로 시작되면 이제 소켓 대신 daemon.jsonhosts 키에 지정된 IP 주소에서 수신 대기해요.

Important Windows용 Docker Desktop이나 Mac용 Docker Desktop에서는 daemon.jsonhosts를 설정하는 것이 지원되지 않아요.

메모리 부족 문제 (Out of memory issues)

컨테이너가 시스템에 사용 가능한 것보다 더 많은 메모리를 사용하려 하면 OOM(Out of Memory) 예외가 발생하고, 컨테이너나 Docker 데몬이 커널 OOM killer에 의해 중지될 수 있어요. 이를 방지하려면 애플리케이션이 충분한 메모리를 가진 호스트에서 실행되도록 하고 메모리 부족의 위험 이해하기를 참고하세요.

커널 호환성 (Kernel compatibility)

커널이 3.10보다 오래되었거나 커널 모듈이 없으면 Docker가 올바르게 실행될 수 없어요. 커널 호환성을 확인하려면 check-config.sh 스크립트를 다운로드해 실행할 수 있어요.

$ curl https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh > check-config.sh

$ bash ./check-config.sh

이 스크립트는 Linux에서만 동작해요.

커널 cgroup swap limit capabilities

Ubuntu 또는 Debian 호스트에서 이미지로 작업할 때 다음과 유사한 메시지가 보일 수 있어요.

WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.

이 capabilities가 필요 없다면 경고를 무시할 수 있어요.

Ubuntu 또는 Debian에서 다음 지침으로 이 capabilities를 켤 수 있어요. 메모리와 swap 어카운팅은 Docker가 실행 중이 아닐 때도 총 사용 가능 메모리의 약 1% 오버헤드와 10%의 전체 성능 저하를 발생시켜요.

  1. sudo 권한이 있는 사용자로 Ubuntu 또는 Debian 호스트에 로그인해요.
  2. /etc/default/grub 파일을 편집해요. GRUB_CMDLINE_LINUX 줄을 추가하거나 편집해 다음 두 키-값 쌍을 추가해요:
GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"

파일을 저장하고 닫아요.

  1. GRUB 부트 로더를 업데이트해요.
$ sudo update-grub

GRUB 구성 파일에 잘못된 구문이 있으면 오류가 발생해요. 이 경우 2단계와 3단계를 반복해요.

변경 사항은 시스템을 재부팅할 때 적용돼요.

네트워킹 (Networking)

IP 포워딩 문제 (IP forwarding problems)

systemd 버전 219 이상으로 systemd-network를 사용해 네트워크를 수동 구성하면 Docker 컨테이너가 네트워크에 접근하지 못할 수 있어요. systemd 버전 220부터 주어진 네트워크의 포워딩 설정(net.ipv4.conf.<interface>.forwarding)은 기본적으로 꺼져요. 이 설정은 IP 포워딩을 방지해요. 또한 컨테이너 내 net.ipv4.conf.all.forwarding 설정을 활성화하는 Docker의 동작과도 충돌해요.

RHEL, CentOS 또는 Fedora에서 이를 해결하려면 Docker 호스트의 /usr/lib/systemd/network/에 있는 <interface>.network 파일(예: /usr/lib/systemd/network/80-container-host0.network)을 편집해요.

[Network] 섹션 안에 다음 블록을 추가해요.

[Network]
...
IPForward=kernel
# OR
IPForward=true

이 구성은 컨테이너에서 예상대로 IP 포워딩을 허용해요.

DNS 해석기 문제 (DNS resolver issues)

DNS resolver found in resolv.conf and containers can't use it

Linux 데스크톱 환경에서는 종종 네트워크 매니저 프로그램이 실행 중이며, dnsmasq가 DNS 요청을 /etc/resolv.conf에 추가해 캐시해요. dnsmasq 인스턴스는 127.0.0.1이나 127.0.1.1 같은 루프백 주소에서 실행돼요. 이는 DNS 조회를 빠르게 하고 DHCP 서비스를 제공해요. 이런 구성은 Docker 컨테이너 내에서는 동작하지 않아요. Docker 컨테이너는 자체 네트워크 네임스페이스를 사용하며 127.0.0.1 같은 루프백 주소를 자기 자신으로 해석하고, 자신의 루프백 주소에서 DNS 서버를 실행하고 있을 가능성은 낮아요.

Docker가 /etc/resolv.conf에서 참조된 어떤 DNS 서버도 완전히 기능하는 DNS 서버가 아니라고 감지하면 다음 경고가 발생해요:

WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers
can't use it. Using default external servers : [8.8.8.8 8.8.4.4]

이 경고가 보이면 먼저 dnsmasq를 사용하는지 확인해요:

$ ps aux | grep dnsmasq

컨테이너가 네트워크 내부의 호스트를 해석해야 한다면 공용 네임서버는 충분하지 않아요. 두 가지 선택지가 있어요:

  • Docker가 사용할 DNS 서버 지정
  • dnsmasq 끄기

dnsmasq를 끄면 실제 DNS 네임서버의 IP 주소가 /etc/resolv.conf에 추가되고, dnsmasq의 이점은 잃게 돼요.

이 방법 중 하나만 사용하면 돼요.

Docker용 DNS 서버 지정 (Specify DNS servers for Docker)

구성 파일의 기본 위치는 /etc/docker/daemon.json이에요. --config-file 데몬 플래그로 구성 파일 위치를 바꿀 수 있어요. 다음 지침은 구성 파일 위치가 /etc/docker/daemon.json이라고 가정해요.

  1. Docker 데몬 구성을 제어하는 /etc/docker/daemon.json 파일(기본값)을 만들거나 편집해요.
$ sudo nano /etc/docker/daemon.json
  1. 값으로 하나 이상의 DNS 서버 IP 주소를 가진 dns 키를 추가해요.
{
  "dns": ["8.8.8.8", "8.8.4.4"]
}

파일에 기존 내용이 있으면 dns 줄만 추가하거나 편집하면 돼요. 내부 DNS 서버가 공용 IP 주소를 해석하지 못한다면 해석할 수 있는 DNS 서버를 최소한 하나 포함해요. 그렇게 하면 Docker Hub에 연결하고 컨테이너가 인터넷 도메인 이름을 해석할 수 있어요. 파일을 저장하고 닫아요.

  1. Docker 데몬을 재시작해요.
$ sudo service docker restart
  1. 이미지를 가져오려 시도해 Docker가 외부 IP 주소를 해석할 수 있는지 확인해요:
$ docker pull hello-world
  1. 필요한 경우 Docker 컨테이너가 내부 호스트 이름을 해석하는지 ping으로 확인해요.
$ docker run --rm -it alpine ping -c4 <my_internal_host>

PING google.com (192.168.1.2): 56 data bytes
64 bytes from 192.168.1.2: seq=0 ttl=41 time=7.597 ms
64 bytes from 192.168.1.2: seq=1 ttl=41 time=7.635 ms
64 bytes from 192.168.1.2: seq=2 ttl=41 time=7.660 ms
64 bytes from 192.168.1.2: seq=3 ttl=41 time=7.677 ms

dnsmasq 끄기 (Turn off dnsmasq)

특정 IP 주소를 사용하도록 Docker 데몬 구성을 바꾸지 않는 것을 선호한다면 다음 지침으로 NetworkManager에서 dnsmasq를 꺼요.

  1. /etc/NetworkManager/NetworkManager.conf 파일을 편집해요.
  2. dns=dnsmasq 줄의 시작 부분에 # 문자를 추가해 주석 처리해요.
# dns=dnsmasq

파일을 저장하고 닫아요.

  1. NetworkManager와 Docker를 둘 다 재시작해요. 대안으로 시스템을 재부팅할 수도 있어요.
$ sudo systemctl restart network-manager
$ sudo systemctl restart docker

RHEL, CentOS 또는 Fedora에서 dnsmasq를 끄려면:

  1. dnsmasq 서비스를 꺼요:
$ sudo systemctl stop dnsmasq
$ sudo systemctl disable dnsmasq
  1. Red Hat 문서를 사용해 DNS 서버를 수동으로 구성해요.

Docker 네트워크 사라짐 (Docker networks disappearing)

docker0 브리지나 사용자 정의 네트워크 같은 Docker 네트워크가 무작위로 사라지거나 다른 방식으로 잘못 동작하는 것처럼 보인다면, 다른 서비스가 Docker 인터페이스를 간섭하거나 수정하고 있기 때문일 수 있어요. 호스트에서 네트워킹 인터페이스를 관리하는 도구가 때로는 Docker 인터페이스를 부적절하게 수정하는 것으로 알려져 있어요.

호스트에 존재하는 네트워크 관리 도구에 따라 네트워크 매니저를 구성해 Docker 인터페이스를 비관리(un-managed)로 설정하는 지침은 다음 섹션을 참고하세요:

  • netscript가 설치되어 있다면 제거를 고려해요
  • 네트워크 매니저가 Docker 인터페이스를 비관리로 취급하도록 구성
  • Netplan을 사용한다면 사용자 지정 Netplan 구성을 적용해야 할 수도 있음

netscript 제거 (Uninstall netscript)

시스템에 netscript가 설치되어 있다면 제거해 이 문제를 해결할 수 있을 거예요. 예를 들어 Debian 기반 시스템에서:

$ sudo apt-get remove netscript-2.4

Docker 인터페이스 비관리 (Un-manage Docker interfaces)

경우에 따라 네트워크 매니저가 기본적으로 Docker 인터페이스를 관리하려 시도해요. 시스템의 네트워크 구성 설정을 편집해 Docker 네트워크를 명시적으로 비관리로 표시할 수 있어요.

NetworkManager를 사용한다면 /etc/network/interfaces 아래에서 시스템 네트워크 구성을 편집해요.

  1. 다음 내용으로 /etc/network/interfaces.d/20-docker0에 파일을 만들어요:
iface docker0 inet manual

이 예시 구성은 기본 docker0 브리지만 "비관리"하며 사용자 정의 네트워크는 비관리하지 않는다는 점에 유의하세요.

  1. 구성 변경이 적용되도록 NetworkManager를 재시작해요.
$ systemctl restart NetworkManager
  1. docker0 인터페이스가 unmanaged 상태인지 확인해요.
$ nmcli device

systemd-networkd를 네트워킹 데몬으로 사용하는 시스템에서 Docker를 실행 중이라면 /etc/systemd/network 아래에 구성 파일을 만들어 Docker 인터페이스를 비관리로 구성해요:

  1. 다음 내용으로 /etc/systemd/network/docker.network을 만들어요:
# Ensure that the Docker interfaces are un-managed

[Match]
Name=docker0 br-* veth*

[Link]
Unmanaged=yes
  1. 구성을 리로드해요.
$ sudo systemctl restart systemd-networkd
  1. Docker 데몬을 재시작해요.
$ sudo systemctl restart docker
  1. Docker 인터페이스가 unmanaged 상태인지 확인해요.
$ networkctl

Netplan이 네트워크 구성을 덮어쓰지 않게 하기 (Prevent Netplan from overriding network configuration)

cloud-init을 통해 Netplan을 사용하는 시스템에서는 netplan이 네트워크 매니저 구성을 덮어쓰지 않도록 사용자 지정 구성을 적용해야 할 수도 있어요:

  1. 네트워크 매니저 구성을 만들기 위해 Un-manage Docker interfaces의 단계를 따라요.
  2. /etc/netplan/50-cloud-init.yml 아래에 netplan 구성 파일을 만들어요. 다음 예시 구성 파일은 출발점이에요. 비관리하려는 인터페이스에 맞게 조정해요. 잘못된 구성은 네트워크 연결 문제를 일으킬 수 있어요.

/etc/netplan/50-cloud-init.yml

network:
  ethernets:
    all:
      dhcp4: true
      dhcp6: true
      match:
        # edit this filter to match whatever makes sense for your system
        name: en*
  renderer: networkd
  version: 2
  1. 새 Netplan 구성을 적용해요.
$ sudo netplan apply
  1. Docker 데몬을 재시작해요:
$ sudo systemctl restart docker
  1. Docker 인터페이스가 unmanaged 상태인지 확인해요.
$ networkctl

볼륨 (Volumes)

파일시스템을 제거할 수 없음 (Unable to remove filesystem)

Error: Unable to remove filesystem

Google cAdvisor 같은 일부 컨테이너 기반 유틸리티는 /var/lib/docker/ 같은 Docker 시스템 디렉토리를 컨테이너에 마운트해요. 예를 들어 cadvisor 문서는 cadvisor 컨테이너를 다음과 같이 실행하도록 지시해요:

$ sudo docker run \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:rw \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --detach=true \
  --name=cadvisor \
  google/cadvisor:latest

/var/lib/docker/를 바인드 마운트하면, 이것은 /var/lib/docker/를 마운트하는 컨테이너의 파일시스템으로서 다른 모든 실행 중인 컨테이너의 모든 리소스를 효과적으로 마운트해요. 이 컨테이너 중 하나를 제거하려 시도하면 다음과 같은 오류로 제거가 실패할 수 있어요:

Error: Unable to remove filesystem for
74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515:
remove /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm:
Device or resource busy

문제는 /var/lib/docker/를 바인드 마운트하는 컨테이너가 /var/lib/docker/ 내의 파일시스템 핸들에 statfs 또는 fstatfs를 사용하고 닫지 않는 경우 발생해요.

일반적으로 이렇게 /var/lib/docker를 바인드 마운트하는 것은 권장하지 않아요. 하지만 cAdvisor는 핵심 기능을 위해 이 바인드 마운트가 필요해요.

오류에서 언급된 경로를 어떤 프로세스가 점유하고 제거를 막는지 확실하지 않다면 lsof 명령으로 그 프로세스를 찾을 수 있어요. 예를 들어 위 오류의 경우:

$ sudo lsof /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm

이 문제를 해결하려면 /var/lib/docker를 바인드 마운트하는 컨테이너를 중지하고 다른 컨테이너를 다시 제거해 보세요.

더 알아보기 (Learn more)