Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як перевірити метадані Docker image?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Три команди покривають майже все:** `docker inspect <image>` для повних JSON-метаданих, `docker history <image>` для layer-by-layer breakdown, `dive <image>` для інтерактивного layer-exploration. ```bash docker inspect nginx:1.27 --format '{{.Config.Cmd}} {{.Architecture}} {{.Size}}' docker history nginx:1.27 docker manifest inspect nginx:1.27 | jq . ``` **Головне:** `inspect` показує, що image робитиме при запуску (CMD, ENV, EXPOSE, USER, шари). `history` показує, як його зібрано. `dive` показує, що у кожному шарі інтерактивно.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Inspect Docker image-метаданих** це те, що ти робиш перед pull, після pull, при дебагу «чому image виріс?» або коли хочеш точно знати, що image обіцяє робити у runtime. Три CLI-tools покривають територію. ## Теорія ### TL;DR - **`docker inspect`** = повний JSON-dump config image, шарів, labels, архітектури, розміру. - **`docker history`** = хронологічний список шарів з інструкцією, що створила кожен. - **`docker manifest inspect`** = registry-level manifest (multi-arch info, layer-digests). - **`dive`** (third-party) = інтерактивний TUI, що показує layer-by-layer file-зміни. - Усі працюють локально; деякі проти remote-image через registry. ### `docker inspect` Головна команда. Повертає 100+ рядковий JSON. Бери `--format`, щоб витягати конкретні поля: ```bash # Усе (багато) docker inspect nginx:1.27 # Конкретні поля docker inspect nginx:1.27 --format '{{.Id}}' docker inspect nginx:1.27 --format '{{.Architecture}}' docker inspect nginx:1.27 --format '{{.Size}}' docker inspect nginx:1.27 --format '{{.Config.Cmd}}' docker inspect nginx:1.27 --format '{{.Config.Entrypoint}}' docker inspect nginx:1.27 --format '{{.Config.User}}' docker inspect nginx:1.27 --format '{{.Config.WorkingDir}}' # JSON секції docker inspect nginx:1.27 --format '{{json .Config.Env}}' | jq docker inspect nginx:1.27 --format '{{json .Config.ExposedPorts}}' | jq docker inspect nginx:1.27 --format '{{json .Config.Labels}}' | jq ``` Зручні поля: - `.Id` — content-digest image - `.RepoTags` — tag, що вказують на цей image - `.RepoDigests` — digest-посилання у registry - `.Architecture`, `.Os` — цільова платформа (`amd64`/`linux`) - `.Size` — загальний розмір (у байтах) - `.Created` — коли image зібрано - `.Config.*` — runtime-config (Cmd, Entrypoint, Env, Labels, ExposedPorts, User, WorkingDir, Volumes, Healthcheck) - `.RootFS.Layers` — список digest шарів (у порядку) - `.History` — build-історія (Dockerfile-еквівалентні кроки) ### `docker history` Показує шари з найстарішого (низ) до найновішого (верх) з інструкцією, що створила кожен: ```bash $ docker history nginx:1.27-alpine IMAGE CREATED CREATED BY SIZE COMMENT 4f06b3e2c0c1 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemo… 0B <missing> 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B <missing> 2 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B <missing> 2 weeks ago /bin/sh -c set -x && addgroup -g 101 -S… 8.94MB <missing> 2 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.27.4 0B <missing> 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:abcd1234… 7.79MB ``` Бери `--no-trunc` для повних інструкцій: ```bash docker history --no-trunc nginx:1.27-alpine ``` `<missing>` означає, що проміжний image не має окремого ID локально, лише фінальний. Інструкції все одно зберігаються у метаданих. ### `docker manifest inspect` Показує registry-side manifest, включно з multi-arch info: ```bash $ docker manifest inspect nginx:1.27 { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "digest": "sha256:abc123...", "platform": { "architecture": "amd64", "os": "linux" } }, { "digest": "sha256:def456...", "platform": { "architecture": "arm64", "os": "linux" } }, ... ] } ``` Корисно для підтвердження, що image підтримує твою архітектуру перед pull, або для пошуку digest конкретної платформи. ### `dive` (third-party) Не вбудовано у Docker, але стандартний tool для розуміння вмісту шарів: ```bash $ dive nginx:1.27-alpine ``` Відкриває інтерактивний TUI: - Верхня панель: шари з розміром і командою. - Нижня панель: file-tree обраного шару (з diff від попереднього). - Права панель: image-деталі (efficiency-score, wasted space). Неоціненно для «чому image 2 GB?», бачиш точні файли, що дав кожен шар. ### Корисні патерни #### «Який CMD запуститься?» ```bash docker inspect <img> --format '{{.Config.Entrypoint}} {{.Config.Cmd}}' ``` #### «Які env-змінні запечено?» ```bash docker inspect <img> --format '{{json .Config.Env}}' | jq ``` #### «На яких портах image слухає?» ```bash docker inspect <img> --format '{{json .Config.ExposedPorts}}' | jq ``` #### «Як який користувач container крутиться?» ```bash docker inspect <img> --format '{{.Config.User}}' # порожньо = root (обережно) ``` #### «Знайти найбільший шар» ```bash docker history --format '{{.Size}}\t{{.CreatedBy}}' --no-trunc <img> | sort -h ``` #### «Який content-digest?» ```bash docker inspect <img> --format '{{index .RepoDigests 0}}' # myimg@sha256:abc123... ``` Незмінний ідентифікатор, бери це у прод-manifest замість мінливих tag. ### Типові помилки **Плутати `docker inspect` для image vs container** ```bash docker inspect myimg # працює на image docker inspect mycontainer # працює на container # Та сама команда, різні об'єкти → різні поля доступні ``` Schema відрізняється. Container `inspect` включає `.State` (running/exited), `.NetworkSettings`, `.Mounts`. Image `inspect` ні. **Читати `<missing>` як помилку** `<missing>` у `docker history` означає, що проміжний layer-ID не зберігається локально. Image все одно працює; це просто артефакт того, як Docker squashes-проміжні метадані. Не проблема. **Забути, що history показує DOCKERFILE-КРОКИ, не вміст файлів** ``` /bin/sh -c apt-get update && apt-get install ... && rm -rf /var/lib/apt/lists/* ``` Це каже, що build робив, не що файли потрапили куди. Для файлів бери `dive` або `docker save` + tar-inspect. **Inspect image, що не pull'нув** Локальний `docker inspect` потребує image у локальному кеші. Для remote-image: спочатку `docker pull` або бери `docker manifest inspect` (працює проти registry). ### Реальне застосування - **Pre-deploy верифікація:** `docker inspect`, щоб підтвердити, що CMD, USER, EXPOSE відповідають очікуванням перед promote. - **Compliance-аудит:** scan усіх прод-image на OCI-labels, expected user, no root. - **Image-size розслідування:** `dive` і `docker history`, щоб знайти найбільші шари. - **Multi-arch верифікація:** `docker manifest inspect`, щоб переконатися, що твій image має варіанти amd64 і arm64 перед деплоєм у змішаних кластерах. - **Відтворення білдів:** `docker history` показує build-команди; cross-reference з source Dockerfile. ### Питання для поглиблення **Q:** Яка різниця між `Id` і `RepoDigest`? **A:** `Id` це локальний image-ID, hash config-blob. `RepoDigest` це registry-side digest (hash manifest, використовується у pull-by-digest). Відрізняються, бо manifest-hash включає tag/registry-info, а локальний ID лише content. **Q:** Як побачити, що у конкретному шарі? **A:** `dive` найпростіше. Руками: `docker save <img> -o img.tar && tar xf img.tar` дає директорію на шар з вмістом. **Q:** Чи можу inspect image running-container? **A:** `docker inspect <container> --format '{{.Image}}'` повертає image-ID; передай його у `docker inspect` для image-метаданих. **Q:** Яка різниця між `docker inspect` і `docker image inspect`? **A:** `docker inspect` загальний (працює на image, container, volume, мережах). `docker image inspect` явна форма лише для image. Той самий output для image. **Q:** (Senior) Як написати CI-перевірку, що падає, якщо image має погані метадані? **A:** Малий скрипт, що крутить `docker inspect` і `docker history`, парсить через `jq` і assert: (1) `Config.User` не порожній (без root-container), (2) обов'язкові OCI-labels present (`org.opencontainers.image.source`, `version`), (3) без `latest`-tag у `Config.Image`, (4) загальний `Size` під порогом, (5) layer-count нижче max. Прив'яжи це у CI як gate; завали pipeline, якщо assertion ламається. Сильніша версія використовує `dive --ci`, що перевіряє image-efficiency-score автоматично. ## Приклади ### Швидкий image-аудит ```bash $ IMG=nginx:1.27-alpine $ docker inspect $IMG --format \ 'Id={{.Id}} Arch={{.Architecture}} OS={{.Os}} Size={{.Size}} User={{.Config.User}} Cmd={{.Config.Cmd}}' Id=sha256:4f06b3e2c0c1... Arch=amd64 OS=linux Size=54923456 User= Cmd=[nginx -g daemon off;] $ docker history --format 'table {{.Size}}\t{{.CreatedBy}}' --no-trunc $IMG | head SIZE CREATED BY 0B /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon off;"] 0B /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B /bin/sh -c #(nop) EXPOSE 80 8.94MB /bin/sh -c set -x && addgroup -g 101 -S nginx ... 0B /bin/sh -c #(nop) ENV NGINX_VERSION=1.27.4 0B /bin/sh -c #(nop) CMD ["/bin/sh"] 7.79MB /bin/sh -c #(nop) ADD file:abcd... ``` Чотири факти на одному погляді плюс layer-breakdown. ### Manifest-inspect для multi-arch ```bash $ docker manifest inspect nginx:1.27 | \ jq '.manifests[] | {arch: .platform.architecture, digest: .digest}' { "arch": "amd64", "digest": "sha256:abc..." } { "arch": "arm64", "digest": "sha256:def..." } { "arch": "arm/v7", "digest": "sha256:ghi..." } { "arch": "386", "digest": "sha256:jkl..." } ``` Підтверджує, які платформи image підтримує і дає per-platform digests для пінінгу. ### Знайти найбільший шар ```bash $ docker history --format '{{.Size}}|{{.CreatedBy}}' --no-trunc node:22-alpine \ | grep -v '^0B|' \ | sort -h \ | tail -5 47.2MB|/bin/sh -c apk add --no-cache python3 ... 42.5MB|/bin/sh -c addgroup -g 1000 node ... 105MB|/bin/sh -c set -ex; ... npm install ``` Найбільший контрибутор (тут `npm install`) це твоя перша мета, якщо треба зменшити image.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.