Skip to main content

What is a Service?

A service in Uncloud is a logical grouping of containers running the same image. Services are the unit of deployment and scaling. Services define:
  • Container image and configuration
  • Number of replicas (for replicated services)
  • Environment variables, volumes, and ports
  • Health checks and update behavior
  • Placement constraints
Uncloud uses the familiar Docker Compose format for defining services, so you can reuse existing compose files with minimal changes.

Service Modes

Uncloud supports two deployment modes for services:

Replicated Mode

In replicated mode, you specify exactly how many container replicas to run. Uncloud distributes these replicas across available machines based on placement constraints.
services:
  api:
    image: myapp/api:latest
    deploy:
      mode: replicated
      replicas: 3
This creates 3 containers that Uncloud spreads across machines. Replicated mode is the default if you don’t specify a mode. Use replicated mode for:
  • Application services that can scale horizontally
  • Stateless web servers and APIs
  • Worker processes that handle background jobs
  • Services where you want explicit control over replica count

Global Mode

In global mode, Uncloud runs exactly one container on every machine in the cluster. When you add a new machine, a container automatically starts there.
services:
  monitoring:
    image: prometheus/node-exporter
    deploy:
      mode: global
This runs one container per machine, automatically scaling as you add or remove machines. Use global mode for:
  • Reverse proxies and load balancers (like Caddy)
  • Monitoring and logging agents
  • Network utilities that need to run everywhere
  • Infrastructure services
Global services cannot specify a replica count - the number of containers is always equal to the number of machines.

Container Lifecycle

Uncloud manages the complete lifecycle of containers in a service:

Starting Containers

When you deploy a service:
  1. Image pull - Uncloud pulls the image according to the pull policy
  2. Machine selection - Target machines are chosen based on placement constraints
  3. Container creation - Containers are created with the specified configuration
  4. Network attachment - Containers join the Docker bridge network and get IPs
  5. State update - Container info is stored in cluster state
  6. DNS registration - Service names become resolvable

Running Containers

Once running, containers:
  • Get cluster-unique IP addresses from the machine’s subnet
  • Can communicate with any other container via the mesh network
  • Are monitored by Docker’s restart policy
  • Report health status if health checks are configured
Docker on each machine ensures containers restart on failures according to the restart policy. However, containers won’t automatically move to other machines if a machine fails.

Updating Containers

When you update a service (new image, config change, etc.):
  1. Change detection - Uncloud compares new spec with existing containers
  2. Rolling update - Containers are updated one at a time
  3. Health monitoring - Each new container must become healthy before continuing
  4. Cleanup - Old containers are removed after successful updates
See Rolling Updates for details on controlling update behavior.

Stopping Containers

When you remove a service:
  1. SIGTERM - Containers receive graceful shutdown signal
  2. Grace period - Wait for configured stop grace period (default 10s)
  3. SIGKILL - Force kill if container hasn’t stopped
  4. Network cleanup - IPs are released back to the pool
  5. State update - Service and container records are removed
  6. DNS cleanup - Service names are unregistered

Service Discovery via DNS

Every machine runs an internal DNS server (part of uncloudd) that resolves service names to container IPs.

DNS Naming

Services are accessible via these DNS names:
DNS NameResolves To
service-name.internalAll container IPs for the service
rr.service-name.internalRound-robin through all containers
nearest.service-name.internalLocal containers first, then remote
machine-name.machine.internalThe machine’s mesh IP
The .internal domain is reserved for cluster-internal service discovery. External DNS queries are forwarded to upstream DNS servers.

Resolution Modes

The DNS server supports multiple resolution modes:

Default (Round-Robin)

curl http://api.internal
Returns all container IPs in random order, approximating round-robin load balancing.

Nearest

curl http://nearest.api.internal  
Returns local containers (same machine) first, then remote containers. Useful for reducing network latency.

Explicit Round-Robin

curl http://rr.api.internal
Same as default mode but explicit.

Example Usage

Here’s how services discover each other:
services:
  web:
    image: nginx
    environment:
      - API_URL=http://api.internal:8000
  
  api:
    image: myapp/api
    ports:
      - 8000
The web service can reach api using api.internal without knowing specific container IPs.
DNS queries are resolved with 0 TTL by default, ensuring clients always get current container IPs. This may be increased to allow some caching in the future.

Health Checks

Uncloud supports Docker-native health checks to monitor container health.

Defining Health Checks

services:
  api:
    image: myapp/api
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Health Check Behavior

  • During deployment - New containers must become healthy before old ones are stopped
  • During updates - Uncloud waits for health checks to pass before continuing to next container
  • At runtime - Docker monitors health and can restart unhealthy containers
If a health check is defined, Uncloud waits for it to pass during deployments. Without a health check, Uncloud only verifies the container started successfully.

Health Check States

Containers can be in these health states:
  • starting - Container is in the start period, failures don’t count yet
  • healthy - Health check is passing
  • unhealthy - Health check failed more than the retry count
You can view health status with uc ps or docker ps on individual machines.

Update Configuration

Control how services are updated with the update_config section:
services:
  api:
    image: myapp/api
    deploy:
      update_config:
        order: start-first
        monitor: 30s

Update Order

start-first (default for stateless services):
  • Starts the new container before stopping the old one
  • Minimizes downtime
  • Briefly runs both containers simultaneously
stop-first (default for services with volumes):
  • Stops the old container before starting the new one
  • Prevents data corruption for stateful services
  • Causes brief downtime during updates

Monitor Period

The monitor field specifies how long to wait after starting a container before considering it stable:
  • Containers with health checks: Succeed early if they become healthy
  • Containers without health checks: Wait full monitor period
  • Default is 10 seconds if not specified

Pull Policies

Control when images are pulled from registries:
services:
  api:
    image: myapp/api:latest
    pull_policy: always
Available policies:
  • missing (default) - Pull only if image is not on the target machine
  • always - Always pull the latest version from registry
  • never - Never pull, fail if image is not available locally
Using latest tag with missing policy may cause different machines to run different versions. Use always policy with latest or use specific version tags.

Environment Variables

Define environment variables for containers:
services:
  api:
    image: myapp/api
    environment:
      - DATABASE_URL=postgres://db.internal:5432/mydb
      - LOG_LEVEL=info
Variables are passed directly to the container.

Resource Limits

Set resource constraints for containers:
services:
  api:
    image: myapp/api
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G
        reservations:
          memory: 512M
Resource limits are enforced by Docker on each machine. Uncloud does not currently perform bin-packing or resource-aware scheduling.

Listing Services

View all running services:
uc ls
This shows:
  • Service name and ID
  • Mode (replicated or global)
  • Number of containers
  • Images in use
  • Exposed endpoints

Removing Services

Remove a service and all its containers:
uc rm service-name
This gracefully stops all containers and removes the service from cluster state.

Further Reading

Networking

Learn how containers communicate across machines

Storage

Use volumes for persistent data

Ingress

Expose services to the internet

Deploying Services

Practical guide to service deployment

Build docs developers (and LLMs) love