디스크 공간과 inode가 Docker 컨테이너에서 RAM을 소비하는 것 같습니다.

디스크 공간과 inode가 Docker 컨테이너에서 RAM을 소비하는 것 같습니다.

Dockerized 환경에서 실행되는 웹 서버가 예상보다 더 많은 메모리를 소비하는 이유를 확인하려고 합니다. 이 문제를 조사하는 동안 이해가 되지 않는 다음 동작을 발견했습니다.

  • Docker 컨테이너를 생성하고,docker run -d --name test ubuntu:22.04 tail -f /dev/null
  • 확인하면 docker stats메모리 사용량이 다음과 같이 보고됩니다.400KiB / 62.68GiB
  • 확인하세요 docker top test. 하나의 프로세스만 실행 중입니다( tail -f /dev/null).
  • 이제 실행 중인 컨테이너에 많은 수의 파일과 디렉터리를 만듭니다.docker exec -it test sh -c 'apt update && apt install -y git && git clone https://git.savannah.gnu.org/git/emacs.git'
  • 다시 확인하면 docker stats이제 메모리 사용량이 다음과 같이 보고됩니다.494.9MiB / 62.68GiB
  • docker top test아직 하나의 프로세스만 실행 중인지 확인하세요( ) tail -f /dev/null.

그렇다면 Docker 컨테이너에 있는 약 500MB의 메모리는 어떤 용도로 사용됩니까? 내 생각에는 프로세스가 메모리를 소비하지만 컨테이너에는 프로세스가 하나만 있고 책임을 질 수 없다는 것입니다.

파일 시스템에서 메모리 사용량이 발생합니까? 호스트 시스템이 btrfs를 실행 중입니다. Docker의 기본 스토리지 드라이버를 사용하고 overlay2있으며 파일 시스템 재정의에 대한 정보는 다음과 같습니다.

% docker inspect test | jq '.[].GraphDriver.Data.MergedDir' -r
/var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/merged

% mount | grep overlay
overlay on /var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/JADZ5UYJDWI5EDAAGALCRWUM3B:/var/lib/docker/overlay2/l/JK3H4JAYNUAUSN2W3V2DQ6TB6C,upperdir=/var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/diff,workdir=/var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/work)

% sudo ls -lAd /var/lib/docker/overlay2/l/JADZ5UYJDWI5EDAAGALCRWUM3B/emacs                                           
ls: cannot access '/var/lib/docker/overlay2/l/JADZ5UYJDWI5EDAAGALCRWUM3B/emacs': No such file or directory

% sudo ls -lAd /var/lib/docker/overlay2/l/JK3H4JAYNUAUSN2W3V2DQ6TB6C/emacs
ls: cannot access '/var/lib/docker/overlay2/l/JK3H4JAYNUAUSN2W3V2DQ6TB6C/emacs': No such file or directory

% sudo ls -lAd /var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/diff/emacs
drwxr-xr-x 1 root root 602 Feb 25 16:08 /var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/diff/emacs

% sudo ls -lAd /var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/merged/emacs
drwxr-xr-x 1 root root 602 Feb 25 16:08 /var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/merged/emacs

/var/lib/docker/overlay2/559d41c89d074c45a1ae89109ebec145e8fd4d929151819f08aaae26f73f7bda/diff내 기본 파일 시스템은 btrfs이므로 복제된 Git 저장소는 특수 볼륨 마운트 내부가 아니므로 메모리를 소비하지 않는 btrfs( btrfs 아래)의 디스크에 있을 것으로 예상합니다 .

예를 들어 추가된 파일과 디렉터리를 제거하면 docker exec test rm -rf emacs메모리 사용량이 즉시 68.16 MiB / 62.68GiB.

질문:

  1. 이 메모리를 소비하는 것은 무엇입니까? overlay2작업 계층에 파일과 디렉터리를 추가하면 메모리를 소비해서는 안 된다고 믿게 만드는 Docker 컨테이너나 파일 시스템에 대해 어떤 오해가 있습니까 ?
  2. Docker 데몬 또는 컨테이너화된 워크로드를 사용하여 구성을 변경하여 프로세스 RAM 이외의 소스에서 Docker 컨테이너에서 소비되는 메모리 양을 줄이는 방법이 있습니까?

UNIX Stack Exchange의 [docker] 태그 아래에 있는 기존 질문을 살펴봤지만 이해하는 데 도움이 되는 질문을 찾을 수 없었습니다. 나도 읽었다overlayfs에 대한 공식 Docker 문서그리고 간략하게 리뷰했습니다Linux 커널의 overlayfs에 대한 문서, 그러나 메모리 사용량을 설명할 수 있는 항목을 찾지 못했습니다.

저의 궁극적인 목표는 CPU 및 메모리 사용량을 기준으로 요금이 청구되므로 프로덕션에서 실행되는 유휴 Dockerized 워크로드의 리소스 소비를 줄이는 것입니다. 프로덕션 지표에 따르면 해당 메모리를 사용하는 프로세스가 종료되었음에도 불구하고 유휴 상태에서 워크로드가 메모리를 많이 확보하지 못하는 것으로 나타났습니다.

위 테스트는 btrfs를 사용하여 Docker CE 23.0.1 및 Linux 커널 6.0.12가 설치된 Pop!_OS 22.04에서 수행되었습니다.

내 btrfs의 시스템 매개변수

/etc/fstab파일 시스템에 대한 마운트 옵션을 표시합니다. 기본적으로 모든 항목에 대한 기본값은 다음과 같습니다 .

UUID=ee43bc7e-1d9d-4300-a46a-5d2d772a1e0f / btrfs defaults,subvol=@ 0 0
UUID=ee43bc7e-1d9d-4300-a46a-5d2d772a1e0f /.snapshots btrfs defaults,subvol=@snapshots 0 0
UUID=127d5704-324b-4a50-97bf-9f5f4646ddd5 /home/raxod502 btrfs defaults,subvol=@ 0 0
UUID=127d5704-324b-4a50-97bf-9f5f4646ddd5 /home/raxod502/.snapshots btrfs defaults,subvol=@snapshots 0 0

다음을 사용하여 자동으로 스냅샷을 찍습니다.도미, 내 보존 정책은 총 약 100개를 유지합니다.

% sudo snapper -c system list | wc -l
41
% sudo snapper -c home list | wc -l  
44

저는 인용 링크를 명시적으로 사용한 적이 없으며 자동으로 인용 링크를 생성하는 소프트웨어도 없습니다. 위에서 언급했듯이 btrfs의 가장 발전된 용도는 snapper입니다.

출력은 다음과 같습니다 sudo slaptop -o.https://gist.github.com/raxod502/843a6580dc6fa0f9949d2f4dc03b5c23

도움이 될 수 있는 추가 시스템 구성 세부정보를 제공해 드리겠습니다.

ext4 비교

다른 Linux 시스템의 ext4에서 동일한 테스트를 실행했는데 거의 동일한 결과를 얻었습니다. 복제 전 메모리 사용량은 입니다 328KiB / 969.4MiB. 복제 후 메모리 사용량은 입니다 233.5MiB / 969.4MiB. 복제된 저장소를 삭제한 후 메모리 사용량은 입니다 16.84MiB / 969.4MiB.

답변1

이는 파일 시스템과 관련된 것이 아니라 파일 캐시와 관련된 것 같습니다. 이 정확한 상황을 재현하기 위해 먼저 Emacs 저장소를 /usr/src/emacs.

$ docker run --mount type=bind,source=/usr/src/emacs/.git,destination=/mnt/emacs.git,ro -d --rm --name test debian tail -f /dev/null
$ docker exec -it test sh -c 'apt update && apt install -y git && git clone /mnt/emacs.git'
$ docker stats --no-stream test
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O    PIDS
c468a203b9d2   test      0.00%     46.91MiB / 15.52GiB   0.30%     30.5MB / 667kB   0B / 786MB   1

내 경우에는 약 500MiB의 메모리 사용량을 얻지 못했습니다. 파일 시스템과 관련이 있는 것으로 추측됩니다. 그러나 요점은 최종 메모리 사용량이 네트워크에서 복제할 때와 거의 동일하다는 것입니다. 다음으로 생성된 디렉터리를 삭제 /emacs하자 메모리 사용량이 감소했습니다.

$ docker exec -it test rm -rf /emacs
$ docker stats --no-stream test
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O    PIDS
c468a203b9d2   test      0.00%     15.84MiB / 15.52GiB   0.10%     30.5MB / 667kB   0B / 786MB   1

이것이 파일 시스템과 관련된 것인지 테스트하기 위해 복제 부분을 건너뛰고 동일한 설치 내에 있는 다른 디렉터리에서 mv해당 디렉터리에 액세스 해 보았습니다. 컨테이너의 오버레이 상위 디렉터리와 동일한 블록 장치 마운트에 있다고 emacs가정합니다 ./usr/src/emacs

$ docker run -d --rm --name test debian tail -f /dev/null
$ TEST_UPPER=$(docker container inspect --format '{{.GraphDriver.Data.UpperDir}}' test)
$ mv -v /usr/src/emacs "$TEST_UPPER/emacs"
renamed '/usr/src/emacs' -> '/var/lib/docker/overlay2/dc228a74029510c61ce454549248132bec806686c4da9eac8909d89595ff5a32/diff/emacs'
$ docker stats --no-stream test
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O         BLOCK I/O   PIDS
e700998acb86   test      0.00%     400KiB / 15.52GiB   0.00%     3.79kB / 866B   0B / 0B     1

다시 말하지만, docker cp루트의 컨테이너 디렉터리로 -ing합니다.

$ docker run -d --rm --name test debian tail -f /dev/null
$ docker exec -it test mkdir /emacs
$ tar -C /usr/src/emacs -c . | docker cp - test:/emacs
$ docker exec -i ls -la /emacs | wc -l
42
$ docker stats --no-stream test
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O         BLOCK I/O   PIDS
4ea520193998   test      0.00%     444KiB / 15.52GiB   0.00%     3.79kB / 866B   0B / 0B     1

이를 토대로 보면 모든 메모리 사용량은 apt캐시 메모리를 사용한 것으로 보입니다 git. 조언은 간단합니다. 런타임에 컨테이너를 수정하지 마세요.

관련 정보