Skip to content

Commit 2341e03

Browse files
committed
oci: buildkit TMPDIR fallback
Detect whether the `~/singularity.d/singularity-buildkit` location can be used for buildkit. Full overlay support is required. If not compatible, try falling back to a temporary directory with a warning that there will be no persistent cache. If TMPDIR is not compatible, give a sensible fatal error. Fixes #3382
1 parent d86359a commit 2341e03

File tree

4 files changed

+59
-14
lines changed

4 files changed

+59
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Fix regression from 4.1.5 that overwrites source image runscript, environment
88
etc. in build from local image.
9+
- Fall back to `$TMPDIR` as singularity-buildkitd root directory if
10+
`~/.singularity` is on a filesystem that does not fully support overlay.
911

1012
### New Features & Functionality
1113

cmd/singularity-buildkitd/main.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,27 @@ import (
99
"context"
1010
"os"
1111

12+
"github.com/spf13/pflag"
1213
bkdaemon "github.com/sylabs/singularity/v4/internal/pkg/build/buildkit/daemon"
1314
"github.com/sylabs/singularity/v4/internal/pkg/buildcfg"
1415
"github.com/sylabs/singularity/v4/pkg/sylog"
1516
"github.com/sylabs/singularity/v4/pkg/util/singularityconf"
1617
)
1718

19+
var (
20+
rootDir string
21+
arch string
22+
bkSocket string
23+
)
24+
1825
func main() {
19-
if len(os.Args) < 2 || len(os.Args) > 3 {
20-
sylog.Fatalf("%s: usage: %s <socket-uri> [architecture]", bkdaemon.DaemonName, os.Args[0])
21-
}
26+
pflag.StringVar(&rootDir, "root", "", "buildkitd root directory")
27+
pflag.StringVar(&arch, "arch", "", "build architecture")
28+
pflag.StringVar(&bkSocket, "socket", "", "socket path")
29+
pflag.Parse()
2230

23-
bkSocket := os.Args[1]
24-
bkArch := ""
25-
if len(os.Args) == 3 {
26-
bkArch = os.Args[2]
31+
if bkSocket == "" {
32+
sylog.Fatalf("%s: usage: %s [--root <dir>] [--arch <arch>] --socket <socket-uri>", bkdaemon.DaemonName, os.Args[0])
2733
}
2834

2935
sylog.Debugf("%s: parsing configuration file %s", bkdaemon.DaemonName, buildcfg.SINGULARITY_CONF_FILE)
@@ -34,8 +40,10 @@ func main() {
3440
singularityconf.SetCurrentConfig(config)
3541

3642
daemonOpts := &bkdaemon.Opts{
37-
ReqArch: bkArch,
43+
ReqArch: arch,
44+
RootDir: rootDir,
3845
}
46+
3947
if err := bkdaemon.Run(context.Background(), daemonOpts, bkSocket); err != nil {
4048
sylog.Fatalf("%s: %v", bkdaemon.DaemonName, err)
4149
}

internal/pkg/build/buildkit/client/client.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ import (
4747
"github.com/sylabs/singularity/v4/internal/pkg/ociplatform"
4848
"github.com/sylabs/singularity/v4/internal/pkg/remote/credential/ociauth"
4949
"github.com/sylabs/singularity/v4/internal/pkg/util/bin"
50+
fsoverlay "github.com/sylabs/singularity/v4/internal/pkg/util/fs/overlay"
51+
"github.com/sylabs/singularity/v4/pkg/syfs"
5052
"github.com/sylabs/singularity/v4/pkg/sylog"
5153
"golang.org/x/sync/errgroup"
5254
)
5355

5456
const (
5557
buildTag = "tag"
5658
bkDefaultSocket = "unix:///run/buildkit/buildkitd.sock"
57-
bkLaunchTimeout = 120 * time.Second
59+
bkLaunchTimeout = 10 * time.Second
5860
bkShutdownTimeout = 10 * time.Second
5961
bkMinVersion = "v0.12.3"
6062
)
@@ -163,11 +165,27 @@ func startBuildkitd(ctx context.Context, opts *Opts) (bkSocket string, cleanup f
163165

164166
bkSocket = generateSocketAddress()
165167

166-
// singularity-buildkitd <socket-uri> [architecture]
167-
args := []string{bkSocket}
168+
args := []string{}
169+
tmpRoot := ""
170+
// Check the user .singularity dir is in a location supporting overlayfs etc. If not, use a tmpdir.
171+
if err := fsoverlay.CheckUpper(syfs.ConfigDir()); err != nil {
172+
tmpRoot, err = os.MkdirTemp("", "singularity-buildkitd-")
173+
if err != nil {
174+
sylog.Fatalf("while creating singularity-buildkitd temporary root dir: %v", err)
175+
}
176+
if err := fsoverlay.CheckUpper(tmpRoot); err != nil {
177+
sylog.Fatalf("Temporary directory does not support buildkit. Please set $TMPDIR to a local filesystem.")
178+
}
179+
180+
sylog.Warningf("~/.singularity filesystem does not support buildkit. Using temporary directory %s. Layers will not be cached for future builds.", tmpRoot)
181+
args = append(args, "--root="+tmpRoot)
182+
}
183+
168184
if opts.ReqArch != "" {
169-
args = append(args, opts.ReqArch)
185+
args = append(args, "--arch="+opts.ReqArch)
170186
}
187+
args = append(args, "--socket="+bkSocket)
188+
171189
cmd := exec.CommandContext(ctx, bkCmd, args...)
172190
cmd.WaitDelay = bkShutdownTimeout
173191
cmd.Cancel = func() error {
@@ -182,8 +200,15 @@ func startBuildkitd(ctx context.Context, opts *Opts) (bkSocket string, cleanup f
182200
sylog.Errorf("while canceling buildkit daemon process: %v", err)
183201
}
184202
cmd.Wait()
203+
if tmpRoot != "" {
204+
sylog.Warningf("removing singularity-buildkitd temporary directory %s", tmpRoot)
205+
if err := os.RemoveAll(tmpRoot); err != nil {
206+
sylog.Errorf("while removing singularity-buildkitd temp dir: %v", err)
207+
}
208+
}
185209
}
186210

211+
sylog.Debugf("starting %s %v", bkCmd, args)
187212
if err := cmd.Start(); err != nil {
188213
return "", nil, err
189214
}

internal/pkg/build/buildkit/daemon/daemon.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ const DaemonName = "singularity-buildkitd"
8080
type Opts struct {
8181
// Requested build architecture
8282
ReqArch string
83+
// Override the location of the singularity-buildkitd root with specified directory
84+
RootDir string
8385
}
8486

8587
type workerInitializerOpt struct {
@@ -149,7 +151,7 @@ func waitLock(ctx context.Context, lockPath string) (*flock.Flock, error) {
149151
func Run(ctx context.Context, opts *Opts, socketPath string) error {
150152
// If we need to, enter a new cgroup now, to workaround an issue with crun container cgroup creation (#1538).
151153
if err := oci.CrunNestCgroup(); err != nil {
152-
sylog.Fatalf("%s: while applying crun cgroup workaround: %v", DaemonName, err)
154+
return fmt.Errorf("%s: while applying crun cgroup workaround: %v", DaemonName, err)
153155
}
154156

155157
cfg, err := config.LoadFile(defaultConfigPath())
@@ -166,6 +168,14 @@ func Run(ctx context.Context, opts *Opts, socketPath string) error {
166168

167169
server := grpc.NewServer()
168170

171+
if opts.RootDir != "" {
172+
ptr := func(v bool) *bool {
173+
return &v
174+
}
175+
cfg.Root = opts.RootDir
176+
cfg.Workers.OCI.GC = ptr(false)
177+
}
178+
169179
// relative path does not work with nightlyone/lockfile
170180
root, err := filepath.Abs(cfg.Root)
171181
if err != nil {
@@ -181,7 +191,7 @@ func Run(ctx context.Context, opts *Opts, socketPath string) error {
181191
sylog.Debugf("%s: path for buildkitd lock file: %s", DaemonName, lockPath)
182192
lock, err := waitLock(ctx, lockPath)
183193
if err != nil {
184-
sylog.Fatalf("%s: while creating lock file: %v", DaemonName, err)
194+
return fmt.Errorf("%s: while creating lock file: %v", DaemonName, err)
185195
}
186196
defer func() {
187197
lock.Unlock()

0 commit comments

Comments
 (0)