Documentation
¶
Overview ¶
Package node is the podium-node daemon: it holds the node's identity, keeps one bidirectional stream to the control plane, and turns each Assign into a container run whose events are batched, buffered and replayed until the server acks them.
Index ¶
Constants ¶
const ( DefaultServer = "http://127.0.0.1:8080" DefaultTransport = "local" DefaultDataDir = "/var/lib/podium-node" DefaultMaxTasks = 4 DefaultImageCacheHighWatermark = 0.80 DefaultMetricsListen = "127.0.0.1:9091" )
Config defaults. Mirrored in docs/node-setup.md; keep the two in step.
const ( // TransportLocal dials a loopback server with a shared bearer token. TransportLocal = "local" // TransportTailnet embeds the node's own Tailscale device (tsnet) and dials the control // plane's MagicDNS name over it. The node listens for nothing. TransportTailnet = "tailnet" // TransportHost dials over the machine's existing tailscaled instead of embedding a device. TransportHost = "host" )
The transports podium-node understands.
const DefaultConfigPath = "/etc/podium/node.yaml"
DefaultConfigPath is where podium-node looks for its config file when --config is not given. A missing file there is not an error: the daemon is fully configurable by environment.
const DefaultReleaseBaseURL = "https://github.com/podium-ade/podium/releases/download"
DefaultReleaseBaseURL is where a released archive lives. GoReleaser publishes <base>/<tag>/podium_<version>_<os>_<arch>.tar.gz alongside <base>/<tag>/checksums.txt.
const MinRedactableSecret = 8
MinRedactableSecret is the shortest value worth searching a log stream for. Below it the false positives cost more than the protection is worth: a two-byte secret would redact every occurrence of those two bytes in every line the task ever prints.
const ReplayBufferBytes = 8 << 20
ReplayBufferBytes bounds one task's unacked events. Past it the oldest log chunks are dropped — never exited, finished or error, which are what the server needs to move the task out of running.
Variables ¶
This section is empty.
Functions ¶
func FetchBinary ¶
func FetchBinary(ctx context.Context, opts UpgradeOptions, stagePath string) error
FetchBinary downloads the release archive, checks its SHA-256 against the release's own checksums.txt, extracts podium-node from it and writes the result to stagePath with mode 0755. It never touches the running binary: swapping is the caller's move, and it is a rename so that it is atomic.
The checksum is verified before anything is extracted. An archive that does not appear in checksums.txt is refused rather than trusted — a release whose manifest does not mention a file is a release that was tampered with or built wrong, and either way it is not the one that was signed.
func SaveIdentity ¶
SaveIdentity writes the identity 0600. It is written before the first stream so a crash never strands a node key that only the server-side hash remembers.
func SwapBinary ¶
SwapBinary replaces dest with the staged file. Rename is atomic within a filesystem and works on a binary that is currently executing: the running process keeps the inode it started from and the next start picks up the new one.
Types ¶
type Config ¶
type Config struct {
// Server is the control plane base URL, PODIUM_NODE_SERVER.
Server string `yaml:"server"`
// Transport is PODIUM_NODE_TRANSPORT: dev only in MVP-0.
Transport string `yaml:"transport"`
// DataDir holds the node identity and each task's state, PODIUM_NODE_DATA_DIR.
DataDir string `yaml:"data_dir"`
// Labels are advertised at enrollment and used for scheduling, PODIUM_NODE_LABELS
// (comma-separated).
Labels []string `yaml:"labels"`
// MaxTasks is the concurrency budget the scheduler assigns against,
// PODIUM_NODE_MAX_TASKS. Zero would mean this node never gets work.
MaxTasks int `yaml:"max_tasks"`
// EnrollToken is consumed on the first run only, PODIUM_NODE_ENROLL_TOKEN.
EnrollToken string `yaml:"enroll_token"`
// LocalToken is the shared bearer token of the local transport, PODIUM_NODE_LOCAL_TOKEN.
LocalToken string `yaml:"local_token"`
// TSAuthKey is the *Tailscale* auth key, PODIUM_NODE_TS_AUTHKEY or TS_AUTHKEY: reusable,
// pre-approved, tagged tag:podium-node. It is read on the first run only, and it is a
// different thing from EnrollToken, which is Podium's own single-use secret.
// SENSITIVE: never log it.
TSAuthKey string `yaml:"ts_auth_key"`
// TSHostname overrides the Tailscale device name, PODIUM_NODE_TS_HOSTNAME. Empty derives
// it from the machine's hostname.
TSHostname string `yaml:"ts_hostname"`
// ImageCachePrune turns on the LRU image cache prune, PODIUM_NODE_IMAGE_CACHE_PRUNE.
// It is off by default and must be turned on deliberately: a developer running a node
// on a laptop shares that Docker engine with the rest of their work, and no amount of
// disk pressure justifies deleting an image out from under it. See docs/node-setup.md.
ImageCachePrune bool `yaml:"image_cache_prune"`
// ImageCacheHighWatermark is the disk-usage fraction above which pruning starts, when
// pruning is enabled at all: PODIUM_NODE_IMAGE_CACHE_HIGH_WATERMARK.
ImageCacheHighWatermark float64 `yaml:"image_cache_high_watermark"`
// MetricsListen serves /healthz, /readyz and /metrics, PODIUM_NODE_METRICS_LISTEN.
MetricsListen string `yaml:"metrics_listen"`
// DockerHost overrides the engine endpoint, PODIUM_NODE_DOCKER_HOST. Empty means
// the usual DOCKER_HOST / docker context / default socket resolution.
DockerHost string `yaml:"docker_host"`
// ExitOnDrain makes the daemon exit 0 once a drain has been requested and the last
// running task has finished, PODIUM_NODE_EXIT_ON_DRAIN or --exit-on-drain. It is the
// upgrade path: a supervisor restarts the process on the new binary. Without it a
// drained node stays connected and idle, which is what an operator taking a machine
// out of service for maintenance wants.
ExitOnDrain bool `yaml:"exit_on_drain"`
// AllowPrivilegedSidecars honours a spec's `privileged: true` on a sidecar,
// PODIUM_NODE_ALLOW_PRIVILEGED_SIDECARS or --allow-privileged-sidecars. It is off by
// default because such a container is root on this machine's kernel: none of the
// sandbox every other task runs under applies to it, and a spec author must not be
// able to opt into that from a YAML file. It is what a docker-in-docker sidecar
// needs. Turn it on only on a machine dedicated to that, and pair it with a label
// (--labels privileged) so the specs that need it are the only ones that land here.
// See docs/security.md.
AllowPrivilegedSidecars bool `yaml:"allow_privileged_sidecars"`
}
Config is the whole of podium-node's configuration: /etc/podium/node.yaml overlaid by PODIUM_NODE_* environment variables, which in turn are overlaid by flags.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig is the configuration a node with no file and no environment runs with.
func LoadConfig ¶
LoadConfig reads path (or DefaultConfigPath when path is empty) over the defaults and then applies the environment. A file that was explicitly asked for must exist; the default one need not.
func (*Config) TSStateDir ¶
TSStateDir is where the node's own Tailscale device identity lives. It sits under the data dir because it is exactly as durable as identity.json: lose it and the node re-registers as a new Tailscale device, leaving a ghost in the admin console.
type HostFacts ¶
HostFacts is what the node tells the server about the machine it runs on. It is gathered once, at startup, and reported at enrollment and in every Hello.
type Identity ¶
type Identity struct {
NodeID string `json:"node_id"`
// SENSITIVE: never log. The server stores only its SHA-256.
NodeKey string `json:"node_key"`
}
Identity is what Enroll returned, persisted 0600. NodeKey is handed out exactly once by the server, so losing this file means enrolling again with a fresh token.
type Node ¶
type Node struct {
// contains filtered or unexported fields
}
Node is the daemon: one Docker executor, one identity, one stream at a time, and one replay buffer per task in flight.
func New ¶
New validates the configuration, connects to Docker, resolves the node's identity — enrolling on the first run — and prepares the stream client. It does not connect the stream; Run does that.
func (*Node) Close ¶
Close releases the Docker client and leaves the tailnet. Running containers are deliberately left alone: the next incarnation adopts them.
func (*Node) MetricsAddr ¶
MetricsAddr is the bound address of the health and metrics server, valid once Run has started it.
type UpgradeOptions ¶
type UpgradeOptions struct {
// Version is the release tag, "v0.3.1". The leading v is optional.
Version string
// BaseURL defaults to DefaultReleaseBaseURL. A test — or an air-gapped mirror — points
// it somewhere else.
BaseURL string
// GOOS and GOARCH default to this process's.
GOOS, GOARCH string
// HTTPClient defaults to http.DefaultClient.
HTTPClient *http.Client
}
UpgradeOptions describes one release to fetch. Everything has a default except Version.
func (UpgradeOptions) ArchiveName ¶
func (o UpgradeOptions) ArchiveName() string
ArchiveName is the release archive for these options, matching .goreleaser.yaml's name_template. It is exported because the installer script and the docs quote it.