Docker Scout 의 초기 액세스 릴리스를 통해 Docker Hub는 마침내 이미지 내부를 시각화하기 시작했습니다. 정말 좋아요! Docker Hub가 몇 년 전에는 왜 이 작업을 수행하지 않았습니까? 비즈니스 모델 때문이다.
더 진행하기 전에 Docker 이미지가 무엇으로 구성되어 있는지 간략하게 살펴보겠습니다.
명령줄에서 docker pull
실행하여 Docker 이미지를 다운로드하면 Docker CLI는 이미지를 가져오는 동안 각 계층의 다운로드 진행률을 표시합니다. Docker 이미지를 다운로드한 적이 있다면 아마도 다음과 같은 내용을 본 적이 있을 것입니다.
이전에 Docker로 작업한 적이 있다면 자신의 이미지에 대해 이러한 레이어 중 일부를 정의했을 것입니다. 개발자는 Dockerfile을 작성할 때 이러한 레이어를 암시적으로 정의합니다. 예를 들어 이 Dockerfile의 모든 줄은 레이어를 생성합니다.
FROM ubuntu:22.04 # install apt dependencies RUN apt-get update RUN apt-get install -y iputils-ping python3 python3-pip # install python dependencies RUN pip3 install numpy # cleanup apt lists RUN rm -rf /var/lib/apt/lists/* CMD ["/bin/bash"]
레이어는 보관된 Linux 디렉터리로, 파일 시스템 tarball입니다. Docker는 모든 이미지 레이어를 다운로드하고 각 레이어를 별도의 디렉터리에 압축을 풉니다. docker run
명령을 사용하여 Docker 이미지에서 컨테이너를 시작하면 Docker 데몬이 이미지 레이어를 결합하여 컨테이너를 형성합니다.
제품으로서 Docker의 많은 부가 가치는 이러한 세부 정보를 추상화하여 사용자가 작동 방식에 대해 생각하지 않고도 계층화된 컨테이너의 이점을 누릴 수 있다는 것입니다. 그러나 모든 추상화는 누출되며 Docker도 예외는 아닙니다. 때로는 커튼을 뒤로 젖혀야 할 때도 있습니다.
Docker 이미지 레이어에는 컨테이너의 파일 시스템에 있는 모든 바이너리에 대한 원본 스토리가 포함되어 있습니다. Docker 이미지의 첫 번째 줄은 "FROM 줄"입니다. Dockerfile이 기반으로 구축되는 Docker 이미지(및 이미지 레이어)를 정의합니다.
개발자는 현재 Dockerfile의 레이어와 상위 이미지 체인의 레이어를 검사하여 컨테이너 루트 파일 시스템의 모든 파일이 어디서 왔는지 확인할 수 있습니다. 이것은 매우 귀중한 정보입니다. 개발자에게 도움이 됩니다.
Docker 이미지 버전 전반에 걸쳐 파일 변경 사항을 추적하기 위해 시각화의 레이어를 클릭한다고 상상해 보세요. 자동화된 보안 스캔이 이미지 중 하나에서 취약점을 식별하면 레이어 검사 도구를 사용하여 취약점이 어떻게 도입되었는지 식별한다고 상상해 보십시오.
과도한 이미지 크기는 회사에 많은 비용을 초래할 수 있습니다. 많은 CI/CD 파이프라인은 모든 풀 요청에 대해 Docker 이미지를 가져오므로 Docker 이미지 다운로드 시간이 길어지면 파이프라인 속도가 느려지고 개발자의 효율성이 떨어지며 CPU 시간이 낭비될 수 있습니다. 조직은 일반적으로 인프라 비용을 시간 단위로 지불하기 때문에 낭비되는 매 시간은 불필요한 비용입니다.
낭비되는 컴퓨팅 리소스 외에도 비대해진 Docker 이미지로 인해 과도한 네트워크 전송 비용이 발생할 수 있습니다. 조직이 AWS 리전 전체에서 또는 AWS에서 개방형 인터넷으로 Docker 이미지를 다운로드하는 경우 Docker 이미지 팽창은 낭비적인 인프라 지출로 직접적으로 해석됩니다. 이것은 빠르게 합산됩니다.
Docker 이미지 레이어에 실수로 부풀림이 발생하기 쉽습니다. 앞서 설명한 Dockerfile에는 전형적인 예가 포함되어 있습니다. 4행의 레이어는 디스크에 40MB의 파일을 저장하고 나중에 11행의 레이어에 의해 삭제됩니다. Docker 이미지 작동 방식으로 인해 해당 데이터는 여전히 이미지의 일부입니다. 40MB의 불필요한 이미지 크기.
이는 간단한 예입니다. 실제로 Docker 설명서 에 나와 있는 내용입니다. 더 복잡한 Dockerfile에서는 이 실수를 발견하기가 훨씬 더 어려울 수 있습니다.
Docker 이미지 레이어는 명령줄을 사용하여 상호 작용하기 어려울 수 있지만 최근 Docker Scout가 출시되기 전에는 명령줄에서 최첨단 기술을 찾을 수 있었습니다. 다음은 두 가지 기본 접근 방식입니다.
이것은 간단하고 스스로 할 수 있는 Unix 방법입니다. Docker 데몬을 실행하는 호스트만 있으면 됩니다. 간단한 접근 방식입니다.
docker create
실행하여 이미지에서 컨테이너를 시작합니다.docker inspect
사용하여 새 컨테이너의 레이어 디렉터리를 찾으세요.cd
하고 머리 속 레이어에 대해 추론합니다.
이것은 번거로운 일입니다. 몇 달 동안 사용했지만 최근 크기가 크게 늘어난 Docker 이미지에서 일부 이미지 팽창을 추적하려고 한다고 가정해 보겠습니다.
먼저 이미지에서 컨테이너를 만듭니다.
where-the@roadmap-ends ~ $ docker create --name example where-the-roadmap-ends 339b8905b681a1d4f7c56f564f6b1f5e63bb6602b62ba5a15d368ed785f44f55
그런 다음 docker inspect
다운로드한 이미지의 레이어 디렉터리가 파일 시스템에서 어디에 있는지 알려줍니다.
where-the@roadmap-ends ~ $ docker inspect example | grep GraphDriver -A7 "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/1c18bd289d9c3f9f0850e301bf86955395c312de3a64a70e0d0e6a5bed337d47-init/diff:/var/lib/docker/overlay2/wbugwbg23oefsf678r7anbn4f/diff:/var/lib/docker/overlay2/j0dekt7y8xgix11n0lturmf8t/diff:/var/lib/docker/overlay2/zd57mz6l4zrsjk9snc2crphfq/diff:/var/lib/docker/overlay2/83za1pmv9xri44tddzyju0usm/diff:/var/lib/docker/overlay2/8c639b22627e0ad91944a70822b442e5bff848968263a37715a293a15483c170/diff", "MergedDir": "/var/lib/docker/overlay2/1c18bd289d9c3f9f0850e301bf86955395c312de3a64a70e0d0e6a5bed337d47/merged", "UpperDir": "/var/lib/docker/overlay2/1c18bd289d9c3f9f0850e301bf86955395c312de3a64a70e0d0e6a5bed337d47/diff", "WorkDir": "/var/lib/docker/overlay2/1c18bd289d9c3f9f0850e301bf86955395c312de3a64a70e0d0e6a5bed337d47/work" }, "Name": "overlay2"
이 조사를 위해 살펴보고 싶은 레이어는 "LowerDir" 디렉터리 목록입니다. 다른 디렉터리는 Docker 이미지 자체의 일부가 아니므로 무시할 수 있습니다.
따라서 명령줄에서 "LowerDir" 디렉터리 목록을 구문 분석합니다.
where-the@roadmap-ends ~ $ docker inspect example | grep GraphDriver -A7 | grep LowerDir | awk '{print $2}' | sed 's|"||g' | sed 's|,||g' | sed 's|:|\n|g' /var/lib/docker/overlay2/1c18bd289d9c3f9f0850e301bf86955395c312de3a64a70e0d0e6a5bed337d47-init/diff /var/lib/docker/overlay2/wbugwbg23oefsf678r7anbn4f/diff /var/lib/docker/overlay2/j0dekt7y8xgix11n0lturmf8t/diff /var/lib/docker/overlay2/zd57mz6l4zrsjk9snc2crphfq/diff /var/lib/docker/overlay2/83za1pmv9xri44tddzyju0usm/diff /var/lib/docker/overlay2/8c639b22627e0ad91944a70822b442e5bff848968263a37715a293a15483c170/diff
가장 낮은 레이어부터 순서대로 이미지의 레이어 목록입니다. 이제 이러한 레이어 디렉터리를 이를 생성한 Dockerfile 라인과 수동으로 연관시켜야 합니다.
안타깝게도 Docker는 Docker 이미지에서 이러한 줄을 직접 추출하는 방법을 제공하지 않습니다. 이는 docker history
사용하여 얻을 수 있는 최선의 방법입니다.
where-the@roadmap-ends ~ $ docker history where-the-roadmap-ends IMAGE CREATED CREATED BY SIZE COMMENT 6bbac081b2a7 2 hours ago CMD ["/bin/bash"] 0B buildkit.dockerfile.v0 <missing> 2 hours ago RUN /bin/sh -c rm -rf /var/lib/apt/lists/* #… 0B buildkit.dockerfile.v0 <missing> 2 hours ago RUN /bin/sh -c pip3 install numpy # buildkit 70MB buildkit.dockerfile.v0 <missing> 2 hours ago RUN /bin/sh -c apt-get install -y iputils-pi… 343MB buildkit.dockerfile.v0 <missing> 2 hours ago RUN /bin/sh -c apt-get update # buildkit 40.1MB buildkit.dockerfile.v0 <missing> 8 months ago /bin/sh -c #(nop) CMD ["bash"] 0B <missing> 8 months ago /bin/sh -c #(nop) ADD file:550e7da19f5f7cef5… 69.2MB
이 출력을 사용하여 디렉토리가 있는 레이어와 레이어를 생성한 Dockerfile 명령을 식별할 수 있습니다(CREATED BY 열에 표시됨).
docker history
명령은 docker inspect
레이어 디렉터리를 나열하는 것과 동일한 순서로 컨테이너의 레이어를 출력합니다. 이를 알고 있으면 두 출력을 수동으로 병합하여 어떤 레이어가 다른 레이어보다 큰지, 어떤 Dockerfile 명령이 이를 생성했는지, 어떤 디렉터리에 각 레이어가 포함되어 있는지 확인할 수 있습니다.
apt-get update
수행하는 레이어 A의 내용은 다음과 같습니다.
where-the@roadmap-ends ~ $ du -hs /var/lib/docker/overlay2/83za1pmv9xri44tddzyju0usm/diff/var/lib/apt/lists 38.2M /var/lib/docker/overlay2/83za1pmv9xri44tddzyju0usm/diff/var/lib/apt/lists
레이어 B의 콘텐츠와 비교하면 레이어 A에서 남은 파일이 삭제됩니다.
where-the@roadmap-ends ~ $ du -hs /var/lib/docker/overlay2/wbugwbg23oefsf678r7anbn4f/diff/var/lib/apt/lists 4.0K /var/lib/docker/overlay2/wbugwbg23oefsf678r7anbn4f/diff/var/lib/apt/lists
/var/lib/apt/lists
디렉터리는 두 레이어 모두에 존재하지만 레이어 B에서는 디렉터리가 공간을 거의 사용하지 않습니다.
이는 레이어 B의 디렉터리에 Docker가 최종 컨테이너 파일 시스템에서 제외할 파일을 표시하는 데 사용하는 "화이트아웃 파일"이 포함되어 있기 때문입니다.
이로 인해 파일이 레이어 B에서 "삭제"되었음에도 불구하고 레이어 A에는 여전히 존재하므로 이미지의 전체 크기(38.2MB)가 불필요하게 커지게 됩니다.
자, 그게 쉽지 않았나요? 😉
수동 방법은 너무 복잡하고 다루기 힘들기 때문에 오픈 소스 커뮤니티에서는 이 작업을 위해 특별히 제작한 도구인 dive
사용했습니다. Dive는 이미지를 입력으로 사용하고, 파일 시스템을 구문 분석하고, 터미널에 텍스트 기반 대화형 UI를 표시하는 CLI 도구입니다. 이미지 레이어를 상호 연관시켜 레이어 디렉토리를 더 쉽게 검사할 수 있습니다.
위 Dockerfile의 Docker 이미지에 대해 실행하면 다음과 같습니다.
┃ ● Layers ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ Aggregated Layer Contents ├─────────────────────────────────────────────────────────────────────────────── Cmp Size Command └── var 69 MB FROM acee8cf20a197c9 └── lib 40 MB RUN /bin/sh -c apt-get update # buildkit └── apt 343 MB RUN /bin/sh -c apt-get install -y iputils-ping python3 python3-pip # buildkit └── lists 70 MB RUN /bin/sh -c pip3 install numpy # buildkit ├── auxfiles 0 B RUN /bin/sh -c rm -rf /var/lib/apt/lists/* # buildkit ├── lock ├── partial │ Layer Details ├─────────────────────────────────────────────────────────────────────────────────────────── ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-backports_InRelease ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-backports_main_binary-arm64_Packages.lz4 Tags: (unavailable) ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-backports_universe_binary-arm64_Packages.lz4 Id: 2bc27a99fd5750414948211814da00079804292360f8e2d7843589b9e7eb5eee ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-security_InRelease Digest: sha256:6e6fb36e04f3abf90c7c87d52629fe154db4ea9aceab539a794d29bbc0919100 ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-security_main_binary-arm64_Packages.lz4 Command: ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-security_multiverse_binary-arm64_Packages.lz4 RUN /bin/sh -c apt-get update # buildkit ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-security_restricted_binary-arm64_Packages.lz4 ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-security_universe_binary-arm64_Packages.lz4 │ Image Details ├─────────────────────────────────────────────────────────────────────────────────────────── ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-updates_InRelease ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-updates_main_binary-arm64_Packages.lz4 Image name: where-the-roadmap-ends ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-updates_multiverse_binary-arm64_Packages.lz4 Total Image size: 522 MB ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-updates_restricted_binary-arm64_Packages.lz4 Potential wasted space: 62 MB ├── ports.ubuntu.com_ubuntu-ports_dists_jammy-updates_universe_binary-arm64_Packages.lz4 Image efficiency score: 90 % ├── ports.ubuntu.com_ubuntu-ports_dists_jammy_InRelease ├── ports.ubuntu.com_ubuntu-ports_dists_jammy_main_binary-arm64_Packages.lz4 Count Total Space Path ├── ports.ubuntu.com_ubuntu-ports_dists_jammy_multiverse_binary-arm64_Packages.lz4 2 28 MB /var/lib/apt/lists/ports.ubuntu.com_ubuntu-ports_dists_jammy_universe_binary-arm64_Pack ├── ports.ubuntu.com_ubuntu-ports_dists_jammy_restricted_binary-arm64_Packages.lz4 2 7.3 MB /usr/bin/perl └── ports.ubuntu.com_ubuntu-ports_dists_jammy_universe_binary-arm64_Packages.lz4 2 4.4 MB /usr/lib/aarch64-linux-gnu/libstdc++.so.6.0.30 2 2.9 MB /var/lib/apt/lists/ports.ubuntu.com_ubuntu-ports_dists_jammy_main_binary-arm64_Packages 2 2.0 MB /var/lib/apt/lists/ports.ubuntu.com_ubuntu-ports_dists_jammy-updates_main_binary-arm64_ 2 1.7 MB /var/lib/apt/lists/ports.ubuntu.com_ubuntu-ports_dists_jammy-updates_universe_binary-ar
다이빙은 훌륭한 도구이며 그것이 존재해서 기쁘지만 때로는 부족할 때도 있습니다. 텍스트 기반 인터페이스는 사용하기 가장 쉽지 않습니다. 때로는 Grafana가 top
보다 더 좋을 때도 있습니다.
또한 큰 이미지는 Dive의 기능을 압도할 수 있습니다. 큰 이미지를 검사할 때 Dive는 많은 메모리를 소비합니다. 때로는 커널이 데이터를 출력하기 전에 Dive 프로세스를 종료합니다.
개발자의 관점에서 Docker 이미지 계층 시각화가 Docker Hub에 존재할 것으로 기대하는 것은 항상 합리적입니다. 결국 Docker 이미지 데이터는 이미 Docker Hub의 백엔드에 있습니다.
나는 종종 다음과 같은 UI를 사용하여 브라우저에서 Docker 이미지 내부를 검사하는 것을 상상해 왔습니다.
Docker Scout를 통해 Docker는 회사로서 그 방향으로 나아가고 있는 것으로 보입니다. 오늘 Docker Hub에서 최신 Postgres 이미지로 이동하면 다음과 같은 메시지가 표시됩니다.
개발자로서 이는 매우 흥미로운 일입니다. 이 새로운 UI를 사용하면 이미지 레이어 세부 정보를 시각적으로 탐색하고 원하는 대로 취약점과 이미지 크기 문제를 강조할 수 있습니다.
Docker Hub가 처음 출시되었을 때 두 가지 유형의 사용자가 있었습니다.
그리고 Docker는 이 두 유형의 사용자에게 다르게 접근해야 했습니다.
2013년 Docker가 출시된 후 개발자들은 즉시 자신의 제품을 사용하고 싶어했습니다. Docker 컨테이너는 모든 사람의 소프트웨어 패키징 및 배포를 표준화합니다. 컨테이너는 소프트웨어 개발자 커뮤니티에서 빠르게 인기를 얻었습니다.
그러나 소프트웨어 게시자는 더 주저했습니다. 소프트웨어 제품 간의 차별화를 제거하는 것이 핵심 유틸리티인 플랫폼에 소프트웨어를 업로드해야 하는 이유는 무엇입니까?
Docker는 Docker Hub를 성공시키기 위해 그들을 이겨야 했습니다. 따라서 개발자 유치에 초점을 맞추는 대신 Docker Hub의 디자인과 기능 세트는 소프트웨어 게시자에게 맞춰졌습니다.
출판사에게 Docker Hub는 마케팅 사이트였습니다. 그것은 그들에게 그들의 제품을 광고할 수 있는 장소를 제공했습니다. 자동차 판매점에서 엔진 블록을 분해할 수 없는 것과 마찬가지로 개발자는 Docker 이미지 내부 세부 정보를 볼 수 없습니다. 내부 엔지니어링 세부 사항은 표시되지 않고 숨겨져 있으므로 쇼핑객은 제품이 어떻게 만들어졌는지가 아니라 제품 자체에 집중할 수 있습니다.
Docker Hub에는 이미지 크기 최적화 및 공급망 자체 검사를 위한 개발자용 기능이 부족했습니다. Docker는 이미 이러한 기능이 없는 개발자를 압도했기 때문입니다. 실제로 이러한 기능은 소프트웨어 게시자를 나쁘게 만드는 경향이 있으며 Docker Hub가 성공하려면 여전히 승리해야 하는 사용자였습니다.
소프트웨어 게시자와 개발자 모두에게 서비스를 제공하는 이러한 역동성은 Docker Hub를 양면 플랫폼으로 만들었습니다.
양면 플랫폼은 서로 다른 두 범주의 사용자를 보유하고 있으며 작업을 수행하려면 두 사용자 모두 플랫폼에 참여해야 하는 비즈니스입니다. 일반적으로 사용자를 여러 그룹으로 나누는 것은 플랫폼을 사용하려는 동기입니다.
두 그룹의 사용자가 서로 직접 거래하지 않을 수도 있지만 양면 플랫폼은 시장과 같습니다. 판매자가 판매하러 나타나고 쇼핑객이 구매하러 나타나지 않는 한 가치를 창출하지 않습니다.
기술 산업에서는 양면 플랫폼이 어디에나 존재합니다. 성공할 경우 이러한 비즈니스 모델은 비즈니스의 지속적인 성장과 수익성을 촉진하는 네트워크 효과를 생성하는 경향이 있습니다. 특정 시점 이후에는 플랫폼의 규모와 공간 내 확고한 위치가 새로운 사용자를 플랫폼으로 끌어들이게 됩니다.
찾고 있는 것이 무엇인지 알게 되면 양면 플랫폼을 쉽게 찾을 수 있습니다. 다음은 세 가지 예입니다.
LinkedIn에는 직원과 채용 관리자라는 두 가지 유형의 사용자가 있습니다. 두 그룹 모두 서로 다른 이유로 참여합니다. 직원은 일자리를 원하고 채용 관리자는 사람을 고용하기를 원합니다.
두 그룹 모두 다른 그룹이 참여하기 시작할 때까지 사이트에서 원하는 것을 얻을 수 없었습니다. 충분한 수의 각 그룹이 가입하면 이 사이트는 두 그룹의 새 구성원을 위한 기본 장소가 되었고 사이트의 성장은 계속해서 Microsoft 에 260억 달러에 인수되었습니다.
유튜브 에는 콘텐츠 창작자가 있고 시청자가 있습니다. 시청자는 비디오를 보기 위해 사이트를 방문합니다. 콘텐츠 제작자는 좋은 분위기, 명성 및 부를 추구하기 위해 사이트에 게시합니다.
유튜브가 콘텐츠 크리에이터가 성공할 수 있는 곳으로 명성을 얻은 이후 점점 더 많은 콘텐츠 크리에이터가 등장했고, 콘텐츠가 많아질수록 찾아오는 시청자도 늘어났습니다. 플랫폼이 일정 규모 이상으로 성장하면 콘텐츠 제작자와 시청자는 이를 계속 사용할 수밖에 없었습니다. 각 그룹은 서로가 필요했고 YouTube를 통해서만 서로를 찾을 수 있었습니다.
Docker Hub가 관련성을 가지려면 소프트웨어 게시자가 이미지를 업로드하고 개발자가 이미지를 다운로드해야 했습니다. 충분한 게시자가 Docker Hub에 이미지를 푸시하면 개발자가 이미지를 가져올 수 있는 기본 장소가 됩니다. 플랫폼이 계속 성장함에 따라 Docker Hub는 모든 것을 지배하는 단일 레지스트리로서의 지배력을 확고히 할 것입니다.
적어도 그것은 계획이었습니다. 실제로 Docker(회사)는 거절했고 Docker Hub는 결코 "하나"가 되지 못했습니다. 양면 플랫폼을 구축할 때 스타트업은 하나의 제품을 가지지만 제품 시장 적합성을 두 번 찾아야 합니다. Docker의 경우 이러한 부담이 너무 커서 결국 Docker를 반으로 나누었습니다 .
이제 Docker는 엔터프라이즈 비즈니스를 매각한 후 개발자와 고용주에게만 구독 서비스를 집중하는 방식으로 재창조되었습니다. Docker Hub는 더 이상 양면 플랫폼이 아니라 단순한 SaaS입니다. 고객은 이미지를 푸시하고 가져오는 대가로 월별 요금을 지불합니다.
이것은 미적분학을 변경합니다. Docker가 만족할 수 있는 "게시자" 사용자 페르소나는 더 이상 존재하지 않습니다. 그들은 모두 개발자에게만 집중되어 있습니다. Docker Hub의 경우 이는 Docker Scout의 이미지 레이어 검사 기능을 위한 기반을 마련합니다. 멀리서 지켜보는 사람들에게 이는 스타트업의 비즈니스 모델과 제품 제공 사이의 미묘하고 근본적인 결합을 보여줍니다.