Skip to content
Merged
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
145 changes: 145 additions & 0 deletions CLI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# CLI Reference

This document describes all available command-line options for Dispenser.

## Usage

```sh
dispenser [OPTIONS]
```

## Options

### `-c, --config <PATH>`

Specify the path to the configuration file.

**Default:** `dispenser.toml`

**Example:**
```sh
dispenser --config /etc/dispenser/my-config.toml
```

### `-t, --test`

Test the configuration file and exit. This validates your configuration files (including variable substitution) to ensure there are no syntax errors or missing variables.

**Example:**
```sh
dispenser --test
```

**Output on success:**
```
Dispenser config is ok.
```

**Output on error:**
```
---------------------------------- <string> -----------------------------------
2 |
3 | [service]
4 | name = "nginx"
5 > image = "${missing}/nginx:latest"
i ^^^^^^^^^^ undefined value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
No referenced variables
-------------------------------------------------------------------------------
```

### `-p, --pid-file <PATH>`

Specify the path to the PID file. This file is used to track the running Dispenser process and is required for sending signals with the `--signal` flag.

**Default:** `dispenser.pid`

**Example:**
```sh
dispenser --pid-file /var/run/dispenser.pid
```

### `-s, --signal <SIGNAL>`

Send a signal to the running Dispenser instance. This command relies on the PID file, so you should run it from the same directory where Dispenser is running (typically `/opt/dispenser` for the default installation).

**Valid signals:**
- `reload` - Reload the `dispenser.toml` configuration without restarting the process
- `stop` - Gracefully stop the Dispenser daemon

**Examples:**
```sh
# Reload configuration
dispenser --signal reload

# Stop the daemon
dispenser --signal stop
```

### `-h, --help`

Display help information about available options.

**Example:**
```sh
dispenser --help
```

### `-V, --version`

Display the current version of Dispenser.

**Example:**
```sh
dispenser --version
```

## Common Usage Patterns

### Running in Foreground (for testing)

```sh
dispenser --config ./dispenser.toml
```

### Validating Configuration Before Deployment

```sh
dispenser --test && echo "Configuration is valid!"
```

### Reloading Configuration After Changes

```sh
# After editing dispenser.toml
dispenser --signal reload
```

### Using Custom Paths

```sh
dispenser --config /etc/dispenser/production.toml --pid-file /var/run/dispenser-prod.pid
```

## Systemd Integration

When Dispenser is installed via the `.deb` or `.rpm` package, it runs as a systemd service. You can manage it using standard systemd commands:

```sh
# Start the service
sudo systemctl start dispenser

# Stop the service
sudo systemctl stop dispenser

# Restart the service
sudo systemctl restart dispenser

# Check service status
sudo systemctl status dispenser

# View logs
sudo journalctl -u dispenser -f
```

The systemd service automatically uses the configuration at `/opt/dispenser/dispenser.toml` and runs as the `dispenser` user.
117 changes: 75 additions & 42 deletions CRON.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,110 @@
# Using Cron for Scheduled Deployments

Dispenser provides a `cron` feature to schedule deployments or restarts of your services at specific intervals. This is useful for tasks that need to run periodically, such as batch jobs, or for ensuring services are restarted regularly for maintenance.
Dispenser supports cron scheduling to deploy or restart services at specific intervals. This is useful for batch jobs, backups, ETL processes, or periodic maintenance restarts.

## How it Works
## Configuration

You can add a `cron` attribute to any `[[instance]]` block in your `dispenser.toml` configuration file. The value of this attribute is a cron expression that defines the schedule for the deployment.
Add a `cron` field to the `[dispenser]` section in your `service.toml`:

When a `cron` schedule is defined for an instance, Dispenser will trigger a redeployment of the corresponding Docker Compose service according to the schedule. This is equivalent to running `docker-compose up -d --force-recreate` for the service.
```toml
[dispenser]
watch = false
initialize = "on-trigger"
cron = "0 0 2 * * *" # Every day at 2 AM
```

The cron scheduler uses a 6-field format that includes seconds:
### Cron Expression Format

Dispenser uses a 6-field format (with seconds):

```
┌───────────── second (0 - 59)
│ ┌───────────── minute (0 - 59)
│ │ ┌───────────── hour (0 - 23)
│ │ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── day of month (1 - 31)
│ │ │ │ ┌───────────── month (1 - 12)
│ │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
│ │ │ │ │ │
│ │ │ │ │ ┌───────────── day of week (0 - 6, Sunday = 0)
│ │ │ │ │ │
* * * * * *
```

You can use online tools like [crontab.guru](https://crontab.guru/) to help generate the correct cron expression. Note that many online tools generate 5-field expressions, so you may need to add the seconds field (`*` or `0`) at the beginning.
**Common expressions:**
- `0 0 2 * * *` - Daily at 2 AM
- `0 0 */6 * * *` - Every 6 hours
- `0 30 9 * * 1-5` - Weekdays at 9:30 AM
- `0 0 0 1 * *` - First day of each month
- `*/10 * * * * *` - Every 10 seconds

Use [crontab.guru](https://crontab.guru/) for help (add `0` for seconds field).

## Examples

### Scheduled Backup Job

```toml
[service]
name = "backup-job"
image = "my-backup:latest"

## Use Cases
[[volume]]
source = "./backups"
target = "/backups"

### Scheduled-Only Deployments
restart = "no"

You can use `cron` without an `images` attribute. This is ideal for services that run on a schedule such as ETLs or batch processing tasks, and do not have a corresponding image to monitor for updates.
[dispenser]
watch = false
initialize = "on-trigger"
cron = "0 0 2 * * *" # Daily at 2 AM
```

**Example:**
The following configuration will run the `hello-world` service every 10 seconds. Since there is no image to watch, the deployment is only triggered by the cron schedule.
### ETL Job Every Hour

```toml
# dispenser.toml
[service]
name = "etl-processor"
image = "my-etl:latest"
command = ["python", "process.py"]

[[instance]]
path = "hello-world"
cron = "*/10 * * * * *"
restart = "no"

[dispenser]
watch = false
initialize = "on-trigger"
cron = "0 0 * * * *" # Every hour
```

The `docker-compose.yaml` for this service might look like this. It is important to set `restart: no` to prevent the container from restarting automatically after its task is complete. It will wait for the next scheduled run from Dispenser.
### Periodic Restart with Image Watching

```toml
[service]
name = "worker"
image = "my-worker:latest"

```yaml
# hello-world/docker-compose.yaml
restart = "always"

version: "3.8"
services:
hello-world:
image: hello-world
restart: no
[dispenser]
watch = true
initialize = "immediately"
cron = "0 0 4 * * *" # Restart daily at 4 AM
```

### Scheduled Restarts with Image Monitoring
This configuration will:
- Deploy when a new image is detected
- Also restart daily at 4 AM (even if no new image)

You can use `cron` in combination with image monitoring. In this case, Dispenser will deploy a new version of your service under two conditions:
1. A new Docker image is detected in the registry.
2. The `cron` schedule is met.
## Options

This is useful for services that should be restarted periodically, even if no new image is available.
### `initialize`

**Example:**
The following configuration watches the `nginx:latest` image and also restarts the service every minute.
- `immediately` (default) - Start when Dispenser starts
- `on-trigger` - Only start when cron fires or image updates

```toml
# dispenser.toml
### `watch`

[[instance]]
path = "nginx"
# Will restart the service every minute or when the nginx image gets updated
cron = "0 */1 * * * *"
images = [{ registry = "docker.io", name = "nginx", tag = "latest" }]
```
- `true` - Monitor registry for image updates
- `false` - Only run on cron schedule

### `restart`

By using the `cron` feature, you can extend Dispenser's capabilities beyond continuous deployment to include scheduled task orchestration. You can find more examples in the `example` directory of the project.
Use `restart = "no"` for one-time jobs to prevent automatic restarts between scheduled runs.
18 changes: 17 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dispenser"
version = "0.6.0"
version = "0.7.0"
edition = "2021"
license = "MIT"

Expand All @@ -10,6 +10,7 @@ chrono = "0.4.42"
clap = { version = "4.5.18", features = ["derive"] }
cron = { version = "0.15.0", features = ["serde"] }
env_logger = "0.11.5"
futures = "0.3.31"
futures-util = "0.3.31"
google-cloud-secretmanager-v1 = "1.2.0"
log = "0.4.22"
Expand Down
Loading