From 2be17666b4cf21995da3e4ddf4ed615e6e6ca63a Mon Sep 17 00:00:00 2001 From: Anda Xu Date: Sun, 5 Aug 2018 18:52:35 -0700 Subject: [PATCH] add optional fields in daemon.json to enable buildkit Signed-off-by: Anda Xu --- api/server/router/build/build.go | 16 +++++++++------ api/server/router/build/build_routes.go | 6 ++++-- api/server/router/system/system.go | 25 +++++++++++++---------- api/server/router/system/system_routes.go | 5 ++++- api/swagger.yaml | 3 +++ api/types/types.go | 7 ++++--- client/ping.go | 5 ++++- cmd/dockerd/config.go | 1 - cmd/dockerd/daemon.go | 23 ++++++++++++++------- daemon/config/config.go | 13 +++++++++++- 10 files changed, 71 insertions(+), 33 deletions(-) diff --git a/api/server/router/build/build.go b/api/server/router/build/build.go index 811cd39181..90e3bb707c 100644 --- a/api/server/router/build/build.go +++ b/api/server/router/build/build.go @@ -1,17 +1,21 @@ package build // import "github.com/docker/docker/api/server/router/build" -import "github.com/docker/docker/api/server/router" +import ( + "github.com/docker/docker/api/server/router" + "github.com/docker/docker/api/types" +) // buildRouter is a router to talk with the build controller type buildRouter struct { - backend Backend - daemon experimentalProvider - routes []router.Route + backend Backend + daemon experimentalProvider + routes []router.Route + builderVersion types.BuilderVersion } // NewRouter initializes a new build router -func NewRouter(b Backend, d experimentalProvider) router.Router { - r := &buildRouter{backend: b, daemon: d} +func NewRouter(b Backend, d experimentalProvider, bv types.BuilderVersion) router.Router { + r := &buildRouter{backend: b, daemon: d, builderVersion: bv} r.initRoutes() return r } diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go index 3073479ccf..62bcf3f13d 100644 --- a/api/server/router/build/build_routes.go +++ b/api/server/router/build/build_routes.go @@ -230,8 +230,10 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode")) } - if buildOptions.Version == types.BuilderBuildKit && !br.daemon.HasExperimental() { - return errdefs.InvalidParameter(errors.New("buildkit is only supported with experimental mode")) + // check if the builder feature has been enabled from daemon as well. + if buildOptions.Version == types.BuilderBuildKit && + (br.builderVersion != types.BuilderBuildKit || !br.daemon.HasExperimental()) { + return errdefs.InvalidParameter(errors.New("buildkit is not enabled on daemon")) } out := io.Writer(output) diff --git a/api/server/router/system/system.go b/api/server/router/system/system.go index 11370584ef..6f73c1e1c1 100644 --- a/api/server/router/system/system.go +++ b/api/server/router/system/system.go @@ -2,6 +2,7 @@ package system // import "github.com/docker/docker/api/server/router/system" import ( "github.com/docker/docker/api/server/router" + "github.com/docker/docker/api/types" buildkit "github.com/docker/docker/builder/builder-next" "github.com/docker/docker/builder/fscache" ) @@ -9,25 +10,27 @@ import ( // systemRouter provides information about the Docker system overall. // It gathers information about host, daemon and container events. type systemRouter struct { - backend Backend - cluster ClusterBackend - routes []router.Route - fscache *fscache.FSCache // legacy - builder *buildkit.Builder + backend Backend + cluster ClusterBackend + routes []router.Route + fscache *fscache.FSCache // legacy + builder *buildkit.Builder + builderVersion types.BuilderVersion } // NewRouter initializes a new system router -func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder) router.Router { +func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, bv types.BuilderVersion) router.Router { r := &systemRouter{ - backend: b, - cluster: c, - fscache: fscache, - builder: builder, + backend: b, + cluster: c, + fscache: fscache, + builder: builder, + builderVersion: bv, } r.routes = []router.Route{ router.NewOptionsRoute("/{anyroute:.*}", optionsHandler), - router.NewGetRoute("/_ping", pingHandler), + router.NewGetRoute("/_ping", r.pingHandler), router.NewGetRoute("/events", r.getEvents, router.WithCancel), router.NewGetRoute("/info", r.getInfo), router.NewGetRoute("/version", r.getVersion), diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go index 15c3120af5..010a74ac3a 100644 --- a/api/server/router/system/system_routes.go +++ b/api/server/router/system/system_routes.go @@ -25,7 +25,10 @@ func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, return nil } -func pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + if bv := s.builderVersion; bv != "" { + w.Header().Set("Builder-Version", string(bv)) + } _, err := w.Write([]byte{'O', 'K'}) return err } diff --git a/api/swagger.yaml b/api/swagger.yaml index 204d5b860f..4383687e05 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -6972,6 +6972,9 @@ paths: API-Version: type: "string" description: "Max API Version the server supports" + BuildKit-Version: + type: "string" + description: "Default version of docker image builder" Docker-Experimental: type: "boolean" description: "If the server is running with experimental mode enabled" diff --git a/api/types/types.go b/api/types/types.go index 06c0ca3a69..af9edbd899 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -102,9 +102,10 @@ type ContainerStats struct { // Ping contains response of Engine API: // GET "/_ping" type Ping struct { - APIVersion string - OSType string - Experimental bool + APIVersion string + OSType string + Experimental bool + BuilderVersion BuilderVersion } // ComponentVersion describes the version information for a specific component. diff --git a/client/ping.go b/client/ping.go index 85d38adb51..dec1423e38 100644 --- a/client/ping.go +++ b/client/ping.go @@ -7,7 +7,7 @@ import ( "github.com/docker/docker/api/types" ) -// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers +// Ping pings the server and returns the value of the "Docker-Experimental", "Builder-Version", "OS-Type" & "API-Version" headers func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { var ping types.Ping req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil) @@ -27,6 +27,9 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { ping.Experimental = true } ping.OSType = serverResp.header.Get("OSType") + if bv := serverResp.header.Get("Builder-Version"); bv != "" { + ping.BuilderVersion = types.BuilderVersion(bv) + } } return ping, cli.checkResponseErr(serverResp) } diff --git a/cmd/dockerd/config.go b/cmd/dockerd/config.go index adf26f82a6..2c8ed8edb4 100644 --- a/cmd/dockerd/config.go +++ b/cmd/dockerd/config.go @@ -65,7 +65,6 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) { flags.StringVar(&conf.SwarmDefaultAdvertiseAddr, "swarm-default-advertise-addr", "", "Set default address or interface for swarm advertised address") flags.BoolVar(&conf.Experimental, "experimental", false, "Enable experimental features") - flags.StringVar(&conf.MetricsAddress, "metrics-addr", "", "Set default address and port to serve the metrics api on") flags.Var(opts.NewNamedListOptsRef("node-generic-resources", &conf.NodeGenericResources, opts.ValidateSingleGenericResource), "node-generic-resource", "Advertise user-defined resource") diff --git a/cmd/dockerd/daemon.go b/cmd/dockerd/daemon.go index 6bb3e90796..128630cddf 100644 --- a/cmd/dockerd/daemon.go +++ b/cmd/dockerd/daemon.go @@ -27,6 +27,7 @@ import ( swarmrouter "github.com/docker/docker/api/server/router/swarm" systemrouter "github.com/docker/docker/api/server/router/system" "github.com/docker/docker/api/server/router/volume" + "github.com/docker/docker/api/types" buildkit "github.com/docker/docker/builder/builder-next" "github.com/docker/docker/builder/dockerfile" "github.com/docker/docker/builder/fscache" @@ -253,6 +254,7 @@ type routerOptions struct { buildBackend *buildbackend.Backend buildCache *fscache.FSCache // legacy buildkit *buildkit.Builder + builderVersion types.BuilderVersion daemon *daemon.Daemon api *apiserver.Server cluster *cluster.Cluster @@ -283,8 +285,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio if err != nil { return opts, err } - - buildkit, err := buildkit.New(buildkit.Opt{ + bk, err := buildkit.New(buildkit.Opt{ SessionManager: sm, Root: filepath.Join(config.Root, "buildkit"), Dist: daemon.DistributionServices(), @@ -293,16 +294,24 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio return opts, err } - bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, buildkit) + bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, bk) if err != nil { return opts, errors.Wrap(err, "failed to create buildmanager") } - + var bv types.BuilderVersion + if v, ok := config.Features["buildkit"]; ok { + if v { + bv = types.BuilderBuildKit + } else { + bv = types.BuilderV1 + } + } return routerOptions{ sessionManager: sm, buildBackend: bb, buildCache: buildCache, - buildkit: buildkit, + buildkit: bk, + builderVersion: bv, daemon: daemon, }, nil } @@ -476,9 +485,9 @@ func initRouter(opts routerOptions) { checkpointrouter.NewRouter(opts.daemon, decoder), container.NewRouter(opts.daemon, decoder), image.NewRouter(opts.daemon.ImageService()), - systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit), + systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.builderVersion), volume.NewRouter(opts.daemon.VolumesService()), - build.NewRouter(opts.buildBackend, opts.daemon), + build.NewRouter(opts.buildBackend, opts.daemon, opts.builderVersion), sessionrouter.NewRouter(opts.sessionManager), swarmrouter.NewRouter(opts.cluster), pluginrouter.NewRouter(opts.daemon.PluginManager()), diff --git a/daemon/config/config.go b/daemon/config/config.go index ec56f8b42c..6081b5c8ed 100644 --- a/daemon/config/config.go +++ b/daemon/config/config.go @@ -56,6 +56,13 @@ var flatOptions = map[string]bool{ "default-ulimits": true, } +// skipValidateOptions contains configuration keys +// that will be skipped from findConfigurationConflicts +// for unknown flag validation. +var skipValidateOptions = map[string]bool{ + "features": true, +} + // LogConfig represents the default log configuration. // It includes json tags to deserialize configuration from a file // using the same names that the flags in the command line use. @@ -203,6 +210,10 @@ type CommonConfig struct { // should be configured with the CRI plugin enabled. This allows using // Docker's containerd instance directly with a Kubernetes kubelet. CriContainerd bool `json:"cri-containerd,omitempty"` + + // Features contains a list of feature key value pairs indicating what features are enabled or disabled. + // If a certain feature doesn't appear in this list then it's unset (i.e. neither true nor false). + Features map[string]bool `json:"features,omitempty"` } // IsValueSet returns true if a configuration value @@ -444,7 +455,7 @@ func findConfigurationConflicts(config map[string]interface{}, flags *pflag.Flag // 1. Search keys from the file that we don't recognize as flags. unknownKeys := make(map[string]interface{}) for key, value := range config { - if flag := flags.Lookup(key); flag == nil { + if flag := flags.Lookup(key); flag == nil && !skipValidateOptions[key] { unknownKeys[key] = value } }