isoloom_compose/lib.rs
1//! Isoloom's Docker Compose backend: the Compose file the `docker` and `hosted` targets run (and
2//! the Docker-on-a-VM targets carry), at `.isoloom/docker/compose.yml`, with the files it mounts
3//! and the `docker` target's run manifest.
4//!
5//! - Each network becomes a Compose network with its subnet (Docker at `.1`, or at the last
6//! address when a machine is the network's gateway); `internet: false` makes it `internal`
7//! when nothing routes between networks.
8//! - A machine that is a network's gateway gets forwarding and `NET_ADMIN`; the machines
9//! behind it route everything through it (in a sidecar, once it answers).
10//! - Each machine becomes a service with its fixed address on every network; services find
11//! each other by name (Compose DNS).
12//! - Machines with services get a healthcheck (a TCP probe, and the machine's own `healthcheck`
13//! beside it), so `depends_on` waits for them to answer and `docker compose up --wait` means
14//! "everything answers". The probe is Isoloom's own static busybox (a one-shot
15//! `isoloom-probe-<arch>` copies it into a volume), so it needs nothing from the image:
16//! distroless and `scratch` machines work too.
17//! - `init:` scripts run once, in one-shot containers of the machine's image on its networks,
18//! after it answers; machines depending on it wait for them to finish.
19//! - Inputs become environment variables read from the shell (`${NAME:-}`), only on the
20//! machines that list them.
21//! - Checks run in a `check` profile, one runner per position (`isoloom-check` where a user
22//! stands, `isoloom-check-<machine>` for the others), each a sh script in `checks/`.
23//! - A service's `publish` port is published on the host's loopback (127.0.0.1) only, on an
24//! ephemeral host port Docker picks, so two labs publishing the same port never collide; the
25//! runner reads the real port back from `docker compose ps`. `ISOLOOM_PUBLISH_ADDRESS`
26//! overrides the address and `ISOLOOM_PUBLISH_FIXED` pins the host port to `publish` (both
27//! set inside the docker-vm and cloud VMs, where the lab is alone and that fixed port is
28//! forwarded from loopback).
29//! - `volumes:` become named volumes: they survive re-creating a container, and go with
30//! `docker compose down -v`.
31//! - Network appliances (`docker.appliance`) run router and switch OSes in containers, wired
32//! the way their image expects.
33//!
34//! It sits with the other backends, above the rendering layer (`isoloom-render`) and below the
35//! targets' registry (`isoloom-targets`), and depends on no other backend: [`ComposeBackend`]
36//! renders a planned [`Environment`](isoloom_plan::Environment), purely, into files, through
37//! typed Compose structs. [`hybrid`] adapts the same file to the `hybrid` target's Docker host,
38//! and [`start_plan`] reads back how to start a file an embedder holds.
39//!
40//! # Example
41//!
42//! ```
43//! use isoloom_compose::{ComposeBackend, start_plan};
44//! use isoloom_plan::{Environment, Lab};
45//! use isoloom_render::backend::Backend;
46//! use isoloom_spec::model::Target;
47//!
48//! let lab = Lab::new(isoloom_spec::parse(
49//! "version: 1
50//! name: hello
51//! networks: { lan: { cidr: 10.9.0.0/24 } }
52//! machines:
53//! web: { networks: { lan: 10 }, ports: { web: 80 }, app: { image: nginx } }
54//! ",
55//! )?);
56//! let env = Environment::build(&lab.for_target(Target::Docker), Target::Docker, None);
57//! let files = ComposeBackend(Target::Docker).render(&env)?;
58//! let compose = files.iter().find(|f| f.path == ".isoloom/docker/compose.yml").ok_or("no Compose file")?;
59//! assert!(compose.contents.contains("ipv4_address: 10.9.0.10"));
60//! // Nothing runs once and exits: everything is waited for.
61//! assert_eq!(start_plan(&compose.contents)?.jobs, Vec::<String>::new());
62//! # Ok::<(), Box<dyn std::error::Error>>(())
63//! ```
64
65mod appliances;
66mod backend;
67mod check_runners;
68mod error;
69mod file;
70pub mod hybrid;
71mod images;
72mod interpolation;
73mod ipv6;
74mod labels;
75mod layout;
76mod machine;
77mod manifest;
78mod names;
79mod networks;
80mod outside;
81mod render;
82mod router;
83mod sidecars;
84mod start;
85mod storage;
86#[cfg(test)]
87mod testing;
88
89pub use backend::{ComposeBackend, capabilities_on_a_vm, guest};
90pub use error::{Error, Result};
91pub use labels::{ENVIRONMENT_LABEL, MANAGED_LABEL};
92pub use render::render;
93pub use start::{StartPlan, start_plan};