Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ run:
gen:
go generate -v ./...

gendocs:
go run ./cmd/gendocs

build:
go build -tags="nomsgpack,remote,exclude_graphdriver_btrfs,containers_image_openpgp" -v ./cmd/sablier

Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Whether you don't want to overload your Raspberry Pi, or your QA environment is
- [Environment Variables](#environment-variables)
- [Arguments](#arguments)
- [Providers](#providers)
- [Digital Ocean](#digital-ocean)
- [Docker](#docker)
- [Docker Swarm](#docker-swarm)
- [Podman](#podman)
Expand Down Expand Up @@ -226,6 +227,21 @@ TODO: Add link to full auto-generated reference

## Providers

### Digital Ocean

<img src="./docs/assets/img/digitalocean.svg" alt="Digital Ocean" width="100" align="right" />

Sablier integrates with Digital Ocean's App Platform to scale apps on demand.

**Features:**
- Scale App Platform services and workers automatically
- Stop apps when not in use to save costs
- API-based integration with Digital Ocean

📚 **[Full Documentation](https://sablierapp.dev/#/providers/digitalocean)**

---

### Docker

<img src="./docs/assets/img/docker.svg" alt="Docker" width="100" align="right" />
Expand Down
2 changes: 2 additions & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
- [Versioning](/versioning)
- **Providers**
- [Overview](/providers/overview)
- [<img src="assets/img/digitalocean.svg" height=24px width=24px />Digital Ocean](/providers/digitalocean)
- [<img src="assets/img/docker.svg" height=24px width=24px />Docker](/providers/docker)
- [<img src="assets/img/docker_swarm.png" height=24px width=24px />Docker Swarm](/providers/docker_swarm)
- [<img src="assets/img/kubernetes.png" height=24px width=24px />Kubernetes](/providers/kubernetes)
- [<img src="assets/img/nomad.svg" height=24px width=24px />Nomad](/providers/nomad)
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sidebar references a Nomad provider on line 14, but no corresponding documentation file or implementation for Nomad is included in this PR. This appears to be an accidental addition. Either remove this line or add the corresponding Nomad documentation.

Suggested change
- [<img src="assets/img/nomad.svg" height=24px width=24px />Nomad](/providers/nomad)

Copilot uses AI. Check for mistakes.
- [<img src="assets/img/podman.png" height=24px width=24px />Podman](/providers/podman)
- **Reverse Proxy Plugins**
- [Overview](/plugins/overview)
Expand Down
4 changes: 4 additions & 0 deletions docs/assets/img/digitalocean.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
193 changes: 193 additions & 0 deletions docs/providers/digitalocean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# Digital Ocean

The Digital Ocean provider integrates with Digital Ocean's App Platform to scale apps on demand.

## Use the Digital Ocean provider

In order to use the Digital Ocean provider you can configure the [provider.name](../configuration) property along with your Digital Ocean API token.

<!-- tabs:start -->

#### **File (YAML)**

```yaml
provider:
name: digitalocean
digitalocean:
token: your-digitalocean-api-token
region: nyc1 # Optional, defaults to nyc1
```

#### **CLI**

```bash
sablier start --provider.name=digitalocean --provider.digitalocean.token=your-digitalocean-api-token
```

#### **Environment Variable**

```bash
PROVIDER_NAME=digitalocean
PROVIDER_DIGITALOCEAN_TOKEN=your-digitalocean-api-token
PROVIDER_DIGITALOCEAN_REGION=nyc1
```

<!-- tabs:end -->

!> **Keep your Digital Ocean API token secure! Never commit it to version control.**

## Register Apps

For Sablier to work, it needs to know which Digital Ocean apps to scale.

You register your apps by adding environment variables to your app specification.

```yaml
spec:
name: my-app
services:
- name: web
instance_count: 1
envs:
- key: SABLIER_ENABLE
value: "true"
- key: SABLIER_GROUP
value: "mygroup"
```

## How does Sablier know when an app is ready?

Sablier monitors the deployment phase of your Digital Ocean app. An app is considered ready when:

- The active deployment is in the `ACTIVE` phase
- Instance count is greater than 0

Apps are considered not ready during:
- `PENDING_BUILD`
- `BUILDING`
- `PENDING_DEPLOY`
- `DEPLOYING`

Apps are in an unrecoverable state during:
- `ERROR`
- `CANCELED`

## Configuration Options

### Digital Ocean API Token

```yaml
provider:
digitalocean:
token: your-digitalocean-api-token
```

**Required.** Your Digital Ocean API token for authentication. You can generate a token in the Digital Ocean control panel under API > Tokens.

### Region

```yaml
provider:
digitalocean:
region: nyc1
```

**Optional.** The Digital Ocean region to use. Defaults to `nyc1`. While the API is global, this setting may be used for future region-specific features.

### Auto-stop on Startup

```yaml
provider:
auto-stop-on-startup: true
```

When enabled, Sablier will scale down all apps with `SABLIER_ENABLE=true` environment variable that are running when Sablier starts.

## App Environment Variables

| Variable | Required | Description | Example |
|----------|----------|-------------|---------|
| `SABLIER_ENABLE` | Yes | Enable Sablier management for this app | `true` |
| `SABLIER_GROUP` | No | Logical group name for the app | `myapp` |

## How Scaling Works

### Starting an App

When Sablier receives a request to start an app:

1. It retrieves the current app specification
2. Updates the `instance_count` for all services and workers to 1 (or their previous value if it was already > 0)
3. Triggers a new deployment with the updated specification

### Stopping an App

When Sablier needs to stop an app:

1. It retrieves the current app specification
2. Sets the `instance_count` for all services and workers to 0
3. Triggers a new deployment with the updated specification

## Event Monitoring

Unlike Docker, Digital Ocean doesn't provide a real-time event stream. Sablier polls the App Platform API every 30 seconds to detect when apps are stopped (scaled to 0 instances).

## Limitations

- Polling-based event detection (30-second interval)
- Requires a valid Digital Ocean API token
- Only works with Digital Ocean App Platform (not Droplets, Kubernetes, or other services)
- Scaling operations trigger full deployments, which may take several minutes
- App identification uses App ID, not human-readable names

## Cost Considerations

⚠️ **Important:** Be aware of Digital Ocean App Platform pricing:

- Apps are billed per hour when running
- Scaling to 0 instances stops billing for compute resources
- Deployments may incur brief charges even when scaling down
- Database and storage resources may have separate billing

Sablier helps reduce costs by automatically scaling apps to 0 when not in use.

## Troubleshooting

### App not starting

1. Check Sablier logs for API errors
2. Verify your Digital Ocean API token is valid and has the correct permissions
3. Ensure the app exists and is accessible via the API
4. Check the app's deployment status in the Digital Ocean console

### Authentication errors

1. Verify your token in the Digital Ocean console
2. Ensure the token has read/write permissions for App Platform
3. Check that the token hasn't expired

### Slow scaling

Digital Ocean App Platform deployments can take several minutes:
- Building the app (if code changes were made)
- Deploying new instances
- Health checks

This is expected behavior. Consider adjusting your Sablier timeout settings accordingly.

## Security Best Practices

1. **Store tokens securely**: Use environment variables or secrets management
2. **Use scoped tokens**: Create tokens with minimal required permissions
3. **Rotate tokens regularly**: Update API tokens periodically
4. **Monitor API usage**: Check Digital Ocean console for unexpected API calls

## Full Example

A complete example would include:

1. A Digital Ocean app with `SABLIER_ENABLE=true` environment variable
2. Sablier running with Digital Ocean provider configuration
3. A reverse proxy (Traefik, Nginx, etc.) configured to use Sablier's API

See the Digital Ocean provider example (if available) for a complete setup.
59 changes: 56 additions & 3 deletions docs/providers/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,61 @@ services:
- sablier.group=mygroup
```

## How does Sablier knows when a container is ready?
## How does Sablier know when a container is ready?

If the container defines a Healthcheck, then it will check for healthiness before stating the `ready` status.
If the container defines a Healthcheck, then Sablier will check for healthiness before marking the container as `ready`.

If the containers do not define a Healthcheck, then as soon as the container has the status `started`
If the container does not define a Healthcheck, then as soon as the container has the status `started`, it is considered ready.

## Configuration Options

### Auto-stop on Startup

```yaml
provider:
auto-stop-on-startup: true
```

When enabled, Sablier will stop all containers with `sablier.enable=true` label that are running but not registered in an active session when Sablier starts.

## Container Labels

| Label | Required | Description | Example |
|-------|----------|-------------|---------|
| `sablier.enable` | Yes | Enable Sablier management for this container | `true` |
| `sablier.group` | Yes | Logical group name for the container | `myapp` |

## Full Example

See the [Docker provider example](../../examples/docker/) for a complete, working setup.

## Limitations

- Requires access to the Docker socket
- Cannot manage containers in remote Docker hosts (use Docker Swarm for multi-host scenarios)
- Healthchecks must be defined in the container image or compose file

## Troubleshooting

### Container not starting

1. Check Sablier logs for errors
2. Verify the container has the correct labels
3. Ensure Sablier has access to the Docker socket

### Permission denied

Sablier needs read/write access to `/var/run/docker.sock`. Ensure the Sablier container has the socket mounted:

```yaml
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
```

### Container starts but Sablier doesn't detect it

If your container has a healthcheck, ensure it's passing. Check with:

```bash
docker inspect <container-name> | grep Health -A 10
```
73 changes: 70 additions & 3 deletions docs/providers/docker_swarm.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,75 @@ services:
- sablier.group=mygroup
```

## How does Sablier knows when a service is ready?
## How does Sablier know when a service is ready?

Sablier checks for the service replicas. As soon as the current replicas matches the wanted replicas, then the service is considered `ready`.
Sablier checks for the service replicas. As soon as the current replicas match the wanted replicas, then the service is considered `ready`.

?> Docker Swarm uses the container's healthcheck to check if the container is up and running. So the provider has a native healthcheck support.
?> Docker Swarm uses the container's healthcheck to check if the container is up and running. So the provider has native healthcheck support.

## Configuration Options

### Auto-stop on Startup

```yaml
provider:
auto-stop-on-startup: true
```

When enabled, Sablier will scale down all services with `sablier.enable=true` label that have non-zero replicas but are not registered in an active session when Sablier starts.

## Service Labels

| Label | Required | Description | Example |
|-------|----------|-------------|---------|
| `sablier.enable` | Yes | Enable Sablier management for this service | `true` |
| `sablier.group` | Yes | Logical group name for the service | `myapp` |

**Important:** Labels must be in the `deploy` section for services, not at the service level.

## Full Example

See the [Docker Swarm provider example](../../examples/docker-swarm/) for a complete, working setup.

## Scaling Behavior

- Services start with 0 replicas
- On first request, Sablier scales to the last known replica count (default: 1)
- When session expires, Sablier scales back to 0
- Swarm automatically distributes replicas across nodes

## Limitations

- Requires Docker Swarm mode to be initialized
- Requires access to the Docker socket on a manager node
- Cannot scale global services (only replicated services)
- Services must use `replicated` mode, not `global`

## Troubleshooting

### Service not scaling

1. Check Sablier logs for errors
2. Verify the service has labels in the `deploy` section
3. Ensure Sablier is running on a manager node
4. Check service status: `docker service ps <service-name>`

### Sablier not starting

Ensure Sablier is deployed with a constraint to run on manager nodes:

```yaml
deploy:
placement:
constraints:
- node.role == manager
```

### Services stuck in "preparing" state

Check if nodes have capacity and if images are available:

```bash
docker service ps <service-name>
docker node ls
```
Loading
Loading