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 리소스 할당의 핵심 통로 역할을 한다.
- NVIDIA Container Toolkit: 파드 생성 요청이 오면
containerd설정을 수정하여 NVIDIA 런타임 훅(Hook)을 주입한다. - 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:
| NAME | READY | STATUS | RESTARTS | AGE |
|---|
| nvidia-container-toolkit-daemonset-84xtt | 0/1 | CrashLoopBackOff | 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)**가 생성되어 있었다.
발생 메커니즘:
containerd데몬이 먹통이거나 재시작되는 도중 소켓 파일이 잠시 사라짐.- 이때
nvidia-container-toolkit파드나 다른 파드가 해당 경로(hostPath)를 볼륨으로 마운트 시도. - Kubernetes/Docker 동작 특성상, 호스트에 해당 파일이 없으면 자동으로 빈 디렉토리를 생성해버림.
- 이후
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)의 기능 마비였다. 이에 따른 연쇄적인 영향도는 다음과 같다.
- 노드 제어 상실: Kubelet이 런타임과 통신할 수 없게 되어 노드 상태 보고가 중단됨 (
NotReady가능성). - GPU 기능 상실: NVIDIA Toolkit이 런타임 훅을 주입하지 못해, 물리 GPU가 있어도 컨테이너가 이를 인식하지 못함 (
nvidia-smi실패). - 좀비 프로세스 및 네트워크 고립: 데몬이 비정상 종료되면서 자식 프로세스(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이 없는 환경이라면, 다음과 같이 ps와 xargs를 사용해 직접 종료할 수 있다.
# 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]. 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.
답글 남기기
댓글을 달기 위해서는 로그인해야합니다.