Reverse Engineering von Docker-Images in Dockerfiles
Reverse Engineering von Docker-Images, indem Sie die Interna untersuchen, wie Docker-Images Daten speichern
TL;DR
In dieser Geschichte werden wir Docker-Images zurückentwickeln, indem wir uns ansehen, wie Docker-Images Daten speichern, wie Tools verwendet werden, um die verschiedenen Aspekte des Images zu betrachten, und wie Tools wie Dedockify erstellt werden , die Python-Docker-APIs zum Erstellen verwenden Dockerfiles.
Einführung
Da öffentliche Docker-Registrierungen wie Docker Hub und TreeScale immer beliebter werden, wird es für Administratoren und Entwickler immer üblicher, von unbekannten Entitäten erstellte Images herunterzuladen. Meistens siegt die Bequemlichkeit über das wahrgenommene Risiko. Wenn ein Docker-Image veröffentlicht wird, wird es in einigen Fällen entweder direkt in der Auflistung, in einem Git-Repository oder über einen zugehörigen Link bereitgestellt. Häufiger wird kein Dockerfile bereitgestellt. Für den Fall, dass ein Dockerfile zur Verfügung gestellt wird, haben wir nur sehr wenige Zusicherungen, dass das vorgefertigte Image mit dem Dockerfile korreliert oder sogar sicher zu verwenden ist.
Vielleicht interessieren Sie sich nicht für Sicherheitslücken. Vielleicht möchten Sie eines Ihrer Lieblingsbilder aktualisieren, damit es auf der neuesten Version von Ubuntu läuft. Oder vielleicht bekommen Sie einen unkontrollierbaren Drang, ein Image zu veröffentlichen, das nur ein wenig optimierter ist, weil es einen Compiler für eine andere Distribution gibt, der besser geeignet ist, Binärdateien während der Kompilierzeit zu erstellen.
Was auch immer der Grund ist, es gibt Optionen zum Wiederherstellen des Dockerfiles eines Images. Ein Docker-Image ist keine Blackbox. Die meisten Informationen, die Sie zum Rekonstruieren einer Dockerfile benötigen, können abgerufen werden. Indem wir in ein Docker-Image schauen und die Interna untersuchen, können wir eine Docker-Datei aus einem beliebigen vorgefertigten Container genau rekonstruieren.
In dieser Story zeigen wir, wie es möglich ist, eine Docker-Datei aus einem Image mit zwei Tools zu rekonstruieren: Dedockify , ein angepasstes Python-Skript, das für diese Story bereitgestellt wird, und Dive , ein Tool zur Untersuchung von Docker-Images. Der verwendete grundlegende Prozessablauf wird wie folgt sein.
Tauchen verwenden
Um schnell zu verstehen, wie Bilder zusammengesetzt werden, lernen wir mithilfe von Dive einige fortgeschrittene und möglicherweise unbekannte Docker-Konzepte kennen. Das Dive-Tool untersucht jede Ebene eines Docker-Images.
Lassen Sie uns eine einfache, leicht verständliche erstellen, Dockerfile
die wir zum Testen verwenden können.
Fügen Sie dieses Snippet direkt in ein leeres Verzeichnis ein:
cat > Dockerfile << EOF ; touch testfile1 testfile2 testfile3
FROM scratch
COPY testfile1 /
COPY testfile2 /
COPY testfile3 /
EOF
$ ls
Dockerfile testfile1 testfile2 testfile3
docker build . -t example1
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
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
example1 latest 374e0127c1bc 31 seconds ago 0B
Wir können hier an der Größe des Bildes erkennen, dass es kein Quellbild gibt. Anstelle eines Quellbildes haben wir scratch
Docker angewiesen, ein leeres Null-Byte-Bild als Quellbild zu verwenden. Wir haben dann das leere Image modifiziert, indem wir drei zusätzliche Null-Byte-Testdateien darauf kopiert und die Änderungen dann als example1
.
Lassen Sie uns nun unser neues Image mit Dive erkunden.
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest example1
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...
Dive screenshot by author.
Wir können sehen, dass sich der Inhalt auf der rechten Seite ändert, wenn wir durch jede Ebene scrollen. Da jede Datei in ein leeres Docker-Image kopiert scratch
wurde, wurde sie als neue Ebene aufgezeichnet.
Beachten Sie auch, dass wir die Befehle sehen können, die zum Erstellen der einzelnen Ebenen verwendet wurden. Wir können auch den Hash-Wert der Quelldatei und der aktualisierten Datei sehen.
Wenn wir die Punkte im Command:
Abschnitt zur Kenntnis nehmen, sollten wir Folgendes sehen:
#(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in /
#(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in /
#(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in /
Docker-Geschichte
Abgesehen von Tools von Drittanbietern wie dive ist das Tool, das wir sofort zur Verfügung haben, docker history
. Wenn wir den docker history
Befehl für unser example1
Image verwenden, können wir die Einträge anzeigen, die wir in der Docker-Datei verwendet haben, um dieses Image zu erstellen.
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
$ 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
Verwenden der Docker Engine-API für Python
Docker hat eine Python-Bibliothek für die Docker Engine API veröffentlicht, die die vollständige Kontrolle über Docker aus Python heraus ermöglicht. Im folgenden Beispiel können wir ähnliche Informationen wiederherstellen, die wir verwendet haben, docker history
indem wir den folgenden Python 3-Code ausführen:
#!/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}]
Abkoppeln
Gehen wir noch ein paar Schritte weiter. Um dieses Bild beim Reverse Engineering in eine Docker-Datei umzuwandeln, müssen wir alles parsen und in eine lesbare Form umformatieren. Bitte beachten Sie, dass für die Zwecke dieser Geschichte der folgende Python 3-Code zur Verfügung gestellt wurde und aus dem Dedockify- Repository auf GitHub abgerufen werden kann. Danksagungen gehen an LanikSJ für all die großartige ursprüngliche Vorarbeit und Codierung .
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()
Wenn Sie es so weit geschafft haben, sollten Sie zwei Bilder haben: wagoodman/dive
und unser benutzerdefiniertes example1
Bild.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
example1 latest 374e0127c1bc 42 minutes ago 0B
wagoodman/dive latest 4d9ce0be7689 2 weeks ago 83.6MB
$ python3 dedockify.py 374e0127c1bc
FROM example1:latest
COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in /
COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in /
COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in /
Machen wir zum Vergleich dasselbe mit unserem wagoodman/dive
Bild.
$ 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"]
Dedockify- Einschränkungstests
Lassen Sie uns experimentieren, indem wir ein Beispiel erstellen, Dockerfile
in dem wir das Basisbild explizit definieren. Führen Sie wie zuvor in einem leeren Verzeichnis das folgende Snippet direkt von der Befehlszeile aus.
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
$ 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
$ 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
Blinde Freestyle-Dockerfile-Rekonstruktion
Lassen Sie uns nun versuchen, einen Docker-Container auf die richtige Weise mit den bereits besprochenen Tools rückzuentwickeln. Der Container, den wir verwenden werden, wurde aus den obigen Beispielen modifiziert. Unsere frühere Dockerfile
Version wurde geändert, um example3
. Das Bild wurde funktionsfähig gemacht, indem eine kleine Binärdatei hinzugefügt wurde. Der Assembly-Quellcode ist hier im GitHub-Repository von Dedockify verfügbar . Da dieses Image so klein ist, müssen wir es nicht erstellen oder ziehen. Wir können einfach unsere Kommandozeilen-Fähigkeiten demonstrieren, indem wir den gesamten Container kopieren und mit dem folgenden Snippet direkt in unsere Docker-Umgebung einfügen.
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
$ 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"]
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest example3:latest
Dive screenshot by author.
Lassen Sie uns diese Dateien jetzt wiederherstellen! Es scheint keine Möglichkeit zu geben, die Dateien direkt aus dem Image zu kopieren, daher müssen wir zuerst einen Container erstellen.
$ 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 cp 6fdca182a128:/testdir1/testfile1 .
docker cp 6fdca182a128:/testdir2/testfile2 .
docker cp 6fdca182a128:/testdir3/testfile3 .
docker cp 6fdca182a128:/app/hello .
$ ./hello
Hello, world!
FROM scratch
WORKDIR /testdir1
COPY testfile1 .
WORKDIR /testdir2
COPY testfile2 .
WORKDIR /testdir3
COPY testfile3 .
WORKDIR /app
COPY hello .
ENTRYPOINT ["/app/hello"]
Zuerst bauen wir den Container.
$ 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
Dive screenshot by author.
Hier ist das Original Dockerfile
, das zum Erzeugen des Originalbildes verwendet wurde example3
.
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"]```
Zukünftige Arbeit
Durch die Verwendung eines ähnlichen Ansatzes wie Dive sollten wir in der Lage sein, den Dedockify -Quellcode so zu aktualisieren, dass er automatisch durch jede der Schichten geht, um alle nützlichen Dateiinformationen wiederherzustellen. Außerdem kann das Programm so aktualisiert werden, dass es automatisch Dateien aus dem Container wiederherstellen und lokal speichern kann, während es auch automatisch entsprechende Aktualisierungen an der Dockerfile
. Schließlich kann das Programm auch aktualisiert werden, um leicht ableiten zu können, ob die Basisebene ein leeres scratch
Bild oder etwas anderes verwendet. Mit einigen zusätzlichen Änderungen an der wiederhergestellten Dockerfile
Syntax kann Dedockify möglicherweise aktualisiert werden, um das Reverse Engineering eines Docker-Images in Dockerfile
den meisten Fällen vollständig zu automatisieren.
Aktualisierung: 11. Juli 2022
Ich habe während des Ausbruchs der Pandemie im Jahr 2020 vorgeschlagen und wurde beauftragt, die obige exemplarische Vorgehensweise zu schreiben. Sie wurde von Appfleet veröffentlicht und am 25. Mai 2020 als Appfleet-Blogbeitrag zur Verfügung gestellt. Eine Version dieses Docker Reverse Engineering-Artikels kann ebenfalls verfügbar sein gefunden auf meinem HavDevOps-Blog . Ich veröffentliche die oben aktualisierte Geschichte mit nur geringfügigen Änderungen an Bearbeitung und Formatierung auf Medium. Wenn jemand einen Fehler findet, der meiner Aufmerksamkeit bedarf, können Sie ihn gerne kommentieren.
Mark Havens ist Gründer und Executive Director der Dallas Maker Community (DMC), einer gemeinnützigen Organisation, die den Aufbau des Dallas Makerspace , des größten rein ehrenamtlich tätigen Makerspace in den Vereinigten Staaten, zum Ziel hat. DMC setzt seine reformierten Bemühungen fort, anderen herstellerorientierten Organisationen in ganz Nordtexas herstellerorientiertes Marketing und Makerspace-Führungsschulungen anzubieten.