Изучение файловой системы контейнера Docker

653

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

То, что было бы идеально, - это иметь возможность использовать ssh или что-то подобное. Есть ли инструмент для этого, или моя концепция докера неверна, когда я думаю, что я смогу это сделать.

user2668128
источник
13
В последних версиях Докер, что - то , как это возможно: docker exec <container> bash. Итак, вы просто открываете оболочку внутри контейнера.
Дашохокша,
7
запуск bash на контейнере работает, только если bash установлен внутри контейнера
Christopher Thomas
7
Точно так же вы можете сделать: docker exec <container> ls <dir path>и docker exec <container> cat <file path>. Однако для bash добавьте -itпараметры.
Ноам Манос
Аналогичный вопрос: stackoverflow.com/questions/44769315/…
Вадим
3
@ ChristopherThomas, точно. Из-за этого я обнаружил, что единственный надежный способ сделать это с помощью, docker image save image_name > image.tarкак указано в ответе @ Gaurav24.
Хайме Хаблутцель

Ответы:

737

ОБНОВЛЕНИЕ
Самый простой метод: использование 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
SSH

Если вам нужен постоянный доступ, вы можете установить 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

Используйте 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 CONTAINER: PATH HOSTPATH ​​Скопируйте файлы / папки из файловой системы контейнеров в путь к хосту. Пути указаны относительно корня файловой системы. #> docker cp 7bb0e258aefe: / etc / debian_version. #> Докер cp blue_frog: / etc / hosts.
Амос Фоларин
4
Вариант 4 настолько важен, что его нужно переместить наверх и переименовать Option 1.
автоморфное
5
@JanusTroelsen Если нет оболочки, вы можете установить ее - например, в dockerfile для альпийского Linux (который действительно не имеет оболочки): RUN apk update && apk add bash(размер: ~ 4 МБ)
Камиль Килчевски
2
по моему опыту, ограничение Docker exec заключается в том, что команда должна быть добавлена ​​в работающий контейнер или как своего рода точка входа. Следовательно, остановленный контейнер выходит за рамки этого метода.
веб-леди
1
Чтобы использовать оболочку Linux для Windows, используйтеdocker exec -t -i mycontainer /bin/sh
Джейсон Мастерс
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-контейнер или изображение :

docker inspect name-of-container-or-image

Вы можете сделать это и выяснить, есть ли там bashили shтам. Ищите точку входа или cmd в возвращении json.

смотрите документацию по Docker Exec

смотрите документацию по excker-compose exec

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

Халил Гарбауи
источник
1
Это очень полезно, спасибо! Мне нужно перетащить файл, содержащийся внутри структуры файла изображения Docker, в приложение, но это будет невозможно, если он не будет открыт в формате GUI. Есть идеи, как я могу обойти это?
Аркья Чаттерджи
2
Должно быть совершенно очевидно, что это будет работать только на контейнере, на котором установлен bash.
инженер-программист
2
Для тех, кто смотрит, как это сделать на Windows Container / Powershell, есть команда docker exec -ti <name> powershell( источник )
ssell
1
@Ssell мой контейнер / изображение не было PowerShell по какой-то причине так docker exec -ti <name> cmdработало. А для других новичков, таких как я, обязательно используйте имя экземпляра контейнера из docker ps(например, 070494393ca5), а не читаемое имя, которое вы ему присвоили.
Simon_Weaver
1
о PowerShell в изображениях github.com/aspnet/aspnet-docker/issues/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работает.
Шон
Чем проще, тем лучше; офигенно, спасибо за совет! Ber
Берто
1
@ShaunBouckaert значение по умолчанию для tar fзависит от конфигурации. Одна часть - это TAPEпеременная окружения. Другие контролируются как часть сборки. Чистый эффект заключается в том, что никогда не следует предполагать, что он читает stdin или пишет stdout, но всегда указывает это явно.
roaima
42

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

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

И теперь текущий рабочий каталог является корнем контейнера.

Rovanion
источник
3
это не будет включать любые подключенные тома, хотя.
hwjp
34

Перед созданием контейнера:

Если вы хотите изучить структуру образа, который монтируется внутри контейнера, вы можете сделать

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

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

После создания контейнера:

Для этого уже есть много ответов выше. мой предпочтительный способ сделать это будет -

docker exec -t -i container /bin/bash
Gaurav24
источник
Смотрите тоже sreeninet.wordpress.com/2016/06/11/… .
Хайме Хаблутцель
Здесь следует упомянуть, что запуск bash внутри контейнера работает только в том случае, если вы делаете это на компьютере с такой же архитектурой, как и в образе. Если вы пытаетесь заглянуть в файловую систему изображений Raspberry Pi, трюк с bash не сработает.
Максим Кулькин
@MaximKulkin Действительно? Если контейнером является Linux, не имеет значения, какой хост, если доступен bash. Возможно, вы думаете о контейнерах Windows?
Торбьерн Равн Андерсен
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! определенно лучший способ
Николас ДиПьяцца
Это даже проще, чем экспорт через tar. Мне пришлось использовать -L, чтобы добраться до файлов через символические ссылки. Не нужно запускать контейнер!
MKaama
17

На Ubuntu 14.04 с Docker 1.3.1 я обнаружил корневую файловую систему контейнера на хост-компьютере в следующем каталоге:

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

Полная информация о версии Docker:

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
piercebot
источник
Работает как шарм: name = <name> dockerId = $ (docker inspect -f {{.Id}} $ name) / var / lib / docker / devicemapper / mnt / $ dockerId / rootfs /
Флоран
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.

Я смотрю на команду, что контейнер работает, например, docker ps и если это Apache или javaя просто делаю следующее:

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

и вуаля ты внутри контейнера.

Как правило, вы можете войти как root в /proc/<PID>/root/папку, пока этот процесс выполняется контейнером. Остерегайтесь символических ссылок не будет иметь смысла, используя этот режим.

атлант
источник
Дополнительная информация об этом методе здесь: superuser.com/a/1288058/195840
Эдуардо Лусио
12

Ответ с наибольшим количеством голосов хорош, за исключением случаев, когда ваш контейнер не является реальной системой Linux.

Многие контейнеры (особенно основанные на Go) не имеют стандартного двоичного файла (нет /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
SHX
источник
10

Вы можете использовать погружение для интерактивного просмотра содержимого изображения с помощью TUI.

https://github.com/wagoodman/dive

введите описание изображения здесь

Энди Вонг
источник
Погружение действительно идеальный инструмент!
Лоран
5

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

запуск докера --rm -it --entrypoint = / bin / bash

LeYAUable
источник
1
это полезно для случаев, когда точка входа по умолчанию не запускается
разбор
4

Для меня это хорошо работает (спасибо последним комментариям за указание на каталог / var / lib / docker / ):

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

Здесь 2465790aa2c4 - это короткий идентификатор работающего контейнера (отображаемый докером ps ), за которым следует звездочка.

dashohoxha
источник
4

В новых версиях Docker вы можете запустить, docker exec [container_name]которая запускает оболочку внутри вашего контейнера

Таким образом, чтобы получить список всех файлов в контейнере, просто запустите docker exec [container_name] ls

XRH
источник
1
Я попробовал это, и это не сработало. Предложение Халила Гарбауи выше сработало.
Ник
Это сработало для меня. Вы также можете попробовать использовать идентификатор контейнера вместо имени изображения
Diwann
4

Для драйвера docker 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
qxo
источник
4

Ни один из существующих ответов не относится к случаю контейнера, который вышел (и не может быть перезапущен) и / или не имеет установленной оболочки (например, бездисковых). Этот работает, пока у вас есть root-доступ к хосту Docker.

Для реальной ручной проверки сначала узнайте идентификаторы слоев:

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

На выходе вы должны увидеть что-то вроде

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

Перейдите в эту папку (как root), чтобы найти текущее видимое состояние файловой системы контейнера.

Рафаэль
источник
3

Этот ответ поможет тем (как я), которые хотят изучить файловую систему тома Docker, даже если контейнер не запущен.

Список запущенных докер-контейнеров:

docker ps

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

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

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

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

Это говорит мне о том, что каталог локальной физической машины / tmp / container-garren сопоставлен с местом назначения тома / tmp.

Знание каталога локальной физической машины (/ tmp / container-garren) означает, что я могу исследовать файловую систему независимо от того, работает ли контейнер Docker. Это было важно, чтобы помочь мне понять, что есть некоторые остаточные данные, которые не должны были сохраняться даже после того, как контейнер не работал.

Гаррен С
источник
1
Это только находит локальный каталог, который монтируется как том внутри контейнера, но не позволяет получить доступ ко всей файловой системе контейнера.
Боян Комазец
3

Другой трюк заключается в использовании атомарного инструмента, чтобы сделать что-то вроде:

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

Образ Docker будет смонтирован в / path / to / mnt, чтобы вы могли его проверить.

Джузеппе Скривано
источник
Но для этого нужно иметь специально изготовленные контейнеры, верно? Может быть, вы должны добавить это в качестве предостережения, потому что большинство людей не смогут продать его своей команде / компании в качестве решения ...
Ангелос Пикулас
3

Только для LINUX

Самым простым способом, который я использовал, было использование proc dir, который должен быть запущен для проверки файлов контейнера докера.

  1. Узнайте идентификатор процесса (PID) контейнера и сохраните в некоторую переменную

    PID = $ (docker inspect -f '{{.State.Pid}}' your-container-name-here)

  2. Убедитесь, что процесс контейнера запущен, и используйте переменную name, чтобы попасть в папку контейнера

    cd / proc / $ PID / root

Если вы хотите пройти через каталог без определения номера 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
    
kgnete
источник
2

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

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

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

Вы должны быть root, чтобы войти в этот каталог. Если вы не root, попробуйте sudo su перед выполнением команды.

Изменить: После v1.3 см. Ответ Jiri - это лучше.

AlonL
источник
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) и слой readwrite:

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

Изменить 2018-03-28:
docker-layer заменен на docker-backup

Винс
источник
1

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

Использование: docker exec [OPTIONS] CONTAINER COMMAND [ARG ...]

Запустите команду в работающем контейнере

Опции:
  -d, --detach Отдельный режим: запустить команду в фоновом режиме
      --detach-keys string Переопределить последовательность клавиш для отсоединения
                             контейнер
  -e, --env list Установить переменные окружения
  -i, --interactive Держите STDIN открытым, даже если он не подключен
      --privileged Предоставляет расширенные привилегии команде
  -t, --tty Выделить псевдо-TTY
  -u, --user string Имя пользователя или UID (формат:
                             [:])
  -w, --workdir строка Рабочий каталог внутри контейнера

Например :

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

docker exec -it containerId bash 

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

docker exec -it -u root containerId bash  

Это особенно полезно, чтобы иметь возможность выполнять некоторую обработку от имени root в контейнере.

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

docker exec -it -w /var/lib containerId bash 
davidxxx
источник
0

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

Ян Юй
источник