ย้อนกลับอิมเมจ Docker ของ Engineer เป็น Dockerfiles

Nov 25 2022
ทำวิศวกรรมย้อนกลับอิมเมจของ Docker โดยตรวจสอบภายในว่าอิมเมจของ Docker เก็บข้อมูลอย่างไร TL;DR ในเรื่องนี้ เราจะทำวิศวกรรมย้อนกลับอิมเมจของ Docker โดยดูว่าอิมเมจของ Docker เก็บข้อมูลอย่างไร วิธีใช้เครื่องมือเพื่อดูแง่มุมต่างๆ ของ ภาพและวิธีการสร้างเครื่องมือเช่น Dedockify ที่ใช้ Python Docker API เพื่อสร้าง Dockerfiles บทนำ เนื่องจากการลงทะเบียน Docker สาธารณะ เช่น Docker Hub และ TreeScale ได้รับความนิยมมากขึ้น จึงเป็นเรื่องปกติมากขึ้นที่ผู้ดูแลระบบและนักพัฒนาจะดาวน์โหลดอิมเมจที่สร้างโดยเอนทิตีที่ไม่รู้จัก

ทำวิศวกรรมย้อนกลับอิมเมจนักเทียบท่าโดยตรวจสอบภายในว่าอิมเมจนักเทียบท่าเก็บข้อมูลอย่างไร

TL;ดร

ในเรื่องนี้ เราจะทำวิศวกรรมย้อนกลับอิมเมจของ Docker โดยดูว่าอิมเมจของ Docker เก็บข้อมูลอย่างไร วิธีใช้เครื่องมือเพื่อดูลักษณะต่างๆ ของอิมเมจ และวิธีสร้างเครื่องมืออย่างเช่นDedockifyที่ใช้ Python Docker API ในการสร้าง ไฟล์นักเทียบท่า

แยกภาพประกอบโดยผู้เขียน

บทนำ

เนื่องจากการลงทะเบียน Docker สาธารณะ เช่นDocker HubและTreeScaleได้รับความนิยมมากขึ้น จึงเป็นเรื่องปกติมากขึ้นที่ผู้ดูแลระบบและนักพัฒนาจะดาวน์โหลดอิมเมจที่สร้างโดยเอนทิตีที่ไม่รู้จัก หลายครั้งที่ความสะดวกสบายมีชัยเหนือความเสี่ยง ในบางกรณี เมื่อมีการเผยแพร่อิมเมจ Docker สู่สาธารณะ อิมเมจนั้นจะถูกจัดเตรียมโดยตรงในรายการ ในที่เก็บ git หรือผ่านลิงก์ที่เกี่ยวข้อง บ่อยครั้งที่ไม่มี Dockerfile ให้ ในกรณีที่มี Dockerfile ให้ใช้งาน เรามีการรับประกันเพียงเล็กน้อยว่าอิมเมจที่สร้างไว้ล่วงหน้ามีความสัมพันธ์กับ Dockerfile หรือแม้แต่ใช้งานได้อย่างปลอดภัย

บางทีคุณอาจไม่สนใจเกี่ยวกับช่องโหว่ด้านความปลอดภัย บางทีคุณอาจต้องการอัปเดตรูปภาพโปรดของคุณเพื่อให้ทำงานบน Ubuntu เวอร์ชันล่าสุด หรือบางทีคุณอาจได้รับแรงกระตุ้นที่ควบคุมไม่ได้ให้ปล่อยภาพที่ได้รับการปรับปรุงให้ดีขึ้นเพียงเล็กน้อยเพราะมีคอมไพเลอร์สำหรับการแจกจ่ายอื่นที่เหมาะสมกว่าในการสร้างไบนารีในช่วงเวลาการคอมไพล์

ไม่ว่าด้วยเหตุผลใดก็ตาม มีตัวเลือกสำหรับการกู้คืนไฟล์ Dockerfile ของอิมเมจ อิมเมจ Docker ไม่ใช่กล่องดำ ข้อมูลส่วนใหญ่ที่คุณต้องการในการสร้าง Dockerfile ใหม่สามารถเรียกค้นได้ เมื่อดูภายในอิมเมจ Docker และตรวจสอบภายใน เราจะสามารถสร้าง Dockerfile ใหม่ได้อย่างใกล้ชิดจากคอนเทนเนอร์ที่สร้างไว้ล่วงหน้าโดยพลการ

ในเรื่องนี้ เราจะแสดงให้เห็นว่าเป็นไปได้อย่างไรที่จะสร้างไฟล์ Docker ใหม่จากอิมเมจโดยใช้เครื่องมือสองอย่าง: Dedockifyซึ่งเป็นสคริปต์ Python แบบกำหนดเองที่มีให้สำหรับเรื่องราวนี้ และDiveซึ่งเป็นเครื่องมือสำรวจอิมเมจของ Docker โฟลว์กระบวนการพื้นฐานที่ใช้จะเป็นดังนี้

โฟลว์กระบวนการพื้นฐานโดยใช้ Dedockify ภาพประกอบโดยผู้เขียน

การใช้ไดฟ์

คลิปสาธิตการดำน้ำโดยผู้เขียน

เพื่อให้เข้าใจอย่างรวดเร็วเกี่ยวกับวิธีการจัดองค์ประกอบภาพ เราจะเรียนรู้แนวคิด Docker ขั้นสูงและอาจไม่คุ้นเคยโดยใช้ Dive เครื่องมือดำน้ำตรวจสอบแต่ละเลเยอร์ของอิมเมจ Docker

มาสร้างแบบง่ายๆ ที่ทำตามได้Dockerfileง่ายเพื่อใช้ในการทดสอบ

ใส่ตัวอย่างนี้ลงในไดเร็กทอรีว่างโดยตรง:

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

เราสามารถดูได้จากขนาดของรูปภาพที่ไม่มีรูปภาพต้นฉบับ แทนที่จะใช้อิมเมจต้นฉบับ เราใช้scratchคำสั่ง Docker ให้ใช้อิมเมจว่างศูนย์ไบต์เป็นอิมเมจต้นฉบับ จากนั้นเราแก้ไขภาพเปล่าโดยการคัดลอกไฟล์ทดสอบศูนย์ไบต์เพิ่มเติมสามไฟล์ลงบนภาพ จากนั้นแท็กการเปลี่ยนแปลงexample1เป็น

ตอนนี้ ให้เราสำรวจภาพลักษณ์ใหม่ของเราด้วย Dive

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.

ภาพหน้าจอดำน้ำโดยผู้เขียน

เราจะเห็นเนื้อหาด้านขวาเปลี่ยนไปเมื่อเราเลื่อนดูแต่ละชั้น เมื่อแต่ละไฟล์ถูกคัดลอกไปยังอิมเมจ Docker เปล่าscratchไฟล์นั้นจะถูกบันทึกเป็นเลเยอร์ใหม่

ภาพหน้าจอดำน้ำโดยผู้เขียน

สังเกตด้วยว่าเราสามารถเห็นคำสั่งที่ใช้สร้างแต่ละเลเยอร์ เรายังสามารถดูค่าแฮชของไฟล์ต้นฉบับและไฟล์ที่อัปเดตได้อีกด้วย

หากเราจดรายการในCommand:ส่วนนี้ เราควรจะเห็นสิ่งต่อไปนี้:

#(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in /
#(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in /
#(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in /

ประวัตินักเทียบท่า

นอกเหนือจากเครื่องมือของบุคคลที่สาม เช่นดำน้ำเครื่องมือที่เราพร้อมใช้งานทันทีdocker historyคือ ถ้าเราใช้docker historyคำสั่งบนexample1 ภาพของเรา เราสามารถดูรายการที่เราใช้ใน 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

$ 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 Engine API สำหรับ Python

Docker เปิดตัวไลบรารี Python สำหรับ Docker Engine APIซึ่งอนุญาตให้ควบคุม Docker จากภายใน Python ได้อย่างสมบูรณ์ ในตัวอย่างต่อไปนี้ เราสามารถกู้คืนข้อมูลที่คล้ายกันที่เราใช้docker historyโดยการรันโค้ด 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}]

แยกโลโก้โดยผู้เขียน

ถอดรหัส

มาดำเนินการต่อไปอีกสองสามขั้นตอน เพื่อช่วยทำวิศวกรรมย้อนกลับภาพนี้ให้เป็นไฟล์ Docker เราจะต้องแยกวิเคราะห์ทุกอย่างและฟอร์แมตใหม่ให้เป็นรูปแบบที่สามารถอ่านได้ โปรดทราบว่าสำหรับจุดประสงค์ของเรื่องราวนี้ โค้ด 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()

หากคุณทำสำเร็จแล้ว คุณควรมีภาพสองภาพ: และ ภาพwagoodman/diveที่เรากำหนดเองexample1

$ 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 /

ในการเปรียบเทียบให้เราทำสิ่งเดียวกันกับ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"]

แยกการทดสอบข้อ จำกัด

เรามาทดลองโดยสร้างตัวอย่าง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

$ 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

การสร้างไฟล์ Dockerfile แบบฟรีสไตล์แบบตาบอด

ตอนนี้ ให้เราลองทำวิศวกรรมย้อนกลับกับคอนเทนเนอร์ Docker ด้วยวิธีที่เหมาะสมโดยใช้เครื่องมือที่เราได้พูดถึงไปแล้ว คอนเทนเนอร์ที่เราจะใช้ได้รับการแก้ไขจากตัวอย่างข้างต้น ก่อนหน้านี้ของเราDockerfileได้รับการแก้ไขเพื่อสร้างexample3. ภาพได้รับการทำให้ใช้งานได้โดยการเพิ่มไบนารีขนาดเล็ก ซอร์สโค้ดแอสเซมบลีมีอยู่ที่นี่ในที่เก็บ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

$ 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.

ตอนนี้ให้เรากู้คืนไฟล์เหล่านั้น! ดูเหมือนจะไม่มีวิธีการคัดลอกไฟล์โดยตรงจากรูปภาพ ดังนั้นเราจะต้องสร้างคอนเทนเนอร์ก่อน

$ 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"]

อันดับแรก เราสร้างคอนเทนเนอร์

$ 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.

นี่คือต้นฉบับที่Dockerfileใช้เพื่อสร้าง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"]```

งานในอนาคต

โดยใช้วิธีการคล้ายกับ Dive เราควรจะสามารถอัปเดต ซอร์สโค้ด Dedockifyให้ละเมิดผ่านแต่ละเลเยอร์โดยอัตโนมัติเพื่อกู้คืนข้อมูลไฟล์ที่มีประโยชน์ทั้งหมด นอกจากนี้ยังสามารถอัปเดตโปรแกรมเพื่อให้สามารถกู้คืนไฟล์โดยอัตโนมัติจากคอนเทนเนอร์และจัดเก็บไว้ในเครื่องได้ ในขณะเดียวกันก็อัปเดตไฟล์Dockerfile. สุดท้ายนี้ โปรแกรมยังสามารถอัปเดตเพื่อให้สามารถอนุมานได้อย่างง่ายดายว่าชั้นฐานกำลังใช้scratchรูปภาพเปล่าหรืออย่างอื่น ด้วยการเปลี่ยนแปลงเพิ่มเติมบางอย่างในDockerfileไวยากรณ์ที่กู้คืนมาDedockifyอาจได้รับการอัปเดตเพื่อทำให้วิศวกรรมย้อนกลับของอิมเมจ Docker เป็นไปโดยอัตโนมัติDockerfileในกรณีส่วนใหญ่

ถ้าคุณชอบโพสต์นี้ โจอีกถ้วยจากแฟนอย่างคุณจะสนับสนุนฉันให้เขียนแบบนี้อีกอย่างแน่นอน แวะมาพูดว่า "สวัสดี" และแจ้งให้เราทราบความคิดของคุณเกี่ยวกับหัวข้อที่คุณอาจสนใจอ่าน คุณสามารถจุดประกายแรงบันดาลใจให้ฉันเขียนเกี่ยวกับบางสิ่งที่ยอดเยี่ยมกว่านี้ได้!

อัปเดต: 11 กรกฎาคม 2022

ฉันเสนอชื่อและได้รับมอบหมายให้เขียนคำแนะนำข้างต้นในช่วงที่มีการระบาดใหญ่ในปี 2020 เผยแพร่โดยAppfleetและเผยแพร่เป็นบล็อกโพสต์ของ Appfleetเมื่อวันที่ 25 พฤษภาคม 2020 เวอร์ชันของบทความ Docker Reverse Engineering นี้ยังสามารถ พบได้ในบล็อก HavDevOps ของฉัน ฉันเผยแพร่เรื่องราวที่อัปเดตข้างต้นไปยังสื่อโดยมีการแก้ไขเล็กน้อยและการเปลี่ยนแปลงการจัดรูปแบบเท่านั้น ถ้าใครพบข้อผิดพลาดที่ต้องการความสนใจของฉัน โปรดอย่าลังเลที่จะแสดงความคิดเห็น

Mark Havensเป็นผู้ก่อตั้งและกรรมการบริหารของDallas Maker Community (DMC) ซึ่งเป็นองค์กรไม่แสวงผลกำไรที่จัดตั้งขึ้นเพื่อ เริ่มต้นระบบ Dallas Makerspaceซึ่งเป็นพื้นที่ทำงานอาสาสมัครทั้งหมดที่ใหญ่ที่สุดในสหรัฐอเมริกา DMC ยังคงพยายามปฏิรูปอย่างต่อเนื่องเพื่อให้การตลาดที่มุ่งเน้นผู้ผลิตและการศึกษาความเป็นผู้นำของผู้ผลิตแก่องค์กรอื่น ๆ ที่มีผู้ผลิตเป็นศูนย์กลางทั่วรัฐเท็กซัสตอนเหนือ