Вивчення файлової системи контейнера Docker


651

Я помітив за допомогою docker, що мені потрібно зрозуміти, що відбувається всередині контейнера або які файли там є. Один із прикладів - завантаження зображень з індексу докера - у вас немає поняття, що містить зображення, тому неможливо запустити програму.

Що було б ідеально - це вміти врізатися в них або подібних до них. Чи є інструмент для цього чи моя концептуалізація докера неправильна в думці, я повинен бути в змозі це зробити.


13
В останніх версіях Докер, що - то , як це можливо: docker exec <container> bash. Отже, ви просто відкриєте оболонку всередині контейнера.
— dashohoxha

7
запуск bash на контейнері працює лише в тому випадку, якщо bash встановлений всередині контейнера
— Christopher Thomas

7
Аналогічно можна зробити: docker exec <container> ls <dir path>і docker exec <container> cat <file path>. Для bash, однак, додайте -itпараметри.
— Ноам Манос

Схожий питання: stackoverflow.com/questions/44769315 / ...
— Vadzim

3
@ChristopherThomas, точно. Через це я виявив, що єдиний надійний спосіб зробити це, docker image save image_name > image.tarяк зазначено у відповіді від @ Gaurav24.
— Хайме Хаблуцель

Відповіді:


736

ОНОВЛЕННЯ
Найпростіший метод: Використання docker exec

Docker версії 1.3 або новішої підтримує команду, execяка поводиться аналогічно nsenter. Ця команда може запустити новий процес у вже запущеному контейнері (у контейнері вже повинен бути запущений процес PID 1). Ви можете запустити /bin/bashдля вивчення стану контейнера:

docker exec -t -i mycontainer /bin/bash

див. документацію до командного рядка Docker

Альтернативний метод 1
Знімок

Ви можете оцінити файлову систему контейнера таким чином:

# find ID of your running container:
docker ps

# create image (snapshot) from container filesystem
docker commit 12345678904b5 mysnapshot

# explore this filesystem using bash (for example)
docker run -t -i mysnapshot /bin/bash

Таким чином, ви можете оцінити файлову систему запущеного контейнера в точний момент часу. Контейнер все ще запущений, майбутні зміни не включаються.

Пізніше ви можете видалити знімок за допомогою (файлова система запущеного контейнера не впливає!):

docker rmi mysnapshot

Альтернативний метод 2
сш

Якщо вам потрібен постійний доступ, ви можете встановити sshd у свій контейнер і запустити демон sshd:

 docker run -d -p 22 mysnapshot /usr/sbin/sshd -D

 # you need to find out which port to connect:
 docker ps

Таким чином, ви можете запустити свою програму за допомогою ssh (підключіть та виконайте те, що ви хочете).

ОНОВЛЕННЯ: Альтернативний метод 3
нецензури

Використовуйте nsenterдивіться https://web.archive.org/web/20160305150559/http://blog.docker.com/2014/06/why-you-dont-need-to-run-sshd-in-docker/

Коротка версія: за допомогою nsenter ви можете отримати оболонку в існуючий контейнер, навіть якщо в цьому контейнері не працює SSH або будь-який демон спеціального призначення


6
але зверніть увагу, якщо вам потрібен доступ до файлів, використовуйте команду "docker cp" Використання: docker cp КОНТЕЙНЕР: PATH HOSTPATH ​​Скопіюйте файли / папки з файлової системи контейнерів на шлях хосту. Шляхи відносно кореня файлової системи. #> docker cp 7bb0e258aefe: / etc / debian_version. #> docker cp blue_frog: / etc / hosts.
— Амос Фоларін

4
Варіант 4 настільки важливий, що його слід перемістити до верху та перейменувати Option 1.
— automorphic

5
@JanusTroelsen Якщо немає оболонки, ви можете встановити її - наприклад, в dockerfile для альпійського Linux (у якого справді немає оболонки) за RUN apk update && apk add bash
— Kamil Kiełczewski

2
на моєму власному досвіді обмеження у Docker exec полягає в тому, що команду потрібно додати до запущеного контейнера або як певної точки входу. Отже, зупинений контейнер виходить за межі цього методу.
— Веб-жінка

1
Для використання linux-оболонки Windowdocker exec -t -i mycontainer /bin/sh
— Jason Masters

266

ОНОВЛЕННЯ: ДОСЛІДЖЕННЯ!

Ця команда повинна дозволити вивчити запущений контейнер докера :

docker exec -it name-of-container bash

Еквівалентом цього в docker-compose було б:

docker-compose exec web bash

(web - це ім'я служби в цьому випадку, і він має tty за замовчуванням.)

Коли ви всередині, зробіть:

ls -lsa

або будь-яка інша команда bash, наприклад:

cd ..

Ця команда повинна дозволити вивчити зображення докера :

docker run --rm -it --entrypoint=/bin/bash name-of-image

як тільки всередині:

ls -lsa

або будь-яка інша команда bash, наприклад:

cd ..

-itЧи означає інтерактивний ... і термінал.


Ця команда повинна дозволити вам перевірити запущений контейнер або зображення докера :

docker inspect name-of-container-or-image

Ви можете зробити це і дізнатись, чи є там bashчи shтам. Шукайте точку входу або cmd у поверненні json.

дивіться документацію докер-виконавця

перегляньте документацію на виконання докер-композиції

див. документацію для перевірки докерів


1
Це надзвичайно корисно, дякую! Мені потрібно перетягнути файл, який міститься в структурі файлів зображення докер-файлу, у додаток, але це неможливо, якщо він не буде відкритий у форматі GUI. Будь-яка ідея, як я міг обійти це?
— Arkya Chatterjee

2
Це повинно бути досить очевидним, що це буде працювати тільки на контейнері, на якому встановлений bash.
— програмний інженер

2
Для всіх, хто дивиться на те, як це зробити на Windows Container / Powershell, команда docker exec -ti <name> powershell( джерело )
— ssell

1
@ssell мій контейнер / зображення чомусь не було повноважень, тому це docker exec -ti <name> cmdспрацювало. А для інших новачків, як я, обов'язково використовуйте ім'я екземпляра контейнера docker ps(щось на зразок 070494393ca5), а не читабельне ім'я, яке ви призначили.
— Simon_Weaver

1
відносно повноважень у зображеннях github.com/aspnet/aspnet-docker/isissue/362 - і якщо вам потрібен лише завиток на зображеннях Windows: blogs.technet.microsoft.com/virtualization/2017/12/19/…
— Simon_Weaver

162

У випадку, якщо ваш контейнер зупинений або не має оболонки (наприклад, hello-worldзгадується в посібнику з встановлення , або не alpine traefik), це, мабуть, єдиний можливий метод дослідження файлової системи.

Ви можете архівувати файлову систему вашого контейнера у файл tar:

docker export adoring_kowalevski > contents.tar

Або перерахуйте файли:

docker export adoring_kowalevski | tar t

Зауважте, що залежно від зображення, це може зайняти деякий час і диск на диску.


12
Я просто хотів перерахувати вміст контейнера, на якому не встановлено стандартних інструментів UNIX. Варіант exportприкладу вище потрапив на місце:docker export adoring_kowalevski | tar tf -
— Берто

3
Попередження для необережних: це може експортувати багато даних (> ГБ) і зайняти багато часу.
— Вінс Боудрен

5
@berto не те, що це велика річ, але вам не потрібно f -в кінці вашої команди, tar за замовчуванням читає зі стандартного вводу. Просто docker export adoring_kowalevski | tar tпрацює.
— Shaun Bouckaert

Чим простіше, тим краще; приголомшливий, дякую за пораду! 🙌🏽
— Берто

1
@ShaunBouckaert за замовчуванням tar fзалежить від конфігурації. Одна частина - це TAPEзмінна середовище. Інші контролюються як частина збірки. Чистий ефект полягає в тому, що ніколи не слід вважати, що він читає stdin або пише stdout, а завжди чітко заявляє про це.
— roaima

42

Файлова система контейнера знаходиться в папці даних докера, як правило, в / var / lib / docker. Для запуску та перевірки працюючої файлової системи контейнерів виконайте наступне:

hash=$(docker run busybox)
cd /var/lib/docker/aufs/mnt/$hash

І тепер поточний робочий каталог є коренем контейнера.


3
це не буде включати жодних змонтованих томів.
— hwjp

34

Перед створенням контейнера:

Якщо ви вивчите структуру зображення, встановленого всередині контейнера, ви можете це зробити

sudo docker image save image_name > image.tar
tar -xvf image.tar

Це дасть вам видимість усіх шарів зображення та його конфігурації, яка присутня у файлах json.

Після створення контейнера:

На це вище вже є багато відповідей. мій кращий спосіб зробити це -

docker exec -t -i container /bin/bash


Тут слід зазначити, що запуск bash всередині контейнера працює лише в тому випадку, якщо ви робите це на машині з тією ж архітектурою, що і зображення. Якщо ви працюєте на ПК, намагаючись зазирнути у файлову систему зображень малинового пі, трюк bash не спрацює.
— Максим Кулкін

@MaximKulkin Дійсно? Якщо контейнер Linux, це не має значення, що хост, якщо bash доступний. Можливо, ви думаєте про контейнери Windows?
— Thorbjørn Ravn Andersen

26

Найбільш актуальна відповідь працює для мене, коли контейнер насправді запущений, але коли неможливо запустити, і ви, наприклад, хочете скопіювати файли з контейнера, це врятувало мене раніше:

docker cp <container-name>:<path/inside/container> <path/on/host/>

Завдяки docker cp ( посилання ) ви можете скопіювати безпосередньо з контейнера, як це була будь-яка інша частина вашої файлової системи. Наприклад, відновлення всіх файлів всередині контейнера:

mkdir /tmp/container_temp
docker cp example_container:/ /tmp/container_temp/

Зауважте, що вам не потрібно вказувати, що потрібно копіювати рекурсивно.


6
чому цього більше немає +1! безумовно найкращий спосіб
— Ніколас ДіПіаца

Це навіть простіше, ніж експорт за допомогою дьогтю. Мені довелося використовувати -L, щоб дістатися до файлів за допомогою посилань. Не потрібно запускати контейнер!
— MKaama

17

У Ubuntu 14.04 під керуванням Docker 1.3.1 я знайшов кореневу файлову систему контейнера на хост-машині в наступному каталозі:

/var/lib/docker/devicemapper/mnt/<container id>/rootfs/

Повна інформація про версію Докера:

Client version: 1.3.1
Client API version: 1.15
Go version (client): go1.3.3
Git commit (client): 4e9bbfa
OS/Arch (client): linux/amd64
Server version: 1.3.1
Server API version: 1.15
Go version (server): go1.3.3
Git commit (server): 4e9bbfa

Працює як шарм: name = <ім'я> dockerId = $ (docker inspect -f {{.Id}} $ name) / var / lib / docker / devicemapper / mnt / $ dockerId / rootfs /
— Florent

3
З Ubuntu 16.10 та docker 1.12.1, на жаль, це вже не так (немає devicemapperкаталогу). Файл існує під /var/lib/docker/overlay/<a sha256 apparently/<upper or merged>/.... Я не впевнений, наскільки портативний / безпечний доступ до файлів там
— WoJ

1
Починаючи з 1.10, Docker представив нову модель зберігання, адресовану вмістом, яка не використовує випадково створений UUID, як це було раніше для ідентифікаторів шару та контейнерів. У новій моделі це замінено захищеним хешем вмісту для ідентифікатора шару. Тож цей метод більше не буде працювати.
— Артем Долобанко

Це не портативно і значною мірою залежить від вибору драйвера зберігання . Не впевнений, чи працює рішення, direct-lvmнаприклад.
— rustyx

14

Спробуйте використовувати

docker exec -it <container-name> /bin/bash

Можливо, існує можливість, що bash не буде реалізований. для цього ви можете скористатися

docker exec -it <container-name> sh

12

Я використовую ще один брудний трюк - це aufs / devicemapper agnostic.

Я дивлюсь на команду про те, що контейнер працює, наприклад, docker ps і якщо це apache або javaя просто виконую наступні дії:

sudo -s
cd /proc/$(pgrep java)/root/

і voilá ти всередині контейнера.

В основному ви можете як root CD в /proc/<PID>/root/папку, поки цей процес запускається контейнером. Обережно, що посилання на цей режим не матимуть сенсу підступно.


Додаткова інформація про цей метод тут: superuser.com/a/1288058/195840
— Eduardo Lucio

12

Відповідь, яка найбільше голосує, хороша за винятком випадків, якщо ваш контейнер не є фактичною системою Linux.

У багатьох контейнерах (особливо на базі даних) немає стандартних бінарних файлів (немає /bin/bashабо /bin/sh). У цьому випадку вам потрібно буде отримати доступ до фактичного файлу контейнерів безпосередньо:

Працює як шарм:

name=<name>
dockerId=$(docker inspect -f {{.Id}} $name)
mountId=$(cat /var/lib/docker/image/aufs/layerdb/mounts/$dockerId/mount-id)
cd /var/lib/docker/aufs/mnt/$mountId

Примітка. Вам потрібно запустити його як root.


Це більше не працює. Папки devicemapper немає.
— 0xcaff

Було б добре, якби люди з застарілими відповідями очистили їх
— Меттью Пердон

2
Я оновив команду, щоб відповідати новій структурі зберігання докера.
— Флорент

10

У моєму випадку жодна оболонка не підтримувалася, крім sh. Отже, це спрацювало як шарм

docker exec -it <container-name> sh


5

Це запустить сеанс bash для зображення:

docker run --rm -it --entrypoint = / bin / bash


1
це корисно для тих випадків, коли точка вводу за замовчуванням не запускається
— проаналізуйте

4

Для мене це добре працює (завдяки останнім коментарям до вказівки на каталог / var / lib / docker / ):

chroot /var/lib/docker/containers/2465790aa2c4*/root/

Тут 2465790aa2c4 - короткий ідентифікатор запущеного контейнера (як показано докерним ps ), за яким слід зірка.


4

У нових версіях Docker ви можете запустити, docker exec [container_name]який запускає оболонку всередині вашого контейнера

Отже, щоб отримати список усіх файлів у контейнері, просто запустіть docker exec [container_name] ls


1
Я спробував це, і це не вийшло. Пропозиція Халила Гарбауї вище спрацювала.
— Нік

Це працювало для мене. Ви також можете спробувати ідентифікатор контейнера замість назви зображення
— Diwann

4

Для драйвера aucker aufs:

Сценарій знайде кореневу діру контейнера (Тест на докер 1.7.1 та 1.10.3)

if [ -z "$1" ] ; then
 echo 'docker-find-root $container_id_or_name '
 exit 1
fi
CID=$(docker inspect   --format {{.Id}} $1)
if [ -n "$CID" ] ; then
    if [ -f  /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id ] ; then
        F1=$(cat /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id)
       d1=/var/lib/docker/aufs/mnt/$F1
    fi
    if [ ! -d "$d1" ] ; then
        d1=/var/lib/docker/aufs/diff/$CID
    fi
    echo $d1
fi

4

Жодна з існуючих відповідей не стосується випадку контейнера, який вийшов (і не може бути перезапущений) та / або не має встановленої оболонки (наприклад, безвідмовної). Цей працює, поки у вас є кореневий доступ до хоста Docker.

Для справжнього ручного огляду спочатку з’ясуйте ідентифікатори шару:

docker inspect my-container | jq '.[0].GraphDriver.Data'

У висновку ви повинні побачити щось подібне

"MergedDir": "/var/lib/docker/overlay2/03e8df748fab9526594cfdd0b6cf9f4b5160197e98fe580df0d36f19830308d9/merged"

Перейдіть у цю папку (як root), щоб знайти поточний видимий стан файлової системи контейнера.


3

Ця відповідь допоможе тим (як я), які хочуть дослідити файлову систему тома докера, навіть якщо контейнер не працює.

Перерахуйте запущені контейнери докера:

docker ps

=> ІД КОНТЕЙНЕР "4c721f1985bd"

Погляньте на точки кріплення гучності докера на локальній фізичній машині ( https://docs.docker.com/engine/tutorials/dockervolumes/ ):

docker inspect -f {{.Mounts}} 4c721f1985bd

=> [{/ tmp / container-garren / tmp true rprivate}]

Це говорить мені про те, що каталог локальної фізичної машини / tmp / контейнер-гаррен відображається в пункт призначення тома докера / tmp.

Знаючи довідник локальної фізичної машини (/ tmp / container-garren), це означає, що я можу дослідити файлову систему, чи працює контейнер докера чи ні. Це було надзвичайно важливим, щоб допомогти мені зрозуміти, що є деякі залишкові дані, які не повинні зберігатися навіть після того, як контейнер не запускався.


1
Це лише знаходить локальний каталог, який встановлений як об'єм всередині контейнера, але не дозволяє отримати доступ до всієї файлової системи контейнера.
— Bojan Komazec

3

Ще одна хитрість - використовувати атомний інструмент, щоб зробити щось на кшталт:

mkdir -p /path/to/mnt && atomic mount IMAGE /path/to/mnt

Зображення Докера буде встановлено на / path / to / mnt, щоб ви його оглянули.


Але для цього вам потрібно мати спеціально виготовлені контейнери, правда? Можливо, вам слід додати це як застереження, бо більшість людей не зможуть продати його своїй команді / компанії як рішення ...
— Angelos Pikoulas

3

Тільки для LINUX

Найпростішим способом, яким я користуюся, було використання proc dir, який є контейнером, має бути запущений, щоб перевірити файли контейнерів docker.

  1. Дізнайтеся ідентифікатор процесу (PID) контейнера та збережіть у деякій змінній

    PID = $ (докер перевіряє -f '{{.State.Pid}}' your-container-name-here)

  2. Переконайтеся, що процес контейнера запущений, і використовуйте змінну nameto, щоб потрапити в папку контейнера

    cd / proc / $ PID / root

Якщо ви хочете пройти через dir, не дізнавшись номер PID, просто скориставшись цією довгою командою

cd /proc/$(docker inspect -f '{{.State.Pid}}' your-container-name-here)/root

Поради:

Після того, як ви потрапите всередину контейнера, все, що ви зробите, вплине на фактичний процес контейнера, як-от зупинка служби або зміна номера порту.

Сподіваюся, це допомагає

Примітка:

Цей метод працює лише в тому випадку, якщо контейнер все ще працює, інакше каталог більше не існуватиме, якщо контейнер зупинився або видалений


2

Мій кращий спосіб зрозуміти, що відбувається всередині контейнера:

  1. виставити -p 8000

    docker run -it -p 8000:8000 image
    
  2. Запустіть сервер всередині нього

    python -m SimpleHTTPServer
    

2

Для вже запущеного контейнера ви можете:

dockerId=$(docker inspect -f {{.Id}} [docker_id_or_name])

cd /var/lib/docker/btrfs/subvolumes/$dockerId

Потрібно мати корінь для того, щоб вступити в цей dir. Якщо ви не root, спробуйте 'sudo su' перед запуском команди.

Редагувати: Після версії 1.3 перегляньте відповідь Джирі - краще.


4
Я сильно частковий до "sudo -i", а не до "sudo su", тому що мало підстав запускати програму suid, яка запускає іншу програму suid, яка запускає оболонку. Виріжте середнього чоловіка. :)
— dannysauer

Ваша відповідь дуже хороша, тільки шлях не є. Ви повинні використовувати шлях piercebot.
— Флорент

2

Якщо ви використовуєте Docker v19.03, виконайте наведені нижче дії.

# find ID of your running container:

  docker ps

# create image (snapshot) from container filesystem

  docker commit 12345678904b5 mysnapshot

# explore this filesystem 

  docker run -t -i mysnapshot /bin/sh

1

Якщо ви використовуєте драйвер зберігання AUFS, ви можете використовувати мій докер-шар сценарій щоб знайти корінь файлової системи будь-якого контейнера (mnt) та шар перезапису:

# docker-layer musing_wiles
rw layer : /var/lib/docker/aufs/diff/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03f
mnt      : /var/lib/docker/aufs/mnt/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03f

Редагувати 2018-03-28: Докер
-шар замінено докер-резервним


1

docker execКоманди для запуску команди в робочому контейнері може допомогти в декількох випадках.

Використання: docker exec [ВАРІАНТИ] CONTAINER COMMAND [ARG ...]

Виконайте команду в запущеному контейнері

Параметри:
  -d, --встановити окремий режим: запустити команду у фоновому режимі
      --detach-рядок-ключі Заміняє послідовність клавіш для від'єднання a
                             контейнер
  -e, --env list Встановити змінні середовища
  -i, - інтерактивне Тримайте STDIN відкритим, навіть якщо він не встановлений
      --privileged Дайте розширені привілеї команді
  -t, --tty Виділіть псевдо-TTY
  -u, - рядоккористувача Ім'я користувача або UID (формат:
                             [:])
  -w, --workdir string Робочий каталог всередині контейнера

Наприклад :

1) Доступ в bash до запущеної файлової системи контейнера:

docker exec -it containerId bash 

2) Доступ в bash до запущеної файлової системи контейнерів як root, щоб мати необхідні права:

docker exec -it -u root containerId bash  

Це особливо корисно, щоб можна було виконати деяку обробку як корінь у контейнері.

3) Доступ в bash до запущеної файлової системи контейнерів із певним робочим каталогом:

docker exec -it -w /var/lib containerId bash 

0

Ви можете запустити bash всередині контейнера за допомогою цього: $ docker run -it ubuntu /bin/bash

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.