Skip to content
Snippets Groups Projects
Select Git revision
  • master default
  • registry-mirror
  • nginx-default-site
  • acmeserver2
  • clickhouse
  • improve-dns-toplevel-probes
  • tabacco-in-container
  • rsyslog-modern-json
  • improve-service-discovery
  • prometheus-external-healthchecks
  • env-vars-in-include-paths
  • dns-resolver
  • service-turndown
  • use_proxy_protocol
  • loki
  • docs_operating
  • net-overlay_firewall_containers
  • webdiff
18 results

reference.md

Blame
  • reference.md 123.27 KiB

    float Reference

    Table of contents

    Overview

    Float is a minimalistic toolkit for managing container-based services on "bare-metal" hardware or virtual machines. This type of software is often known as a container orchestration framework.

    Compared with other, more powerful and sophisticated entries in this space (Kubernetes, Nomad, etc), float attempts to be both much, much simpler in its underlying concepts and data model, and more featureful, by providing a set of high quality built-in services that offer a lot of the common functionality one would expect in a distributed environment.

    Float attempts to reduce the complexity of the problem space by making many explicit and radical decisions on behalf of the user: while this limits its flexibility, we think it manages to strike a good balance between expressive power and simplicity. The criteria for trade-offs is that, while float might not provide high availability mechanisms by itself, it must be possible (and easy) to build highly available services on top of it.

    The first and most important of such decisions is that float is a static orchestrator: there is no dynamic allocation of resources, no auto-scaling of service instances, no automatic rescheduling of instances on broken machines, etc. All changes are actuated manually. If this looks like the behavior of a push-based configuration management system, that's because, although its API is isolated from the implementation, float is built on top of one of them: Ansible, and it is in fact implemented as a set of Ansible plugins and roles. This choice allows for a great deal of extensibility (at the cost of coupling with this specific CMS), and lets float take advantage of the existing ecosystem of tools and best practices. The lowest layer of float's functionality (which could be summarized as "using Ansible to run containers") is implemented with common and familiar models, using podman and systemd to run containers: this helps with gradually transitioning legacy services to a containerized model, as it's easy to make any systemd service into a float service and integrate it with the built-in functionality.

    Other important simplifications include:

    • 1:1 instance/host mapping - the scheduler won't run more than one instance of a service on each host;
    • manual port assignments - you must manually pick a unique port for your services, there's no automatic allocation;
    • the service discovery protocol is based on simple DNS hostname lookups - as a consequence, clients are expected to know the port that they need to be talking to.

    Float does not make assumptions on the shape of the deployment infrastructure, but it wants to self-host its built-in services (including HTTP and DNS), so a production deployment will probably need at least two separate servers for redundancy. The design of some of float built-in services, such as the HTTP routing layer, naturally suggests a two-tier architecture, but float will not force you to use it.

    Services

    The fundamental concept in float is the service, a loose articulation of compute elements (containers, system-level daemons) and data, with standardized metadata properties that float uses to integrate it with its infrastructure.

    A description of the service (its specification) is provided to float as part of its configuration. Float can manage an arbitrary number of services on a single infrastructure. The mapping between a "float service" and a "high-level, user-visible service" is quite often not one-to-one: float services are meant to describe the high-level service's internal architecture, which can be made up of multiple components.

    In float, a service is also a schedulable unit: the service specification is in fact a template for specific service instances, of which there can be again more than one; consider for example the case of service replication for reliability / high-availability purposes. Float will never schedule more than one instance of a service on each host.

    The decision to assign an instance of a service to a specific host is called scheduling, and it is completely controlled by float based on parameters of the service specification: it is possible to control the desired number of instances, and to restrict the choice of possible hosts by using host groups (leveraging the Ansible host group concept). The operator has no control on the specific assignments beyond that, and they may change at any time.

    Float's scheduler is not particularly smart. It does not perform any kind of bin-packing (it only looks at instance counts), and, most importantly, it is offline-only: scheduling is only performed when Ansible runs, there is no online component to rebalance instances when they fail or to react to changes in load etc.

    The float scheduler produces stable and reproducible results, which is very important given how it is meant to be used. The randomness used by the scheduling algorithm is seeded on the configuration itself, so two people running float on the same configuration on two different machines will obtain identical assignments.

    Compute units

    Compute units in float are long-running processes controlled via systemd. Float creates a systemd unit for every service instance on the hosts where it is supposed to run.