도커 에러 정리

Hunter Joe·2026년 3월 20일

Docker 컨테이너에서 Telegram Bot API 호출 시 ETIMEDOUT 발생 원인과 해결

증상

  • NestJS 서버에서 에러 발생 시 Telegram Bot API로 알림을 보내는 기능

  • 간헐적으로 알림이 오지 않는 현상 발생

  • 서버 로그에는 에러가 정상적으로 찍히지만, Telegram 메시지는 도착하지 않음

    디버깅 과정

    1단계: 코드 문제 확인

    TelegramTransport에서 axios 에러를 .catch(() => {})로 무시하고 있어서, 실패해도 아무 로그가 남지 않았음.
    catch에 로그를 추가하여 원인 파악 시작.

    // 기존 — 에러를 삼킴
    axios.post(url, data).catch(() => {});

    // 디버깅용 — 에러 내용 출력
    axios.post(url, data).catch((err) => {
    console.error('[TelegramTransport]', err.code, err.message);
    });

    결과: ETIMEDOUT 확인

    2단계: 네트워크 문제 확인

    Docker 컨테이너 내부에서 테스트

    wget → 성공

    docker exec server wget -q -O- https://api.telegram.org

    Node.js https 모듈 → ETIMEDOUT

    docker exec server node -e "require('https').get('https://api.telegram.org', ...)"

    Google은 정상

    docker exec server node -e "require('https').get('https://google.com', ...)"

    → status: 301 (성공)

    wget은 되고 Node.js는 안 되는 상황.

    3단계: DNS 조회

    docker exec server node -e "
    require('dns').resolve4('api.telegram.org', (e, a) => console.log('IPv4:', a));
    require('dns').resolve6('api.telegram.org', (e, a) => console.log('IPv6:', a));
    "

    IPv4: [ '149.154.166.110' ]
    IPv6: [ '2001:67c:4e8:f004::9' ]

    api.telegram.org는 IPv4, IPv6 둘 다 지원.

    4단계: IPv4 직접 연결 테스트

    IPv4 IP로 직접 연결 → 성공. IPv6 경로가 문제라는 것을 확인.

    원인

  • api.telegram.org는 IPv4/IPv6 듀얼 스택

  • Node.js는 기본적으로 IPv6를 우선 사용 (happy eyeballs 알고리즘)

  • Docker 기본 네트워크(bridge)는 IPv6 외부 라우팅을 지원하지 않는 경우가 많음

  • IPv6로 연결 시도 → 라우팅 불가 → ETIMEDOUT

  • wget은 IPv4를 우선 사용하기 때문에 성공

  • 간헐적으로 알림이 온 이유: Node.js가 IPv4로 먼저 연결되는 경우도 있었기 때문

    해결

    axios 인스턴스에 family: 4 옵션을 추가하여 IPv4 연결을 강제.

    // 변경 전
    axios.post(this.apiUrl, { chat_id: this.chatId, text }).catch(() => {});

    // 변경 후
    this.httpClient = axios.create({
    timeout: 10000,
    family: 4, // IPv4 강제
    });
    this.httpClient.post(this.apiUrl, { chat_id: this.chatId, text }).catch(() => {});

    핵심 정리

    ┌──────┬───────────────────────────────────────────────┐
    │ 항목 │ 내용 │
    ├──────┼───────────────────────────────────────────────┤
    │ 환경 │ Docker (bridge network) + Node.js │
    ├──────┼───────────────────────────────────────────────┤
    │ 증상 │ 외부 API 호출 간헐적 ETIMEDOUT │
    ├──────┼───────────────────────────────────────────────┤
    │ 원인 │ Node.js IPv6 우선 + Docker IPv6 라우팅 미지원 │
    ├──────┼───────────────────────────────────────────────┤
    │ 해결 │ family: 4로 IPv4 강제 │
    ├──────┼───────────────────────────────────────────────┤
    │ 교훈 │ .catch(() => {})로 에러를 삼키지 말 것 │
    └──────┴───────────────────────────────────────────────┘

profile
Improvise, Adapt, Overcome

0개의 댓글