Service
Source:
src/Docker/Service.ts
A Docker Swarm service: N replicas of a container kept alive by the swarm, deployed through the active (or a named) Docker context.
The target engine must be a swarm manager — Service wraps
docker service, swarm mode’s orchestration API. Declare the swarm with
Docker.Swarm and pass it as context so the service deploys after the
swarm exists; for a plain single container on a non-swarm daemon use
Docker.Container instead.
The service’s image comes from one of two sources:
image— run a pre-built reference (a registry ref, or aDocker.Image/Docker.RemoteImageresource).main— bundle an inline Effect program into a generated bun image, built directly against the service’s Docker context. The impl returns{ fetch }and may register background loops viaServerHost.run— the same effectful platform shape asAWS.ECS.Service.
The bundled image is content-addressed and only rebuilt when the program
(or its generated Dockerfile) changes. It is built on the target engine’s
local store — single-node swarms run it as-is; multi-node swarms need the
image on a registry every node can reach (build with Docker.Image +
registry and pass the pushed ref as image instead).
Only replicated services are supported. Configuration changes replace the
service (delete-then-create); swarm tasks are stateless, so replacement is
cheap and avoids partially-applied service update drift.
Creating Services
Section titled “Creating Services”Replicated Nginx
const swarm = yield* Docker.Swarm("swarm");const web = yield* Docker.Service("web", { context: swarm, image: "nginx:alpine", replicas: 3, ports: [{ external: 8080, internal: 80 }],});Run a Built Image
const image = yield* Docker.Image("app-image", { build: { context: "./app" },});const app = yield* Docker.Service("app", { context: swarm, image, replicas: 2,});Effectful Services
Section titled “Effectful Services”Inline Effect Server
const swarm = yield* Docker.Swarm("swarm");const api = yield* Docker.Service( "Api", { context: swarm, main: import.meta.url, port: 3000, ports: [{ external: 8080, internal: 3000 }], replicas: 2, }, Effect.gen(function* () { return { fetch: Effect.gen(function* () { return yield* HttpServerResponse.json({ ok: true }); }), }; }),);Background Loops with ServerHost
// Class props may be an Effect, so the service can yield the swarm it// deploys into (declared once at module level).const Swarm = Docker.Swarm("swarm");
export default class Worker extends Docker.Service<Worker>()( "Worker", Effect.gen(function* () { const swarm = yield* Swarm; return { context: swarm, main: import.meta.url, port: 3000 }; }), Effect.gen(function* () { const host = yield* ServerHost; yield* host.run( pollQueue.pipe(Effect.repeat(Schedule.spaced("5 seconds")), Effect.asVoid), ); return { fetch: Effect.succeed(HttpServerResponse.text("ok")), }; }),) {}Docker Contexts
Section titled “Docker Contexts”const vps = yield* Docker.Context("vps", { docker: "host=ssh://deploy@example.com",});const swarm = yield* Docker.Swarm("swarm", { context: vps, advertiseAddr: "10.0.0.1",});const app = yield* Docker.Service("app", { context: swarm, image: "nginx:alpine", replicas: 3,});Networks & Volumes
Section titled “Networks & Volumes”const network = yield* Docker.Network("app-net", { context: swarm, driver: "overlay",});const db = yield* Docker.Service("db", { context: swarm, image: "postgres:18-alpine", networks: [{ name: network.name, aliases: ["postgres"] }], volumes: [{ hostPath: "pg-data", containerPath: "/var/lib/postgresql/data" }],});Rollouts & Placement
Section titled “Rollouts & Placement”const app = yield* Docker.Service("app", { image: "ghcr.io/acme/app:latest", replicas: 4, updateConfig: { parallelism: 1, delay: "10s", failureAction: "rollback", order: "start-first", }, placement: { constraints: ["node.role==worker"], maxReplicasPerNode: 2, },});Secrets & Configs
Section titled “Secrets & Configs”const app = yield* Docker.Service("app", { image: "ghcr.io/acme/app:latest", secrets: [{ source: "db-password", target: "db_password", mode: 0o400 }], configs: [{ source: "app-config", target: "/etc/app/config.yaml" }],});