콘텐츠로 이동






curl,wget 없는 컨테이너에서 HTTP 응답 확인하기

소 개

컨테이너에 curl과 wget이 없어도 Bash의 /dev/tcp 기능으로 HTTP 응답을 확인할 수 있다.

TCP 연결을 열고 HTTP 요청을 직접 전송하는 방식이다. 추가 패키지 설치 없이 간단한 API 점검에 활용한다.

실행 조건

  • 컨테이너에 bash와 cat이 있어야 한다.
  • Bash에 네트워크 리다이렉션 기능이 활성화되어 있어야 한다.
  • 아래 명령은 Bash에서 실행한다. 일반적인 sh에서는 동작을 보장하지 않는다.
  • HTTPS가 아닌 평문 HTTP 확인용이다.

/dev/tcp는 실제 장치 파일이 아니다. Bash가 리다이렉션 구문에서 특별하게 처리하는 경로다.

HTTP 응답 확인

확인 대상은 http://localhost:8180/monitor.jsp다.

# Bash 셸에서 실행

# TCP 연결을 열고 파일 디스크립터 3에 연결
# 연결에 실패하면 이후 명령은 실행하지 않음
if exec 3<>/dev/tcp/localhost/8180; then
    # HTTP 요청 전송: 마지막 빈 줄까지 포함해야 함
    printf 'GET /monitor.jsp HTTP/1.0\r\nHost: localhost\r\n\r\n' >&3

    # 응답 헤더와 본문 출력: 서버가 연결을 닫을 때까지 읽음
    cat <&3

    # 파일 디스크립터 3 닫기
    exec 3<&-
fi

응답 예시

아래는 설명용 예시다. 실제 상태 코드와 본문은 애플리케이션에 따라 다르다.

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 15

{"status":"ok"}

TCP 연결 성공 여부뿐 아니라 HTTP 상태 코드와 응답 본문까지 확인한다.

명령어 해설

구문 역할
exec 3<>/dev/tcp/localhost/8180 TCP 연결을 열고 읽기·쓰기 가능한 FD 3에 연결
printf '...' >&3 FD 3을 통해 HTTP 요청 전송
cat <&3 FD 3에서 응답을 읽어 화면에 출력
exec 3<&- FD 3 닫기

파일 디스크립터(FD)는 프로세스가 입출력 대상을 구분하는 번호다.

기본적으로 0은 표준 입력, 1은 표준 출력, 2는 표준 오류다. 예제에서는 사용하지 않는 번호로 3을 사용한다.

exec를 명령어 없이 사용하면 현재 셸에 리다이렉션이 유지된다. 따라서 여러 명령이 같은 TCP 연결을 사용할 수 있다.

HTTP 요청 구조

GET /monitor.jsp HTTP/1.0\r\n
Host: localhost\r\n
\r\n
  • GET /monitor.jsp HTTP/1.0: 요청 메서드, 경로, HTTP 버전.
  • Host: localhost: 요청할 호스트.
  • \r\n: HTTP 헤더의 줄바꿈.
  • 마지막 \r\n: 헤더 종료를 알리는 빈 줄.

printf는 지정한 줄바꿈을 그대로 전송하기 위해 사용한다.

주의사항

localhost는 실행 위치 기준

컨테이너 내부에서 실행하면 해당 컨테이너가 속한 네트워크 네임스페이스의 localhost에 접속한다.

호스트 서버나 다른 Pod의 localhost에 접속하는 것이 아니다.

응답이 끝나지 않으면 cat도 대기

cat <&3은 서버가 연결을 닫아 EOF를 전달할 때까지 읽는다.

HTTP/1.0 요청은 일반적으로 응답 후 연결을 종료하지만, 서버가 응답을 끝내지 않으면 명령도 대기할 수 있다. 이 예제에는 별도 타임아웃이 없다.

HTTPS는 직접 처리하지 못함

/dev/tcp는 TCP 연결만 제공한다. TLS 협상과 인증서 검증은 수행하지 않는다.

따라서 HTTPS 포트에 연결하더라도 위 방식으로 HTTPS 응답을 확인할 수는 없다.

FD 닫기는 한 번이면 충분

예제의 exec 3<&-는 FD 3 자체를 닫는다. 읽기 방향만 종료하는 TCP half-close 명령이 아니다.

이 경우 exec 3>&-로 닫아도 되며, 두 명령을 모두 실행할 필요는 없다.