diff --git a/Documentation/architecture.md b/Documentation/architecture.md index d4619b227..a501d1451 100644 --- a/Documentation/architecture.md +++ b/Documentation/architecture.md @@ -11,6 +11,10 @@ Every system in the fleet cluster runs a single `fleetd` daemon. Each daemon enc - The engine uses a _lease model_ to enforce that only one engine is running at a time. Every time a reconciliation is due, an engine will attempt to take a lease on etcd. If the lease succeeds, the reconciliation proceeds; otherwise, that engine will remain idle until the next reconciliation period begins. - The engine uses a simplistic "least-loaded" scheduling algorithm: when considering where to schedule a given unit, preference is given to agents running the smallest number of units. +The reconciliation loop of the engine can be disabled with the `--disable-engine` flag. This means that +this `fleetd` daemon will *never* become a cluster leader. If all running daemons have this setting, +your cluster is dead; i.e. no jobs will be scheduled. Use with care. + ### Agent - The agent is responsible for actually executing Units on systems. It communicates with the local systemd instance over D-Bus. @@ -19,7 +23,7 @@ Every system in the fleet cluster runs a single `fleetd` daemon. Each daemon enc ## etcd -etcd is the sole datastore in a fleet cluster. All persistent and ephemeral data is stored in etcd: unit files, cluster presence, unit state, etc. +etcd is the sole datastore in a fleet cluster. All persistent and ephemeral data is stored in etcd: unit files, cluster presence, unit state, etc. etcd is also used for all internal communication between fleet engines and agents. diff --git a/Documentation/fleet-scaling.md b/Documentation/fleet-scaling.md index 1738c87e8..db44f7255 100644 --- a/Documentation/fleet-scaling.md +++ b/Documentation/fleet-scaling.md @@ -5,6 +5,7 @@ minimizing the load it puts on etcd. This is true for reads, writes, and watches. ## Known issues + Currently when fleet schedules a job *all* `fleetd`s are woken up (via a watch) and then do a recursive GET on the Unit file in etcd to figure out if it should schedule a job. This is a very expensive operation. @@ -33,9 +34,8 @@ wins: this is an expensive operation. The fewer nodes that are engaged in this election, the better. Possible downside is that if there isn't a leader at all, the cluster is inoperable. However the (usually) 5 machines running - etcd are also a single point of failure. Proposal: - https://github.com/coreos/fleet/pull/1263 + etcd are also a single point of failure. See the `--disable-engine` flag. * Making some defaults exported and allow them to be overridden. For instance - fleet's tokenLimit controls how many Units are listed per "page". Proposal: - https://github.com/coreos/fleet/pull/1265 + fleet's tokenLimit controls how many Units are listed per "page". See the + `--token-limit` flag. diff --git a/config/config.go b/config/config.go index fd15ce4af..b7881d5e7 100644 --- a/config/config.go +++ b/config/config.go @@ -31,6 +31,7 @@ type Config struct { RawMetadata string AgentTTL string TokenLimit int + DisableEngine bool VerifyUnits bool AuthorizedKeysFile string } diff --git a/fleetd/fleetd.go b/fleetd/fleetd.go index 0b9e01619..bdd898c76 100644 --- a/fleetd/fleetd.go +++ b/fleetd/fleetd.go @@ -76,6 +76,7 @@ func main() { cfgset.String("metadata", "", "List of key-value metadata to assign to the fleet machine") cfgset.String("agent_ttl", agent.DefaultTTL, "TTL in seconds of fleet machine state in etcd") cfgset.Int("token_limit", 100, "Maximum number of entries per page returned from API requests") + cfgset.Bool("disable_engine", false, "Disable the engine entirely, use with care") cfgset.Bool("verify_units", false, "DEPRECATED - This option is ignored") cfgset.String("authorized_keys_file", "", "DEPRECATED - This option is ignored") @@ -188,6 +189,7 @@ func getConfig(flagset *flag.FlagSet, userCfgFile string) (*config.Config, error PublicIP: (*flagset.Lookup("public_ip")).Value.(flag.Getter).Get().(string), RawMetadata: (*flagset.Lookup("metadata")).Value.(flag.Getter).Get().(string), AgentTTL: (*flagset.Lookup("agent_ttl")).Value.(flag.Getter).Get().(string), + DisableEngine: (*flagset.Lookup("disable_engine")).Value.(flag.Getter).Get().(bool), VerifyUnits: (*flagset.Lookup("verify_units")).Value.(flag.Getter).Get().(bool), TokenLimit: (*flagset.Lookup("token_limit")).Value.(flag.Getter).Get().(int), AuthorizedKeysFile: (*flagset.Lookup("authorized_keys_file")).Value.(flag.Getter).Get().(string), diff --git a/server/server.go b/server/server.go index 7102fb858..da068bf80 100644 --- a/server/server.go +++ b/server/server.go @@ -45,15 +45,16 @@ const ( ) type Server struct { - agent *agent.Agent - aReconciler *agent.AgentReconciler - usPub *agent.UnitStatePublisher - usGen *unit.UnitStateGenerator - engine *engine.Engine - mach *machine.CoreOSMachine - hrt heart.Heart - mon *heart.Monitor - api *api.Server + agent *agent.Agent + aReconciler *agent.AgentReconciler + usPub *agent.UnitStatePublisher + usGen *unit.UnitStateGenerator + engine *engine.Engine + mach *machine.CoreOSMachine + hrt heart.Heart + mon *heart.Monitor + api *api.Server + disableEngine bool engineReconcileInterval time.Duration @@ -131,6 +132,7 @@ func New(cfg config.Config) (*Server, error) { api: apiServer, stop: nil, engineReconcileInterval: eIval, + disableEngine: cfg.DisableEngine, } return &srv, nil @@ -174,7 +176,11 @@ func (s *Server) Run() { go s.mach.PeriodicRefresh(machineStateRefreshInterval, s.stop) go s.agent.Heartbeat(s.stop) go s.aReconciler.Run(s.agent, s.stop) - go s.engine.Run(s.engineReconcileInterval, s.stop) + if s.disableEngine { + log.Info("Not starting engine; disable-engine is set") + } else { + go s.engine.Run(s.engineReconcileInterval, s.stop) + } beatchan := make(chan *unit.UnitStateHeartbeat) go s.usGen.Run(beatchan, s.stop)