我正在编写一个Go程序,以便从我的扩展底座主机获取以GB为单位的总磁盘使用量.为此,我使用来自Go lib的Func DiskUsage():

查看代码,此函数将调用docker API端点/system/df:

然而,当我使用这个库与使用命令docker system df计算GB时,我注意到一个奇怪的行为:

  • docker system df输出:
    $ docker system df
    TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
    Images          223       4         21.02GB   20.7GB (98%)
    Containers      6         0         0B        0B
    Local Volumes   13        1         536.4MB   340.4MB (63%)
    Build Cache     954       0         13.51GB   13.51GB
    
  • 我的GO应用程序输出:
    $ go run ./cmd/main.go
    Images: TOTAL (223), 17GB
    Build Cache: TOTAL (954), 29GB
    

正如您所看到的,我们在两个输出之间存在差异.I would like a help to understand if I am doing something wrong with this calculation which gets data from the 100 endpoint.谢谢:)

GO申请:

package main

import (
    "context"
    "fmt"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func main() {
    cli, err := client.NewClientWithOpts(client.FromEnv)
    if err != nil {
        panic(err)
    }

    diskUsg, err := cli.DiskUsage(context.Background(), types.DiskUsageOptions{})
    if err != nil {
        panic(err)
    }
    b := float64(0)
    for _, ch := range diskUsg.BuildCache {
        b = b + float64(ch.Size)
    }

    b2 := float64(0)
    for _, ch := range diskUsg.Images {
        if ch.Size > ch.SharedSize {
            b2 = b2 + (float64(ch.Size) - float64(ch.SharedSize))
            continue
        }
        b2 = b2 + (float64(ch.SharedSize) - float64(ch.Size))
    }

    fmt.Printf("Images: TOTAL (%d), %2.fGB\n", len(diskUsg.Images), float64(b2)/(1<<30))
    fmt.Printf("Build Cache: TOTAL (%d), %2.fGB\n", len(diskUsg.BuildCache), float64(b)/(1<<30))
}

推荐答案

基于Docker源码:

您应该能够使用以下代码精确地重现docker system df所做的事情:

  • go.mod
module 76982562-docker-system-df-vs-system-df-docker-api-endpoint

go 1.21.0

require (
    github.com/docker/cli v24.0.5+incompatible
    github.com/docker/docker v24.0.5+incompatible
)
  • main.go
package main

import (
    "context"
    "fmt"
    "os"

    "github.com/docker/cli/cli/command/formatter"
    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
    "github.com/docker/go-units"
)

func main() {
    cli, err := client.NewClientWithOpts(client.FromEnv)
    if err != nil {
        panic(err)
    }

    diskUsage, err := cli.DiskUsage(context.Background(), types.DiskUsageOptions{})
    if err != nil {
        panic(err)
    }

    var bsz int64
    for _, bc := range diskUsage.BuildCache {
        if !bc.Shared {
            bsz += bc.Size
        }
    }

    fmt.Printf("Images: TOTAL (%d), %s\n", len(diskUsage.Images), units.HumanSize(float64(diskUsage.LayersSize)))
    fmt.Printf("Build Cache: TOTAL (%d), %s\n", len(diskUsage.BuildCache), units.HumanSize(float64(bsz)))
}
  • 对于图像,docker库直接提供diskUsage.LayersSize来表示总大小,所以你不必自己计算
  • 对于构建缓存,您需要排除共享项目(if !bc.Shared)

要将尺寸转换为正确的单位,我强烈建议使用github.com/docker/go-units(例如units.HumanSize(float64(diskUsage.LayersSize))).这将避免你的单位转换噩梦!

Go相关问答推荐

gorm插入不支持的数据

在整个SQL事务中将使用上下文作为默认设置吗?

如何使用 Go 连接到非默认 firestore 数据库?

在VSCode中如何使用特定的文件名提供编译命令

如何解决构建Docker Compose时的权限被拒绝问题

如何将已知类型转换为指向switch 中类型参数的指针?

Github Actions Go lambda 项目不同的 sha256sums

如何在 `hashicorp / terraform-exec` 中将 `ApplyConfig` 传递给 `tf.Apply()`?

没有任务角色的 AWS CDK ECS 任务定义

如何在自定义验证函数中获取 struct 名称

将shell输出绑定到Go中的 struct 的最佳方法?

try 运行 docker-compose up -d 时出现错误

panic :拨号 tcp:在 172.22.64.1:53 上查找 bookstoreDB:没有这样的主机

Go:等待多个通道的性能损失

如何通过组合来自不同包的接口来创建接口?

如何在 GORM 中迭代一个 int 数组

从另一个没有重复的确定性 int

Go:如何创建一个可以提供配置文件中描述的 url 的服务器

如何在 docker 文件中安装 golang 包?

Golang 'defer' 导致发送(接收)API 响应延迟