2026년 2월 22일
Docker 로그는 어디에 저장되는걸까?
docker logs는 어디서 오는 걸까?
컨테이너를 실행하다가 에러가 나면 우리는 습관처럼 아래 명령어를 입력한다.
docker logs <container-name>
그러면 방금 전 애플리케이션에서 찍힌 로그들이 주르륵 출력된다.

그런데 문득 이런 생각이 들었다.
“이 로그는 대체 어디에 저장되어 있는거고, 도커는 어떻게 이걸 보여주는 걸까?”
컨테이너는 “격리된 환경” 이라고 배웠는데, 그 안에서 찍힌 로그를 호스트에서 어떻게 읽을 수 있는 걸까?
오늘 글에서는
docker logs의 정체를 파헤쳐보려 한다.로그는 어디에 저장되는가?
Docker에는 실행 중인 컨테이너에서 정보를 얻는 데 도움이 되는 여러 로깅 메커니즘이 포함되어 있다.
이러한 메커니즘을 로깅 드라이버라고 한다.
기본적으로 도커는 별도의 설정을 하지 않으면
json-file 로깅 드라이버를 사용한다.저장 경로는 호스트 OS의
/var/lib/docker/containers/<container-id>/ 디렉토리 내에 존재하고, 파일 명은 <container-id>-json.log 라는 이름의 JSON 형식 파일로 저장된다.ls /var/lib/docker/containers

- 6개의 컨테이너 로그가 존재한다.
cat <container-id>

- 로그가 JSON 형태로 저장되는 것을 확인할 수 있다.
어떤 원리로 저장되는가?
도커 로그가 저장되는 원리는 마치 중간에서 가로채는 도청 장치와 비슷하다.
애플리케이션이 화면에 글자를 내보내는 그 순간을 도커 엔진이 포착해서 파일로 기록한다.
1. 표준 스트림 (Standard Streams) 포착
모든 프로세스는 기본적으로 두 가지 출력 통로를 가진다.
- stdout (Standard Output): 정상적인 실행 정보 (예:
print,console.log)
- stderr (Standard Error): 에러나 경고 메시지
도커 컨테이너 내부에서 실행되는 애플리케이션이 이 통로로 데이터를 내보내면, 도커 데몬(Docker Daemon)이 이 스트림을 끝단에서 기다리고 있다가 전부 읽어들인다.
2. 로깅 드라이버(Logging Driver)의 개입
도커 데몬은 가로챈 텍스트 데이터를 그대로 두지 않고, 설정된 로깅 드라이버에게 넘긴다.
기본값인
json-file 드라이버는 데이터를 다음과 같이 가공한다.- 메타데이터 부착: 로그가 발생한 정확한 시간(time), 어떤 통로(stdout/stderr)였는지 정보를 붙인다.
- JSON 직렬화: 데이터를 아래와 같은 정형화된 포맷으로 변환한다.
{"log":"Hello World!\n","stream":"stdout","time":"2026-02-22T12:45:00Z"}
3. 호스트 파일 시스템에 기록
가공된 JSON 데이터는 이제 호스트 OS의 특정 위치에 물리적인 파일로 저장된다.
- 기본값:
/var/lib/docker/containers/<컨테이너ID>/<컨테이너ID>-json.log
애플리케이션이 로그를
stdout으로 내보내지 않고 내부 파일(예: /app/logs/error.log)에 직접 쓰게 된다면, 도커 엔진은 중간에서 가로챌 데이터가 없으므로 로그를 수집할 수 없다.로그 파일이 무한정 커지면 어떻게 될까?
당연한 이야기이겠지만 로그 파일이 무한정 커지면 호스트 OS의 디스크 용량을 전부 차지하게 된다.
docker logs 명령어를 실행할 때 수 GB짜리 파일을 읽어야 하므로 일반적인 에디터로 열리지도 않아 장애 대응 시 로그 분석이 불가능해진다.만약 지금 당장 디스크가 꽉 찼다면, 컨테이너를 지우지 않고 로그 내용만 비우는 ‘응급 처치’ 방법도 있다.
# 특정 컨테이너의 로그 파일 경로를 찾아 내용을 비웁니다 (0바이트로 만듦) truncate -s 0 $(docker inspect --format='{{.LogPath}}' <컨테이너_이름>)
로그 로테이션 (Log Roation)
도커는 로그 파일의 최대 크기와 저장할 파일 개수를 제한하는 기능을 제공한다. 이를 설정하면 가장 오래된 로그부터 자동으로 지우며 새 로그를 쌓는다.
방법 A: 특정 컨테이너에 적용 (
docker run)컨테이너를 실행할 때 옵션을 추가한다. 아래 예시는 로그 파일을 최대 10MB로 제한하고, 3개까지만 보관하도록 설정한다.
docker run -d \ --log-driver json-file \ --log-opt max-size=10m \ --log-opt max-file=3 \ nginx
방법 B: 도커 데몬 전체에 적용
모든 컨테이너에 일일이 설정하기 번거롭다면, 도커 설정 파일에 기본값을 지정하는 방식도 존재한다.
- 파일 수정:
sudo nano /etc/docker/daemon.json
- 내용 추가:
{ "log-driver": "json-file", "log-opts": { "max-size": "20m", "max-file": "5" } }
- 도커 재시작:
sudo systemctl restart docker
컨테이너를 내리면 로그가 삭제될까?
- 컨테이너를 중지(Stop)했을 때
- 삭제 되지 않는다.
docker stop은 프로세스만 종료시킨 상태이므로, 컨테이너 객체는 호스트의 디스크에 그대로 남아있다.- 따라서
docker logs명령어로 이전 로그를 여전히 확인할 수 있다.
- 컨테이너를 삭제(Remove)했을 때
- 로그는 삭제된다.
docker rm명령어를 사용하거나,docker run -rm옵션으로 실행된 컨테이너가 종료되어 자동으로 삭제되면 로그 파일도 함께 삭제된다.- 도커 로그는 컨테이너의 라이프사이클과 운명을 같이한다.
로그를 유실하지 않으려면?
컨테이너가 삭제되더라도 로그를 보존하고 싶다면 주로 다음과 같은 방법을 사용한다.
방법 A: 호스트 볼륨 연결 (Volume Mount)
애플리케이션이 로그를 파일로 남긴다면, 호스트의 특정 디렉토리와 컨테이너를 연결한다.
이렇게 하면 컨테이너가 삭제 되어도
/home/user/logs 에 로그가 남는다.docker run -v /home/user/logs:/app/logs my-app
방법 B: 로그 수집기 활용 (Logging Driver)
로그를 파일로 저장하지 않고 외부 서비스(CloudWatch, ELK, Fluentd 등)로 즉시 쏴주는 방식이다.
운영 환경에서
docker logs 에만 의존하다가 컨테이너를 재배포(삭제 후 재생성)하면 과거 기록이 모두 사라지는 대참사가 발생할 수 있다. 그래서 중요한 서비스라면 반드시 외부 저장소 설정을 병행해야 한다. (Cloud-native pattern)json-file 방식의 치명적인 한계
docker logs로 확인하는 json-file 방식은 소규모 프로젝트에는 좋지만, 서비스 규모가 커지면 다음과 같은 벽에 부딪힌다.- 로그 휘발성: 컨테이너를 삭제(
rm)하면 로그도 영구 삭제된다. 장애 원인을 파악해야 하는데 증거가 사라지는 셈이다.
- 검색의 어려움: 서버가 100대라면, 에러를 찾기 위해 서버에 일일이 접속해서
docker logs를 쳐야 한다.
- 디스크 압박: 로그 파일이 호스트 디스크를 가득 채워 서비스 전체를 마비시킬 위험이 높다.
- 비정형 데이터: 로그는 단순 텍스트이다. “최근 1시간 동안 500 에러가 몇 번 발생했지?”라는 통계를 내기가 매우 어렵다.
외부 로그 수집기(ELK Stack)를 쓰는 이유
ELK Stack을 사용하면 로그의 흐름이 [생성 → 수집 → 저장 → 시각화] 의 파이프라인을 타게 된다.
단계 | 도구 | 실무에서의 역할 |
수집 (Ship) | Logstash / Fluentd | 각 컨테이너의 stdout을 실시간으로 낚아채서 중앙 서버로 보냅니다. |
저장/검색 (Store) | Elasticsearch | 방대한 로그 데이터를 인덱싱(색인)하여 0.1초 만에 검색 가능하게 만듭니다. |
시각화 (Visualize) | Kibana | 로그 데이터를 차트나 그래프로 그려줍니다. (예: 에러 발생률 그래프) |
이에 대한 이점은 다음과 같다.
- 중앙 집중형 관리: 어떤 컨테이너에서 로그가 발생하든 한 곳에서 모두 볼 수 있다. 서버 IP를 몰라도 서비스 이름만으로 로그 검색이 가능해진다.
- 실시간 알람: “에러 로그가 1분에 10번 이상 발생하면 담당자에게 슬랙(Slack) 메시지를 보내라”는 식의 자동화가 가능하다. 장애 대응 속도가 압도적으로 빨라진다.
- 로그 보존 및 법적 근거: 컨테이너가 죽거나 사라져도 로그는 별도의 스토리지에 안전하게 보관된다. 이는 보안 사고 발생 시 추적을 위한 법적 근거로도 활용된다.
- 데이터 분석: 단순히 “에러 찾기”를 넘어, “사용자가 주로 어떤 페이지를 보는지”, “응답 시간이 느려지는 구간은 어디인지” 같은 비즈니스 인사이트를 추출할 수 있다.
번외: PLG Stack
- ELK Stack보다 더 가벼운 PLG Stack도 존재한다고 한다.
구성 요소 | 역할 | 비유 |
Promtail | 로그 수집기 (컨테이너 로그를 낚아채서 Loki로 전송) | 우체부 |
Loki | 로그 저장소 (데이터를 압축 저장하고 쿼리 처리) | 우체국 물류 창고 |
Grafana | 시각화 도구 (로그를 검색하고 대시보드 출력) | 수신용 모니터 |
ELK와 Loki의 가장 큰 차이점은 인덱싱 방식이다.
- ELK (전체 인덱싱): 로그의 모든 단어를 인덱싱한다. 검색은 빠르지만, 저장 용량을 엄청나게 차지하고 CPU와 메모리를 많이 쓴다.
- Loki (레이블 인덱싱): 로그 본문은 그냥 압축해서 쌓아두기만 하고, ‘어떤 컨테이너인가?’, ‘어떤 앱인가?’ 같은 레이블(Label) 정보만 인덱싱한다.
Loki의 장점은 다음과 같다.
- 가벼움: 로그 본문을 다 뒤지지 않고 레이블만 관리하므로, Elasticsearch에 비해 디스크 사용량이 1/10 수준으로 낮고 운영 비용이 저렴하다.
- Grafana와의 완벽합 궁합: 이미 서버 모니터링을 위해 Grafana를 쓰고 있다면, 별도의 툴(Kibana)을 배울 필요 없이 한 화면에서 메트릭과 로그를 동시에 볼 수 있다.
- 예시: "서버 CPU가 튀었네? (메트릭) -> 그 시점에 어떤 로그가 찍혔지? (Loki)"
- 쿠버네티스 친화적: Loki는 쿠버네티스의 ‘Pod 레이블’을 그대로 가져와서 로그 인덱스로 활용한다. 클라우드 네이티브 환경에 최적화되어 있다.
Loki의 단점은 다음과 같다.
- 전문화된 검색의 한계: 로그 본문의 특정 단어로 복잡한 통계를 내야 한다면(예: “모든 로그 중 ‘error’ 단어의 빈도 분석”), 모든 본문을 인덱싱하는 Elasticsearch보다 느릴 수밖에 없다.
- 단순 검색 위주: 주로 “장애 발생 시 특정 시간대의 로그를 확인”하는 용도에 최적화되어 있다.
요약
docker logs는 컨테이너의 표준 출력을 도커 데몬이 낚아채서 호스트 디스크의 JSON 파일에 기록해둔 것을 보여주는 도구이다.
- 기본 로깅 드라이브는
json-file이다.
- 로그는 컨테이너의 라이프사이클과 함께 움직인다.
- 로그 파일이 무한히 커지는 것을 방지하려면 반드시 로그 로테이션(max-size, max-file) 설정이 필요하다.
- 운영 환경에서는
json-file에만 의존하지 않고, 외부 로그 수집 시스템을 사용하는 것이 일반적이다.
