Tìm mã nguồn cho kích thước tính toán của hình ảnh docker


8

Tôi đã nghe nói số lượng không bằng tất cả các kích thước của các lớp cộng lại với nhau bên trong một hình ảnh. Và nó cũng không phải là kích thước của không gian đĩa mà nó chiếm.

Bây giờ tôi muốn kiểm tra logic bằng mã nguồn (trong repo này: https://github.com/docker/docker-ce ), bởi vì nhìn thấy là tin tưởng! Nhưng sau khi điều hướng mã trong nhiều thời gian, tôi thấy rằng tôi không thể tìm thấy mã tính toán kích thước hình ảnh thực.

Vì vậy, chức năng / tập tin nào là docker được sử dụng để thực hiện logic kích thước?

Câu trả lời:


13

Trước khi đào quá sâu, bạn có thể thấy hữu ích để hiểu cách Linux triển khai hệ thống tệp lớp phủ. Tôi bao gồm một chút về điều này bài tập đầu tiên của phần xây dựng phần giới thiệu của tôi . Các ghi chú demo bao gồm từng lệnh tôi đang chạy và nó cho bạn ý tưởng về cách các lớp được hợp nhất và điều gì xảy ra khi bạn thêm / sửa đổi / xóa từ một lớp.


Điều này phụ thuộc vào việc triển khai, dựa trên hệ điều hành máy chủ của bạn và trình điều khiển biểu đồ đang được sử dụng. Tôi lấy ví dụ về HĐH Linux và Overlay2 vì đó là trường hợp sử dụng phổ biến nhất.

Nó bắt đầu bằng cách nhìn vào kích thước lưu trữ của lớp hình ảnh :

// GetContainerLayerSize returns the real size & virtual size of the container.
func (i *ImageService) GetContainerLayerSize(containerID string) (int64, int64) {
    var (
        sizeRw, sizeRootfs int64
        err                error
    )

    // Safe to index by runtime.GOOS as Unix hosts don't support multiple
    // container operating systems.
    rwlayer, err := i.layerStores[runtime.GOOS].GetRWLayer(containerID)
    if err != nil {
        logrus.Errorf("Failed to compute size of container rootfs %v: %v", containerID, err)
        return sizeRw, sizeRootfs
    }
    defer i.layerStores[runtime.GOOS].ReleaseRWLayer(rwlayer)

    sizeRw, err = rwlayer.Size()
    if err != nil {
        logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
            i.layerStores[runtime.GOOS].DriverName(), containerID, err)
        // FIXME: GetSize should return an error. Not changing it now in case
        // there is a side-effect.
        sizeRw = -1
    }

    if parent := rwlayer.Parent(); parent != nil {
        sizeRootfs, err = parent.Size()
        if err != nil {
            sizeRootfs = -1
        } else if sizeRw != -1 {
            sizeRootfs += sizeRw
        }
    }
    return sizeRw, sizeRootfs
}

Trong đó có một cuộc gọi layerStoresmà chính nó là ánh xạ tới layer.Store :

// ImageServiceConfig is the configuration used to create a new ImageService
type ImageServiceConfig struct {
    ContainerStore            containerStore
    DistributionMetadataStore metadata.Store
    EventsService             *daemonevents.Events
    ImageStore                image.Store
    LayerStores               map[string]layer.Store
    MaxConcurrentDownloads    int
    MaxConcurrentUploads      int
    MaxDownloadAttempts       int
    ReferenceStore            dockerreference.Store
    RegistryService           registry.Service
    TrustKey                  libtrust.PrivateKey
}

Đi sâu vào layer.Storethực hiện GetRWLayer, có định nghĩa sau :

func (ls *layerStore) GetRWLayer(id string) (RWLayer, error) {
    ls.locker.Lock(id)
    defer ls.locker.Unlock(id)

    ls.mountL.Lock()
    mount := ls.mounts[id]
    ls.mountL.Unlock()
    if mount == nil {
        return nil, ErrMountDoesNotExist
    }

    return mount.getReference(), nil
}

Theo đó để tìm cách Sizetriển khai cho tham chiếu gắn kết, có chức năng này được đưa vào trình điều khiển biểu đồ cụ thể:

func (ml *mountedLayer) Size() (int64, error) {
    return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
}

Nhìn vào trình điều khiển biểu đồ lớp phủ2 để tìm hàm DiffSize :

func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
    if useNaiveDiff(d.home) || !d.isParent(id, parent) {
        return d.naiveDiff.DiffSize(id, parent)
    }
    return directory.Size(context.TODO(), d.getDiffPath(id))
}

Đó là cách gọi naiveDiffthực hiện Kích thước trong gói graphDriver :

func (gdw *NaiveDiffDriver) DiffSize(id, parent string) (size int64, err error) {
    driver := gdw.ProtoDriver

    changes, err := gdw.Changes(id, parent)
    if err != nil {
        return
    }

    layerFs, err := driver.Get(id, "")
    if err != nil {
        return
    }
    defer driver.Put(id)

    return archive.ChangesSize(layerFs.Path(), changes), nil
}

Sau đây archive.ChangeSizechúng ta có thể thấy việc thực hiện này :

// ChangesSize calculates the size in bytes of the provided changes, based on newDir.
func ChangesSize(newDir string, changes []Change) int64 {
    var (
        size int64
        sf   = make(map[uint64]struct{})
    )
    for _, change := range changes {
        if change.Kind == ChangeModify || change.Kind == ChangeAdd {
            file := filepath.Join(newDir, change.Path)
            fileInfo, err := os.Lstat(file)
            if err != nil {
                logrus.Errorf("Can not stat %q: %s", file, err)
                continue
            }

            if fileInfo != nil && !fileInfo.IsDir() {
                if hasHardlinks(fileInfo) {
                    inode := getIno(fileInfo)
                    if _, ok := sf[inode]; !ok {
                        size += fileInfo.Size()
                        sf[inode] = struct{}{}
                    }
                } else {
                    size += fileInfo.Size()
                }
            }
        }
    }
    return size
}

Tại điểm chúng ta đang sử dụng os.Lstatđể trả về một cấu trúc bao gồm Sizetrên mỗi mục nhập là thêm hoặc sửa đổi cho mỗi thư mục. Lưu ý rằng đây là một trong một số đường dẫn có thể có của mã, nhưng tôi tin rằng đó là một trong những đường dẫn phổ biến hơn cho kịch bản này.


2
Rất hướng dẫn. Nâng cao. Thêm vào đó, tôi đã nghe player.fm/series/devops-and-docker-talk/ , vì vậy ... tôi cố gắng giúp đỡ bất cứ khi nào tôi có thể!
VonC

0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.