TL; DR
В этой статье исследуется, как мы можем переоценить изображения Docker Docker, изучив внутренние значения того, как изображения Docker хранят данные, как использовать инструменты для изучения различных аспектов изображения, и как мы можем создавать такие инструменты, как такие инструменты, как Dedockify Использовать API Python Docker для создания Dockerfiles из исходных изображений.
Введение
Как публичные реестры Docker, такие как Docker Hub и Treescale Увеличение популярности, за исключением наиболее ограничительной среды, для администраторов и разработчиков стало обычным явлением случайной загрузки изображения, созданного неизвестным объектом. Часто это сводится к тому, что ощущение, перевешивающее воспринимаемый риск. Когда изображение Docker становится общедоступным, иногда также предоставляется Dockerfile, либо непосредственно в списке, в репозитории GIT, либо через связанную ссылку, но иногда это не так. Даже если DockerFile был доступен, у нас нет много гарантий, что опубликованное изображение безопасно для использования.
Может быть, уязвимости безопасности не вы можете. Возможно, одно из ваших любимых изображений больше не поддерживается, и вы хотели бы обновить его так, чтобы оно работало на последней версии Ubuntu. Или, возможно, компилятор для другого распределения имеет эксклюзивную функцию, которая делает его более оптимизированным для производства двоичных файлов во время компиляции, и у вас есть неконтролируемое принуждение, чтобы выпустить аналогичное изображение, которое немного более оптимизировано.
Какой бы ни была причина, если вы хотите восстановить Dockerfile с изображения, есть варианты. Изображения Docker — это не черный ящик. Часто вы можете получить большую часть информации, необходимой для восстановления Dockerfile. В этой статье мы точно рассмотрим, как это сделать, заглядывая в изображение Docker, чтобы мы могли очень внимательно восстановить Dockerfile, который его построил.
В этой статье мы покажем, как можно реконструировать Dockerfile с изображения, используя два инструмента, Dedockify
, индивидуальный сценарий Python, предусмотренного для этой статьи, и Погружение
Анкет Используемый базовый процесс будет следующим.
Используя погружение
Чтобы получить некоторую быструю, минимальную интуицию относительно того, как составляются изображения, мы представим себя с различными продвинутыми и потенциально незнакомыми концепциями Docker с использованием Dive. Dive — это инструмент исследования изображения, который позволяет исследовать каждый слой изображения Docker.
Во -первых, позвольте нам создать простой, легкий в Dockerfile, который мы можем исследовать для тестирования.
В пустую каталог введите следующий фрагмент непосредственно в командную строку:
cat > Dockerfile << EOF ; touch testfile1 testfile2 testfile3 FROM scratch COPY testfile1 / COPY testfile2 / COPY testfile3 / EOF
Вводя приведенное выше и нажав Enter, мы только что создали новый Dockerfile
и заполненные три нулевых тестовых файла в том же каталоге.
$ ls Dockerfile testfile1 testfile2 testfile3
Итак, теперь давайте создадим изображение, используя этот Dockerfile и отметим его как Пример 1
Анкет
docker build . -t example1
Построение Пример 1
Изображение должно создать следующий выход:
Sending build context to Docker daemon 3.584kB Step 1/4 : FROM scratch ---> Step 2/4 : COPY testfile1 / ---> a9cc49948e40 Step 3/4 : COPY testfile2 / ---> 84acff3a5554 Step 4/4 : COPY testfile3 / ---> 374e0127c1bc Successfully built 374e0127c1bc Successfully tagged example1:latest
Следующая ноль-байт Пример 1
Изображение должно быть доступно:
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE example1 latest 374e0127c1bc 31 seconds ago 0B
Обратите внимание, что, поскольку нет двоичных данных, это изображение не будет функциональным. Мы используем его только в качестве упрощенного примера того, как слои можно просматривать на изображениях Docker.
Здесь мы можем видеть по размеру изображения, что нет исходного изображения. Вместо исходного изображения мы использовали царапина
который поручил Docker использовать с нулевое пустое изображение в качестве исходного изображения. Затем мы изменили пустое изображение, копировав три дополнительных нулевых тестовых файла, а затем отметили изменения как Пример 1
Анкет
Теперь давайте рассмотрим наше новое изображение с погружением.
docker run --rm -it \ -v /var/run/docker.sock:/var/run/docker.sock \ wagoodman/dive:latest example1
Выполнение вышеупомянутой команды должно автоматически тянуть Wagoodman/Dive
от Docker Hub и создайте выходной сигнал полированного интерфейса DIVE.
Unable to find image 'wagoodman/dive:latest' locally latest: Pulling from wagoodman/dive 89d9c30c1d48: Pull complete 5ac8ae86f99b: Pull complete f10575f61141: Pull complete Digest: sha256:2d3be9e9362ecdcb04bf3afdd402a785b877e3bcca3d2fc6e10a83d99ce0955f Status: Downloaded newer image for wagoodman/dive:latest Image Source: docker://example-image Fetching image... (this can take a while for large images) Analyzing image... Building cache...
Прокрутите три слоя изображения в списке, чтобы найти три файла в дереве, отображаемые справа.
Мы можем видеть содержимое на правильном изменении, когда мы прокручиваем каждый слой. Поскольку каждый файл был скопирован в пустой докер царапина
Изображение было записано как новый слой.
Обратите также, что мы можем увидеть команды, которые использовались для получения каждого уровня. Мы также можем увидеть значение хэша исходного файла и файл, который был обновлен.
Если мы примем к сведению элементы в Команда:
Раздел, мы должны увидеть следующее:
#(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in / #(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in / #(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in /
Каждая команда дает солидное понимание исходной команды, используемой в DockerFile для получения изображения. Однако первоначальное имя файла потеряно. Похоже, что единственный способ восстановить эту информацию — это сделать наблюдения об изменениях в целевой файловой системе или, возможно, вывод на основе других деталей. Подробнее об этом позже.
история докеров
Помимо сторонних инструментов, таких как погружение
, инструмент, который мы имеем немедленно доступным, — это история докеров
. Если мы используем История докеров
командовать на нашем Пример 1
Изображение, мы можем просмотреть записи, которые мы использовали в DockerFile, чтобы создать это изображение.
docker history example1
Поэтому мы должны получить следующий результат:
IMAGE CREATED CREATED BY SIZE COMMENT 374e0127c1bc 25 minutes ago /bin/sh -c #(nop) COPY file:aa717ff85b39d3ed… 0B 84acff3a5554 25 minutes ago /bin/sh -c #(nop) COPY file:2a949ad55eee33f6… 0B a9cc49948e40 25 minutes ago /bin/sh -c #(nop) COPY file:e3c862873fa89cbf… 0B
Обратите внимание, что все в Создан
колонка усечена. Это директивы DockerFile, проходящие через Bourne Shell. Эта информация может быть полезна для воссоздания нашего Dockerfile, и, хотя она здесь усечена, мы можем просмотреть все это, также используя --нет трэнд
вариант:
$ docker history example1 --no-trunc IMAGE CREATED CREATED BY SIZE COMMENT sha256:374e0127c1bc51bca9330c01a9956be163850162f3c9f3be0340bb142bc57d81 29 minutes ago /bin/sh -c #(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in / 0B sha256:84acff3a5554aea9a3a98549286347dd466d46db6aa7c2e13bb77f0012490cef 29 minutes ago /bin/sh -c #(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in / 0B sha256:a9cc49948e40d15166b06dab42ea0e388f9905dfdddee7092f9f291d481467fc 29 minutes ago /bin/sh -c #(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in / 0B
Хотя это имеет некоторые полезные данные, это может быть проблемой для анализа из командной строки. Мы также могли бы использовать Docker осмотреть
Анкет Однако в этой статье мы сосредоточимся на использовании API Docker Engine для Python.
Использование API Docker Engine для Python
Докер выпустил Библиотека Python для Docker Engine API , что позволяет полноценному контролю докера из Python. В следующем примере мы можем восстановить аналогичную информацию, которую мы сделали, используя История докеров
Запустив следующий код Python 3:
#!/usr/bin/python3 import docker cli = docker.APIClient(base_url='unix://var/run/docker.sock') print (cli.history('example1'))
Это должно привести к тому, что вывод очень похож на следующее:
[{'Comment': '', 'Created': 1583008507, 'CreatedBy': '/bin/sh -c #(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in / ', 'Id': 'sha256:374e0127c1bc51bca9330c01a9956be163850162f3c9f3be0340bb142bc57d81', 'Size': 0, 'Tags': ['example:latest']}, {'Comment': '', 'Created': 1583008507, 'CreatedBy': '/bin/sh -c #(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in / ', 'Id': 'sha256:84acff3a5554aea9a3a98549286347dd466d46db6aa7c2e13bb77f0012490cef', 'Size': 0, 'Tags': None}, {'Comment': '', 'Created': 1583008507, 'CreatedBy': '/bin/sh -c #(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in / ', 'Id': 'sha256:a9cc49948e40d15166b06dab42ea0e388f9905dfdddee7092f9f291d481467fc', 'Size': 0, 'Tags': None}]
Глядя на вывод, мы видим, что реконструкция большей части DockerFile является лишь вопросом анализа всех соответствующих данных и отмены записей. Но, как мы видели ранее, мы также замечаем, что в Копия
Директивы. Как упоминалось ранее, хешированные записи здесь представляют собой имена файлов, используемые снаружи слоя. Эта информация не подлежит непосредственно. Однако, как мы видели в Погружение
, мы можем сделать вывод этих имен, когда мы ищем изменения, внесенные в слой. Также иногда можно сделать вывод в тех случаях, когда оригинальная директива копирования включала целевое имя файла в качестве пункта назначения. В других случаях имена файлов могут не быть критическими, что позволяет нам использовать произвольные имена файлов. И все еще в других случаях, хотя и сложнее оценить, мы можем сделать вывод имен файлов, которые обращаются к обратном порядке в других местах системы, например, в поддержке таких зависимостей, как сценарии или файлы конфигурации. Но в любом случае поиск всех изменений между слоями является наиболее надежным.
DeDockify
Давайте сделаем это еще на несколько шагов. Чтобы помочь переоборудовать это изображение в DockerFile, нам нужно будет проанализировать все и переформатировать его в форму, которая читается. Обратите внимание, что для целей настоящей статьи был доступен следующий код Python 3 и может быть получен из Dedockify Репозиторий на GitHub. Спасибо Laniksj для всех Предыдущая работа Анкет
from sys import argv import docker class ImageNotFound(Exception): pass class MainObj: def __init__(self): super(MainObj, self).__init__() self.commands = [] self.cli = docker.APIClient(base_url='unix://var/run/docker.sock') self._get_image(argv[-1]) self.hist = self.cli.history(self.img['RepoTags'][0]) self._parse_history() self.commands.reverse() self._print_commands() def _print_commands(self): for i in self.commands: print(i) def _get_image(self, img_hash): images = self.cli.images() for i in images: if img_hash in i['Id']: self.img = i return raise ImageNotFound("Image {} not found\n".format(img_hash)) def _insert_step(self, step): if "#(nop)" in step: to_add = step.split("#(nop) ")[1] else: to_add = ("RUN {}".format(step)) to_add = to_add.replace("&&", "\\\n &&") self.commands.append(to_add.strip(' ')) def _parse_history(self, rec=False): first_tag = False actual_tag = False for i in self.hist: if i['Tags']: actual_tag = i['Tags'][0] if first_tag and not rec: break first_tag = True self._insert_step(i['CreatedBy']) if not rec: self.commands.append("FROM {}".format(actual_tag)) __main__ = MainObj()
Первоначальная генерация Dockerfile
Если вы сделали это так далеко, то у вас должно быть два изображения: Wagoodman/Dive
и наш обычай Пример 1
изображение.
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE example1 latest 374e0127c1bc 42 minutes ago 0B wagoodman/dive latest 4d9ce0be7689 2 weeks ago 83.6MB
Запуск этого кода против нашего Пример 1
Изображение наконец -то даст следующее:
$ python3 dedockify.py 374e0127c1bc FROM example1:latest COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in / COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in / COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in /
Мы извлекли почти ту же информацию, которую мы наблюдали, когда исследовали изображение с Погружение
ранее. Обратите внимание на От
Директива показывает нам Пример 1: Последний
вместо царапать
. Наш код делает предположение о базовом изображении, которое технически неверно в этом случае.
Для сравнения, давайте сделаем то же самое с нашим Wagoodman/Dive
изображение.
$ python3 dedockify.py 4d9ce0be7689 FROM wagoodman/dive:latest ADD file:fe1f09249227e2da2089afb4d07e16cbf832eeb804120074acd2b8192876cd28 in / CMD ["/bin/sh"] ARG DOCKER_CLI_VERSION= RUN |1 DOCKER_CLI_VERSION=19.03.1 /bin/sh -c wget -O- https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.tgz | tar -xzf - docker/docker --strip-component=1 \ && mv docker /usr/local/bin COPY file:8385774b036879eb290175cc42a388877142f8abf1342382c4d0496b6a659034 in /usr/local/bin/ ENTRYPOINT ["/usr/local/bin/dive"]
Это показывает намного больше разнообразия по сравнению с нашим Пример 1
изображение. Мы замечаем Добавить
Директива незадолго до От
директива. Наш код снова делает неправильное предположение. Мы не знаем, что такое Добавить
Директива добавляет. Однако мы можем интуитивно сделать предположение, что мы не знаем наверняка, что такое базовое изображение. Добавить
Директива могла быть использована для извлечения локального TAR
Файл в корневой каталог. Возможно, он использовал этот метод для загрузки другого базового изображения.
Decockify Limition Testing
Давайте экспериментируем, создав пример Dockerfile
где мы явно определяем базовое изображение. Как мы делали ранее, в пустом каталоге запустите следующий фрагмент непосредственно из командной строки.
cat > Dockerfile << EOF ; touch testfile1 testfile2 testfile3 FROM ubuntu:latest RUN mkdir testdir1 COPY testfile1 /testdir1 RUN mkdir testdir2 COPY testfile2 /testdir2 RUN mkdir testdir3 COPY testfile3 /testdir3 EOF
Теперь выполните сборку, которая помечает наше новое изображение как Пример 2
Анкет Это создаст аналогичное изображение, как и раньше, кроме как вместо использования царапать
он будет использовать Ubuntu: последний
как базовое изображение.
$ docker build . -t example2 Sending build context to Docker daemon 3.584kB Step 1/7 : FROM ubuntu:latest ---> 72300a873c2c Step 2/7 : RUN mkdir testdir1 ---> Using cache ---> 4110037ae26d Step 3/7 : COPY testfile1 /testdir1 ---> Using cache ---> e4adf6dc5677 Step 4/7 : RUN mkdir testdir2 ---> Using cache ---> 22d301b39a57 Step 5/7 : COPY testfile2 /testdir2 ---> Using cache ---> f60e5f378e13 Step 6/7 : RUN mkdir testdir3 ---> Using cache ---> cec486378382 Step 7/7 : COPY testfile3 /testdir3 ---> Using cache ---> 05651f084d67 Successfully built 05651f084d67 Successfully tagged example2:latest
Поскольку у нас теперь немного более сложное Dockerfile
реконструировать, и у нас есть точное Dockerfile
Мы использовали для создания этого изображения, мы можем провести сравнение. Давайте сгенерируем вывод из нашего сценария Python.
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE example2 latest 05651f084d67 2 minutes ago 64.2MB example1 latest 374e0127c1bc 1 hour ago 0B ubuntu latest 72300a873c2c 9 days ago 64.2MB wagoodman/dive latest 4d9ce0be7689 3 weeks ago 83.6MB
$ python3 dedockify.py 05651f084d67 FROM ubuntu:latest RUN /bin/sh -c mkdir testdir1 COPY file:cc4f6e89a1bc3e3c361a1c6de5acc64d3bac297f0b99aa75af737981a19bc9d6 in /testdir1 RUN /bin/sh -c mkdir testdir2 COPY file:a04cdcdf5fd077a994fe5427a04f6b9a52288af02dad44bb1f8025ecf209b339 in /testdir2 RUN /bin/sh -c mkdir testdir3 COPY file:2ed8ccde7cd97bc95ca15f0ec24ec447484a8761fa901df6032742e8f1a2a191 in /testdir3
Это хорошо коррелирует с оригиналом Dockerfile
Анкет Нет Добавить
Директива на этот раз, и От
Директива верна. При условии, что наше базовое изображение определено в оригинале Dockerfile
, и это избегает использования царапина
или избегать использования Добавить
Директива для создания базового изображения из TAR
Файл, мы должны быть в состоянии реконструировать Dockerfile
с некоторой точностью. Однако мы до сих пор не знаем имена исходных файлов, которые были скопированы.
Слепая вольная реконструкция Dockerfile
Теперь давайте попробуем обратно разработку контейнера Docker правильным способом, используя инструменты, которые мы уже обсуждали. Контейнер, который мы будем использовать, был изменен из приведенных выше примеров. Наш более ранний DockerFile был изменен для создания Пример 3
. Изображение было сделано функциональным, добавив небольшой бинар. Исходный код сборки доступен Здесь в Dedockify Репозиторий GitHub. Поскольку это изображение настолько маленькое, нам не нужно будет построить или тянуть его. Мы можем просто скопировать и вставить весь контейнер прямо в нашу среду Docker с фрагментом ниже.
uudecode << EOF | zcat | docker load begin-base64 600 - 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 YUoB50E7iU4JFD4ESbcok5Kq6SWbIWjFpbFSCOmUYaxwiR1yiY3tvxX+T3JR 3v/sBK8Cy+4O/yfO+L/y/lcnWOn/rvF/hf8vKCgoaBXGQgwYvEKWwNmY0euo As/cks/mFGMgBI+BfD7jaJtrHaMnhx1ZMAF9a/M/6dL/d4HG+m9r/qfS/3eC wv/dbzS2/7bmfyr23wmW/F/TanCR/7PKBZAyeI7SuGDqd0Y9ahVYZj6nJFFq pZS2UieBDAC05HRxNBKE06nwfx3yf43tv6X5n3iJ/+0Er96ovHP8X/H/O8FK /3eN/yu//xUUFBS0iqbOekv8nzSs9P9doLH+23n/V4ky/1cnKPzf/UZj+2+H /wNd7L8TLPm/NXB2K/5vDbGEhf/riv9rbP/t8H/Ayvt/naDE/xX9L/S/mrxv /Wnc7P9f1P+C/5OyxP8WFBQUtIqmizW1Ff9X+v9u0Fj/Lc3/Z4r/3wkK/3e/ 0dj+W4r/K/P/dIMl/7eGNRtX/N8aYgkL/9cV/9fY/lua/0+xYv9doMT/Ff0v 9L9atWL9abwV/1fi/wsKCgpaRdPJetqK/6vX/y39f/torP+W4v94+f2vExT+ 736jsf23FP+niv13glf8X/M5+1b8X1lL5H3i/5rafzv8n9Bl/a9OcPfW/1jy f8X/7wQr/a/WMF5/Gm/F/xX+v6CgoKBVJPK8tUkQIUjIXCXMBoJj0oPO3Btu jJc86SyRWaFFDOhQ8QxKJ8uya2n9D6bK+h+doLH+25n/j/My/0cnKPzf/UZj +2/O/wmQr63/a0r8TzdY8n9Nq8FF/o+xoB1a6zBk51lkXpMADhmswByzE+Bd AG5V5skJj1zaSKm4aOhYEpf4P8EE22KwxcSugIHiAwF9KbR2grlLRGCdsKrf XuUQrJe25hYlS5SRHDFpoxNDACOzDxhToCpmUcUYc5JJRMWNZjfzihdTuGsc 41719NPdR59sH8+m26NJ9KPtWRiOBxf2V7vnJxYbZ7v0Ue0vScq9qt7dnh3Q o2xF+vjwo/Hk6ONezUc+2X329dOdx092e3vPq21/dLR9gKPR5Hm1X9/+itic HXih9EB4CIFjBOm8wKB4CIxMnRkbubaokRoGgd5zFUwEBcIw5FkxRbpC4/AG frRO/gpHunchT3WGfoEtPTk93azSJH5Hqv4ep7PhZLxgm/sM+vqsItx9Wnmd Kr/MS9919S3Jbj+NB8M5xvnxtM61P0y6tst3uJ72+4bG/X9z/l+9Pv4DXd7/ 6Qa1sbWdxhuP/znXqsT/doJVY9tiGrX9X6t/Y67w/9SPlPF/J/jnw8//8sFq 78Fvf7Xx640/0Hf9/xs68h9OG//+/c8//am38cHGv37+6VFdWTZ7P0ymo/TH 3727jBcUFBQUNMKhHw8zzub9W/B4b4sb/H8O0lzyBemIEuX9n06wd1I9WFId FVPOgzU2oVQ+SAkqeKdN1IASaKiPUrsFr2aNy0Znn8hNTzlz453ywBZ1iIbf z/BosutfzOrRPP7oD49GCIORryNM6iH95/WIcXGyaaTg+eCTUl1fJBsJW9+y uCRsfXPskbD1LdhRl9na3v4lYU1530vC1sdLVPun+8VP/SVMyVZnw/lkOsRZ W2nc9PsvB7ja/pNBlPa/C5ysWuia61420mv4Pej0tNhcQUFBwV3GfwHMszUX AMIAAA== ==== EOF
Запуск всего напрямую из командной строки загрузится Пример 3: Последний
Анкет Теперь давайте попробуем воссоздать Dockerfile
Анкет
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE example3 latest 059a3878de45 5 minutes ago 63B
$ python3 dedockify.py 059a3878de45 FROM example3:latest WORKDIR /testdir1 COPY file:322f9f92e3c94eaee1dc0d23758e17b798f39aea6baec8f9594b2e4ccd03e9d0 in testfile1 WORKDIR /testdir2 COPY file:322f9f92e3c94eaee1dc0d23758e17b798f39aea6baec8f9594b2e4ccd03e9d0 in testfile2 WORKDIR /testdir3 COPY file:322f9f92e3c94eaee1dc0d23758e17b798f39aea6baec8f9594b2e4ccd03e9d0 in testfile3 WORKDIR /app COPY file:b33b40f2c07ced0b9ba6377b37f666041d542205e0964bc26dc0440432d6e861 in hello ENTRYPOINT ["/app/hello"]
Это дает нам базу Dockerfile
работать с. С тех пор Пример 3: Последний
Имя этого изображения, мы можем предположить из контекста, что оно использует царапать
. Теперь нам нужно посмотреть, в какие файлы были скопированы в /testDir1
, /testDir2
, /testDir3
и /приложение
Анкет Давайте запустим это изображение против Погружение
Чтобы увидеть, как мы восстановим недостающие данные.
docker run --rm -it \ -v /var/run/docker.sock:/var/run/docker.sock \ wagoodman/dive:latest example3:latest
Если вы прокрутите вниз до последнего уровня, вы сможете увидеть все недостающие данные, заполняющие дерево справа. В каждом из каталогов были нулевые файлы с именем TestFile1
, TestFile2
и TestFile3
скопировано с этим. И в последнем позже был скопирован файл 63-байтовых Привет
к /приложение
каталог.
Теперь позвольте нам восстановить эти файлы! Похоже, нет способа копировать файлы непосредственно с изображения, поэтому нам нужно сначала создать контейнер.
$ docker run -td example3:latest 6fdca182a128df7a76e618931c85a67e14a73adc69ad23782bc9a5dc29420a27
Теперь давайте скопируем необходимые файлы из контейнера на хост, используя путь и имена файлов, которые мы восстановили из Пять
ниже.
/testdir1/testfile1 /testdir2/testfile2 /testdir3/testfile3 /app/hello
Сначала мы могли бы проверить, работает ли наш контейнер.
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6fdca182a128 example3:latest "/app/hello" 2 minutes ago Up 2 minutes wizardly_lamport
Если контейнер по какой -то причине не работает, это нормально. Мы можем проверить его статус, чтобы увидеть, что он остановлен.
$ docker container ls -a
Мы также можем проверить журналы.
$ docker logs 6fdca182a128 Hello, world!
Похоже, он работает на постоянном Привет, мир!
программа На самом деле, в этом случае Привет, мир!
Программа не была разработана, чтобы быть настойчивой. В версии Docker 19.03.6
может быть ошибка, которая мешает приложению нормально завершать нормально. Это приемлемо на данный момент. Контейнер может быть активным или остановленным; Приложение не должно быть настойчивым, чтобы восстановить какие -либо данные, которые нам нужны. Контейнер в любом состоянии должен быть сгенерирован только из исходного изображения, для которого мы извлекаем данные.
docker cp 6fdca182a128:/testdir1/testfile1 . docker cp 6fdca182a128:/testdir2/testfile2 . docker cp 6fdca182a128:/testdir3/testfile3 . docker cp 6fdca182a128:/app/hello .
Запустив восстановленный исполняемый файл, чтобы проверить его поведение, мы должны увидеть следующее:
$ ./hello Hello, world!
С Dockerfile
Мы сгенерировали ранее, мы можем обновить его, чтобы включить все новые детали. Это включает в себя обновление От
Директива на царапина
Наряду со всеми обнаруженными именами файлов, которые мы нашли, исследуя с Погружение
Анкет
FROM scratch WORKDIR /testdir1 COPY testfile1 . WORKDIR /testdir2 COPY testfile2 . WORKDIR /testdir3 COPY testfile3 . WORKDIR /app COPY hello . ENTRYPOINT ["/app/hello"]
Опять же, объединив все файлы в общей папке, мы готовы запустить нашу обратную инженерную Dockerfile
Анкет
$ docker build . -t example3:recovered Sending build context to Docker daemon 4.608kB Step 1/10 : FROM scratch ---> Step 2/10 : WORKDIR /testdir1 ---> Running in 5e8e47505ca6 Removing intermediate container 5e8e47505ca6 ---> d30a2f002626 Step 3/10 : COPY testfile1 . ---> 4ac46077a588 Step 4/10 : WORKDIR /testdir2 ---> Running in 8c48189da985 Removing intermediate container 8c48189da985 ---> 7c7d90bc2219 Step 5/10 : COPY testfile2 . ---> 5b40d33100e1 Step 6/10 : WORKDIR /testdir3 ---> Running in 4ccd634a04db Removing intermediate container 4ccd634a04db ---> f89fdda8f059 Step 7/10 : COPY testfile3 . ---> 9542f614200d Step 8/10 : WORKDIR /app ---> Running in 7614b0fdba42 Removing intermediate container 7614b0fdba42 ---> 6d686935a791 Step 9/10 : COPY hello . ---> cd4baca758dd Step 10/10 : ENTRYPOINT ["/app/hello"] ---> Running in 28a1ca58b27f Removing intermediate container 28a1ca58b27f ---> 35dfd9240a2e Successfully built 35dfd9240a2e Successfully tagged example3:recovered
$ docker run --name recovered -dt example3:recovered 0f696bf500267a996339b522cf584e010434103fe82497df2c1fa58a9c548f20 $ docker logs recovered Hello, world!
Теперь для дальнейшей проверки давайте проверим слои с Погружение
опять таки.
docker run --rm -it \ -v /var/run/docker.sock:/var/run/docker.sock \ wagoodman/dive:latest example3:recovered
Это изображение показывает те же файлы, что и оригинал. Сравнивая сторону двух изображений, они оба показывают, что они совпадают. Оба показывают одинаковые размеры файлов. И оба функционируют одинаково.
Вот оригинал Dockerfile
используется для генерации оригинала Пример 3
изображение.
FROM alpine:3.9.2 RUN apk add --no-cache nasm WORKDIR /app COPY hello.s /app/hello.s RUN touch testfile && nasm -f bin -o hello hello.s && chmod +x hello FROM scratch WORKDIR /testdir1 COPY --from=0 /app/testfile testfile1 WORKDIR /testdir2 COPY --from=0 /app/testfile testfile2 WORKDIR /testdir3 COPY --from=0 /app/testfile testfile3 WORKDIR /app COPY --from=0 /app/hello hello ENTRYPOINT ["/app/hello"]
Мы видим это, хотя мы не смогли полностью его реконструировать, мы смогли реконструировать приблизительно. Невозможно восстановить Dockerfile, который использует многоэтапную сборку, подобную этой. Информация просто недоступна. Наш единственный вариант — реконструировать Dockerfile изображения, который у нас на самом деле есть. Если у нас есть изображения с более ранних этапов сборки, мы можем воспроизвести Dockerfile для каждого из них, но в этом случае все, что у нас было, было окончательным сборкой. Но независимо от того, мы все еще успешно воспроизводили полезный Dockerfile
Из изображения Docker.
Будущая работа
Используя аналогичный подход, как Погружение
, мы должны быть в состоянии обновить Dedockify
исходный код автоматически пройти через каждый из слоев, чтобы восстановить всю полезную информацию файла. Кроме того, программа может быть обновлена, чтобы иметь возможность автоматически восстанавливать файлы из контейнера и хранить их локально, а также автоматически вносит соответствующие обновления для Dockerfile
Анкет Наконец, программа также может быть обновлена, чтобы иметь возможность легко сделать вывод, если базовый уровень использует пустой царапина
изображение или что -то еще. С некоторыми дополнительными изменениями в восстановленном Dockerfile
Синтаксис, Dedockify
Возможно, может быть обновлено, чтобы полностью автоматизировать обратную инженерию изображения Docker в функциональный Dockerfile
в большинстве случаев.
Оригинал: «https://dev.to/appfleet/reverse-engineer-docker-images-into-dockerfiles-3ll0»