Skip to content

Commit 304ebae

Browse files
committed
buildkitd: allow multiple units for gc config
In addition to parsing the raw number of bytes, we can additionally supporting reading short notations from strings, such as "50MB", or "10GB". We can also support different percentages, such as "20%", which allows for consuming a maximum percentage of the disk easily (previously, only the default was set to 10%, with no ability to change to use an arbitrary percentage). Signed-off-by: Justin Chadwell <[email protected]>
1 parent 3187d2d commit 304ebae

File tree

8 files changed

+98
-29
lines changed

8 files changed

+98
-29
lines changed

cmd/buildkitd/config/config.go

Lines changed: 5 additions & 5 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 int64 `toml:"keepDuration"`
120+
Filters []string `toml:"filters"`
121121
}
122122

123123
type DNSConfig struct {

cmd/buildkitd/config/gcpolicy.go

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,55 @@
11
package config
22

3+
import (
4+
"strconv"
5+
"strings"
6+
7+
"github.com/docker/go-units"
8+
"github.com/pkg/errors"
9+
)
10+
11+
type DiskSpace struct {
12+
Bytes int64
13+
Percentage int64
14+
}
15+
16+
var _ encoding.TextUnmarshaler = &DiskSpace{}
17+
18+
func (d *DiskSpace) UnmarshalText(textb []byte) error {
19+
text := stripQuotes(string(textb))
20+
if len(text) == 0 {
21+
return nil
22+
}
23+
24+
if text2 := strings.TrimSuffix(text, "%"); len(text2) < len(text) {
25+
i, err := strconv.ParseInt(text2, 10, 64)
26+
if err != nil {
27+
return err
28+
}
29+
d.Percentage = i
30+
return nil
31+
}
32+
33+
if i, err := units.RAMInBytes(text); err == nil {
34+
d.Bytes = i
35+
return nil
36+
}
37+
38+
return errors.Errorf("invalid disk space %s", text)
39+
}
40+
341
const defaultCap int64 = 2e9 // 2GB
442

5-
func DefaultGCPolicy(p string, keep int64) []GCPolicy {
6-
if keep == 0 {
7-
keep = DetectDefaultGCCap(p)
43+
func DefaultGCPolicy(keep DiskSpace) []GCPolicy {
44+
if keep == (DiskSpace{}) {
45+
keep = DetectDefaultGCCap()
846
}
947
return []GCPolicy{
1048
// if build cache uses more than 512MB delete the most easily reproducible data after it has not been used for 2 days
1149
{
1250
Filters: []string{"type==source.local,type==exec.cachemount,type==source.git.checkout"},
13-
KeepDuration: 48 * 3600, // 48h
14-
KeepBytes: 512 * 1e6, // 512MB
51+
KeepDuration: 48 * 3600, // 48h
52+
KeepBytes: DiskSpace{Bytes: 512 * 1e6}, // 512MB
1553
},
1654
// remove any data not used for 60 days
1755
{
@@ -29,3 +67,13 @@ func DefaultGCPolicy(p string, keep int64) []GCPolicy {
2967
},
3068
}
3169
}
70+
71+
func stripQuotes(s string) string {
72+
if len(s) == 0 {
73+
return s
74+
}
75+
if s[0] == '"' && s[len(s)-1] == '"' {
76+
return s[1 : len(s)-1]
77+
}
78+
return s
79+
}

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: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ filters=["foo==bar"]
4444
keepBytes=20
4545
keepDuration=3600
4646
[[worker.containerd.gcpolicy]]
47-
keepBytes=40
47+
keepBytes="40MB"
4848
keepDuration=7200
49+
[[worker.containerd.gcpolicy]]
50+
keepBytes="20%"
4951
5052
[registry."docker.io"]
5153
mirrors=["hub.docker.io"]
@@ -78,7 +80,7 @@ searchDomains=["example.com"]
7880
require.Equal(t, "mycert.pem", cfg.GRPC.TLS.Cert)
7981

8082
require.NotNil(t, cfg.Workers.OCI.Enabled)
81-
require.Equal(t, int64(123456789), cfg.Workers.OCI.GCKeepStorage)
83+
require.Equal(t, int64(123456789), cfg.Workers.OCI.GCKeepStorage.Bytes)
8284
require.Equal(t, true, *cfg.Workers.OCI.Enabled)
8385
require.Equal(t, "overlay", cfg.Workers.OCI.Snapshotter)
8486
require.Equal(t, true, cfg.Workers.OCI.Rootless)
@@ -93,13 +95,15 @@ searchDomains=["example.com"]
9395

9496
require.Equal(t, 0, len(cfg.Workers.OCI.GCPolicy))
9597
require.Equal(t, "non-default", cfg.Workers.Containerd.Namespace)
96-
require.Equal(t, 2, len(cfg.Workers.Containerd.GCPolicy))
98+
require.Equal(t, 3, len(cfg.Workers.Containerd.GCPolicy))
9799

98100
require.Nil(t, cfg.Workers.Containerd.GC)
99101
require.Equal(t, true, cfg.Workers.Containerd.GCPolicy[0].All)
100102
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, false, cfg.Workers.Containerd.GCPolicy[2].All)
104+
require.Equal(t, int64(20), cfg.Workers.Containerd.GCPolicy[0].KeepBytes.Bytes)
105+
require.Equal(t, int64(40*1024*1024), cfg.Workers.Containerd.GCPolicy[1].KeepBytes.Bytes)
106+
require.Equal(t, int64(20), cfg.Workers.Containerd.GCPolicy[2].KeepBytes.Percentage)
103107
require.Equal(t, int64(3600), cfg.Workers.Containerd.GCPolicy[0].KeepDuration)
104108
require.Equal(t, int64(7200), cfg.Workers.Containerd.GCPolicy[1].KeepDuration)
105109
require.Equal(t, 1, len(cfg.Workers.Containerd.GCPolicy[0].Filters))

cmd/buildkitd/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -769,14 +769,14 @@ func getGCPolicy(cfg config.GCConfig, root string) []client.PruneInfo {
769769
return nil
770770
}
771771
if len(cfg.GCPolicy) == 0 {
772-
cfg.GCPolicy = config.DefaultGCPolicy(root, cfg.GCKeepStorage)
772+
cfg.GCPolicy = config.DefaultGCPolicy(cfg.GCKeepStorage)
773773
}
774774
out := make([]client.PruneInfo, 0, len(cfg.GCPolicy))
775775
for _, rule := range cfg.GCPolicy {
776776
out = append(out, client.PruneInfo{
777777
Filter: rule.Filters,
778778
All: rule.All,
779-
KeepBytes: rule.KeepBytes,
779+
KeepBytes: rule.KeepBytes.AsBytes(root),
780780
KeepDuration: time.Duration(rule.KeepDuration) * time.Second,
781781
})
782782
}

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") {

0 commit comments

Comments
 (0)