Tag: Docker

  • Setting Up an OpenCV CUDA Dev Environment with Docker and Debugging via VSCode

    Docker OpenCV CUDA Python VSCode RTX 3060

    To use CUDA acceleration with OpenCV, pip install opencv-python simply won’t cut it. CUDA support requires building OpenCV from source. In this post, I’ll show you how to set up a clean, isolated development environment using Docker — without polluting your host system — and debug your code directly inside the container using VSCode.


    Why Can’t We Just Use pip install?

    The opencv-python package on PyPI is a generic build with no CUDA support. CUDA features must be enabled at compile time by linking against the CUDA libraries.

    MethodCUDA SupportNotes
    pip install opencv-pythonGeneric build, CPU only
    Build from source (host)Pollutes host environment
    Docker + build from sourceIsolated, clean — recommended

    1 Prerequisites

    Make sure the following are installed on your host machine:

    • NVIDIA Driver (verify with nvidia-smi)
    • Docker
    • nvidia-container-toolkit
    # Install nvidia-container-toolkit
    sudo apt install nvidia-container-toolkit
    sudo systemctl restart docker
    
    # Verify GPU is accessible inside Docker
    docker run --gpus all --rm nvidia/cuda:12.8.0-base-ubuntu22.04 nvidia-smi
    💡 Note
    You do NOT need to install the CUDA Toolkit (nvcc) on your host. It’s already included inside the Docker image.

    2 Run the NVIDIA Official CUDA Image

    docker run --gpus all -it \
      --name opencv-cuda \
      -v /your/project/path:/workspace \
      nvidia/cuda:12.8.0-cudnn-devel-ubuntu22.04 \
      bash

    Verify GPU and nvcc inside the container:

    nvcc --version
    nvidia-smi
    ✅ Expected Output
    nvcc: NVIDIA (R) Cuda compiler driver
    Cuda compilation tools, release 12.8
    
    NVIDIA GeForce RTX 3060  |  CUDA Version: 12.8

    3 Install Dependencies

    If apt is slow, switch to a faster mirror first:

    # Switch to a faster mirror (optional)
    sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list
    sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list
    
    apt update && apt install -y \
      python3 python3-pip python3-dev \
      cmake git g++ \
      libgtk2.0-dev pkg-config \
      libavcodec-dev libavformat-dev libswscale-dev
    
    pip3 install numpy

    4 Build OpenCV from Source

    cd /workspace
    
    git clone https://github.com/opencv/opencv.git
    git clone https://github.com/opencv/opencv_contrib.git
    
    cd opencv && mkdir build && cd build
    
    cmake .. \
      -D WITH_CUDA=ON \
      -D OPENCV_CUDA_ARCH_BIN="8.6" \
      -D CUDA_ARCH_BIN="8.6" \
      -D CUDA_ARCH_PTX="" \
      -D OPENCV_EXTRA_MODULES_PATH=/workspace/opencv_contrib/modules \
      -D WITH_CUBLAS=ON \
      -D BUILD_opencv_python3=ON \
      -D CMAKE_BUILD_TYPE=Release
    💡 CUDA_ARCH_BIN by GPU
    RTX 3060 → 8.6  |  RTX 3090 → 8.6  |  RTX 4090 → 8.9  |  RTX 5070 Ti → 8.9 ~ 9.0

    After cmake completes, verify these lines in the output:

    --   NVIDIA CUDA:   YES (ver 12.8, CUFFT CUBLAS)  ✅
    --     NVIDIA GPU arch:  86                        ✅
    --   cuDNN:          YES (ver 9.7.0)               ✅
    --   Python 3:
    --     Libraries:    /usr/lib/.../libpython3.10.so ✅
    --     numpy:        .../numpy/_core/include       ✅

    Build and install (takes 30min ~ 1hr):

    make -j$(nproc)
    make install

    5 Verify the Build

    python3 -c "
    import cv2
    print('OpenCV version:', cv2.__version__)
    print('CUDA devices:', cv2.cuda.getCudaEnabledDeviceCount())
    "
    ✅ Success
    OpenCV version: 4.14.0-pre
    CUDA devices: 1

    6 Save the Container as an Image

    If you exit the container, everything will be lost (due to –rm). Commit it as a reusable image from a new host terminal:

    # On the host
    docker ps  # Get container ID
    docker commit <container_id> opencv-cuda:latest
    
    # Verify
    docker images | grep opencv-cuda
    ⚠️ Image Size
    The resulting image will be around 13GB. Using a multi-stage Dockerfile build can reduce this to 4–5GB.

    7 Debug Inside the Container with VSCode

    Install these two VSCode extensions:

    • Remote – SSH (already installed)
    • Dev Containers (install additionally)

    Start the container:

    docker run --gpus all -it \
      --name opencv-cuda \
      -v /your/project/path:/workspace \
      opencv-cuda:latest bash

    In VSCode: click the blue button at the bottom-left → Attach to Running Container → select opencv-cuda

    Create .vscode/launch.json:

    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": "Python Debugger: Current File",
          "type": "debugpy",
          "request": "launch",
          "program": "${file}",
          "console": "integratedTerminal"
        }
      ]
    }

    8 CPU vs GPU Speed Comparison

    First Attempt — Single GaussianBlur

    import cv2
    import numpy as np
    import time
    
    img = np.random.randint(0, 255, (4096, 4096, 3), dtype=np.uint8)
    
    # CPU
    start = time.time()
    result_cpu = cv2.GaussianBlur(img, (21, 21), 0)
    cpu_time = time.time() - start
    print(f"CPU time: {cpu_time:.4f}s")
    
    # GPU
    gpu_img = cv2.cuda_GpuMat()
    gpu_img.upload(img)
    start = time.time()
    gpu_filter = cv2.cuda.createGaussianFilter(cv2.CV_8UC3, cv2.CV_8UC3, (21, 21), 0)
    result_gpu = gpu_filter.apply(gpu_img)
    result_gpu.download()
    gpu_time = time.time() - start
    print(f"GPU time: {gpu_time:.4f}s")
    Result
    CPU time: 0.0437s
    GPU time: 0.0982s
    GPU is 0.4x slower 😅

    The GPU was slower because the upload/download overhead exceeded the actual computation time for a single operation.

    Second Attempt — Chained Operations (with Error)

    laplacian_filter = cv2.cuda.createLaplacianFilter(
        cv2.CV_8UC3, cv2.CV_8UC3  # ← 3-channel attempt
    )
    ❌ Error
    OpenCV Error: (-215:Assertion failed) scn == 1 || scn == 4
    in function 'LinearFilter'

    Cause: The CUDA Laplacian filter only supports 1-channel (grayscale) or 4-channel images. 3-channel BGR images are not supported.

    Fixed Code — Grayscale + 5 Chained Operations

    import cv2
    import numpy as np
    import time
    
    img = np.random.randint(0, 255, (4096, 4096, 3), dtype=np.uint8)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # Convert to 1 channel
    
    # CPU
    start = time.time()
    result = img_gray.copy()
    for _ in range(5):
        result = cv2.GaussianBlur(result, (21, 21), 0)
        result = cv2.Laplacian(result, cv2.CV_8U)
        result = cv2.GaussianBlur(result, (21, 21), 0)
    cpu_time = time.time() - start
    print(f"CPU time: {cpu_time:.4f}s")
    
    # GPU — upload once, compute 15 times, download once
    gpu_img = cv2.cuda_GpuMat()
    gpu_img.upload(img_gray)
    
    gaussian_filter = cv2.cuda.createGaussianFilter(cv2.CV_8UC1, cv2.CV_8UC1, (21, 21), 0)
    laplacian_filter = cv2.cuda.createLaplacianFilter(cv2.CV_8UC1, cv2.CV_8UC1)
    
    start = time.time()
    gpu_result = gpu_img
    for _ in range(5):
        gpu_result = gaussian_filter.apply(gpu_result)
        gpu_result = laplacian_filter.apply(gpu_result)
        gpu_result = gaussian_filter.apply(gpu_result)
    result = gpu_result.download()
    gpu_time = time.time() - start
    print(f"GPU time: {gpu_time:.4f}s")
    print(f"Speedup: {cpu_time/gpu_time:.1f}x")
    ✅ Final Result
    CPU time: 0.1283s
    GPU time: 0.0553s
    Speedup: 2.3x 🎉

    Key Takeaways

    PointDetail
    pip install opencvNo CUDA — must build from source
    Why DockerIsolated environment, host stays clean
    GPU slower than CPUupload/download overhead > computation time
    GPU faster than CPUMore chained operations = better GPU efficiency
    Laplacian errorCUDA only supports CV_8UC1 (grayscale), not BGR
    VSCode debuggingDev Containers lets you F5-debug inside a container
  • OpenCV CUDA 개발환경 Docker로 구축하고 VSCode에서 디버깅까지

    Docker OpenCV CUDA Python VSCode RTX 3060

    OpenCV에서 CUDA 가속을 쓰려면 pip install opencv-python으로는 안 됩니다. CUDA 지원은 소스에서 직접 빌드해야 활성화됩니다. 하지만 호스트 시스템을 더럽히지 않고, Docker를 이용해 깔끔하게 환경을 구축하고 VSCode에서 디버깅까지 하는 방법을 정리했습니다.


    왜 pip install로는 안 되나?

    PyPI에 올라온 opencv-python은 범용 빌드라 CUDA가 빠져 있습니다. OpenCV는 빌드 시점에 CUDA 라이브러리를 링크해서 컴파일해야 CUDA 기능이 활성화됩니다.

    방법CUDA 지원비고
    pip install opencv-python범용 빌드, CPU만
    소스 직접 빌드호스트 환경 오염
    Docker + 소스 빌드격리, 깔끔, 추천

    1 환경 준비

    호스트에 다음이 설치되어 있어야 합니다.

    • NVIDIA 드라이버 (nvidia-smi로 확인)
    • Docker
    • nvidia-container-toolkit
    # nvidia-container-toolkit 설치
    sudo apt install nvidia-container-toolkit
    sudo systemctl restart docker
    
    # GPU가 Docker에서 보이는지 확인
    docker run --gpus all --rm nvidia/cuda:12.8.0-base-ubuntu22.04 nvidia-smi
    💡 참고
    CUDA Toolkit(nvcc)은 호스트에 설치하지 않아도 됩니다. Docker 이미지 안에 포함되어 있습니다.

    2 NVIDIA 공식 CUDA 이미지로 컨테이너 실행

    docker run --gpus all -it \
      --name opencv-cuda \
      -v /your/project/path:/workspace \
      nvidia/cuda:12.8.0-cudnn-devel-ubuntu22.04 \
      bash

    컨테이너 안에서 GPU 및 nvcc 확인:

    nvcc --version
    nvidia-smi
    ✅ 정상 출력
    nvcc: NVIDIA (R) Cuda compiler driver
    Cuda compilation tools, release 12.8
    
    NVIDIA GeForce RTX 3060  |  CUDA Version: 12.8

    3 의존성 설치

    apt 속도가 느리다면 카카오 미러로 변경합니다.

    # 카카오 미러로 변경 (한국 사용자 권장)
    sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list
    sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list
    
    apt update && apt install -y \
      python3 python3-pip python3-dev \
      cmake git g++ \
      libgtk2.0-dev pkg-config \
      libavcodec-dev libavformat-dev libswscale-dev
    
    pip3 install numpy

    4 OpenCV 소스 빌드

    cd /workspace
    
    git clone https://github.com/opencv/opencv.git
    git clone https://github.com/opencv/opencv_contrib.git
    
    cd opencv && mkdir build && cd build
    
    cmake .. \
      -D WITH_CUDA=ON \
      -D OPENCV_CUDA_ARCH_BIN="8.6" \
      -D CUDA_ARCH_BIN="8.6" \
      -D CUDA_ARCH_PTX="" \
      -D OPENCV_EXTRA_MODULES_PATH=/workspace/opencv_contrib/modules \
      -D WITH_CUBLAS=ON \
      -D BUILD_opencv_python3=ON \
      -D CMAKE_BUILD_TYPE=Release
    💡 CUDA_ARCH_BIN GPU별 값
    RTX 3060 → 8.6  |  RTX 3090 → 8.6  |  RTX 4090 → 8.9  |  RTX 5070 Ti → 8.9 ~ 9.0

    cmake 완료 후 반드시 아래 항목 확인:

    --   NVIDIA CUDA:   YES (ver 12.8, CUFFT CUBLAS)  ✅
    --     NVIDIA GPU arch:  86                        ✅
    --   cuDNN:          YES (ver 9.7.0)               ✅
    --   Python 3:
    --     Libraries:    /usr/lib/.../libpython3.10.so ✅
    --     numpy:        .../numpy/_core/include       ✅

    빌드 및 설치 (30분~1시간 소요):

    make -j$(nproc)
    make install

    5 빌드 확인

    python3 -c "
    import cv2
    print('OpenCV version:', cv2.__version__)
    print('CUDA devices:', cv2.cuda.getCudaEnabledDeviceCount())
    "
    ✅ 성공 출력
    OpenCV version: 4.14.0-pre
    CUDA devices: 1

    6 이미지 저장

    컨테이너를 나가면 빌드한 내용이 사라집니다. 호스트의 새 터미널에서 커밋해 이미지로 저장합니다.

    # 호스트에서
    docker ps  # 컨테이너 ID 확인
    docker commit <container_id> opencv-cuda:latest
    
    # 확인
    docker images | grep opencv-cuda
    ⚠️ 이미지 크기
    빌드 결과물이 모두 포함되어 약 13GB 정도 됩니다. 멀티스테이지 빌드를 사용하면 4~5GB로 줄일 수 있습니다.

    7 VSCode Dev Containers로 디버깅 연결

    VSCode 확장 2개를 설치합니다.

    • Remote – SSH (기존)
    • Dev Containers (추가 설치)

    컨테이너를 실행한 후:

    docker run --gpus all -it \
      --name opencv-cuda \
      -v /your/project/path:/workspace \
      opencv-cuda:latest bash

    VSCode 왼쪽 하단 파란 버튼 → Attach to Running Containeropencv-cuda 선택

    .vscode/launch.json 생성:

    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": "Python Debugger: Current File",
          "type": "debugpy",
          "request": "launch",
          "program": "${file}",
          "console": "integratedTerminal"
        }
      ]
    }

    8 CPU vs GPU 속도 비교 테스트

    첫 번째 시도 – 단순 GaussianBlur 1회

    import cv2
    import numpy as np
    import time
    
    img = np.random.randint(0, 255, (4096, 4096, 3), dtype=np.uint8)
    
    # CPU
    start = time.time()
    result_cpu = cv2.GaussianBlur(img, (21, 21), 0)
    cpu_time = time.time() - start
    print(f"CPU 시간: {cpu_time:.4f}초")
    
    # GPU
    gpu_img = cv2.cuda_GpuMat()
    gpu_img.upload(img)
    start = time.time()
    gpu_filter = cv2.cuda.createGaussianFilter(cv2.CV_8UC3, cv2.CV_8UC3, (21, 21), 0)
    result_gpu = gpu_filter.apply(gpu_img)
    result_gpu.download()
    gpu_time = time.time() - start
    print(f"GPU 시간: {gpu_time:.4f}초")
    결과
    CPU 시간: 0.0437초
    GPU 시간: 0.0982초
    속도 차이: 0.4배 (GPU가 더 느림 😅)

    GPU가 더 느린 이유는 upload/download 전송 오버헤드가 연산 시간보다 크기 때문입니다.

    두 번째 시도 – 연속 연산 (Laplacian 에러 발생)

    laplacian_filter = cv2.cuda.createLaplacianFilter(
        cv2.CV_8UC3, cv2.CV_8UC3  # ← 3채널로 생성 시도
    )
    ❌ 에러 발생
    OpenCV Error: (-215:Assertion failed) scn == 1 || scn == 4
    in function 'LinearFilter'

    원인: CUDA Laplacian 필터는 1채널(그레이스케일) 또는 4채널만 지원합니다. 3채널(BGR) 컬러 이미지는 지원하지 않습니다.

    수정 코드 – 그레이스케일 변환 후 연속 연산 5회

    import cv2
    import numpy as np
    import time
    
    img = np.random.randint(0, 255, (4096, 4096, 3), dtype=np.uint8)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 1채널 변환
    
    # CPU
    start = time.time()
    result = img_gray.copy()
    for _ in range(5):
        result = cv2.GaussianBlur(result, (21, 21), 0)
        result = cv2.Laplacian(result, cv2.CV_8U)
        result = cv2.GaussianBlur(result, (21, 21), 0)
    cpu_time = time.time() - start
    print(f"CPU 시간: {cpu_time:.4f}초")
    
    # GPU - 업로드 1번, 연산 15번, 다운로드 1번
    gpu_img = cv2.cuda_GpuMat()
    gpu_img.upload(img_gray)
    
    gaussian_filter = cv2.cuda.createGaussianFilter(cv2.CV_8UC1, cv2.CV_8UC1, (21, 21), 0)
    laplacian_filter = cv2.cuda.createLaplacianFilter(cv2.CV_8UC1, cv2.CV_8UC1)
    
    start = time.time()
    gpu_result = gpu_img
    for _ in range(5):
        gpu_result = gaussian_filter.apply(gpu_result)
        gpu_result = laplacian_filter.apply(gpu_result)
        gpu_result = gaussian_filter.apply(gpu_result)
    result = gpu_result.download()
    gpu_time = time.time() - start
    print(f"GPU 시간: {gpu_time:.4f}초")
    print(f"속도 차이: {cpu_time/gpu_time:.1f}배")
    ✅ 최종 결과
    CPU 시간: 0.1283초
    GPU 시간: 0.0553초
    속도 차이: 2.3배 🎉

    핵심 정리

    포인트내용
    pip install opencvCUDA 미포함, 소스 빌드 필요
    Docker 사용 이유호스트 시스템 오염 없이 격리된 환경 구축
    GPU가 느린 경우upload/download 오버헤드 > 연산 시간
    GPU가 빠른 경우연산을 많이 연속으로 할수록 유리
    Laplacian 에러CUDA는 1채널(CV_8UC1)만 지원, BGR 불가
    VSCode 디버깅Dev Containers로 컨테이너 안에서 F5 디버깅 가능
  • [FastAPI + Ollama] Hunting the Real 404

    🛠️ Debugging Story

    The Route Exists. So Why Is It Returning 404?
    A FastAPI + Ollama Deep Dive 🔍

    I finally got my mini AI-RAG and chatbot service talking to my app. Still a prototype — text only, nothing fancy to look at. But when it all clicked together, that feeling made every late night worth it.

    ⚡ FastAPI🐳 Docker🤖 Ollama☁️ Cloud Run

    🏗️ Service Architecture

    📱 App→☁️ Cloud Run→🔒 Cloudflare→🏠 Home Router→🖥️ Prod Server→💻 Dev Server (RTX 3060)

    😰As the layers stacked up, strange things started happening

    iptables + NordVPN + Docker were interfering with each other — packets were vanishing, and tcpdump was the only thing giving me any direction. My MacBook’s SSH tunnel kept dropping and reconnecting, and at some point the dev server started silently swallowing requests. Nothing in the logs, server still running. Rebooted the MacBook. Fixed immediately.

    Once I got through all that, a 404 was waiting for me.

    🚨The route exists. So why 404?

    POST /internal/llm/chat kept returning 404 inside Docker while working perfectly on the dev server. I printed the route table directly — the endpoint was clearly registered. It wasn’t a proxy issue either, since requests were showing up in the FastAPI logs.

    💡 From inside the container (127.0.0.1): 401 Unauthorized. From outside via nginx: 404 Not Found. Same container, same process, different results.

    🔎The key clue: response size

    The response sizes in the nginx access log looked wrong.

    ⚠️ FastAPI default 404 {"detail":"Not Found"} = 22 bytes
    Actual response sizes = 64–89 bytes
    Something else was generating that 404.

    Working backwards, it was an Ollama error message:

    {“detail”:”model ‘llama3’ not found, try pulling it first”}

    🕵️Root cause: upstream error propagation

    A client service was reading OLLAMA_MODEL=llama3 from GCP Secret Manager and passing it in the request body. The model actually installed was llama3.1:8b. Ollama’s 404 was propagating straight through FastAPI to the client — making it look like the route didn’t exist. Not a routing problem. An upstream error propagation problem.

    🤖Debugging with AI

    I had been relying on AI to analyze the flood of logs. At some point, it started nudging me toward tearing down the architecture itself. I stepped back, worked through it with Claude from scratch, and eventually tracked down the real cause.

    AI compressed what could have been weeks of debugging into days. But holding the design together was still a human job. The more network layers you add, the easier it is for AI to lose the thread too.


    📝What I took away

    1️⃣

    Check the response size

    22 bytes vs 64 bytes. Two 404s can mean completely different things. That single number was the decisive clue.

    2️⃣

    404 doesn’t always mean routing failure

    Upstream errors propagate silently. If you don’t handle them explicitly, they’re very hard to trace.

    3️⃣

    Wrap upstream errors as 502/503

    Returning internal errors and routing errors with the same status code multiplies your debugging time significantly.

    4️⃣

    When nothing makes sense — reboot. Seriously.

    Sometimes the most powerful debugging tool is turning it off and back on. Your mental health will thank you.

    When the logs go quiet, widen your view. 🔭
    And when nothing makes sense — reboot first.

  • [FastAPI + Ollama] 404의 진짜 범인을 찾아서

    라우트는 있는데 왜 404가 날까요?
    FastAPI + Ollama 삽질기 🔍

    집에서 mini AI-RAG와 챗봇 서비스를 앱에 간신히 연결했습니다. 아직 프로토타입이라 텍스트밖에 없어 볼품없지만, 딱 붙여서 되었을 땐 정말 뿌듯했습니다. 그 과정에서 생긴 이야기입니다.

    ⚡ FastAPI🐳 Docker🤖 Ollama☁️ Cloud Run

    🏗️ 서비스 구성

    📱 앱→☁️ Cloud Run→🔒 Cloudflare→🏠 공유기→🖥️ 운영 서버→💻 개발 서버 (RTX 3060)

    😰레이어가 쌓일수록 이상한 일이 생겼습니다

    iptables + NordVPN + Docker가 얽히면서 패킷이 사라졌고, tcpdump로 겨우 방향을 잡았습니다. 맥북 SSH 터널이 끊겼다 붙었다 하면서 개발 서버가 요청을 통째로 삼키는 증상도 있었습니다. 로그엔 아무것도 안 찍히는데 서버는 살아있는 상황 — 껐다 켜니까 바로 해결됐습니다.

    그걸 뚫고 나니 이번엔 404가 기다리고 있었습니다.

    🚨증상: 라우트는 있는데 404

    Docker 컨테이너에서 POST /internal/llm/chat 요청이 계속 404를 반환했습니다. 개발 서버에서는 정상 동작. 라우트 목록을 직접 출력해봤더니 엔드포인트는 분명히 등록되어 있었습니다.

    💡 내부(127.0.0.1)에서는 401 Unauthorized, 외부(nginx)에서는 404 Not Found. 같은 컨테이너, 같은 프로세스에서 다른 결과가 나왔습니다.

    🔎결정적 단서: 응답 크기

    nginx 액세스 로그의 응답 크기가 이상했습니다.

    ⚠️ FastAPI 기본 404 응답 {"detail":"Not Found"} = 22바이트
    실제 응답 크기 = 64~89바이트
    누군가 다른 404를 만들고 있었습니다.

    역산해보니 Ollama의 에러 메시지였습니다.

    {“detail”:”model ‘llama3’ not found, try pulling it first”}

    🕵️원인: upstream 에러 전파

    클라이언트 서비스가 GCP Secret Manager에서 OLLAMA_MODEL=llama3를 읽어 요청 body에 담아 보내고 있었고, 서버에 실제 설치된 모델은 llama3.1:8b였습니다. Ollama의 404가 FastAPI를 통해 그대로 전파된 것입니다. 라우팅 문제가 아니라 upstream 에러 전파 문제였습니다.

    🤖AI와 함께 판 이야기

    AI에게 대량의 로그 분석을 맡겼는데, 어느 순간 AI가 설계 구성 자체를 무너뜨리는 방향으로 유도하기 시작했습니다. Claude와 함께 다시 처음부터 파고들어서 간신히 실제 원인을 찾아냈습니다.

    AI는 몇 주의 삽질을 며칠로 줄여줬지만, 설계를 지키는 건 결국 사람의 몫이었습니다. 네트워크 관리 포인트가 늘어날수록, AI도 길을 잃습니다.


    📝이 경험에서 얻은 교훈

    1️⃣

    응답 크기를 확인하라

    22바이트 vs 64바이트. 같은 404도 내용이 다릅니다. 응답 크기 하나가 결정적 단서가 됩니다.

    2️⃣

    404가 항상 라우팅 문제는 아니다

    Upstream 에러는 조용히 전파됩니다. 명시적으로 처리하지 않으면 추적이 매우 어렵습니다.

    3️⃣

    Upstream 에러는 502/503으로 변환하라

    내부 오류와 라우팅 오류를 같은 코드로 반환하면 디버깅 시간이 몇 배로 늘어납니다.

    4️⃣

    이해 안 되면 일단 끄고 켜라 — 진지하게

    뭔가 정말 이해 안 되는 상황이 생기면, 일단 정리하고 컴퓨터를 껐다 키는 게 정신건강에 좋습니다.

    로그가 조용할수록, 시야를 넓혀야 합니다. 🔭
    그리고 뭔가 이상하면 — 일단 재부팅부터.