[Kubernetes] GPU 노드 CrashLoop 해결: Containerd 소켓 파일 이슈 분석

Zabbix 모니터링 시스템에서 GPU 노드의 nvidia-container-toolkit 파드에 경고 알람이 발생했다. 상태는 CrashLoopBackOff. 단순한 파드 설정 오류로 보였으나, 로그 분석 결과 Kubernetes의 컨테이너 런타임인 containerd의 소켓 파일 형상(Type) 변질이 근본 원인임이 밝혀졌다.

본 포스팅에서는 해당 이슈의 트러블슈팅 과정과 더불어, Kubernetes 및 GPU 환경에서 containerd가 수행하는 역할과 장애 발생 시의 영향도를 상세히 기술한다.


1. 배경 지식: Containerd의 역할과 중요성

트러블슈팅에 앞서, containerd가 Kubernetes 클러스터, 특히 GPU 노드에서 어떤 역할을 하는지 이해가 필요하다.

1.1 Kubernetes 아키텍처 내 역할 (CRI)

Kubernetes의 에이전트인 Kubelet은 컨테이너를 직접 제어하지 않는다. 대신 **CRI(Container Runtime Interface)**라는 표준 인터페이스를 통해 런타임에 명령을 내린다.

  • Containerd: Docker에서 분리된 경량화된 표준 컨테이너 런타임. 이미지 풀링, 네트워크 네임스페이스 생성, 컨테이너 라이프사이클 관리를 담당한다.
  • 통신 방식: Kubelet은 unix:///run/containerd/containerd.sock 소켓을 통해 gRPC 프로토콜로 Containerd와 통신한다. 이 소켓이 막히면 해당 노드는 사실상 뇌사 상태가 된다.

1.2 GPU 워크로드와의 관계 (NVIDIA Runtime)

GPU 노드에서 containerd는 단순 실행기를 넘어 GPU 리소스 할당의 핵심 통로 역할을 한다.

  1. NVIDIA Container Toolkit: 파드 생성 요청이 오면 containerd 설정을 수정하여 NVIDIA 런타임 훅(Hook)을 주입한다.
  2. Runtime Hook: 컨테이너가 시작될 때(prestart), containerd는 훅을 호출하여 GPU 드라이버 라이브러리(libnvidia-ml.so)와 디바이스 파일(/dev/nvidia0)을 컨테이너 내부에 마운트한다.

즉, Containerd가 비정상일 경우:

  • Kubelet이 파드를 생성할 수 없다.
  • GPU 드라이버가 컨테이너에 주입되지 않아 nvidia-smi 호출이 실패한다.
  • CNI(네트워크) 플러그인이 설정되지 않아 노드 전체 네트워크가 마비된다.

2. 장애 현상

💡 독자를 위한 트러블슈팅 가이드

본 포스팅은 Containerd 관련 이슈가 발생했을 때의 해결 과정을 다루었지만,
무작정 명령어를 복사/붙여넣기 하지 말고, 반드시 본인의 시스템 로그를 먼저 확인한 후
자신의 운영환경 상황에 맞게 응용하길 바란다.

1단계: 로그 확인 (진단) 먼저 시스템 로그를 통해 Containerd 상황을 확인한다

journalctl -xeu containerd --no-pager

2단계: 로그 결과에 따른 행동 요령 예시

  • CASE A: “is a directory” 에러가 보인다면?
    • 진단: 소켓 파일이 디렉토리로 변질된 상태. (본문 케이스)
    • 해결: 본문의 [소켓 디렉토리 삭제] 과정만 수행.
    • 주의: 멀쩡한 config.toml은 수정하지 말 것.
  • CASE B: “timeout” 에러만 보인다면?
    • 진단: 데몬이 단순히 응답을 못 하는 상태(Hang).
    • 해결: 설정이나 파일을 건드리지 말고, systemctl restart containerd 재시작 부터 시도
  • CASE C: “parse error”, “invalid character” 에러가 보인다면?
    • 진단: 설정 파일(config.toml) 문법이 깨진 상태.
    • 해결: 이때는 config.toml을 백업 후 초기화 및 상황에 따라 수동 수정.

핵심: 로그가 가리키는 원인(파일 형상 vs 타임아웃 vs 설정 오류 등)에 따라 처방은 완전히 달라진다는 걸 명심하자

2.1 Zabbix 알람 및 파드 상태

  • Trigger: K8s Pod Crash Looping
  • Target: gpu-operator/nvidia-container-toolkit-daemonset
  • POD Status:
NAMEREADYSTATUSRESTARTSAGE
nvidia-container-toolkit-daemonset-84xtt 0/1CrashLoopBackOff 681 2d

2.2 파드 로그 분석

파드 내부 로그 확인 시, 호스트의 containerd 소켓에 연결을 시도했으나 실패함.

level=warning msg="Error signaling containerd ... dial unix /run/containerd/containerd.sock: connect: connection refused"

일반적인 connection refused는 프로세스가 죽어있을 때 발생한다. 그러나 systemctl status containerd 확인 시 프로세스는 Active 상태였다.


3. 심층 분석 및 원인 파악

3.1 노드 시스템 로그 확인 (Systemd/Journalctl)

프로세스는 떠 있는데 연결이 거부되는 현상을 파악하기 위해 해당 노드의 시스템 로그를 확인

# journalctl -xeu containerd

3.2 원인 분석: TTRPC Timeout 및 SIGHUP Storm

  • 현상: containerd 프로세스는 살아있으나 내부 통신 프로토콜인 ttrpc가 타임아웃 되며 응답 불가(Hang) 상태에 빠졌다.
  • 원인: nvidia-container-toolkit 파드가 680회 이상 재시작되는 과정에서 문제가 발생했다. 이 파드는 시작될 때마다 containerd 설정을 변경하고 적용하기 위해 데몬에 SIGHUP(설정 리로드) 신호를 보낸다.
  • 결론: 반복적인 파드 크래시로 인해 과도한 SIGHUP 시그널이 발생했고, 이로 인해 containerd 데몬이 부하를 견디지 못하고 **교착 상태(Deadlocked)**에 빠진 것으로 추정.

3.3 1차 조치: 서비스 재시작 시도

데몬이 먹통이므로 프로세스 재시작을 시도했다.

systemctl restart containerd

그러나 예상과 달리 서비스가 올라오지 않고 Exit Code 1로 실패했다.

4. 트러블슈팅 1단계: Containerd 설정(config.toml) 복구

노드에 접속하여 systemctl status containerd를 확인했으나 서비스가 제대로 구동되지 않고 있었다. nvidia-container-toolkit 파드가 CrashLoopBackOff로 반복 재시작되며, 호스트의 /etc/containerd/config.toml에 런타임 설정을 반복 적용하는 과정에서 설정이 중복되거나 불완전하게 반영되어 containerd가 정상 기동하지 못하는 상태가 되었을 가능성이 있다.

4.1 설정 파일 초기화 및 재설정

기존 설정 파일을 백업하고 기본값으로 초기화한 뒤, Kubernetes 구동에 필수적인 systemdCgroup 옵션을 활성화했다.

# systemctl stop containerd

// 반드시 백업할것 문제 생길시 복원
# mv /etc/containerd/config.toml /etc/containerd/config.toml.bak

# containerd config default > /etc/containerd/config.toml

// 반드시 true로 변경
# sed -i 's/systemdCgroup = false/systemdCgroup = true/' /etc/containerd/config.toml

4.2 서비스 시작 (실패)

설정을 바로잡은 후 재시작을 시도했으나, 여전히 서비스가 올라오지 않았다.

# systemctl start containerd
Job for containerd.service failed because the control process exited with error code.
See "systemctl status containerd.service" and "journalctl -xeu containerd.service" fo

5. 트러블슈팅 2단계: 소켓 파일 변질

재시작 실패 원인을 파악하기 위해 다시 로그를 확인하던 중, 더 근본적인 파일 시스템 문제를 발견했다.

5.1 재시작 실패 로그 분석

# journalctl -xeu containerd
...
level=info msg=serving... address=/run/containerd/containerd.sock.ttrpc
containerd: failed to get listener for main endpoint: is a directory
systemd[1]: containerd.service: Main process exited, code=exited, status=1/FAILURE

5.2 원인 분석: “is a directory”

로그의 핵심은 failed to get listener ... : is a directory이다.

  • 정상 상황: /run/containerd/containerd.sock 경로는 통신을 위한 **소켓 파일(Socket File)**이어야 한다.
  • 장애 상황: 확인 결과 해당 경로에 **디렉토리(Directory)**가 생성되어 있었다.

발생 메커니즘:

  1. containerd 데몬이 먹통이거나 재시작되는 도중 소켓 파일이 잠시 사라짐.
  2. 이때 nvidia-container-toolkit 파드나 다른 파드가 해당 경로(hostPath)를 볼륨으로 마운트 시도.
  3. Kubernetes/Docker 동작 특성상, 호스트에 해당 파일이 없으면 자동으로 빈 디렉토리를 생성해버림.
  4. 이후 containerd가 다시 뜨려 할 때, 소켓을 만들어야 할 자리에 이미 디렉토리가 버티고 있어 실행 실패.

6. 최종 해결 과정

문제의 핵심은 **”잘못 생성된 디렉토리를 제거하고 데몬을 정상화”**하는 것이다.

6.1 잘못된 형상 삭제 및 데몬 복구

반드시 마스터 노드가 아닌 문제가 있는 해당 노드에서 실행하도록 한다

// 1. 파일 타입 확인 ('d'로 시작하는 디렉토리 확인)

# ls -ld /run/containerd/containerd.sock
drwxr-xr-x 2 root root 40 ... /run/containerd/containerd.sock

// 2. containerd stop 및 디렉토리 삭제

# systemctl stop containerd
# rm -rf /run/containerd/containerd.sock

// 3. 서비스 시작

# systemctl start containerd

# systemctl restart kubulet

// 4. 정상 소켓 생성 확인 ('s'로 시작)

# ls -ld /run/containerd/containerd.sock
srw-rw---- 1 root root 0 ... /run/containerd/containerd.sock

6.2 파드 상태 정상화

노드 런타임이 정상화되었으므로, 마스터 노드에서 문제가 된 파드를 삭제하여 깨끗한 상태에서 재생성되도록 유도했다.

해당 네임스페이스 및 pod 이름 등 환경에 맞게 명령어 변경 (마스터 노드에서 실행)

# kubectl delete pod nvidia-container-toolkit-daemonset-84xtt -n gpu-operator

7. 장애 영향도 분석 (Impact Analysis)

이번 장애는 단순한 파드 에러가 아닌, 노드 런타임(containerd)의 기능 마비였다. 이에 따른 연쇄적인 영향도는 다음과 같다.

  1. 노드 제어 상실: Kubelet이 런타임과 통신할 수 없게 되어 노드 상태 보고가 중단됨 (NotReady 가능성).
  2. GPU 기능 상실: NVIDIA Toolkit이 런타임 훅을 주입하지 못해, 물리 GPU가 있어도 컨테이너가 이를 인식하지 못함 (nvidia-smi 실패).
  3. 좀비 프로세스 및 네트워크 고립: 데몬이 비정상 종료되면서 자식 프로세스(shim)들이 고아(Zombie) 상태로 남아 리소스를 점유하거나, CNI 플러그인 설정이 꼬여 파드 네트워크 통신(kube-proxy, calico)까지 마비시킴.

8. 위의 트러블슈팅 단계에서 containerd 재기동 실패 시 대응 (Left-over processes 대응)

journalctl -xeu containerd.service 로그에 Found left-over process (containerd-shim) 메시지가 반복적으로 출력되는 경우, 이는 이전 containerd가 비정상 종료되며 자식 프로세스(containerd-shim)들이 정리되지 않고 남아 있는 상태를 의미한다.
이 상태에서는 systemd가 containerd 재기동을 시도하더라도, 런타임 환경이 이미 꼬여 있어 정상적으로 올라오지 못하는 경우가 많다.

이때 가장 먼저 해야 할 작업은 잔존한 containerd 관련 프로세스를 명시적으로 정리하는 것이다.

Ubuntu 최소 설치 환경에서는 killall 명령어가 없을 수 있으므로, 아래 방식으로 대체한다.

// containerd 및 shim 프로세스 강제 종료
# pkill -9 -f containerd

pkill이 없는 환경이라면, 다음과 같이 psxargs를 사용해 직접 종료할 수 있다.

# ps -ef | grep containerd | grep -v grep | awk '{print $2}' | xargs -r kill -9

9. 결론

Kubernetes 환경에서 CrashLoopBackOff가 발생했을 때, 단순히 파드 로그만 볼 것이 아니라 **인프라 레벨(Systemd, Journalctl)**의 로그 확인이 필수적이다. 특히 hostPath를 사용하는 시스템 파드들의 경우, 런타임 재시작 시점에 파일이 디렉토리로 변질되는 현상이 발생할 수 있음을 인지하고 있어야 신속한 트러블슈팅이 가능하다.

🛠 마지막 수정일: 2025.12.18

ⓒ 2025 엉뚱한 녀석의 블로그 [quirky guy's Blog]. 본문 및 이미지를 무단 복제·배포할 수 없습니다. 공유 시 반드시 원문 링크를 명시해 주세요.
ⓒ 2025 엉뚱한 녀석의 블로그 [quirky guy's Blog]. All rights reserved. Unauthorized copying or redistribution of the text and images is prohibited. When sharing, please include the original source link.

💡 도움이 필요하신가요?
Zabbix, Kubernetes, 그리고 다양한 오픈소스 인프라 환경에 대한 구축, 운영, 최적화, 장애 분석, 광고 및 협업 제안이 필요하다면 언제든 편하게 연락 주세요.

📧 Contact: jikimy75@gmail.com
💼 Service: 구축 대행 | 성능 튜닝 | 장애 분석 컨설팅

📖 E-BooK [PDF] 전자책 (Gumroad): Zabbix 엔터프라이즈 최적화 핸드북
블로그에서 다룬 Zabbix 관련 글들을 기반으로 실무 중심의 지침서로 재구성했습니다. 운영 환경에서 바로 적용할 수 있는 최적화·트러블슈팅 노하우까지 모두 포함되어 있습니다.


💡 Need Professional Support?
If you need deployment, optimization, or troubleshooting support for Zabbix, Kubernetes, or any other open-source infrastructure in your production environment, or if you are interested in sponsorships, ads, or technical collaboration, feel free to contact me anytime.

📧 Email: jikimy75@gmail.com
💼 Services: Deployment Support | Performance Tuning | Incident Analysis Consulting

📖 PDF eBook (Gumroad): Zabbix Enterprise Optimization Handbook
A single, production-ready PDF that compiles my in-depth Zabbix and Kubernetes monitoring guides.