Documentation
¶
Overview ¶
Package multidocker runs apps on several Docker hosts (notes-multi-host-docker-issue-72.md, issue #72 PR 7).
It is a router in front of one single-host Docker adapter per host: every operation on an app runs the existing Docker adapter's code against the app's host. What it adds is placement (R-256), the forwarding agent each host runs so Pando's proxy can reach an app on another host without routing around itself (O-45, design 06 §4), and capacity summed over hosts.
Like every adapter it does not authorize, audit or touch Pando's state (R-027). Where an app runs is recorded on the hosts themselves: the app's network and volumes carry its bundle label, and the adapter reads them back.
Index ¶
- Constants
- func Info() api.KindInfo
- type Adapter
- func (a *Adapter) Apply(ctx context.Context, p api.BundlePlan) (api.BundleHandle, error)
- func (a *Adapter) ApplyEdge(ctx context.Context, p api.EdgePlan) error
- func (a *Adapter) Capabilities(ctx context.Context) (api.RuntimeCapabilities, error)
- func (a *Adapter) Capacity(ctx context.Context) (api.Capacity, error)
- func (a *Adapter) Category() api.Category
- func (a *Adapter) Configure(_ context.Context, raw json.RawMessage) error
- func (a *Adapter) CreateVolume(ctx context.Context, req api.VolumeRequest) (api.VolumeHandle, error)
- func (a *Adapter) Destroy(ctx context.Context, ref api.BundleRef, opts api.DestroyOptions) error
- func (a *Adapter) DestroyVolume(ctx context.Context, vh api.VolumeHandle) error
- func (a *Adapter) EdgeVolumes(ctx context.Context) ([]api.VolumeHandle, error)
- func (a *Adapter) Edges(ctx context.Context) ([]string, error)
- func (a *Adapter) Exec(ctx context.Context, ref api.WorkloadRef, req api.ExecRequest) (api.ExecSession, error)
- func (a *Adapter) HealthCheck(ctx context.Context) error
- func (a *Adapter) ImportImage(context.Context, io.Reader) (string, error)
- func (a *Adapter) InUse(ctx context.Context) (api.InUse, error)
- func (a *Adapter) Kind() string
- func (a *Adapter) LargestFitFor(ctx context.Context, bundleID string) (*api.Fit, error)
- func (a *Adapter) Logs(ctx context.Context, ref api.WorkloadRef, opts api.LogOptions) (io.ReadCloser, error)
- func (a *Adapter) Observe(ctx context.Context, ref api.BundleRef) (api.ObservedBundle, error)
- func (a *Adapter) ObserveEdge(ctx context.Context, name string) (api.EdgeState, error)
- func (a *Adapter) PullImage(ctx context.Context, ref string) error
- func (a *Adapter) ReclaimNetworks(ctx context.Context, owns func(string) bool) (int, error)
- func (a *Adapter) RejoinNetworks(ctx context.Context, owns func(string) bool) (int, error)
- func (a *Adapter) RemoveEdge(ctx context.Context, name string) error
- func (a *Adapter) RemoveHelpers(ctx context.Context) error
- func (a *Adapter) RestoreVolume(ctx context.Context, vh api.VolumeHandle, src io.Reader) error
- func (a *Adapter) Self(ctx context.Context) (api.SelfWorkload, error)
- func (a *Adapter) SnapshotVolume(ctx context.Context, vh api.VolumeHandle, dst io.Writer) error
- func (a *Adapter) StartHelper(ctx context.Context, spec api.HelperSpec) (string, error)
- func (a *Adapter) Stop(ctx context.Context, ref api.BundleRef) error
- func (a *Adapter) Trial(ctx context.Context, req api.TrialRequest) (api.TrialResult, error)
- func (a *Adapter) Upstream(ctx context.Context, ref api.WorkloadRef, port int) (api.Upstream, error)
- func (a *Adapter) Usage(ctx context.Context, ref api.BundleRef) (api.BundleUsage, error)
- func (a *Adapter) WatchBundles(ctx context.Context, sink func(api.BundleEvent)) error
- type Config
- type Credentials
- type HostConfig
Constants ¶
const ( EnvAgentCert = "PANDO_AGENT_CERT" EnvAgentKey = "PANDO_AGENT_KEY" EnvAgentAuthorities = "PANDO_AGENT_AUTHORITIES" EnvAgentPool = "PANDO_AGENT_NETWORK_POOL" EnvAgentListen = "PANDO_AGENT_LISTEN" )
Environment the agent reads its certificate, key and the authorities from. Set on its container by this adapter; the agent's key is on its own host only, and it is a server key: it cannot open a connection through any agent.
const Kind = "docker-hosts"
Kind is the adapter's kind string.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter runs workloads on several Docker hosts.
func (*Adapter) Apply ¶
func (a *Adapter) Apply(ctx context.Context, p api.BundlePlan) (api.BundleHandle, error)
Apply places the bundle if it has no host (placement.go), makes sure the host's agent is running, and applies the plan there with the single-host adapter's code. The handle names the host.
func (*Adapter) ApplyEdge ¶
The edge runs on the control host beside Pando's replicas, as on one host.
func (*Adapter) Capabilities ¶
Capabilities are the control host's, with what several hosts change (R-254).
func (*Adapter) Capacity ¶
Capacity sums the hosts open to new apps, with each host's figures in Details and the roomiest one's free space as LargestFit (R-243).
func (*Adapter) Configure ¶
Configure reads the host list and the credentials, makes one Docker client per host and issues Pando's client certificate for the agents, in memory. Nothing is contacted: a host that is down at start is reported by HealthCheck and Observe, not by refusing to configure.
func (*Adapter) CreateVolume ¶
func (a *Adapter) CreateVolume(ctx context.Context, req api.VolumeRequest) (api.VolumeHandle, error)
CreateVolume makes storage on the bundle's host, placing the bundle first if it has none: the volume is then what keeps it there.
func (*Adapter) Destroy ¶
Destroy tears the bundle down on its host. With its volumes kept, the host stays the app's home (R-204): a re-created app returns to its data.
func (*Adapter) DestroyVolume ¶
func (*Adapter) EdgeVolumes ¶
func (*Adapter) Exec ¶
func (a *Adapter) Exec(ctx context.Context, ref api.WorkloadRef, req api.ExecRequest) (api.ExecSession, error)
func (*Adapter) HealthCheck ¶
HealthCheck asks every host. The adapter is healthy while the control host and at least one host open to new apps answer, and every answering host runs the same platform; a host that does not answer makes its own apps unobservable (Observe), not every app undeployable.
func (*Adapter) ImportImage ¶
ImportImage is not offered (ImageDelivery is registry only).
func (*Adapter) LargestFitFor ¶
LargestFitFor is the roomiest place this bundle may go, for the planner (R-242 per host). A bundle already on a host may go only there, and what it holds there counts as free. A new one may go to any host open to new apps that answers. Nil when its host does not answer: Observe reports that, and the planner checks the totals alone.
func (*Adapter) Logs ¶
func (a *Adapter) Logs(ctx context.Context, ref api.WorkloadRef, opts api.LogOptions) (io.ReadCloser, error)
func (*Adapter) Observe ¶
Observe reports the bundle on its host. An app whose host does not answer is an error, which the reconciler records as unobservable — never as failed (R-151, design 05 §2) — and never as absent, which would have the reconciler create it again on another host (O-46).
func (*Adapter) ObserveEdge ¶
func (*Adapter) ReclaimNetworks ¶
ReclaimNetworks removes each host's app networks nothing is attached to.
func (*Adapter) RejoinNetworks ¶
RejoinNetworks keeps each host's agent running and joined to that host's app networks, and refreshes the placement map. Called at start and every fifteen seconds on every replica (cmd/pando); Pando's own replicas join no app network on this runtime.
func (*Adapter) RestoreVolume ¶
func (*Adapter) Self ¶
Self-upgrade replaces Pando's container on the control host, as on one host (R-359); core allows it only with a single replica.
func (*Adapter) SnapshotVolume ¶
func (*Adapter) StartHelper ¶
func (*Adapter) Trial ¶
func (a *Adapter) Trial(ctx context.Context, req api.TrialRequest) (api.TrialResult, error)
Trial runs on the control host [P]: it is thrown away, so it needs no placement.
func (*Adapter) Upstream ¶
func (a *Adapter) Upstream(ctx context.Context, ref api.WorkloadRef, port int) (api.Upstream, error)
Upstream is the workload's container name on its host, as one host's adapter answers, and a Dial through that host's agent (O-45). The proxy decides the request before it calls Dial; the agent only carries it.
Answered from the placement map, which is in memory: this runs on every proxied request.
func (*Adapter) WatchBundles ¶
WatchBundles follows every host's event stream at once, one stream per host (O-52), and reports what happened without acting on it (R-148).
A host whose stream drops is reconnected here, with backoff, while every other host's stream carries on: one host restarting its daemon must not make the reconciler look at every app on every host. When a host's stream opens again after a gap, BundleEventMissed says that something on it may have been missed. BundleEventWatching is sent once every host's first attempt has opened or failed — a host that is down at the start is caught up with BundleEventMissed when it comes back. It returns only when ctx ends.
type Config ¶
type Config struct {
// Hosts are the Docker hosts, in order. Exactly one is the control host:
// the one Pando's replicas, the edge, BuildKit and the registry run on
// (O-47). A JSON list, or a string holding one, which is how a form's
// text area sends it.
Hosts json.RawMessage `json:"hosts"`
// NetworkPool, NetworkBlockBits and OCIRuntime are the single-host Docker
// adapter's settings of the same names, applied on every host. Each host
// carves its own app networks from the same range: a bridge network
// exists on one host only.
NetworkPool string `json:"network_pool,omitempty"`
NetworkBlockBits int `json:"network_block_bits,omitempty"`
OCIRuntime string `json:"oci_runtime,omitempty"`
// AgentImage is the image each host's forwarding agent and each
// restricted app's egress gateway run: an image of Pando that every host
// can pull. Empty is the image Pando's own container on the control host
// was started from.
AgentImage string `json:"agent_image,omitempty"`
// AgentPort is the host port each agent publishes. Zero is 7443.
AgentPort int `json:"agent_port,omitempty"`
// Credentials arrive from the encrypted adapter_credentials store and
// are held in memory only (R-190).
Credentials Credentials `json:"credentials"`
}
Config is the adapter's configuration.
type Credentials ¶
type Credentials struct {
// AgentAuthority is the agents' certificate authority as PEM, each
// certificate followed by its key, the one that issues first. Generated
// by `pando host-agent new-authority`. Pando issues its own client
// certificate and each agent's server certificate from it.
AgentAuthority string `json:"agent_authority"`
// DockerTLS is the client certificate, its key and the CA that signed the
// daemons' certificates, as PEM, for hosts reached over tcp://.
DockerTLS string `json:"docker_tls,omitempty"`
// SSHKey is the private key for hosts reached over ssh://.
SSHKey string `json:"ssh_key,omitempty"`
}
Credentials are the adapter's secrets.
type HostConfig ¶
type HostConfig struct {
// Name is how the host is known in placement, the console, errors and
// the agent's certificate: lower-case letters, digits and dashes.
Name string `json:"name"`
// Endpoint is the Docker API: unix:///var/run/docker.sock (the control
// host, usually), tcp://host:2376 with docker_tls, or ssh://user@host
// with ssh_key. Empty is the environment, as the single-host adapter.
Endpoint string `json:"endpoint,omitempty"`
// SSHHostKey is the host's SSH public key, as in known_hosts or
// authorized_keys, for an ssh:// endpoint. Required: an unverified SSH
// host key would hand the root-equivalent Docker credential to whoever
// answers.
SSHHostKey string `json:"ssh_host_key,omitempty"`
// AgentAddress is where Pando's proxy reaches this host's agent, as
// host:port. Empty is the endpoint's host and the agent port.
AgentAddress string `json:"agent_address,omitempty"`
// Control marks the control host.
Control bool `json:"control,omitempty"`
// NoPlacement keeps new apps off the host; apps already on it stay
// (R-256). It is how a host is emptied before it is removed.
NoPlacement bool `json:"no_placement,omitempty"`
// TotalCPUMillis and TotalMemoryBytes tell Pando how much of the host it
// may use, as on one host. Empty asks the daemon.
TotalCPUMillis int `json:"total_cpu_millis,omitempty"`
TotalMemoryBytes int64 `json:"total_memory_bytes,omitempty"`
TotalDiskBytes int64 `json:"total_disk_bytes,omitempty"`
}
HostConfig is one Docker host.