2020-07-24 16:14:44 +00:00
// +build linux,!no_containerd_worker windows,!no_containerd_worker
2017-06-08 19:00:31 +00:00
package main
import (
2021-07-09 07:48:03 +00:00
"context"
2017-11-21 08:08:36 +00:00
"os"
2018-08-29 21:00:25 +00:00
"strconv"
2017-11-21 08:08:36 +00:00
"strings"
2018-08-23 07:59:41 +00:00
"time"
2017-11-21 08:08:36 +00:00
ctd "github.com/containerd/containerd"
2018-08-29 21:00:25 +00:00
"github.com/moby/buildkit/cmd/buildkitd/config"
2019-08-06 05:23:23 +00:00
"github.com/moby/buildkit/util/network/cniprovider"
"github.com/moby/buildkit/util/network/netproviders"
2017-11-21 08:08:36 +00:00
"github.com/moby/buildkit/worker"
2017-12-15 08:06:54 +00:00
"github.com/moby/buildkit/worker/base"
2017-11-21 08:08:36 +00:00
"github.com/moby/buildkit/worker/containerd"
2018-07-16 17:05:05 +00:00
"github.com/pkg/errors"
2017-11-21 08:08:36 +00:00
"github.com/sirupsen/logrus"
2017-06-08 19:00:31 +00:00
"github.com/urfave/cli"
2021-05-12 10:41:33 +00:00
"golang.org/x/sync/semaphore"
2017-06-08 19:00:31 +00:00
)
2018-09-05 06:09:27 +00:00
const (
defaultContainerdAddress = "/run/containerd/containerd.sock"
defaultContainerdNamespace = "buildkit"
)
2018-08-29 21:00:25 +00:00
2017-11-21 08:08:36 +00:00
func init ( ) {
2021-08-20 10:57:51 +00:00
defaultConf , _ := defaultConf ( )
2018-08-29 21:00:25 +00:00
enabledValue := func ( b * bool ) string {
if b == nil {
return "auto"
}
return strconv . FormatBool ( * b )
}
if defaultConf . Workers . Containerd . Address == "" {
defaultConf . Workers . Containerd . Address = defaultContainerdAddress
}
2018-09-05 06:09:27 +00:00
if defaultConf . Workers . Containerd . Namespace == "" {
defaultConf . Workers . Containerd . Namespace = defaultContainerdNamespace
}
2019-01-23 01:32:30 +00:00
flags := [ ] cli . Flag {
2017-11-21 08:08:36 +00:00
cli . StringFlag {
Name : "containerd-worker" ,
Usage : "enable containerd workers (true/false/auto)" ,
2018-08-29 21:00:25 +00:00
Value : enabledValue ( defaultConf . Workers . Containerd . Enabled ) ,
2017-11-21 08:08:36 +00:00
} ,
2017-06-08 19:00:31 +00:00
cli . StringFlag {
2017-11-21 08:08:36 +00:00
Name : "containerd-worker-addr" ,
2017-06-08 19:00:31 +00:00
Usage : "containerd socket" ,
2018-08-29 21:00:25 +00:00
Value : defaultConf . Workers . Containerd . Address ,
2017-12-19 09:34:34 +00:00
} ,
cli . StringSliceFlag {
Name : "containerd-worker-labels" ,
Usage : "user-specific annotation labels (com.example.foo=bar)" ,
} ,
2018-07-16 17:05:05 +00:00
// TODO: containerd-worker-platform should be replaced by ability
// to set these from containerd configuration
cli . StringSliceFlag {
Name : "containerd-worker-platform" ,
Usage : "override supported platforms for worker" ,
Hidden : true ,
} ,
2018-09-05 06:09:27 +00:00
cli . StringFlag {
Name : "containerd-worker-namespace" ,
Usage : "override containerd namespace" ,
Value : defaultConf . Workers . Containerd . Namespace ,
Hidden : true ,
} ,
2019-07-10 21:42:30 +00:00
cli . StringFlag {
Name : "containerd-worker-net" ,
Usage : "worker network type (auto, cni or host)" ,
Value : defaultConf . Workers . Containerd . NetworkConfig . Mode ,
} ,
cli . StringFlag {
Name : "containerd-cni-config-path" ,
Usage : "path of cni config file" ,
Value : defaultConf . Workers . Containerd . NetworkConfig . CNIConfigPath ,
} ,
cli . StringFlag {
Name : "containerd-cni-binary-dir" ,
Usage : "path of cni binary files" ,
Value : defaultConf . Workers . Containerd . NetworkConfig . CNIBinaryPath ,
} ,
2020-08-17 09:34:33 +00:00
cli . StringFlag {
Name : "containerd-worker-snapshotter" ,
Usage : "snapshotter name to use" ,
Value : ctd . DefaultSnapshotter ,
} ,
2020-12-07 19:15:52 +00:00
cli . StringFlag {
Name : "containerd-worker-apparmor-profile" ,
Usage : "set the name of the apparmor profile applied to containers" ,
} ,
2019-01-23 01:32:30 +00:00
}
if defaultConf . Workers . Containerd . GC == nil || * defaultConf . Workers . Containerd . GC {
flags = append ( flags , cli . BoolTFlag {
Name : "containerd-worker-gc" ,
Usage : "Enable automatic garbage collection on worker" ,
} )
} else {
flags = append ( flags , cli . BoolFlag {
Name : "containerd-worker-gc" ,
Usage : "Enable automatic garbage collection on worker" ,
} )
}
flags = append ( flags , cli . Int64Flag {
Name : "containerd-worker-gc-keepstorage" ,
Usage : "Amount of storage GC keep locally (MB)" ,
Value : func ( ) int64 {
if defaultConf . Workers . Containerd . GCKeepStorage != 0 {
return defaultConf . Workers . Containerd . GCKeepStorage / 1e6
}
return config . DetectDefaultGCCap ( defaultConf . Root ) / 1e6
} ( ) ,
Hidden : len ( defaultConf . Workers . Containerd . GCPolicy ) != 0 ,
} )
registerWorkerInitializer (
workerInitializer {
fn : containerdWorkerInitializer ,
// 1 is less preferred than 0 (runcCtor)
priority : 1 ,
} ,
flags ... ,
2017-12-19 09:34:34 +00:00
)
2017-11-21 08:08:36 +00:00
// TODO(AkihiroSuda): allow using multiple snapshotters. should be useful for some applications that does not work with the default overlay snapshotter. e.g. mysql (docker/for-linux#72)",
2017-06-08 19:00:31 +00:00
}
2018-08-29 21:00:25 +00:00
func applyContainerdFlags ( c * cli . Context , cfg * config . Config ) error {
if cfg . Workers . Containerd . Address == "" {
cfg . Workers . Containerd . Address = defaultContainerdAddress
2017-11-21 08:08:36 +00:00
}
2018-08-29 21:00:25 +00:00
if c . GlobalIsSet ( "containerd-worker" ) {
boolOrAuto , err := parseBoolOrAuto ( c . GlobalString ( "containerd-worker" ) )
if err != nil {
return err
}
cfg . Workers . Containerd . Enabled = boolOrAuto
2017-12-19 09:34:34 +00:00
}
2018-08-29 21:00:25 +00:00
2018-05-30 02:49:43 +00:00
// GlobalBool works for BoolT as well
rootless := c . GlobalBool ( "rootless" )
if rootless {
logrus . Warn ( "rootless mode is not supported for containerd workers. disabling containerd worker." )
2018-08-29 21:00:25 +00:00
b := false
cfg . Workers . Containerd . Enabled = & b
return nil
}
labels , err := attrMap ( c . GlobalStringSlice ( "containerd-worker-labels" ) )
if err != nil {
return err
}
Initialise workers' label maps before assigning.
Otherwise:
panic: assignment to entry in nil map
goroutine 1 [running]:
main.applyOCIFlags(0xc4200e71e0, 0xc420400000, 0x0, 0x0)
/go/src/github.com/moby/buildkit/cmd/buildkitd/main_oci_worker.go:97 +0x1ac
main.ociWorkerInitializer(0xc4200e71e0, 0xc4204104e0, 0xc420400000, 0x43409b, 0x12, 0xc42026b0f8, 0x4337fc, 0xc420000180)
/go/src/github.com/moby/buildkit/cmd/buildkitd/main_oci_worker.go:118 +0x50
main.newWorkerController(0xc4200e71e0, 0xc4204104e0, 0xc420400000, 0xc420422000, 0xe5dc54, 0x11)
/go/src/github.com/moby/buildkit/cmd/buildkitd/main.go:520 +0x324
main.newController(0xc4200e71e0, 0xc420400000, 0x1c0, 0x0, 0x0)
/go/src/github.com/moby/buildkit/cmd/buildkitd/main.go:489 +0xdc
main.main.func3(0xc4200e71e0, 0x0, 0x0)
/go/src/github.com/moby/buildkit/cmd/buildkitd/main.go:203 +0x3dd
github.com/moby/buildkit/vendor/github.com/urfave/cli.HandleAction(0xcdd420, 0xe93e98, 0xc4200e71e0, 0xc4200e71e0, 0xc42026b888)
/go/src/github.com/moby/buildkit/vendor/github.com/urfave/cli/app.go:502 +0xc8
github.com/moby/buildkit/vendor/github.com/urfave/cli.(*App).Run(0xc4201b6540, 0xc4200300a0, 0xa, 0xa, 0x0, 0x0)
/go/src/github.com/moby/buildkit/vendor/github.com/urfave/cli/app.go:268 +0x60c
main.main()
/go/src/github.com/moby/buildkit/cmd/buildkitd/main.go:238 +0xc64
Also add some random labels to the integration sandbox (which I have confirmed
is enough to trigger this issue before the fix).
Signed-off-by: Ian Campbell <ijc@docker.com>
2018-09-03 10:31:03 +00:00
if cfg . Workers . Containerd . Labels == nil {
cfg . Workers . Containerd . Labels = make ( map [ string ] string )
}
2018-08-29 21:00:25 +00:00
for k , v := range labels {
cfg . Workers . Containerd . Labels [ k ] = v
}
if c . GlobalIsSet ( "containerd-worker-addr" ) {
cfg . Workers . Containerd . Address = c . GlobalString ( "containerd-worker-addr" )
}
if platforms := c . GlobalStringSlice ( "containerd-worker-platform" ) ; len ( platforms ) != 0 {
cfg . Workers . Containerd . Platforms = platforms
}
2018-09-05 06:09:27 +00:00
if c . GlobalIsSet ( "containerd-worker-namespace" ) || cfg . Workers . Containerd . Namespace == "" {
cfg . Workers . Containerd . Namespace = c . GlobalString ( "containerd-worker-namespace" )
}
2019-01-23 01:32:30 +00:00
if c . GlobalIsSet ( "containerd-worker-gc" ) {
v := c . GlobalBool ( "containerd-worker-gc" )
cfg . Workers . Containerd . GC = & v
}
if c . GlobalIsSet ( "containerd-worker-gc-keepstorage" ) {
cfg . Workers . Containerd . GCKeepStorage = c . GlobalInt64 ( "containerd-worker-gc-keepstorage" ) * 1e6
}
2019-07-10 21:42:30 +00:00
if c . GlobalIsSet ( "containerd-worker-net" ) {
cfg . Workers . Containerd . NetworkConfig . Mode = c . GlobalString ( "containerd-worker-net" )
}
if c . GlobalIsSet ( "containerd-cni-config-path" ) {
2020-01-11 04:41:07 +00:00
cfg . Workers . Containerd . NetworkConfig . CNIConfigPath = c . GlobalString ( "containerd-cni-config-path" )
2019-07-10 21:42:30 +00:00
}
if c . GlobalIsSet ( "containerd-cni-binary-dir" ) {
cfg . Workers . Containerd . NetworkConfig . CNIBinaryPath = c . GlobalString ( "containerd-cni-binary-dir" )
}
2020-08-17 09:34:33 +00:00
if c . GlobalIsSet ( "containerd-worker-snapshotter" ) {
cfg . Workers . Containerd . Snapshotter = c . GlobalString ( "containerd-worker-snapshotter" )
}
2020-12-07 19:15:52 +00:00
if c . GlobalIsSet ( "containerd-worker-apparmor-profile" ) {
cfg . Workers . Containerd . ApparmorProfile = c . GlobalString ( "containerd-worker-apparmor-profile" )
}
2019-07-10 21:42:30 +00:00
2018-08-29 21:00:25 +00:00
return nil
}
func containerdWorkerInitializer ( c * cli . Context , common workerInitializerOpt ) ( [ ] worker . Worker , error ) {
if err := applyContainerdFlags ( c , common . config ) ; err != nil {
return nil , err
}
cfg := common . config . Workers . Containerd
if ( cfg . Enabled == nil && ! validContainerdSocket ( cfg . Address ) ) || ( cfg . Enabled != nil && ! * cfg . Enabled ) {
2018-05-30 02:49:43 +00:00
return nil , nil
}
2018-08-29 21:00:25 +00:00
2019-06-06 01:46:52 +00:00
dns := getDNSConfig ( common . config . DNS )
2019-08-06 05:23:23 +00:00
nc := netproviders . Opt {
Mode : common . config . Workers . Containerd . NetworkConfig . Mode ,
CNI : cniprovider . Opt {
Root : common . config . Root ,
ConfigPath : common . config . Workers . Containerd . CNIConfigPath ,
BinaryDir : common . config . Workers . Containerd . CNIBinaryPath ,
} ,
2019-07-10 21:42:30 +00:00
}
2021-05-12 10:41:33 +00:00
var parallelismSem * semaphore . Weighted
2021-05-13 11:55:36 +00:00
if cfg . MaxParallelism > 0 {
parallelismSem = semaphore . NewWeighted ( int64 ( cfg . MaxParallelism ) )
2021-05-12 10:41:33 +00:00
}
2020-08-17 09:34:33 +00:00
snapshotter := ctd . DefaultSnapshotter
if cfg . Snapshotter != "" {
snapshotter = cfg . Snapshotter
}
2021-06-14 06:29:08 +00:00
opt , err := containerd . NewWorkerOpt ( common . config . Root , cfg . Address , snapshotter , cfg . Namespace , cfg . Labels , dns , nc , common . config . Workers . Containerd . ApparmorProfile , parallelismSem , common . traceSocket , ctd . WithTimeout ( 60 * time . Second ) )
2017-11-21 08:08:36 +00:00
if err != nil {
return nil , err
}
2019-01-23 01:28:21 +00:00
opt . GCPolicy = getGCPolicy ( cfg . GCConfig , common . config . Root )
2020-03-05 19:10:21 +00:00
opt . RegistryHosts = resolverFunc ( common . config )
2018-07-16 17:05:05 +00:00
2018-08-29 21:00:25 +00:00
if platformsStr := cfg . Platforms ; len ( platformsStr ) != 0 {
2018-07-16 17:05:05 +00:00
platforms , err := parsePlatforms ( platformsStr )
if err != nil {
return nil , errors . Wrap ( err , "invalid platforms" )
}
opt . Platforms = platforms
}
2021-07-09 07:48:03 +00:00
w , err := base . NewWorker ( context . TODO ( ) , opt )
2017-11-21 08:08:36 +00:00
if err != nil {
return nil , err
}
2017-12-15 08:06:54 +00:00
return [ ] worker . Worker { w } , nil
2017-11-21 08:08:36 +00:00
}
2017-06-08 19:00:31 +00:00
2017-11-21 08:08:36 +00:00
func validContainerdSocket ( socket string ) bool {
if strings . HasPrefix ( socket , "tcp://" ) {
// FIXME(AkihiroSuda): prohibit tcp?
return true
}
socketPath := strings . TrimPrefix ( socket , "unix://" )
2020-04-19 05:17:47 +00:00
if _ , err := os . Stat ( socketPath ) ; errors . Is ( err , os . ErrNotExist ) {
2017-11-21 08:08:36 +00:00
// FIXME(AkihiroSuda): add more conditions
logrus . Warnf ( "skipping containerd worker, as %q does not exist" , socketPath )
return false
}
// TODO: actually dial and call introspection API
return true
2017-06-08 19:00:31 +00:00
}