교체된 로그 파일과 표준 출력에 스크립트 출력을 어떻게 쓸 수 있습니까?

교체된 로그 파일과 표준 출력에 스크립트 출력을 어떻게 쓸 수 있습니까?

우리는 컨테이너 내에서 마이크로서비스를 K8s Pod로 실행합니다. 애플리케이션이 컨테이너로 전송된 모든 신호(특히 포드 제거 시 SIGTERM)를 수신하도록 하기 위해 일반적으로 exec시작 스크립트의 끝 부분에 사용하여 시작 스크립트 bash 프로세스(PID는 1)가 효과적으로 애플리케이션 프로세스가 "됩니다". 따라서 시작 스크립트는 일반적으로 다음으로 끝납니다.

exec <ourCommand>

편의를 위해 로그 출력(stdout 및 stderr)이 의 출력에 표시되기를 원 kubectl logs하지만 사후 분석을 위해 출력이 파일로 끝나기를 원합니다(예, 해당 파일은 존재하는 위치에서 끝납니다). Pod가 다시 시작됩니다. -)). 파일이 너무 커지는 것을 방지하려면 파일을 회전해야 합니다. 로그 회전의 경우 rotatelogsApache 도구에 대한 좋은 경험이 있습니다. "-e" 옵션은 "stdout에 에코 로그"를 지정하여 파일 및 stdout에 대한 로깅 출력을 제공합니다. 가장 확실한 방법은 다음과 같이 스크립트 출력을 파이프하는 것입니다.

exec <ourCommand> | rotatelogs -e -n 10 stdout.log 10M

exec 이것은 잘 작동하는 것처럼 보였지만 예상되는 동작을 효과적으로 방지하고 시작 스크립트가 여전히 루트 프로세스라는 것을 알았습니다 . 예를 들어 pstree -p 다음 구조가 표시됩니다.

start.sh(1)-+-<ourCommand>(17)
        `-rotatelogs(18)

따라서 신호 처리가 중단되어 애플리케이션이 SIGTERM을 수신하지 않고 정상적으로 종료되지 않고 대신 종료 유예 기간이 끝난 후 Pod가 종료됩니다.

많은 시행착오 끝에 우리는 프로세스 대체를 사용하여 이 솔루션에 도달했습니다. exec <ourCommand> &> >( rotatelogs -e -n 10 stdout.log 10M)

결과는 원하는 프로세스 구조와 다시 작동하는 신호 처리입니다. pstree -p이제 이 구조가 표시됩니다.

<ourCommand>(1)---start.sh(17)---rotatelogs(18)

그러나 우리는 Pod가 충돌하는 상황을 반복적으로 발견했으며 때로는 눈에 띄는 오류 메시지도 표시되지 않았습니다 kubectl logs(그러나예전에는로그 파일에 표시되지만 거기를 보는 사람은 동일한 내용을 가질 것이라고 기대하지 않으므로 kubectl logs"왜 귀찮게"합니까? 흥미롭게도 이는 프로덕션 환경(EKS 및 AKS 클러스터)에서 더 자주 발생하며 로컬 환경(minikube)에서 문제를 재현하려고 할 때 안정성이 떨어집니다.

가장 좋은 추측은rotatelogs가 항상 출력 버퍼를 플러시하는 것은 아니기 때문에 특히 스크립트 출력의 마지막 줄(일반적으로 유용한 오류 메시지...)이 손실될 수 있다는 것입니다. Rotatelogs는 각 행을 강제로 새로 고치는 설정을 제공하지 않으므로 이제 이 방법을 사용하는 것이 좋습니다("이중 프로세스 교체"라고 함).

exec <ourCommand> &> >(tee >(rotatelogs -n 10 stdout.log 10M ))

아이디어는 티가 "스트림 분할"을 수행하도록 하는 것이며 회전하는 로그에서 발생하는 플러시 문제가 없기 때문에 -e잘 작동합니다. 충돌한 응용 프로그램의 "유명한 마지막 단어"가 로그 파일에 안정적으로 표시됩니다. , 그리고 kubectl logs.

그런 다음 누군가 TS 필터링을 통해 모든 로그 줄에 타임스탬프를 찍는 훌륭한 아이디어를 생각해 냈습니다.

exec <ourCommand> &> >(ts | tee >(rotatelogs -n 10 stdout.log 10M ))

이는 결국 "유명한 마지막 단어"가 종종 나타나지 않는다는 사실로 이어집니다 kubectl logs. 현재 프로세스 구조는 다음과 같습니다.

<ourCommand>(1)---start.sh(17)-+-tee(19)---start.sh(20)---rotatelogs(21)
                               `-ts(18)

예, "3중 프로세스 교체"를 시도했지만 :-D 문제가 해결되지 않았습니다. ts만 삭제하면 됩니다.

Bash에 대해 더 깊이 이해하고 있는 사람이라면 여기서 무슨 일이 일어나고 있는지 설명할 수 있습니까(그리고 가급적 해결책을 제안할 수 있습니까)?

감사해요

답변1

ts타임스탬프를 추가하고 인쇄하기 전에 전체 행을 수신할 것으로 예상됩니다. 따라서 프로세스의 "마지막 단어"가 - 로 끝나지 않으면 \n손실될 수 있습니다.

어떻게 고치나요? 직접 작성해 ts보세요. 다음과 같습니다.

#!/bin/perl
$foundLF = 1;

while($ch=getc) {
    if ($foundLF == 1) {
        $datestring = gmtime();
        print "$datestring ";
        $foundLF = 0;
    }

    print $ch;

    $foundLF = 1 if (ord($ch) == 10);
}

ts작성 되어 있으니 perl참고하시면 됩니다.

해당 기능을 자신만의 기능에 tee포함 시키면 쉽게 수행할 수 있습니다 .rotatelogtsperl

관련 정보