add optional fields in daemon.json to enable buildkit

Signed-off-by: Anda Xu <anda.xu@docker.com>
This commit is contained in:
Anda Xu 2018-08-05 18:52:35 -07:00
parent 14d5569f19
commit 2be17666b4
10 changed files with 71 additions and 33 deletions

View file

@ -1,17 +1,21 @@
package build // import "github.com/docker/docker/api/server/router/build" 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 // buildRouter is a router to talk with the build controller
type buildRouter struct { type buildRouter struct {
backend Backend backend Backend
daemon experimentalProvider daemon experimentalProvider
routes []router.Route routes []router.Route
builderVersion types.BuilderVersion
} }
// NewRouter initializes a new build router // NewRouter initializes a new build router
func NewRouter(b Backend, d experimentalProvider) router.Router { func NewRouter(b Backend, d experimentalProvider, bv types.BuilderVersion) router.Router {
r := &buildRouter{backend: b, daemon: d} r := &buildRouter{backend: b, daemon: d, builderVersion: bv}
r.initRoutes() r.initRoutes()
return r return r
} }

View file

@ -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")) return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode"))
} }
if buildOptions.Version == types.BuilderBuildKit && !br.daemon.HasExperimental() { // check if the builder feature has been enabled from daemon as well.
return errdefs.InvalidParameter(errors.New("buildkit is only supported with experimental mode")) 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) out := io.Writer(output)

View file

@ -2,6 +2,7 @@ package system // import "github.com/docker/docker/api/server/router/system"
import ( import (
"github.com/docker/docker/api/server/router" "github.com/docker/docker/api/server/router"
"github.com/docker/docker/api/types"
buildkit "github.com/docker/docker/builder/builder-next" buildkit "github.com/docker/docker/builder/builder-next"
"github.com/docker/docker/builder/fscache" "github.com/docker/docker/builder/fscache"
) )
@ -14,20 +15,22 @@ type systemRouter struct {
routes []router.Route routes []router.Route
fscache *fscache.FSCache // legacy fscache *fscache.FSCache // legacy
builder *buildkit.Builder builder *buildkit.Builder
builderVersion types.BuilderVersion
} }
// NewRouter initializes a new system router // 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{ r := &systemRouter{
backend: b, backend: b,
cluster: c, cluster: c,
fscache: fscache, fscache: fscache,
builder: builder, builder: builder,
builderVersion: bv,
} }
r.routes = []router.Route{ r.routes = []router.Route{
router.NewOptionsRoute("/{anyroute:.*}", optionsHandler), router.NewOptionsRoute("/{anyroute:.*}", optionsHandler),
router.NewGetRoute("/_ping", pingHandler), router.NewGetRoute("/_ping", r.pingHandler),
router.NewGetRoute("/events", r.getEvents, router.WithCancel), router.NewGetRoute("/events", r.getEvents, router.WithCancel),
router.NewGetRoute("/info", r.getInfo), router.NewGetRoute("/info", r.getInfo),
router.NewGetRoute("/version", r.getVersion), router.NewGetRoute("/version", r.getVersion),

View file

@ -25,7 +25,10 @@ func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
return nil 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'}) _, err := w.Write([]byte{'O', 'K'})
return err return err
} }

View file

@ -6972,6 +6972,9 @@ paths:
API-Version: API-Version:
type: "string" type: "string"
description: "Max API Version the server supports" description: "Max API Version the server supports"
BuildKit-Version:
type: "string"
description: "Default version of docker image builder"
Docker-Experimental: Docker-Experimental:
type: "boolean" type: "boolean"
description: "If the server is running with experimental mode enabled" description: "If the server is running with experimental mode enabled"

View file

@ -105,6 +105,7 @@ type Ping struct {
APIVersion string APIVersion string
OSType string OSType string
Experimental bool Experimental bool
BuilderVersion BuilderVersion
} }
// ComponentVersion describes the version information for a specific component. // ComponentVersion describes the version information for a specific component.

View file

@ -7,7 +7,7 @@ import (
"github.com/docker/docker/api/types" "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) { func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
var ping types.Ping var ping types.Ping
req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil) 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.Experimental = true
} }
ping.OSType = serverResp.header.Get("OSType") ping.OSType = serverResp.header.Get("OSType")
if bv := serverResp.header.Get("Builder-Version"); bv != "" {
ping.BuilderVersion = types.BuilderVersion(bv)
}
} }
return ping, cli.checkResponseErr(serverResp) return ping, cli.checkResponseErr(serverResp)
} }

View file

@ -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.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.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.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") flags.Var(opts.NewNamedListOptsRef("node-generic-resources", &conf.NodeGenericResources, opts.ValidateSingleGenericResource), "node-generic-resource", "Advertise user-defined resource")

View file

@ -27,6 +27,7 @@ import (
swarmrouter "github.com/docker/docker/api/server/router/swarm" swarmrouter "github.com/docker/docker/api/server/router/swarm"
systemrouter "github.com/docker/docker/api/server/router/system" systemrouter "github.com/docker/docker/api/server/router/system"
"github.com/docker/docker/api/server/router/volume" "github.com/docker/docker/api/server/router/volume"
"github.com/docker/docker/api/types"
buildkit "github.com/docker/docker/builder/builder-next" buildkit "github.com/docker/docker/builder/builder-next"
"github.com/docker/docker/builder/dockerfile" "github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/fscache" "github.com/docker/docker/builder/fscache"
@ -253,6 +254,7 @@ type routerOptions struct {
buildBackend *buildbackend.Backend buildBackend *buildbackend.Backend
buildCache *fscache.FSCache // legacy buildCache *fscache.FSCache // legacy
buildkit *buildkit.Builder buildkit *buildkit.Builder
builderVersion types.BuilderVersion
daemon *daemon.Daemon daemon *daemon.Daemon
api *apiserver.Server api *apiserver.Server
cluster *cluster.Cluster cluster *cluster.Cluster
@ -283,8 +285,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
if err != nil { if err != nil {
return opts, err return opts, err
} }
bk, err := buildkit.New(buildkit.Opt{
buildkit, err := buildkit.New(buildkit.Opt{
SessionManager: sm, SessionManager: sm,
Root: filepath.Join(config.Root, "buildkit"), Root: filepath.Join(config.Root, "buildkit"),
Dist: daemon.DistributionServices(), Dist: daemon.DistributionServices(),
@ -293,16 +294,24 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
return opts, err return opts, err
} }
bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, buildkit) bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache, bk)
if err != nil { if err != nil {
return opts, errors.Wrap(err, "failed to create buildmanager") 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{ return routerOptions{
sessionManager: sm, sessionManager: sm,
buildBackend: bb, buildBackend: bb,
buildCache: buildCache, buildCache: buildCache,
buildkit: buildkit, buildkit: bk,
builderVersion: bv,
daemon: daemon, daemon: daemon,
}, nil }, nil
} }
@ -476,9 +485,9 @@ func initRouter(opts routerOptions) {
checkpointrouter.NewRouter(opts.daemon, decoder), checkpointrouter.NewRouter(opts.daemon, decoder),
container.NewRouter(opts.daemon, decoder), container.NewRouter(opts.daemon, decoder),
image.NewRouter(opts.daemon.ImageService()), 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()), volume.NewRouter(opts.daemon.VolumesService()),
build.NewRouter(opts.buildBackend, opts.daemon), build.NewRouter(opts.buildBackend, opts.daemon, opts.builderVersion),
sessionrouter.NewRouter(opts.sessionManager), sessionrouter.NewRouter(opts.sessionManager),
swarmrouter.NewRouter(opts.cluster), swarmrouter.NewRouter(opts.cluster),
pluginrouter.NewRouter(opts.daemon.PluginManager()), pluginrouter.NewRouter(opts.daemon.PluginManager()),

View file

@ -56,6 +56,13 @@ var flatOptions = map[string]bool{
"default-ulimits": true, "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. // LogConfig represents the default log configuration.
// It includes json tags to deserialize configuration from a file // It includes json tags to deserialize configuration from a file
// using the same names that the flags in the command line use. // 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 // should be configured with the CRI plugin enabled. This allows using
// Docker's containerd instance directly with a Kubernetes kubelet. // Docker's containerd instance directly with a Kubernetes kubelet.
CriContainerd bool `json:"cri-containerd,omitempty"` 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 // 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. // 1. Search keys from the file that we don't recognize as flags.
unknownKeys := make(map[string]interface{}) unknownKeys := make(map[string]interface{})
for key, value := range config { for key, value := range config {
if flag := flags.Lookup(key); flag == nil { if flag := flags.Lookup(key); flag == nil && !skipValidateOptions[key] {
unknownKeys[key] = value unknownKeys[key] = value
} }
} }