Skip to content

Commit 07ff714

Browse files
authored
Merge pull request moby#3773 from jedevc/config-allow-storage-units
2 parents 1d30640 + 4cd5b7b commit 07ff714

File tree

10 files changed

+144
-41
lines changed

10 files changed

+144
-41
lines changed

cmd/buildkitd/config/config.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type TLSConfig struct {
4747

4848
type GCConfig struct {
4949
GC *bool `toml:"gc"`
50-
GCKeepStorage int64 `toml:"gckeepstorage"`
50+
GCKeepStorage DiskSpace `toml:"gckeepstorage"`
5151
GCPolicy []GCPolicy `toml:"gcpolicy"`
5252
}
5353

@@ -114,10 +114,10 @@ type ContainerdConfig struct {
114114
}
115115

116116
type GCPolicy struct {
117-
All bool `toml:"all"`
118-
KeepBytes int64 `toml:"keepBytes"`
119-
KeepDuration int64 `toml:"keepDuration"`
120-
Filters []string `toml:"filters"`
117+
All bool `toml:"all"`
118+
KeepBytes DiskSpace `toml:"keepBytes"`
119+
KeepDuration Duration `toml:"keepDuration"`
120+
Filters []string `toml:"filters"`
121121
}
122122

123123
type DNSConfig struct {
@@ -127,6 +127,6 @@ type DNSConfig struct {
127127
}
128128

129129
type HistoryConfig struct {
130-
MaxAge int64 `toml:"maxAge"`
131-
MaxEntries int64 `toml:"maxEntries"`
130+
MaxAge Duration `toml:"maxAge"`
131+
MaxEntries int64 `toml:"maxEntries"`
132132
}

cmd/buildkitd/config/gcpolicy.go

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,86 @@
11
package config
22

3+
import (
4+
"encoding"
5+
"strconv"
6+
"strings"
7+
"time"
8+
9+
"github.com/docker/go-units"
10+
"github.com/pkg/errors"
11+
)
12+
13+
type Duration struct {
14+
time.Duration
15+
}
16+
17+
func (d *Duration) UnmarshalText(textb []byte) error {
18+
text := stripQuotes(string(textb))
19+
if len(text) == 0 {
20+
return nil
21+
}
22+
23+
if duration, err := time.ParseDuration(text); err == nil {
24+
d.Duration = duration
25+
return nil
26+
}
27+
28+
if i, err := strconv.ParseInt(text, 10, 64); err == nil {
29+
d.Duration = time.Duration(i) * time.Second
30+
return nil
31+
}
32+
33+
return errors.Errorf("invalid duration %s", text)
34+
}
35+
36+
var _ encoding.TextUnmarshaler = &Duration{}
37+
38+
type DiskSpace struct {
39+
Bytes int64
40+
Percentage int64
41+
}
42+
43+
var _ encoding.TextUnmarshaler = &DiskSpace{}
44+
45+
func (d *DiskSpace) UnmarshalText(textb []byte) error {
46+
text := stripQuotes(string(textb))
47+
if len(text) == 0 {
48+
return nil
49+
}
50+
51+
if text2 := strings.TrimSuffix(text, "%"); len(text2) < len(text) {
52+
i, err := strconv.ParseInt(text2, 10, 64)
53+
if err != nil {
54+
return err
55+
}
56+
d.Percentage = i
57+
return nil
58+
}
59+
60+
if i, err := units.RAMInBytes(text); err == nil {
61+
d.Bytes = i
62+
return nil
63+
}
64+
65+
return errors.Errorf("invalid disk space %s", text)
66+
}
67+
368
const defaultCap int64 = 2e9 // 2GB
469

5-
func DefaultGCPolicy(p string, keep int64) []GCPolicy {
6-
if keep == 0 {
7-
keep = DetectDefaultGCCap(p)
70+
func DefaultGCPolicy(keep DiskSpace) []GCPolicy {
71+
if keep == (DiskSpace{}) {
72+
keep = DetectDefaultGCCap()
873
}
974
return []GCPolicy{
1075
// if build cache uses more than 512MB delete the most easily reproducible data after it has not been used for 2 days
1176
{
1277
Filters: []string{"type==source.local,type==exec.cachemount,type==source.git.checkout"},
13-
KeepDuration: 48 * 3600, // 48h
14-
KeepBytes: 512 * 1e6, // 512MB
78+
KeepDuration: Duration{Duration: time.Duration(48) * time.Hour}, // 48h
79+
KeepBytes: DiskSpace{Bytes: 512 * 1e6}, // 512MB
1580
},
1681
// remove any data not used for 60 days
1782
{
18-
KeepDuration: 60 * 24 * 3600, // 60d
83+
KeepDuration: Duration{Duration: time.Duration(60) * 24 * time.Hour}, // 60d
1984
KeepBytes: keep,
2085
},
2186
// keep the unshared build cache under cap
@@ -29,3 +94,13 @@ func DefaultGCPolicy(p string, keep int64) []GCPolicy {
2994
},
3095
}
3196
}
97+
98+
func stripQuotes(s string) string {
99+
if len(s) == 0 {
100+
return s
101+
}
102+
if s[0] == '"' && s[len(s)-1] == '"' {
103+
return s[1 : len(s)-1]
104+
}
105+
return s
106+
}

cmd/buildkitd/config/gcpolicy_unix.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,23 @@ import (
77
"syscall"
88
)
99

10-
func DetectDefaultGCCap(root string) int64 {
10+
func DetectDefaultGCCap() DiskSpace {
11+
return DiskSpace{Percentage: 10}
12+
}
13+
14+
func (d DiskSpace) AsBytes(root string) int64 {
15+
if d.Bytes != 0 {
16+
return d.Bytes
17+
}
18+
if d.Percentage == 0 {
19+
return 0
20+
}
21+
1122
var st syscall.Statfs_t
1223
if err := syscall.Statfs(root, &st); err != nil {
1324
return defaultCap
1425
}
1526
diskSize := int64(st.Bsize) * int64(st.Blocks)
16-
avail := diskSize / 10
27+
avail := diskSize * d.Percentage / 100
1728
return (avail/(1<<30) + 1) * 1e9 // round up
1829
}

cmd/buildkitd/config/gcpolicy_windows.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
package config
55

6-
func DetectDefaultGCCap(root string) int64 {
7-
return defaultCap
6+
func DetectDefaultGCCap() DiskSpace {
7+
return DiskSpace{Bytes: defaultCap}
8+
}
9+
10+
func (d DiskSpace) AsBytes(root string) int64 {
11+
return d.Bytes
812
}

cmd/buildkitd/config/load_test.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package config
33
import (
44
"bytes"
55
"testing"
6+
"time"
67

78
"github.com/stretchr/testify/require"
89
)
@@ -44,8 +45,11 @@ filters=["foo==bar"]
4445
keepBytes=20
4546
keepDuration=3600
4647
[[worker.containerd.gcpolicy]]
47-
keepBytes=40
48+
keepBytes="40MB"
4849
keepDuration=7200
50+
[[worker.containerd.gcpolicy]]
51+
keepBytes="20%"
52+
keepDuration="24h"
4953
5054
[registry."docker.io"]
5155
mirrors=["hub.docker.io"]
@@ -78,7 +82,7 @@ searchDomains=["example.com"]
7882
require.Equal(t, "mycert.pem", cfg.GRPC.TLS.Cert)
7983

8084
require.NotNil(t, cfg.Workers.OCI.Enabled)
81-
require.Equal(t, int64(123456789), cfg.Workers.OCI.GCKeepStorage)
85+
require.Equal(t, int64(123456789), cfg.Workers.OCI.GCKeepStorage.Bytes)
8286
require.Equal(t, true, *cfg.Workers.OCI.Enabled)
8387
require.Equal(t, "overlay", cfg.Workers.OCI.Snapshotter)
8488
require.Equal(t, true, cfg.Workers.OCI.Rootless)
@@ -93,15 +97,18 @@ searchDomains=["example.com"]
9397

9498
require.Equal(t, 0, len(cfg.Workers.OCI.GCPolicy))
9599
require.Equal(t, "non-default", cfg.Workers.Containerd.Namespace)
96-
require.Equal(t, 2, len(cfg.Workers.Containerd.GCPolicy))
100+
require.Equal(t, 3, len(cfg.Workers.Containerd.GCPolicy))
97101

98102
require.Nil(t, cfg.Workers.Containerd.GC)
99103
require.Equal(t, true, cfg.Workers.Containerd.GCPolicy[0].All)
100104
require.Equal(t, false, cfg.Workers.Containerd.GCPolicy[1].All)
101-
require.Equal(t, int64(20), cfg.Workers.Containerd.GCPolicy[0].KeepBytes)
102-
require.Equal(t, int64(40), cfg.Workers.Containerd.GCPolicy[1].KeepBytes)
103-
require.Equal(t, int64(3600), cfg.Workers.Containerd.GCPolicy[0].KeepDuration)
104-
require.Equal(t, int64(7200), cfg.Workers.Containerd.GCPolicy[1].KeepDuration)
105+
require.Equal(t, false, cfg.Workers.Containerd.GCPolicy[2].All)
106+
require.Equal(t, int64(20), cfg.Workers.Containerd.GCPolicy[0].KeepBytes.Bytes)
107+
require.Equal(t, int64(40*1024*1024), cfg.Workers.Containerd.GCPolicy[1].KeepBytes.Bytes)
108+
require.Equal(t, int64(20), cfg.Workers.Containerd.GCPolicy[2].KeepBytes.Percentage)
109+
require.Equal(t, time.Duration(3600), cfg.Workers.Containerd.GCPolicy[0].KeepDuration.Duration/time.Second)
110+
require.Equal(t, time.Duration(7200), cfg.Workers.Containerd.GCPolicy[1].KeepDuration.Duration/time.Second)
111+
require.Equal(t, time.Duration(86400), cfg.Workers.Containerd.GCPolicy[2].KeepDuration.Duration/time.Second)
105112
require.Equal(t, 1, len(cfg.Workers.Containerd.GCPolicy[0].Filters))
106113
require.Equal(t, 0, len(cfg.Workers.Containerd.GCPolicy[1].Filters))
107114

cmd/buildkitd/main.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"sort"
1313
"strconv"
1414
"strings"
15-
"time"
1615

1716
"github.com/containerd/containerd/pkg/seed" //nolint:staticcheck // SA1019 deprecated
1817
"github.com/containerd/containerd/pkg/userns"
@@ -771,15 +770,15 @@ func getGCPolicy(cfg config.GCConfig, root string) []client.PruneInfo {
771770
return nil
772771
}
773772
if len(cfg.GCPolicy) == 0 {
774-
cfg.GCPolicy = config.DefaultGCPolicy(root, cfg.GCKeepStorage)
773+
cfg.GCPolicy = config.DefaultGCPolicy(cfg.GCKeepStorage)
775774
}
776775
out := make([]client.PruneInfo, 0, len(cfg.GCPolicy))
777776
for _, rule := range cfg.GCPolicy {
778777
out = append(out, client.PruneInfo{
779778
Filter: rule.Filters,
780779
All: rule.All,
781-
KeepBytes: rule.KeepBytes,
782-
KeepDuration: time.Duration(rule.KeepDuration) * time.Second,
780+
KeepBytes: rule.KeepBytes.AsBytes(root),
781+
KeepDuration: rule.KeepDuration.Duration,
783782
})
784783
}
785784
return out

cmd/buildkitd/main_containerd_worker.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,11 @@ func init() {
137137
Name: "containerd-worker-gc-keepstorage",
138138
Usage: "Amount of storage GC keep locally (MB)",
139139
Value: func() int64 {
140-
if defaultConf.Workers.Containerd.GCKeepStorage != 0 {
141-
return defaultConf.Workers.Containerd.GCKeepStorage / 1e6
140+
keep := defaultConf.Workers.Containerd.GCKeepStorage.AsBytes(defaultConf.Root)
141+
if keep == 0 {
142+
keep = config.DetectDefaultGCCap().AsBytes(defaultConf.Root)
142143
}
143-
return config.DetectDefaultGCCap(defaultConf.Root) / 1e6
144+
return keep / 1e6
144145
}(),
145146
Hidden: len(defaultConf.Workers.Containerd.GCPolicy) != 0,
146147
})
@@ -207,7 +208,7 @@ func applyContainerdFlags(c *cli.Context, cfg *config.Config) error {
207208
}
208209

209210
if c.GlobalIsSet("containerd-worker-gc-keepstorage") {
210-
cfg.Workers.Containerd.GCKeepStorage = c.GlobalInt64("containerd-worker-gc-keepstorage") * 1e6
211+
cfg.Workers.Containerd.GCKeepStorage = config.DiskSpace{Bytes: c.GlobalInt64("containerd-worker-gc-keepstorage") * 1e6}
211212
}
212213

213214
if c.GlobalIsSet("containerd-worker-net") {

cmd/buildkitd/main_oci_worker.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,11 @@ func init() {
153153
Name: "oci-worker-gc-keepstorage",
154154
Usage: "Amount of storage GC keep locally (MB)",
155155
Value: func() int64 {
156-
if defaultConf.Workers.OCI.GCKeepStorage != 0 {
157-
return defaultConf.Workers.OCI.GCKeepStorage / 1e6
156+
keep := defaultConf.Workers.OCI.GCKeepStorage.AsBytes(defaultConf.Root)
157+
if keep == 0 {
158+
keep = config.DetectDefaultGCCap().AsBytes(defaultConf.Root)
158159
}
159-
return config.DetectDefaultGCCap(defaultConf.Root) / 1e6
160+
return keep / 1e6
160161
}(),
161162
Hidden: len(defaultConf.Workers.OCI.GCPolicy) != 0,
162163
})
@@ -221,7 +222,7 @@ func applyOCIFlags(c *cli.Context, cfg *config.Config) error {
221222
}
222223

223224
if c.GlobalIsSet("oci-worker-gc-keepstorage") {
224-
cfg.Workers.OCI.GCKeepStorage = c.GlobalInt64("oci-worker-gc-keepstorage") * 1e6
225+
cfg.Workers.OCI.GCKeepStorage = config.DiskSpace{Bytes: c.GlobalInt64("oci-worker-gc-keepstorage") * 1e6}
225226
}
226227

227228
if c.GlobalIsSet("oci-worker-net") {

docs/buildkitd.toml.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ insecure-entitlements = [ "network.host", "security.insecure" ]
6363
"foo" = "bar"
6464

6565
[[worker.oci.gcpolicy]]
66-
keepBytes = 512000000
67-
keepDuration = 172800
66+
# keepBytes can be an integer number of bytes (e.g. 512000000), a string
67+
# with a unit (e.g. "512MB"), or a string percentage of available disk
68+
# space (e.g. "10%")
69+
keepBytes = "512MB"
70+
# keepDuration can be an integer number of seconds (e.g. 172800), or a
71+
# string duration (e.g. "48h")
72+
keepDuration = "48h"
6873
filters = [ "type==source.local", "type==exec.cachemount", "type==source.git.checkout"]
6974
[[worker.oci.gcpolicy]]
7075
all = true
@@ -87,7 +92,7 @@ insecure-entitlements = [ "network.host", "security.insecure" ]
8792

8893
[[worker.containerd.gcpolicy]]
8994
keepBytes = 512000000
90-
keepDuration = 172800 # in seconds
95+
keepDuration = 172800
9196
filters = [ "type==source.local", "type==exec.cachemount", "type==source.git.checkout"]
9297
[[worker.containerd.gcpolicy]]
9398
all = true

solver/llbsolver/history.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ type StatusImportResult struct {
5454
func NewHistoryQueue(opt HistoryQueueOpt) *HistoryQueue {
5555
if opt.CleanConfig == nil {
5656
opt.CleanConfig = &config.HistoryConfig{
57-
MaxAge: int64((48 * time.Hour).Seconds()),
57+
MaxAge: config.Duration{Duration: 48 * time.Hour},
5858
MaxEntries: 50,
5959
}
6060
}
@@ -116,7 +116,7 @@ func (h *HistoryQueue) gc() error {
116116

117117
now := time.Now()
118118
for _, r := range records[h.CleanConfig.MaxEntries:] {
119-
if now.Add(time.Duration(h.CleanConfig.MaxAge) * -time.Second).After(*r.CompletedAt) {
119+
if now.Add(0 - h.CleanConfig.MaxAge.Duration).After(*r.CompletedAt) {
120120
if err := h.delete(r.Ref, false); err != nil {
121121
return err
122122
}

0 commit comments

Comments
 (0)