VS Code Jupyter 커널 무응답 — ZMQ 소켓 충돌 진단과 해결

pyenv + Poetry 환경에서 두 Python 프로세스가 같은 소켓을 잡을 때

VS Code에서 Jupyter 커널이 응답하지 않는 현상의 근본 원인을 단계적으로 진단한다. 환경 자체는 정상인데도 커널이 무응답인 경우, 두 Python 프로세스가 동일한 ZMQ 소켓을 선점하는 충돌이 원인이다. 즉각 조치·근본 조치·재발 방지까지 체계적으로 정리한다.

Engineering
DevOps
저자

Kwangmin Kim

공개

2026년 04월 02일

1 개요

VS Code에서 .ipynb 파일을 열고 커널을 선택했을 때, 1 + 1 같은 단순 연산도 실행이 멈추고 커널 인디케이터가 “연결 중” 상태에서 벗어나지 않는 현상이 있다. 환경 점검(venv, ipykernel, pyzmq, kernelspec)을 모두 통과해도 증상이 지속된다면, 실행 중인 Python 프로세스가 두 개 이상 같은 ZMQ 소켓을 잡은 경우이다.

이 포스트는 해당 현상의 원인 분석 과정을 재현하고, 즉각 조치·근본 조치·재발 방지 패턴을 정리한다.


2 현상

VS Code에서 .ipynb 파일을 열고 data-standardization (Python 3.11.9) 커널을 선택했다. 첫 번째 셀은 물론이고 단순 연산도 실행이 멈추고 아무 반응이 없었다. 커널 인디케이터는 “연결 중” 상태에서 멈추거나, 실행 버튼을 눌러도 셀 번호가 바뀌지 않았다.


3 원인 분석 과정

환경이 정상인지 확인하는 표준 체크포인트를 하나씩 검토한다.

3.1 1단계 — venv 유효성 확인

가장 먼저 .venv 자체가 손상된 것이 아닌지 확인한다.

poetry env info
poetry run python --version

결과는 정상이었다. Python 3.11.9, .venv 경로도 유효(Valid: True).

3.2 2단계 — ipykernel 설치 여부 확인

커널이 응답하지 않는 흔한 원인 중 하나는 ipykernel이 venv에 없는 경우다.

.venv/Scripts/python.exe -c "import ipykernel; print(ipykernel.__version__)"

7.2.0 출력. 설치돼 있다.

3.3 3단계 — ZMQ 확인

Jupyter 커널은 ZMQ(ZeroMQ) 소켓으로 VS Code와 통신한다. pyzmq가 없으면 커널이 시작 직후 종료된다.

.venv/Scripts/python.exe -c "import zmq; print(zmq.__version__)"

27.1.0 출력. 이것도 정상이다.

3.4 4단계 — 등록된 kernelspec 확인

jupyter kernelspec list
data-standardization    C:\Users\...\jupyter\kernels\data-standardization

등록돼 있고, kernel.json을 확인하니 .venv\Scripts\python.exe를 정상적으로 가리키고 있었다.

3.5 5단계 — 실행 중인 프로세스 확인 ← 여기서 원인 발견

환경도 정상, 설치도 정상, kernelspec도 정상인데 커널이 동작하지 않는다면 현재 실행 중인 Python 프로세스를 확인해야 한다.

Get-WmiObject Win32_Process |
  Where-Object { $_.Name -like "*python*" } |
  Select-Object ProcessId, CommandLine

출력에서 이상한 점이 보였다.

PID 26484  .venv\Scripts\python.exe -m ipykernel_launcher
           --f=kernel-v323f838...json

PID 26096  .pyenv\versions\3.11.9\python.exe -m ipykernel_launcher
           --f=kernel-v323f838...json   ← 같은 connection file!

두 개의 Python 프로세스가 완전히 동일한 connection file(= 동일한 ZMQ 포트)로 ipykernel_launcher를 실행 중이었다.


4 근본 원인

4.1 ZMQ 소켓 충돌 메커니즘

ZMQ 소켓은 한 프로세스만 바인딩(bind)할 수 있다. 먼저 뜬 프로세스가 포트를 선점하면, 나중에 뜬 프로세스는 바인딩에 실패하거나 충돌이 발생한다. VS Code는 어느 커널에 연결해야 할지 모르는 상태가 되어 메시지를 보내도 응답이 오지 않는다.

VS Code
  ├── Jupyter 확장 ──→ kernel.json → .venv\python.exe  ─┐
  │                                                      ├─ 같은 ZMQ 포트 충돌
  └── Python 확장  ──→ pyenv\3.11.9\python.exe         ─┘

4.2 원인 1 — .vscode/settings.json이 없었다

워크스페이스에 인터프리터가 명시적으로 지정돼 있지 않으면 VS Code의 Python 확장Jupyter 확장이 각자 독립적으로 “어떤 Python을 쓸까”를 결정한다.

  • Jupyter 확장 → 등록된 kernelspec data-standardization을 보고 .venv\python.exe로 커널 실행
  • Python 확장 → pyenv에 설치된 3.11.9를 “Python 3.11.9” 인터프리터로 인식, VS Code UI에서 선택한 “data-standardization (Python 3.11.9)” 항목이 이 인터프리터로도 연결되어 두 번째 커널 프로세스 추가 실행

두 프로세스가 같은 connection file을 공유하며 같은 포트를 두고 경쟁한다.

4.3 원인 2 — pyenv base Python과 .venv Python의 버전이 동일하다

.venv는 pyenv 3.11.9로 만들어진 가상환경이다. VS Code 입장에서 Python 3.11.9 인터프리터가 두 개 보인다.

pyenv\versions\3.11.9\python.exe   ← Python 3.11.9 (base)
.venv\Scripts\python.exe           ← Python 3.11.9 (venv)

버전이 같으니 UI에서 구분이 어렵고, 각 확장이 자기 기준으로 하나씩 골라 실행한다.

4.4 원인 3 — 두 확장이 같은 connection file을 공유한다

VS Code Jupyter 확장은 커널 시작 시 ZMQ 포트 정보가 담긴 connection file을 생성하고 그 경로를 --f=<파일> 인자로 넘긴다. 두 프로세스에게 같은 파일을 줬기 때문에 ZMQ 소켓을 먼저 bind()한 프로세스가 포트를 선점하고 나머지는 충돌한다.

4.5 연쇄 구조

.vscode/settings.json 없음
  → 두 확장이 각자 인터프리터 결정
    → 우연히 같은 버전(3.11.9)짜리 두 Python 선택
      → 같은 connection file로 두 커널 동시 실행
        → ZMQ 포트 충돌 → 무응답

5 해결 방법

5.1 즉각 조치 — 충돌 프로세스 종료

# Process ID는 Get-WmiObject Win32_Process 출력에서 확인한 값을 사용한다
Stop-Process -Id 26096 -Force  # pyenv base Python 커널
Stop-Process -Id 26484 -Force  # venv 커널 (중복)

이후 VS Code에서 Ctrl+Shift+PJupyter: Restart Kernel.

Linux/macOS에서는 다음 명령으로 connection file이 겹치는 프로세스를 확인한다.

ps aux | grep ipykernel

5.2 근본 조치 — .vscode/settings.json으로 인터프리터 고정

.vscode/settings.json에 아래를 추가하면 VS Code가 이 워크스페이스에서 항상 .venv만 사용한다.

{
  "python.defaultInterpreterPath": "${workspaceFolder}\\.venv\\Scripts\\python.exe",
  "python.terminal.activateEnvironment": true,
  "jupyter.kernels.filter": [
    {
      "path": "${workspaceFolder}\\.venv\\Scripts\\python.exe",
      "type": "pythonEnvironment"
    }
  ]
}
설정 키 역할
python.defaultInterpreterPath Python 확장이 pyenv base Python을 선택하지 않도록 .venv로 고정
jupyter.kernels.filter Jupyter 커널 선택 목록을 .venv로 제한하여 중복 커널 항목 제거
settings.json만으로는 부족하다

python.defaultInterpreterPath는 “힌트”일 뿐이다. VS Code Python 확장의 내부 인터프리터 선택 캐시가 비어있으면 이 힌트를 무시하고 pyenv Python을 다시 끌어온다.

반드시 Python: Select Interpreter로 한 번 명시적으로 선택해야 VS Code 워크스페이스 상태에 .venv가 확정 인터프리터로 캐싱된다.

Ctrl+Shift+P → Python: Select Interpreter → .venv\Scripts\python.exe (Poetry) 선택

이 선택이 이루어지면 Python 확장 레지스트리에 .venv가 포함되고, Jupyter 확장이 .venv 기반 커널을 valid로 인식하여 pyenv Python이 더 이상 개입하지 않는다.


6 재발 방지 패턴

6.1 Python: Select Interpreter vs 노트북 커널 선택의 차이

두 개념은 역할이 다르다. 순서가 있다 — Python: Select Interpreter를 먼저 해야 Jupyter 커널 선택이 제대로 작동한다.

Python: Select Interpreter 노트북 커널 선택
위치 Command Palette 노트북 우측 상단
역할 린팅, IntelliSense, 터미널, 디버깅에 쓸 Python 결정 노트북 셀을 실행할 커널 결정
영향 범위 워크스페이스 전체 Python 기능 해당 노트북 파일만
Jupyter와의 관계 Jupyter 확장이 이 선택을 참조해 커널 valid 여부 판단 실제 실행 커널

python.defaultInterpreterPath(settings.json) → 힌트, 재시작 시 무시될 수 있다
Python: Select Interpreter(UI 선택) → 캐싱, 이후 시작에도 유지된다

프로젝트를 처음 열거나 Reload Window 후에는 항상 Python: Select Interpreter.venv를 한 번 선택해두는 것이 두 커널 모두 안정적으로 쓰는 방법이다.

6.2 다중 프로젝트 설정

.vscode/settings.json해당 프로젝트 폴더에만 적용된다. ${workspaceFolder}가 각 프로젝트 루트를 가리키므로 다른 프로젝트에는 영향을 주지 않는다.

project-a/
  .vscode/settings.json  ← project-a에만 적용

project-b/
  .vscode/settings.json  ← 따로 만들어야 함

pyenv + poetry 조합으로 프로젝트가 여러 개라면 각 프로젝트에 최소한 아래를 추가해두는 것을 권장한다.

{
  "python.defaultInterpreterPath": "${workspaceFolder}\\.venv\\Scripts\\python.exe",
  "python.terminal.activateEnvironment": true
}

conda 기반 프로젝트는 ${workspaceFolder}가 아닌 conda env의 절대 경로를 직접 지정한다.

{
  "python.defaultInterpreterPath": "C:\\Users\\<user>\\AppData\\Local\\miniconda3\\envs\\<env-name>\\python.exe"
}

7 Python Environment vs Jupyter Kernel (kernelspec) 비교

VS Code에서 노트북 커널을 선택할 때 두 종류가 나타난다. 이 차이를 이해하면 위의 충돌 원인이 명확해진다.

7.1 Python Environment

VS Code Python 확장이 시스템에서 Python 인터프리터를 자동 탐지해서 보여주는 것이다.

# 등록 불필요 — VS Code가 알아서 발견
# 이름: 폴더명 기반 (.venv (Python 3.11.9))

7.2 Jupyter Kernel (kernelspec)

ipykernel install직접 등록한 커널이다.

.venv\Scripts\python.exe -m ipykernel install ^
  --user ^
  --name data-standardization ^
  --display-name "data-standardization"

등록 위치: %APPDATA%\jupyter\kernels\<name>\kernel.json

7.3 비교

Python Environment Jupyter Kernel
발견 방식 VS Code 자동 탐지 ipykernel install로 등록
표시 이름 폴더명 (.venv) 직접 지정 (data-standardization)
등록 위치 VS Code 내부 %APPDATA%\jupyter\kernels\
호환성 VS Code 전용 모든 Jupyter 클라이언트
실행 옵션 제어 불가 kernel.json으로 가능

둘 다 같은 .venv\Scripts\python.exe를 실행하므로 동작은 동일하다. 그러나 두 경로가 별개로 존재하기 때문에 설정 없이 두 확장이 각자 하나씩 실행하면 충돌이 발생한다.

7.4 커널 선택 방법

노트북 우측 상단 커널 버튼 클릭 → Select Another Kernel...Jupyter Kernel...data-standardization 선택.

Python Environment 경로로 들어가면 .venv 이름으로 보이고, Jupyter Kernel 경로로 들어가면 등록한 이름(data-standardization)으로 보인다.


8 진단 체크리스트

체크 포인트 확인 명령 기대 결과
.venv 유효성 poetry env info Valid: True
ipykernel 설치 .venv/Scripts/python.exe -c "import ipykernel" 버전 출력
pyzmq 설치 .venv/Scripts/python.exe -c "import zmq" 버전 출력
kernelspec 등록 jupyter kernelspec list 올바른 .venv 경로
실행 중 프로세스 Get-WmiObject Win32_Process \| Where { $_.Name -like "*python*" } connection file 중복 없음
.vscode/settings.json 파일 존재 여부 확인 python.defaultInterpreterPath 설정됨
Python: Select Interpreter VS Code Command Palette .venv 선택 완료

환경이 전부 정상인데 커널이 응답하지 않는다면, 설치 여부보다 지금 실행 중인 프로세스를 먼저 본다. connection file이 겹치는 프로세스가 있는지 확인하는 것이 진단의 핵심이다.


9 관련 주제

선행 지식

관련 문제

관련 개념

  • ZMQ(ZeroMQ) — 메시지 패싱 라이브러리. Jupyter 커널-클라이언트 통신 기반
  • Python: Jupyter 통신 프로토콜 — 커널 lifecycle 심층 (미작성)

Subscribe

Enjoy this blog? Get notified of new posts by email: