github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/builder/builder-next/controller.go (about) 1 package buildkit 2 3 import ( 4 "context" 5 "net/http" 6 "os" 7 "path/filepath" 8 "time" 9 10 "github.com/Prakhar-Agarwal-byte/moby/api/types" 11 "github.com/Prakhar-Agarwal-byte/moby/api/types/filters" 12 "github.com/Prakhar-Agarwal-byte/moby/builder/builder-next/adapters/containerimage" 13 "github.com/Prakhar-Agarwal-byte/moby/builder/builder-next/adapters/localinlinecache" 14 "github.com/Prakhar-Agarwal-byte/moby/builder/builder-next/adapters/snapshot" 15 "github.com/Prakhar-Agarwal-byte/moby/builder/builder-next/exporter/mobyexporter" 16 "github.com/Prakhar-Agarwal-byte/moby/builder/builder-next/imagerefchecker" 17 mobyworker "github.com/Prakhar-Agarwal-byte/moby/builder/builder-next/worker" 18 wlabel "github.com/Prakhar-Agarwal-byte/moby/builder/builder-next/worker/label" 19 "github.com/Prakhar-Agarwal-byte/moby/daemon/config" 20 "github.com/Prakhar-Agarwal-byte/moby/daemon/graphdriver" 21 ctd "github.com/containerd/containerd" 22 "github.com/containerd/containerd/content/local" 23 ctdmetadata "github.com/containerd/containerd/metadata" 24 "github.com/containerd/containerd/snapshots" 25 "github.com/containerd/log" 26 units "github.com/docker/go-units" 27 "github.com/moby/buildkit/cache" 28 "github.com/moby/buildkit/cache/metadata" 29 "github.com/moby/buildkit/cache/remotecache" 30 "github.com/moby/buildkit/cache/remotecache/gha" 31 inlineremotecache "github.com/moby/buildkit/cache/remotecache/inline" 32 localremotecache "github.com/moby/buildkit/cache/remotecache/local" 33 registryremotecache "github.com/moby/buildkit/cache/remotecache/registry" 34 "github.com/moby/buildkit/client" 35 bkconfig "github.com/moby/buildkit/cmd/buildkitd/config" 36 "github.com/moby/buildkit/control" 37 "github.com/moby/buildkit/frontend" 38 dockerfile "github.com/moby/buildkit/frontend/dockerfile/builder" 39 "github.com/moby/buildkit/frontend/gateway" 40 "github.com/moby/buildkit/frontend/gateway/forwarder" 41 containerdsnapshot "github.com/moby/buildkit/snapshot/containerd" 42 "github.com/moby/buildkit/solver" 43 "github.com/moby/buildkit/solver/bboltcachestorage" 44 "github.com/moby/buildkit/util/archutil" 45 "github.com/moby/buildkit/util/entitlements" 46 "github.com/moby/buildkit/util/network/netproviders" 47 "github.com/moby/buildkit/util/tracing/detect" 48 "github.com/moby/buildkit/worker" 49 "github.com/moby/buildkit/worker/containerd" 50 "github.com/moby/buildkit/worker/label" 51 "github.com/pkg/errors" 52 "go.etcd.io/bbolt" 53 bolt "go.etcd.io/bbolt" 54 "go.opentelemetry.io/otel/sdk/trace" 55 56 "github.com/moby/buildkit/solver/pb" 57 "github.com/moby/buildkit/util/apicaps" 58 ) 59 60 func newController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) { 61 if opt.UseSnapshotter { 62 return newSnapshotterController(ctx, rt, opt) 63 } 64 return newGraphDriverController(ctx, rt, opt) 65 } 66 67 func getTraceExporter(ctx context.Context) trace.SpanExporter { 68 exp, err := detect.Exporter() 69 if err != nil { 70 log.G(ctx).WithError(err).Error("Failed to detect trace exporter for buildkit controller") 71 } 72 return exp 73 } 74 75 func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) { 76 if err := os.MkdirAll(opt.Root, 0o711); err != nil { 77 return nil, err 78 } 79 80 historyDB, historyConf, err := openHistoryDB(opt.Root, opt.BuilderConfig.History) 81 if err != nil { 82 return nil, err 83 } 84 85 cacheStorage, err := bboltcachestorage.NewStore(filepath.Join(opt.Root, "cache.db")) 86 if err != nil { 87 return nil, err 88 } 89 90 nc := netproviders.Opt{ 91 Mode: "host", 92 } 93 dns := getDNSConfig(opt.DNSConfig) 94 95 wo, err := containerd.NewWorkerOpt(opt.Root, opt.ContainerdAddress, opt.Snapshotter, opt.ContainerdNamespace, 96 opt.Rootless, map[string]string{ 97 label.Snapshotter: opt.Snapshotter, 98 }, dns, nc, opt.ApparmorProfile, false, nil, "", ctd.WithTimeout(60*time.Second)) 99 if err != nil { 100 return nil, err 101 } 102 103 policy, err := getGCPolicy(opt.BuilderConfig, opt.Root) 104 if err != nil { 105 return nil, err 106 } 107 108 wo.GCPolicy = policy 109 wo.RegistryHosts = opt.RegistryHosts 110 wo.Labels = getLabels(opt, wo.Labels) 111 112 exec, err := newExecutor(opt.Root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile) 113 if err != nil { 114 return nil, err 115 } 116 wo.Executor = exec 117 118 w, err := mobyworker.NewContainerdWorker(ctx, wo) 119 if err != nil { 120 return nil, err 121 } 122 123 wc := &worker.Controller{} 124 125 err = wc.Add(w) 126 if err != nil { 127 return nil, err 128 } 129 frontends := map[string]frontend.Frontend{ 130 "dockerfile.v0": forwarder.NewGatewayForwarder(wc, dockerfile.Build), 131 "gateway.v0": gateway.NewGatewayFrontend(wc), 132 } 133 134 return control.NewController(control.Opt{ 135 SessionManager: opt.SessionManager, 136 WorkerController: wc, 137 Frontends: frontends, 138 CacheManager: solver.NewCacheManager(ctx, "local", cacheStorage, worker.NewCacheResultStorage(wc)), 139 CacheStore: cacheStorage, 140 ResolveCacheImporterFuncs: map[string]remotecache.ResolveCacheImporterFunc{ 141 "gha": gha.ResolveCacheImporterFunc(), 142 "local": localremotecache.ResolveCacheImporterFunc(opt.SessionManager), 143 "registry": registryremotecache.ResolveCacheImporterFunc(opt.SessionManager, wo.ContentStore, opt.RegistryHosts), 144 }, 145 ResolveCacheExporterFuncs: map[string]remotecache.ResolveCacheExporterFunc{ 146 "gha": gha.ResolveCacheExporterFunc(), 147 "inline": inlineremotecache.ResolveCacheExporterFunc(), 148 "local": localremotecache.ResolveCacheExporterFunc(opt.SessionManager), 149 "registry": registryremotecache.ResolveCacheExporterFunc(opt.SessionManager, opt.RegistryHosts), 150 }, 151 Entitlements: getEntitlements(opt.BuilderConfig), 152 HistoryDB: historyDB, 153 HistoryConfig: historyConf, 154 LeaseManager: wo.LeaseManager, 155 ContentStore: wo.ContentStore, 156 TraceCollector: getTraceExporter(ctx), 157 }) 158 } 159 160 func openHistoryDB(root string, cfg *config.BuilderHistoryConfig) (*bolt.DB, *bkconfig.HistoryConfig, error) { 161 db, err := bbolt.Open(filepath.Join(root, "history.db"), 0o600, nil) 162 if err != nil { 163 return nil, nil, err 164 } 165 166 var conf *bkconfig.HistoryConfig 167 if cfg != nil { 168 conf = &bkconfig.HistoryConfig{ 169 MaxAge: cfg.MaxAge, 170 MaxEntries: cfg.MaxEntries, 171 } 172 } 173 174 return db, conf, nil 175 } 176 177 func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) { 178 if err := os.MkdirAll(opt.Root, 0o711); err != nil { 179 return nil, err 180 } 181 182 dist := opt.Dist 183 root := opt.Root 184 185 pb.Caps.Init(apicaps.Cap{ 186 ID: pb.CapMergeOp, 187 Enabled: false, 188 DisabledReasonMsg: "only enabled with containerd image store backend", 189 }) 190 191 pb.Caps.Init(apicaps.Cap{ 192 ID: pb.CapDiffOp, 193 Enabled: false, 194 DisabledReasonMsg: "only enabled with containerd image store backend", 195 }) 196 197 var driver graphdriver.Driver 198 if ls, ok := dist.LayerStore.(interface { 199 Driver() graphdriver.Driver 200 }); ok { 201 driver = ls.Driver() 202 } else { 203 return nil, errors.Errorf("could not access graphdriver") 204 } 205 206 innerStore, err := local.NewStore(filepath.Join(root, "content")) 207 if err != nil { 208 return nil, err 209 } 210 211 db, err := bolt.Open(filepath.Join(root, "containerdmeta.db"), 0o644, nil) 212 if err != nil { 213 return nil, errors.WithStack(err) 214 } 215 216 mdb := ctdmetadata.NewDB(db, innerStore, map[string]snapshots.Snapshotter{}) 217 218 store := containerdsnapshot.NewContentStore(mdb.ContentStore(), "buildkit") 219 220 snapshotter, lm, err := snapshot.NewSnapshotter(snapshot.Opt{ 221 GraphDriver: driver, 222 LayerStore: dist.LayerStore, 223 Root: root, 224 IdentityMapping: opt.IdentityMapping, 225 }, ctdmetadata.NewLeaseManager(mdb), "buildkit") 226 if err != nil { 227 return nil, err 228 } 229 230 if err := cache.MigrateV2(context.Background(), filepath.Join(root, "metadata.db"), filepath.Join(root, "metadata_v2.db"), store, snapshotter, lm); err != nil { 231 return nil, err 232 } 233 234 md, err := metadata.NewStore(filepath.Join(root, "metadata_v2.db")) 235 if err != nil { 236 return nil, err 237 } 238 239 layerGetter, ok := snapshotter.(imagerefchecker.LayerGetter) 240 if !ok { 241 return nil, errors.Errorf("snapshotter does not implement layergetter") 242 } 243 244 refChecker := imagerefchecker.New(imagerefchecker.Opt{ 245 ImageStore: dist.ImageStore, 246 LayerGetter: layerGetter, 247 }) 248 249 cm, err := cache.NewManager(cache.ManagerOpt{ 250 Snapshotter: snapshotter, 251 MetadataStore: md, 252 PruneRefChecker: refChecker, 253 LeaseManager: lm, 254 ContentStore: store, 255 GarbageCollect: mdb.GarbageCollect, 256 }) 257 if err != nil { 258 return nil, err 259 } 260 261 src, err := containerimage.NewSource(containerimage.SourceOpt{ 262 CacheAccessor: cm, 263 ContentStore: store, 264 DownloadManager: dist.DownloadManager, 265 MetadataStore: dist.V2MetadataService, 266 ImageStore: dist.ImageStore, 267 ReferenceStore: dist.ReferenceStore, 268 RegistryHosts: opt.RegistryHosts, 269 LayerStore: dist.LayerStore, 270 LeaseManager: lm, 271 GarbageCollect: mdb.GarbageCollect, 272 }) 273 if err != nil { 274 return nil, err 275 } 276 277 dns := getDNSConfig(opt.DNSConfig) 278 279 exec, err := newExecutor(root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile) 280 if err != nil { 281 return nil, err 282 } 283 284 differ, ok := snapshotter.(mobyexporter.Differ) 285 if !ok { 286 return nil, errors.Errorf("snapshotter doesn't support differ") 287 } 288 289 exp, err := mobyexporter.New(mobyexporter.Opt{ 290 ImageStore: dist.ImageStore, 291 Differ: differ, 292 ImageTagger: opt.ImageTagger, 293 }) 294 if err != nil { 295 return nil, err 296 } 297 298 cacheStorage, err := bboltcachestorage.NewStore(filepath.Join(opt.Root, "cache.db")) 299 if err != nil { 300 return nil, err 301 } 302 303 historyDB, historyConf, err := openHistoryDB(opt.Root, opt.BuilderConfig.History) 304 if err != nil { 305 return nil, err 306 } 307 308 gcPolicy, err := getGCPolicy(opt.BuilderConfig, root) 309 if err != nil { 310 return nil, errors.Wrap(err, "could not get builder GC policy") 311 } 312 313 layers, ok := snapshotter.(mobyworker.LayerAccess) 314 if !ok { 315 return nil, errors.Errorf("snapshotter doesn't support differ") 316 } 317 318 leases, err := lm.List(ctx, `labels."buildkit/lease.temporary"`) 319 if err != nil { 320 return nil, err 321 } 322 for _, l := range leases { 323 lm.Delete(ctx, l) 324 } 325 326 wopt := mobyworker.Opt{ 327 ID: opt.EngineID, 328 ContentStore: store, 329 CacheManager: cm, 330 GCPolicy: gcPolicy, 331 Snapshotter: snapshotter, 332 Executor: exec, 333 ImageSource: src, 334 DownloadManager: dist.DownloadManager, 335 V2MetadataService: dist.V2MetadataService, 336 Exporter: exp, 337 Transport: rt, 338 Layers: layers, 339 Platforms: archutil.SupportedPlatforms(true), 340 LeaseManager: lm, 341 Labels: getLabels(opt, nil), 342 } 343 344 wc := &worker.Controller{} 345 w, err := mobyworker.NewWorker(wopt) 346 if err != nil { 347 return nil, err 348 } 349 wc.Add(w) 350 351 frontends := map[string]frontend.Frontend{ 352 "dockerfile.v0": forwarder.NewGatewayForwarder(wc, dockerfile.Build), 353 "gateway.v0": gateway.NewGatewayFrontend(wc), 354 } 355 356 return control.NewController(control.Opt{ 357 SessionManager: opt.SessionManager, 358 WorkerController: wc, 359 Frontends: frontends, 360 CacheManager: solver.NewCacheManager(ctx, "local", cacheStorage, worker.NewCacheResultStorage(wc)), 361 CacheStore: cacheStorage, 362 ResolveCacheImporterFuncs: map[string]remotecache.ResolveCacheImporterFunc{ 363 "registry": localinlinecache.ResolveCacheImporterFunc(opt.SessionManager, opt.RegistryHosts, store, dist.ReferenceStore, dist.ImageStore), 364 "local": localremotecache.ResolveCacheImporterFunc(opt.SessionManager), 365 }, 366 ResolveCacheExporterFuncs: map[string]remotecache.ResolveCacheExporterFunc{ 367 "inline": inlineremotecache.ResolveCacheExporterFunc(), 368 }, 369 Entitlements: getEntitlements(opt.BuilderConfig), 370 LeaseManager: lm, 371 ContentStore: store, 372 HistoryDB: historyDB, 373 HistoryConfig: historyConf, 374 TraceCollector: getTraceExporter(ctx), 375 }) 376 } 377 378 func getGCPolicy(conf config.BuilderConfig, root string) ([]client.PruneInfo, error) { 379 var gcPolicy []client.PruneInfo 380 if conf.GC.Enabled { 381 var ( 382 defaultKeepStorage int64 383 err error 384 ) 385 386 if conf.GC.DefaultKeepStorage != "" { 387 defaultKeepStorage, err = units.RAMInBytes(conf.GC.DefaultKeepStorage) 388 if err != nil { 389 return nil, errors.Wrapf(err, "could not parse '%s' as Builder.GC.DefaultKeepStorage config", conf.GC.DefaultKeepStorage) 390 } 391 } 392 393 if conf.GC.Policy == nil { 394 gcPolicy = mobyworker.DefaultGCPolicy(root, defaultKeepStorage) 395 } else { 396 gcPolicy = make([]client.PruneInfo, len(conf.GC.Policy)) 397 for i, p := range conf.GC.Policy { 398 b, err := units.RAMInBytes(p.KeepStorage) 399 if err != nil { 400 return nil, err 401 } 402 if b == 0 { 403 b = defaultKeepStorage 404 } 405 gcPolicy[i], err = toBuildkitPruneInfo(types.BuildCachePruneOptions{ 406 All: p.All, 407 KeepStorage: b, 408 Filters: filters.Args(p.Filter), 409 }) 410 if err != nil { 411 return nil, err 412 } 413 } 414 } 415 } 416 return gcPolicy, nil 417 } 418 419 func getEntitlements(conf config.BuilderConfig) []string { 420 var ents []string 421 // Incase of no config settings, NetworkHost should be enabled & SecurityInsecure must be disabled. 422 if conf.Entitlements.NetworkHost == nil || *conf.Entitlements.NetworkHost { 423 ents = append(ents, string(entitlements.EntitlementNetworkHost)) 424 } 425 if conf.Entitlements.SecurityInsecure != nil && *conf.Entitlements.SecurityInsecure { 426 ents = append(ents, string(entitlements.EntitlementSecurityInsecure)) 427 } 428 return ents 429 } 430 431 func getLabels(opt Opt, labels map[string]string) map[string]string { 432 if labels == nil { 433 labels = make(map[string]string) 434 } 435 labels[wlabel.HostGatewayIP] = opt.DNSConfig.HostGatewayIP.String() 436 return labels 437 }