Docker 로그 드라이버 플러그인

Docker 로그 드라이버 플러그인 (Docker log driver plugins)

이 문서는 Docker용 로깅 드라이버 플러그인을 설명해요.

로깅 드라이버는 사용자가 컨테이너 로그를 처리용 다른 서비스로 전달할 수 있게 해줘요. Docker는 여러 로깅 드라이버를 내장으로 포함하지만 내장 드라이버로 모든 사용 사례를 지원할 수는 없어요. 플러그인은 주 Docker 코드베이스에 이 서비스들의 클라이언트 라이브러리를 포함시키지 않고도 Docker가 광범위한 로깅 서비스를 지원할 수 있게 해줘요. 자세한 내용은 플러그인 문서를 참고하세요.

출처: 문서

본문

로깅 플러그인 만들기 (Create a logging plugin)

로깅 플러그인의 주요 인터페이스는 다른 플러그인 유형이 사용하는 것과 같은 JSON+HTTP RPC 프로토콜을 사용해요. 로깅 플러그인의 레퍼런스 구현은 예시 플러그인을 참고하세요. 이 예시는 내장 jsonfilelog 로그 드라이버를 래핑해요.

LogDriver 프로토콜 (LogDriver protocol)

로깅 플러그인은 플러그인 활성화 중 LogDriver로 등록해야 해요. 활성화되면 사용자는 플러그인을 로그 드라이버로 지정할 수 있어요.

로깅 플러그인이 구현해야 하는 두 개의 HTTP 엔드포인트가 있어요:

/LogDriver.StartLogging

플러그인에 컨테이너가 시작되고 있으며 플러그인이 로그 수신을 시작해야 한다는 신호를 보내요.

로그는 요청에 정의된 파일 위로 스트리밍돼요. Linux에서 이 파일은 FIFO예요. 로깅 플러그인은 현재 Windows에서 지원되지 않아요.

Request:

{
  "File": "/path/to/file/stream",
  "Info": {
          "ContainerID": "123456"
  }
}

File은 소비해야 할 로그 스트림의 경로예요. StartLogging에 대한 각 호출은, 플러그인이 이전에 이미 로그를 받은 컨테이너여도, 다른 파일 경로를 제공해야 해요. 파일은 Docker가 무작위 생성 이름으로 만들어요.

Info는 로깅되는 컨테이너에 대한 세부 정보예요. 상당히 자유 형식이지만 다음 구조체 정의로 정의돼요:

type Info struct {
	Config              map[string]string
	ContainerID         string
	ContainerName       string
	ContainerEntrypoint string
	ContainerArgs       []string
	ContainerImageID    string
	ContainerImageName  string
	ContainerCreated    time.Time
	ContainerEnv        []string
	ContainerLabels     map[string]string
	LogPath             string
	DaemonName          string
}

ContainerID는 항상 이 구조체와 함께 제공되지만, 다른 필드는 비어 있거나 누락될 수 있어요.

Response:

{
  "Err": ""
}

이 요청 중에 오류가 발생하면 응답의 Err 필드에 오류 메시지를 추가해요. 오류가 없다면 빈 응답({}) 또는 Err 필드의 빈 값을 보낼 수 있어요.

드라이버는 이 시점에서 전달된 파일에서 로그 메시지를 소비하고 있어야 해요. 메시지가 소비되지 않으면 컨테이너가 stdio 스트림에 쓰는 것을 차단하며 블로킹될 수 있어요.

로그 스트림 메시지는 프로토콜 버퍼로 인코딩돼요. protobuf 정의는 moby 저장소에 있어요.

프로토콜 버퍼는 자기 구분(self-delimited)이 아니므로 다음 스트림 형식을 사용해 스트림에서 디코딩해야 해요:

[size][message]

여기서 size는 4바이트 빅 엔디언 바이너리 인코딩된 uint32예요. 이 경우 size는 다음 메시지의 크기를 정의해요. message는 실제 로그 항목이에요.

스트림 인코더/디코더의 golang 레퍼런스 구현은 여기에서 찾을 수 있어요.

/LogDriver.StopLogging

정의된 파일에서 로그 수집을 중지하도록 플러그인에 신호를 보내요. 응답을 받으면 파일은 Docker가 제거해요. 이 요청에 응답하기 전에 스트림의 모든 로그를 수집했는지 확인해야 해요, 그렇지 않으면 로그 데이터를 잃을 위험이 있어요.

이 엔드포인트에 대한 요청은 컨테이너가 제거되었음을 의미하지 않고 중지되었음을 의미해요.

Request:

{
  "File": "/path/to/file/stream"
}

Response:

{
  "Err": ""
}

이 요청 중에 오류가 발생하면 응답의 Err 필드에 오류 메시지를 추가해요. 오류가 없다면 빈 응답({}) 또는 Err 필드의 빈 값을 보낼 수 있어요.

선택적 엔드포인트 (Optional endpoints)

로깅 플러그인은 두 개의 추가 로깅 엔드포인트를 구현할 수 있어요:

/LogDriver.Capabilities

로그 드라이버의 capabilities를 정의해요. Docker가 정의된 capabilities 중 하나라도 활용할 수 있게 하려면 이 엔드포인트를 구현해야 해요.

Request:

{}

Response:

{
  "ReadLogs": true
}

지원되는 capabilities:

  • ReadLogs - 이것은 플러그인이 클라이언트에 로그를 다시 읽어주는 것이 가능하다고 Docker에 알려줘요. ReadLogs를 지원한다고 보고하는 플러그인은 /LogDriver.ReadLogs 엔드포인트를 구현해야 해요.

/LogDriver.ReadLogs

클라이언트에 로그를 다시 읽어줘요. docker logs <container>가 호출될 때 사용돼요.

Docker가 이 엔드포인트를 사용하려면 플러그인이 /LogDriver.Capabilities가 호출될 때 그렇게 지정해야 해요.

Request:

{
  "ReadConfig": {},
  "Info": {
    "ContainerID": "123456"
  }
}

ReadConfig는 읽기 위한 옵션 목록이며 다음 golang 구조체로 정의돼요:

type ReadConfig struct {
	Since  time.Time
	Tail   int
	Follow bool
}
  • Since는 보내야 할 가장 오래된 로그를 정의해요.
  • Tail은 읽을 줄 수를 정의해요(예: tail -n 10 명령처럼).
  • Follow는 기존 로그를 읽은 후 새 로그 메시지가 들어올 때 클라이언트가 연결된 채로 유지되길 원한다는 신호예요.

Info/LogDriver.StartLogging에서 정의된 것과 같은 타입이에요. 읽을 로그 세트를 결정하는 데 사용해야 해요.

Response:

{{ log stream }}

응답은 플러그인이 Docker에서 소비한 메시지와 같은 형식을 사용해 인코딩된 로그 메시지여야 해요.

더 알아보기 (Learn more)