docs: first draft for doc website
0
docs/.nojekyll
Normal file
23
docs/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
  
|
||||
|
||||
# Sablier - Scale to Zero
|
||||
|
||||
Sablier is an API that start containers for a given duration.
|
||||
|
||||
It provides an integrations with multiple reverse proxies and different loading strategies.
|
||||
|
||||
Which allows you to start your containers on demand and shut them down automatically as soon as there's no activity.
|
||||
|
||||

|
||||
|
||||
## Glossary
|
||||
|
||||
I'll use these terms in order to be provider agnostic.
|
||||
|
||||
- **Session**: A Session is a set of **instances**
|
||||
- **Instance**: An instance is either a docker container, docker swarm service, kubernetes deployment or kubernetes statefulset
|
||||
|
||||
## Credits
|
||||
|
||||
- [Hourglass icons created by Vectors Market - Flaticon](https://www.flaticon.com/free-icons/hourglass)
|
||||
- [tarampampam/error-pages](https://github.com/tarampampam/error-pages/) for the themes
|
||||
24
docs/_sidebar.md
Normal file
@@ -0,0 +1,24 @@
|
||||
- [Introduction](/)
|
||||
- [Getting started](/getting-started)
|
||||
- [Installation](/installation)
|
||||
- [Configuration](/configuration)
|
||||
- [Strategies](/strategies)
|
||||
- [Themes](/themes)
|
||||
- [FAQ](/faq)
|
||||
- [Versioning](/versioning)
|
||||
- **Providers**
|
||||
- [Overview](/providers/overview)
|
||||
- [Docker](/providers/docker)
|
||||
- [Docker Swarm](/providers/docker_swarm)
|
||||
- [Kubernetes](/providers/kubernetes)
|
||||
- **Reverse Proxy Plugins**
|
||||
- [Overview](/plugins/overview)
|
||||
- [Traefik](/plugins/traefik)
|
||||
- [Nginx](/plugins/nginx)
|
||||
- [Caddy](/plugins/caddy)
|
||||
- **Guides**
|
||||
- [Overview](/guides/overview)
|
||||
- [VSCode Server with Traefik and Kubernetes](/guides/code-server-traefik-kubernetes.md)
|
||||
- **Links**
|
||||
- [<img src="/assets/img/github.svg" />Github](https://github.com/acouvreur/sablier)
|
||||
- [<img src="/assets/img/docker.svg" height=24px />Docker Hub](https://hub.docker.com/r/acouvreur/sablier)
|
||||
95
docs/api/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Documentation for Sablier
|
||||
|
||||
<a name="documentation-for-api-endpoints"></a>
|
||||
## Documentation for API Endpoints
|
||||
|
||||
All URIs are relative to *http://localhost:10000*
|
||||
|
||||
| Class | Method | HTTP request | Description |
|
||||
|------------ | ------------- | ------------- | -------------|
|
||||
| *ScaleApi* | [**scaleBlocking**](Apis/ScaleApi.md#scaleblocking) | **GET** /api/strategies/blocking | Hangs the request until the services are ready |
|
||||
*ScaleApi* | [**scaleDynamic**](Apis/ScaleApi.md#scaledynamic) | **GET** /api/strategies/dynamic | The waiting page for the given services |
|
||||
| *ThemeApi* | [**getTheme**](Apis/ThemeApi.md#gettheme) | **GET** /api/strategies/dynamoc/themes | |
|
||||
|
||||
|
||||
<a name="documentation-for-models"></a>
|
||||
## Documentation for Models
|
||||
|
||||
- [instance](./Models/instance.md)
|
||||
- [session](./Models/session.md)
|
||||
- [status](./Models/status.md)
|
||||
- [themes](./Models/themes.md)
|
||||
|
||||
|
||||
<a name="documentation-for-authorization"></a>
|
||||
## Documentation for Authorization
|
||||
|
||||
All endpoints do not require authorization.
|
||||
|
||||
## API
|
||||
|
||||
To run the following examples you can create two containers:
|
||||
|
||||
- `docker create --name nginx nginx`
|
||||
- `docker create --name apache httpd`
|
||||
|
||||
### GET `/api/strategies/dynamic`
|
||||
|
||||
**Description**: The `/api/strategies/dynamic` endpoint allows you to request a waiting page for multiple instances
|
||||
|
||||
| Parameter | Value | Description |
|
||||
| -------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `names` | array of string | The instances to be started (cannot be used with `group` parameter) |
|
||||
| `group` | string | The instance group to be started (using `sablier.group=mygroup` labels) (cannot be used with `names` parameter) |
|
||||
| `session_duration` | duration [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) | The session duration for all services, which will reset at each subsequent calls |
|
||||
| `show_details` *(optional)* | bool | The details about instances |
|
||||
| `display_name` *(optional)* | string | The display name |
|
||||
| `theme` *(optional)* | string | The theme to use |
|
||||
| `refresh_frequency` *(optional)* | duration [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) | The refresh frequency for the loading page |
|
||||
|
||||
Go to http://localhost:10000/api/strategies/dynamic?names=nginx&names=apache&session_duration=5m&show_details=true&display_name=example&theme=hacker-terminal&refresh_frequency=10s and you should see
|
||||
|
||||
A special header `X-Sablier-Session-Status` is returned and will have the value `ready` if all instances are ready. Or else `not-ready`.
|
||||
|
||||

|
||||
|
||||
### GET `/api/strategies/blocking`
|
||||
|
||||
**Description**: The `/api/strategies/blocking` endpoint allows you to wait until the instances are ready
|
||||
|
||||
| Parameter | Value | Description |
|
||||
| ---------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `names` | array of string | The instances to be started (cannot be used with `group` parameter) |
|
||||
| `group` | string | The instance group to be started (using `sablier.group=mygroup` labels) (cannot be used with `names` parameter) |
|
||||
| `session_duration` | duration [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) | The session duration for all services, which will reset at each subsequent calls |
|
||||
| `timeout` *(optional)* | duration [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) | The maximum time to wait for instances to be ready |
|
||||
|
||||
A special header `X-Sablier-Session-Status` is returned and will have the value `ready` if all instances are ready. Or else `not-ready`.
|
||||
|
||||
**Curl example**
|
||||
```bash
|
||||
curl -X GET -v "http://localhost:10000/api/strategies/blocking?names=nginx&names=apache&session_duration=5m&timeout=5s"
|
||||
* Trying 127.0.0.1:10000...
|
||||
* Connected to localhost (127.0.0.1) port 10000 (#0)
|
||||
> GET /api/strategies/blocking?names=nginx&names=apache&session_duration=5m&timeout=30s HTTP/1.1
|
||||
> Host: localhost:10000
|
||||
> User-Agent: curl/7.74.0
|
||||
> Accept: */*
|
||||
>
|
||||
* Mark bundle as not supporting multiuse
|
||||
< HTTP/1.1 200 OK
|
||||
< Content-Type: application/json; charset=utf-8
|
||||
< X-Sablier-Session-Status: ready
|
||||
< Date: Mon, 14 Nov 2022 19:20:50 GMT
|
||||
< Content-Length: 245
|
||||
<
|
||||
{"session":
|
||||
{"instances":
|
||||
[
|
||||
{"instance":{"name":"nginx","currentReplicas":1,"desiredReplicas":1,"status":"ready"},"error":null},
|
||||
{"instance":{"name":"apache","currentReplicas":1,"desiredReplicas":1,"status":"ready"},"error":null}
|
||||
],
|
||||
"status":"ready"
|
||||
}
|
||||
}
|
||||
```
|
||||
4
docs/assets/img/docker.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
aria-label="Docker" role="img"
|
||||
viewBox="0 0 512 512"><path stroke="#066da5" stroke-width="38" d="M296 226h42m-92 0h42m-91 0h42m-91 0h41m-91 0h42m8-46h41m8 0h42m7 0h42m-42-46h42"/><path fill="#066da5" d="m472 228s-18-17-55-11c-4-29-35-46-35-46s-29 35-8 74c-6 3-16 7-31 7H68c-5 19-5 145 133 145 99 0 173-46 208-130 52 4 63-39 63-39"/></svg>
|
||||
|
After Width: | Height: | Size: 417 B |
1
docs/assets/img/github.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
|
After Width: | Height: | Size: 814 B |
BIN
docs/assets/img/integration.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
122
docs/configuration.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Configuration
|
||||
|
||||
There are three different ways to define configuration options in Sablier:
|
||||
|
||||
1. In a configuration file
|
||||
2. As environment variables
|
||||
3. In the command-line arguments
|
||||
|
||||
These ways are evaluated in the order listed above.
|
||||
|
||||
If no value was provided for a given option, a default value applies.
|
||||
|
||||
## Configuration File
|
||||
|
||||
At startup, Sablier searches for configuration in a file named sablier.yml (or sablier.yaml) in:
|
||||
|
||||
- `/etc/sablier/`
|
||||
- `$XDG_CONFIG_HOME/`
|
||||
- `$HOME/.config/`
|
||||
- `.` *(the working directory).*
|
||||
|
||||
You can override this using the configFile argument.
|
||||
|
||||
```bash
|
||||
sablier --configFile=path/to/myconfigfile.yml
|
||||
```
|
||||
|
||||
```yaml
|
||||
provider:
|
||||
# Provider to use to manage containers (docker, swarm, kubernetes)
|
||||
name: docker
|
||||
server:
|
||||
# The server port to use
|
||||
port: 10000
|
||||
# The base path for the API
|
||||
base-path: /
|
||||
storage:
|
||||
# File path to save the state (default stateless)
|
||||
file:
|
||||
sessions:
|
||||
# The default session duration (default 5m)
|
||||
default-duration: 5m
|
||||
# The expiration checking interval.
|
||||
# Higher duration gives less stress on CPU.
|
||||
# If you only use sessions of 1h, setting this to 5m is a good trade-off.
|
||||
expiration-interval: 20s
|
||||
logging:
|
||||
level: trace
|
||||
strategy:
|
||||
dynamic:
|
||||
# Custom themes folder, will load all .html files recursively (default empty)
|
||||
custom-themes-path:
|
||||
# Show instances details by default in waiting UI
|
||||
show-details-by-default: false
|
||||
# Default theme used for dynamic strategy (default "hacker-terminal")
|
||||
default-theme: hacker-terminal
|
||||
# Default refresh frequency in the HTML page for dynamic strategy
|
||||
default-refresh-frequency: 5s
|
||||
blocking:
|
||||
# Default timeout used for blocking strategy (default 1m)
|
||||
default-timeout: 1m
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All environment variables can be used in the form of the config file such as
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
dynamic:
|
||||
custom-themes-path: /my/path
|
||||
```
|
||||
|
||||
Becomes
|
||||
|
||||
```bash
|
||||
STRATEGY_DYNAMIC_CUSTOM_THEMES_PATH=/my/path
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
To get the list of all available arguments:
|
||||
|
||||
```bash
|
||||
sablier --help
|
||||
|
||||
# or
|
||||
|
||||
docker run acouvreur/sablier[:version] --help
|
||||
# ex: docker run acouvreur/sablier:1.4.0-beta.3 --help
|
||||
```
|
||||
|
||||
All arguments can be used in the form of the config file such as
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
dynamic:
|
||||
custom-themes-path: /my/path
|
||||
```
|
||||
|
||||
Becomes
|
||||
|
||||
```bash
|
||||
sablier start --strategy.dynamic.custom-themes-path /my/path
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```
|
||||
-h, --help help for start
|
||||
--provider.name string Provider to use to manage containers [docker swarm kubernetes] (default "docker")
|
||||
--server.base-path string The base path for the API (default "/")
|
||||
--server.port int The server port to use (default 10000)
|
||||
--sessions.default-duration duration The default session duration (default 5m0s)
|
||||
--sessions.expiration-interval duration The expiration checking interval. Higher duration gives less stress on CPU. If you only use sessions of 1h, setting this to 5m is a good trade-off. (default 20s)
|
||||
--storage.file string File path to save the state
|
||||
--strategy.blocking.default-timeout duration Default timeout used for blocking strategy (default 1m0s)
|
||||
--strategy.dynamic.custom-themes-path string Custom themes folder, will load all .html files recursively
|
||||
--strategy.dynamic.default-refresh-frequency duration Default refresh frequency in the HTML page for dynamic strategy (default 5s)
|
||||
--strategy.dynamic.default-theme string Default theme used for dynamic strategy (default "hacker-terminal")
|
||||
--strategy.dynamic.show-details-by-default Show the loading instances details by default (default true)
|
||||
```
|
||||
5
docs/faq.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Frequenty Asked Questions
|
||||
|
||||
## How to start multiple instances?
|
||||
|
||||
## How do I do
|
||||
BIN
docs/favicon.ico
Normal file
|
After Width: | Height: | Size: 31 KiB |
178
docs/getting-started.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# Getting started
|
||||
|
||||
This Getting Started will get you through what you need to understand how to use Sablier as a scale to zero middleware with a reverse proxy.
|
||||
|
||||

|
||||
|
||||
## Identify your provider
|
||||
|
||||
The first thing you need to do is to identify your [Provider](/providers/overview).
|
||||
|
||||
?> A Provider is how Sablier can interact with your instances and scale them up and down to zero.
|
||||
|
||||
You can check the available providers [here](/providers/overview?id=available-providers).
|
||||
|
||||
## Identify your reverse proxy
|
||||
|
||||
Once you've identified you're [Provider](/providers/overview), you'll want to identify your [Reverse Proxy](/plugins/overview).
|
||||
|
||||
?> Because Sablier is designed as an API that can be used on its own, reverse proxy integrations acts as a client of that API.
|
||||
|
||||
You can check the available reverse proxy plugins [here](/plugins/overview?id=available-reverse-proxies)
|
||||
|
||||
## Connect it all together
|
||||
|
||||
- Let's say we're using the [Docker Provider](/providers/docker).
|
||||
- Let's say we're using the [Caddy Reverse Proxy Plugin](/plugins/caddy).
|
||||
|
||||
### 1. Initial setup with Caddy
|
||||
|
||||
Suppose this is your initial setup with Caddy. You have your reverse proxy with a Caddyfile that does a simple reverse proxy on `/whoami`.
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **docker-compose.yaml**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
proxy:
|
||||
image: caddy:2.6.4
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
```
|
||||
|
||||
#### **Caddyfile**
|
||||
|
||||
```Caddyfile
|
||||
:80 {
|
||||
route /whoami {
|
||||
reverse_proxy whoami:80
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
At this point you can run `docker compose up` and go to `http://localhost:8080/whoami` and you will see your service.
|
||||
|
||||
|
||||
### 2. Install Sablier with the Docker Provider
|
||||
|
||||
Add the Sablier container in the `docker-compose.yaml` file.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
proxy:
|
||||
image: caddy:2.6.4
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
|
||||
sablier:
|
||||
image: acouvreur/sablier:1.4.0-beta.3
|
||||
command:
|
||||
- start
|
||||
- --provider.name=docker
|
||||
volumes:
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
```
|
||||
|
||||
### 3. Add the Sablier Caddy Plugin to Caddy
|
||||
|
||||
Because Caddy does not provide any runtime evaluation for the plugins, we need to build Caddy with this specific plugin.
|
||||
|
||||
I'll use the provided Dockerfile to build the custom Caddy image.
|
||||
|
||||
```bash
|
||||
docker build https://github.com/acouvreur/sablier.git#v1.4.0-beta.3:plugins/caddy
|
||||
--build-arg=CADDY_VERSION=2.6.4
|
||||
-t caddy:2.6.4-with-sablier
|
||||
```
|
||||
|
||||
Then change the image to from `caddy:2.6.4` to `caddy:2.6.4-with-sablier`
|
||||
|
||||
```yaml
|
||||
services:
|
||||
proxy:
|
||||
image: caddy:2.6.4-with-sablier
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
|
||||
sablier:
|
||||
image: acouvreur/sablier:1.4.0-beta.3
|
||||
command:
|
||||
- start
|
||||
- --provider.name=docker
|
||||
volumes:
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
```
|
||||
|
||||
### 4. Configure Caddy to use the Sablier Caddy Plugin on the `whoami` service
|
||||
|
||||
This is how you opt-in your services and link them with the plugin.
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **docker-compose.yaml**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
proxy:
|
||||
image: caddy:local
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
labels:
|
||||
- sablier.enable=true
|
||||
- sablier.group=demo
|
||||
|
||||
sablier:
|
||||
image: acouvreur/sablier:local
|
||||
volumes:
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
```
|
||||
|
||||
#### **Caddyfile**
|
||||
|
||||
```Caddyfile
|
||||
:80 {
|
||||
route /whoami {
|
||||
sablier url=http://sablier:10000 {
|
||||
group demo
|
||||
session_duration 1m
|
||||
dynamic {
|
||||
display_name My Whoami Service
|
||||
}
|
||||
}
|
||||
|
||||
reverse_proxy whoami:80
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here we've configured the following things when we're accessing the service on `http://localhost:8080/whoami`:
|
||||
- The containers that have the label `sablier.group=demo` will be started on demand
|
||||
- The period of innactivity after which the containers should be shut down is one minute
|
||||
- It uses the dynamic configuration and configures the title with `My Whoami Service`
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
?> We've assigned the group `demo` to the service and we use this to identify the workload i
|
||||
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,13 +1,4 @@
|
||||
# Sablier Guide: Code-Server + Traefik + Kubernetes Ingress
|
||||
|
||||
- [Sablier Guide: Code-Server + Traefik + Kubernetes Ingress](#sablier-guide-code-server--traefik--kubernetes-ingress)
|
||||
- [1. Prerequisites](#1-prerequisites)
|
||||
- [2. Create the Kubernetes Cluster using K3S](#2-create-the-kubernetes-cluster-using-k3s)
|
||||
- [3. Deploy Traefik using Helm](#3-deploy-traefik-using-helm)
|
||||
- [3. Deploy Sablier](#3-deploy-sablier)
|
||||
- [4. Deploy Code-Server](#4-deploy-code-server)
|
||||
- [5. Routing Code-Server through Traefik with the Sablier Plugin Middleware](#5-routing-code-server-through-traefik-with-the-sablier-plugin-middleware)
|
||||
- [6. Clean up](#6-clean-up)
|
||||
# Code-Server + Traefik + Kubernetes Ingress
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
|
||||
5
docs/guides/overview.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Guides
|
||||
|
||||
Guides are here to help you to understand more how to use this API in complex use cases.
|
||||
|
||||
Because the nature of Sablier involves multiple reverse proxies and multiple providers, the complexity multiplies.
|
||||
|
Before Width: | Height: | Size: 133 KiB |
23
docs/health.md
Normal file
@@ -0,0 +1,23 @@
|
||||
## Sablier Healthcheck
|
||||
|
||||
### Using the `/health` route
|
||||
|
||||
You can use the route `/health` to check for healthiness.
|
||||
|
||||
- Returns 200 `OK` when ready
|
||||
- Returns 503 `Service Unavailable` when terminating
|
||||
|
||||
### Using the `sablier health` command
|
||||
|
||||
You can use the command `sablier health` to check for healthiness.
|
||||
|
||||
`sablier health` takes on argument `--url` which defaults to `http://localhost:10000/health`.
|
||||
|
||||
```yml
|
||||
services:
|
||||
sablier:
|
||||
image: acouvreur/sablier:1.4.0-beta.3
|
||||
healthcheck:
|
||||
test: ["sablier", "health"]
|
||||
interval: 1m30s
|
||||
```
|
||||
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 74 KiB |
59
docs/index.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Sablier - Scale to Zero</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple-dark.css">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--base-font-size: 16px;
|
||||
--theme-color : #ffd05b;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'sablier',
|
||||
repo: 'https://github.com/acouvreur/sablier',
|
||||
notFoundPage: true,
|
||||
loadSidebar: true,
|
||||
alias: {
|
||||
'/.*/_sidebar.md': '/_sidebar.md'
|
||||
},
|
||||
auto2top : true,
|
||||
maxLevel : 3,
|
||||
subMaxLevel: 3,
|
||||
tabs: {
|
||||
persist : true, // default
|
||||
sync : true, // default
|
||||
theme : 'classic', // default
|
||||
tabComments: true, // default
|
||||
tabHeadings: true // default
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Docsify v4 -->
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/js/docsify-themeable.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify-tabs@1"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-go.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-yaml.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-docker.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
|
||||
|
||||
<!-- plugins -->
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="https://unpkg.com/docsify-copy-code@2"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-edit-on-github"></script>
|
||||
<script src="//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify@4/lib/plugins/zoom-image.min.js"></script>
|
||||
<script src="//unpkg.com/docsify-plantuml/dist/docsify-plantuml.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
42
docs/installation.md
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
# Install Sablier on its own
|
||||
|
||||
You can install Sablier with the following flavors:
|
||||
|
||||
- Use the Docker image
|
||||
- Use the binary distribution
|
||||
- Compile your binary from the sources
|
||||
|
||||
## Use the Docker image
|
||||
|
||||
- **Docker Hub**: [acouvreur/sablier](https://hub.docker.com/r/acouvreur/sablier)
|
||||
- **Github Container Registry**: [ghcr.io/acouvreur/sablier](https://github.com/acouvreur/sablier/pkgs/container/sablier)
|
||||
|
||||
Choose one of the Docker images and run it with one sample configuration file:
|
||||
|
||||
- [sablier.yaml](https://raw.githubusercontent.com/acouvreur/sablier/main/sablier.sample.yaml)
|
||||
|
||||
```bash
|
||||
docker run -d -p 10000:10000 \
|
||||
-v $PWD/sablier.yml:/etc/sablier/sablier.yml acouvreur/sablier:1.4.0-beta.3
|
||||
```
|
||||
|
||||
## Use the binary distribution
|
||||
|
||||
Grab the latest binary from the [releases](https://github.com/acouvreur/sablier/releases) page.
|
||||
|
||||
And run it:
|
||||
|
||||
```bash
|
||||
./sablier --help
|
||||
```
|
||||
|
||||
## Compile your binary from the sources
|
||||
|
||||
```bash
|
||||
git clone git@github.com:acouvreur/sablier.git
|
||||
cd sablier
|
||||
make
|
||||
# Output will change depending on your distro
|
||||
./sablier_draft_linux-amd64
|
||||
```
|
||||
88
docs/plugins/caddy.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Caddy Sablier Plugin
|
||||
|
||||
Caddy Sablier Plugin.
|
||||
|
||||
## Provider compatibility grid
|
||||
|
||||
| Provider | Dynamic | Blocking |
|
||||
| --------------------------------------- | :-----: | :------: |
|
||||
| [Docker](/providers/docker) | ✅ | ✅ |
|
||||
| [Docker Swarm](/providers/docker_swarm) | ✅ | ✅ |
|
||||
| [Kubernetes](/providers/kubernetes) | ❌ | ❌ |
|
||||
|
||||
## Install the plugin to Caddy
|
||||
|
||||
Because Caddy does not do runtime evaluation, you need to build the base image with the plugin source code.
|
||||
|
||||
In order to use the custom plugin for Caddy, you need to bundle it with Caddy.
|
||||
Here I'll show you two options with Docker.
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **Using the provided Dockerfile**
|
||||
|
||||
```bash
|
||||
docker build https://github.com/acouvreur/sablier.git#v1.4.0-beta.3:plugins/caddy
|
||||
--build-arg=CADDY_VERSION=2.6.4
|
||||
-t caddy:2.6.4-with-sablier
|
||||
```
|
||||
|
||||
#### **Updating your Caddy Dockerfile**
|
||||
|
||||
```docker
|
||||
ARG CADDY_VERSION=2.6.4
|
||||
FROM caddy:${CADDY_VERSION}-builder AS builder
|
||||
|
||||
ADD https://github.com /acouvreur/sablier.git#v1.4.0-beta.3 /sablier
|
||||
|
||||
RUN xcaddy build \
|
||||
--with github.com/acouvreur/sablier/plugins/caddy=/sablier/plugins/caddy
|
||||
|
||||
FROM caddy:${CADDY_VERSION}
|
||||
|
||||
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
## Configuration
|
||||
|
||||
You can have the following configuration:
|
||||
|
||||
```Caddyfile
|
||||
:80 {
|
||||
route /my/route {
|
||||
sablier [<sablierURL>=http://sablier:10000] {
|
||||
[names container1,container2,...]
|
||||
[group mygroup]
|
||||
[session_duration 30m]
|
||||
dynamic {
|
||||
[display_name This is my display name]
|
||||
[show_details yes|true|on]
|
||||
[theme hacker-terminal]
|
||||
[refresh_frequency 2s]
|
||||
}
|
||||
blocking {
|
||||
[timeout 1m]
|
||||
}
|
||||
}
|
||||
reverse_proxy myservice:port
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Exemple with a minimal configuration
|
||||
|
||||
Almost all options are optional and you can setup very simple rules to use the server default values.
|
||||
|
||||
```Caddyfile
|
||||
:80 {
|
||||
route /my/route {
|
||||
sablier {
|
||||
group mygroup
|
||||
dynamic
|
||||
}
|
||||
reverse_proxy myservice:port
|
||||
}
|
||||
}
|
||||
```
|
||||
94
docs/plugins/nginx.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Nginx Sablier Plugin
|
||||
|
||||
The Nginx Sablier Plugin is a javascript file that runs through the NJS Module.
|
||||
|
||||
## Provider compatibility grid
|
||||
|
||||
| Provider | Dynamic | Blocking |
|
||||
| --------------------------------------- | :-----: | :------: |
|
||||
| [Docker](/providers/docker) | ✅ | ✅ |
|
||||
| [Docker Swarm](/providers/docker_swarm) | ✅ | ✅ |
|
||||
| [Kubernetes](/providers/kubernetes) | ❌ | ❌ |
|
||||
|
||||
|
||||
## Install the plugin to NGINX
|
||||
|
||||
1. Load the `ngx_http_js_module.so` in the main nginx config file `/etc/nginx/nginx.conf`
|
||||
```nginx
|
||||
load_module modules/ngx_http_js_module.so;
|
||||
```
|
||||
2. Copy/volume the `sablier.js` file to `/etc/nginx/conf.d/sablier.js`
|
||||
|
||||
## Configure the plugin
|
||||
|
||||
Use this sample for your APIs
|
||||
|
||||
```nginx
|
||||
js_import conf.d/sablier.js;
|
||||
|
||||
resolver 127.0.0.11 valid=10s ipv6=off;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
subrequest_output_buffer_size 32k;
|
||||
|
||||
# The internal location to reach sablier API
|
||||
set $sablierUrl /sablier;
|
||||
# Shared variable for default session duration
|
||||
set $sablierSessionDuration 1m;
|
||||
|
||||
# internal location for sablier middleware
|
||||
# here, the sablier API is a container named "sablier" inside the same network as nginx
|
||||
location /sablier/ {
|
||||
internal;
|
||||
proxy_method GET;
|
||||
proxy_pass http://sablier:10000/;
|
||||
}
|
||||
|
||||
# A named location that can be used by the sablier middleware to redirect
|
||||
location @whoami {
|
||||
# Use variable in order to refresh DNS cache
|
||||
set $whoami_server whoami;
|
||||
proxy_pass http://$whoami_server:80;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# The actual location to match your API
|
||||
# Will answer by a waiting page or redirect to your app if
|
||||
# it is already up
|
||||
location /dynamic/whoami {
|
||||
set $sablierDynamicShowDetails true;
|
||||
set $sablierDynamicRefreshFrequency 5s;
|
||||
set $sablierNginxInternalRedirect @whoami;
|
||||
set $sablierGroup my-group;
|
||||
set $sablierDynamicName "Dynamic Whoami";
|
||||
set $sablierDynamicTheme hacker-terminal;
|
||||
js_content sablier.call;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Available variables
|
||||
|
||||
You can configure the middleware behavior with the following variables:
|
||||
|
||||
**General Configuration**
|
||||
|
||||
- `set $sablierUrl` The internal routing to reach Sablier API
|
||||
- `set $sablierGroup` Group name to use to filter by label, ignored if sablierNames is set
|
||||
- `set $sablierSessionDuration` The session duration after which containers/services/deployments instances are shutdown
|
||||
- `set $sablierNginxInternalRedirect` The internal location for the service to redirect e.g. @nginx
|
||||
|
||||
**Dynamic Configuration**
|
||||
|
||||
*if any of these variables is set, then all Blocking Configuration is ignored*
|
||||
|
||||
- `set $sablierDynamicName`
|
||||
- `set $sablierDynamicShowDetails` Set to true or false to show details specifcally for this middleware, unset to use Sablier server defaults
|
||||
- `set $sablierDynamicTheme` The theme to use
|
||||
- `set $sablierDynamicRefreshFrequency` The loading page refresh frequency
|
||||
|
||||
**Blocking Configuration**
|
||||
|
||||
- `set $sablierBlockingTimeout` waits until services are up and running but will not wait more than `timeout`
|
||||
25
docs/plugins/overview.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Reverse Proxy Plugins
|
||||
|
||||
## What is a Reverse Proxy Plugin ?
|
||||
|
||||
Reverse proxy plugins are the integration with a reverse proxy.
|
||||
|
||||
?> Because Sablier is designed as an API that can be used on its own, reverse proxy integrations acts as a client of that API.
|
||||
|
||||
It leverages the API calls to plugin integration to catch in-flight requests to Sablier.
|
||||
|
||||

|
||||
|
||||
## Available Reverse Proxies
|
||||
|
||||
| Reverse Proxy | Docker | Docker Swarm mode | Kubernetes | Podman |
|
||||
| ---------------------------- | :----: | :---------------: | :--------: | :-------------------------------------------------------: |
|
||||
| [Traefik](/plugins/traefik) | ✅ | ✅ | ✅ | [See #70](https://github.com/acouvreur/sablier/issues/70) |
|
||||
| [Nginx](/plugins/nginx) | ✅ | ✅ | ❌ |
|
||||
| [Caddy](/plugins/caddy) | ✅ | ✅ | ❌ |
|
||||
|
||||
## Runtime and Compiled plugins
|
||||
|
||||
Some reverse proxies have the capability to evaluate the plugins at runtime (Traefik with Yaegi, NGINX with Lua and JS plugins) which means the reverse proxy provides a way to consume the plugin directly.
|
||||
|
||||
Some others enforce you to rebuild your reverse proxy (Caddy).
|
||||
160
docs/plugins/traefik.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Traefik Sablier Plugin
|
||||
|
||||
The [Traefik Sablier Plugin](https://plugins.traefik.io/plugins/633b4658a4caa9ddeffda119/sablier) in the plugin catalog.
|
||||
|
||||
## Provider compatibility grid
|
||||
|
||||
| Provider | Dynamic | Blocking |
|
||||
| --------------------------------------- | :-----: | :-----------------------------------------------------: |
|
||||
| [Docker](/providers/docker) | ✅ | ✅ |
|
||||
| [Docker Swarm](/providers/docker_swarm) | ✅ | ✅ |
|
||||
| [Kubernetes](/providers/kubernetes) | ✅ | ❌ [#62](https://github.com/acouvreur/sablier/issues/62) |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **Docker**
|
||||
|
||||
**Traefik will evict containers from its pool if they are stopped.**
|
||||
|
||||
Meaning labels attached to containers to autodiscover them is not possible with this plugin.
|
||||
|
||||
You have to use the dynamic config file provider instead.
|
||||
|
||||
**❌ You cannot do the following:**
|
||||
|
||||
```yaml
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
labels:
|
||||
- traefik.enable
|
||||
- traefik.http.routers.whoami.rule=PathPrefix(`/whoami`)
|
||||
- traefik.http.routers.whoami.middlewares=my-sablier@file
|
||||
```
|
||||
|
||||
**✅ You should do the following instead:**
|
||||
|
||||
```yaml
|
||||
http:
|
||||
services:
|
||||
whoami:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://whoami:80"
|
||||
|
||||
routers:
|
||||
whoami:
|
||||
rule: PathPrefix(`/whoami`)
|
||||
entryPoints:
|
||||
- "http"
|
||||
middlewares:
|
||||
- my-sablier@file
|
||||
service: "whoami"
|
||||
```
|
||||
*dynamic-config.yaml*
|
||||
|
||||
|
||||
#### **Docker Swarm**
|
||||
|
||||
**Traefik will evict services from its pool if they have 0 replicas.**
|
||||
|
||||
In order to use service labels, you have to add the following option on top of each services that will use this plugin.
|
||||
|
||||
See also [`traefik.docker.lbswarm`](https://doc.traefik.io/traefik/routing/providers/docker/#traefikdockerlbswarm) label
|
||||
|
||||
```yaml
|
||||
services:
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
deploy:
|
||||
replicas: 0
|
||||
labels:
|
||||
- traefik.docker.lbswarm=true
|
||||
```
|
||||
|
||||
Traefik also have [allowEmptyServices](https://doc.traefik.io/traefik/providers/docker/#allowemptyservices) option which can be used instead.
|
||||
|
||||
But the blocking strategy won't work for the same reasons described in [#62](https://github.com/acouvreur/sablier/issues/62).
|
||||
|
||||
#### **Kubernetes**
|
||||
|
||||
**Traefik will evict deployments from its pool if they have 0 endpoints available.**
|
||||
|
||||
You must use [`allowEmptyServices`](https://doc.traefik.io/traefik/providers/kubernetes-ingress/#allowemptyservices)
|
||||
|
||||
The blocking strategy is not supported because everytime the underlying configuration changes, the whole router is regenrated, thus changing the router during a request will still map to the old router. For more details, see [#62](https://github.com/acouvreur/sablier/issues/62).
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
## Install the plugin to Traefik
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **File (YAML)**
|
||||
|
||||
```yaml
|
||||
experimental:
|
||||
plugins:
|
||||
sablier:
|
||||
moduleName: "github.com/acouvreur/sablier"
|
||||
version: "v1.4.0-beta.3"
|
||||
```
|
||||
|
||||
#### **CLI**
|
||||
|
||||
```bash
|
||||
--experimental.plugins.sablier.modulename=github.com/acouvreur/sablier
|
||||
--experimental.plugins.sablier.version=v1.4.0-beta.3
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
## Configure the plugin using the Dynamic Configuration
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **File (YAML)**
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
my-sablier:
|
||||
plugin:
|
||||
sablier:
|
||||
group: default
|
||||
dynamic:
|
||||
displayName: My Title
|
||||
refreshFrequency: 5s
|
||||
showDetails: "true"
|
||||
theme: hacker-terminal
|
||||
sablierUrl: http://sablier:10000
|
||||
sessionDuration: 1m
|
||||
```
|
||||
|
||||
#### **Kubernetes CRD**
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: my-sablier
|
||||
namespace: my-namespace
|
||||
spec:
|
||||
plugin:
|
||||
sablier:
|
||||
group: default
|
||||
dynamic:
|
||||
displayName: My Title
|
||||
refreshFrequency: 5s
|
||||
showDetails: "true"
|
||||
theme: hacker-terminal
|
||||
sablierUrl: http://sablier:10000
|
||||
sessionDuration: 1m
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
## Configuration reference
|
||||
|
||||
TODO
|
||||
64
docs/providers/docker.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Docker
|
||||
|
||||
The Docker provider communicates with the `docker.sock` socket to start and stop containers on demand.
|
||||
|
||||
## Use the Docker provider
|
||||
|
||||
In order to use the docker provider you can configure the [provider.name](TODO) property.
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **File (YAML)**
|
||||
|
||||
```yaml
|
||||
provider:
|
||||
name: docker
|
||||
```
|
||||
|
||||
#### **CLI**
|
||||
|
||||
```bash
|
||||
sablier start --provider.name=docker
|
||||
```
|
||||
|
||||
#### **Environment Variable**
|
||||
|
||||
```bash
|
||||
PROVIDER_NAME=docker
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
!> **Ensure that Sablier has access to the docker socket!**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
sablier:
|
||||
image: acouvreur/sablier:1.4.0-beta.3
|
||||
command:
|
||||
- start
|
||||
- --provider.name=docker
|
||||
volumes:
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
```
|
||||
|
||||
## Register containers
|
||||
|
||||
For Sablier to work, it needs to know which docker container to start and stop.
|
||||
|
||||
You have to register your containers by opting-in with labels.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
labels:
|
||||
- sablier.enable=true
|
||||
- sablier.group=mygroup
|
||||
```
|
||||
|
||||
## How does Sablier knows when a container is ready?
|
||||
|
||||
If the container defines a Healthcheck, then it will check for healthiness before stating the `ready` status.
|
||||
|
||||
If the containers does not define a Healthcheck, then as soon as the container has the status `started`
|
||||
66
docs/providers/docker_swarm.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Docker Swarm
|
||||
|
||||
The Docker Swarm provider communicates with the `docker.sock` socket to scale services on demand.
|
||||
|
||||
## Use the Docker Swarm provider
|
||||
|
||||
In order to use the docker provider you can configure the [provider.name](TODO) property.
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **File (YAML)**
|
||||
|
||||
```yaml
|
||||
provider:
|
||||
name: docker_swarm
|
||||
```
|
||||
|
||||
#### **CLI**
|
||||
|
||||
```bash
|
||||
sablier start --provider.name=docker_swarm
|
||||
```
|
||||
|
||||
#### **Environment Variable**
|
||||
|
||||
```bash
|
||||
PROVIDER_NAME=docker_swarm
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
|
||||
!> **Ensure that Sablier has access to the docker socket!**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
sablier:
|
||||
image: acouvreur/sablier:1.4.0-beta.3
|
||||
command:
|
||||
- start
|
||||
- --provider.name=docker_swarm
|
||||
volumes:
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
```
|
||||
|
||||
## Register services
|
||||
|
||||
For Sablier to work, it needs to know which docker services to scale up and down.
|
||||
|
||||
You have to register your services by opting-in with labels.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
whoami:
|
||||
image: containous/whoami:v1.5.0
|
||||
deploy:
|
||||
labels:
|
||||
- sablier.enable=true
|
||||
- sablier.group=mygroup
|
||||
```
|
||||
|
||||
## How does Sablier knows 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`.
|
||||
|
||||
?> Docker Swarm uses the container's healthcheck to check if the container is up and running. So the provider has a native healthcheck support.
|
||||
98
docs/providers/kubernetes.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Kubernetes
|
||||
|
||||
Sablier assumes that it is deployed within the Kubernetes cluster to use the Kubernetes API internally.
|
||||
|
||||
## Use the Kubernetes provider
|
||||
|
||||
In order to use the docker provider you can configure the [provider.name](TODO) property.
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **File (YAML)**
|
||||
|
||||
```yaml
|
||||
provider:
|
||||
name: kubernetes
|
||||
```
|
||||
|
||||
#### **CLI**
|
||||
|
||||
```bash
|
||||
sablier start --provider.name=kubernetes
|
||||
```
|
||||
|
||||
#### **Environment Variable**
|
||||
|
||||
```bash
|
||||
PROVIDER_NAME=kubernetes
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
!> **Ensure that Sablier has the necessary roles!**
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: sablier
|
||||
rules:
|
||||
- apiGroups:
|
||||
- apps
|
||||
- ""
|
||||
resources:
|
||||
- deployments
|
||||
- statefulsets
|
||||
verbs:
|
||||
- get # Retrieve info about specific dep
|
||||
- list # Events
|
||||
- watch # Events
|
||||
- apiGroups:
|
||||
- apps
|
||||
- ""
|
||||
resources:
|
||||
- deployments/scale
|
||||
- statefulsets/scale
|
||||
verbs:
|
||||
- patch # Scale up and down
|
||||
- update # Scale up and down
|
||||
- get # Retrieve info about specific dep
|
||||
- list # Events
|
||||
- watch # Events
|
||||
```
|
||||
|
||||
## Register Deployments
|
||||
|
||||
For Sablier to work, it needs to know which deployments to scale up and down.
|
||||
|
||||
You have to register your deployments by opting-in with labels.
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami
|
||||
labels:
|
||||
app: whoami
|
||||
sablier.enable: "true"
|
||||
sablier.group: mygroup
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoami
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoami
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: containous/whoami:v1.5.0
|
||||
```
|
||||
|
||||
## How does Sablier knows when a deployment is ready?
|
||||
|
||||
Sablier checks for the deployment replicas. As soon as the current replicas matches the wanted replicas, then the deployment is considered `ready`.
|
||||
|
||||
?> Kubernetes uses the Pod healthcheck to check if the Pod is up and running. So the provider has a native healthcheck support.
|
||||
24
docs/providers/overview.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Providers
|
||||
|
||||
## What is a Provider?
|
||||
|
||||
A Provider is how Sablier can interact with your instances.
|
||||
|
||||
A Provider typically have the following capabilities:
|
||||
- Start an instance
|
||||
- Stop an instance
|
||||
- Get the current status of an instance
|
||||
- Listen for instance lifecycle events (started, stopped)
|
||||
|
||||
## Available providers
|
||||
|
||||
| | Provider | Name | Details |
|
||||
| :---: | --------------------------------------- | -------------- | -------------------------------------------------------- |
|
||||
| | [Docker](/providers/docker) | `docker` | Stop and start containers on demand |
|
||||
| | [Docker Swarm](/providers/docker_swarm) | `docker_swarm` | Scale down to zero and up services on demand |
|
||||
| | [Docker](/providers/kubernetes) | `kubernetes` | Scale down and up deployments and statefulsets on demand |
|
||||
| | [Podman](/providers/podman) | `podman` | Work in progress |
|
||||
| | [EC2](/providers/ec2) | `ec2` | Work in progress |
|
||||
| | [Systemd](/providers/systemd) | `systemd` | Work in progress |
|
||||
|
||||
*Your Provider is not on the list? Open an issue or a pull request to add this functionnality here!*
|
||||
59
docs/strategies.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Strategies
|
||||
|
||||
When configuring
|
||||
|
||||
## Dynamic Strategy
|
||||
|
||||
The **Dynamic Strategy** provides a waiting page for your session.
|
||||
|
||||
?> This strategy is well suited for a user that would access a frontend directly and expects to see a loading page.
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
User -> Proxy: Website Request
|
||||
Proxy -> Sablier: Reverse Proxy Plugin Request Session Status
|
||||
Proxy <-- Sablier: Returns the X-Sablier-Status Header
|
||||
|
||||
alt `X-Sablier-Status` value is `not-ready`
|
||||
|
||||
User <-- Proxy: Serve the waiting page
|
||||
loop until `X-Sablier-Status` value is `ready`
|
||||
User -> Proxy: Self-Reload Waiting Page
|
||||
Proxy -> Sablier: Reverse Proxy Plugin Request Session Status
|
||||
Sablier -> Provider: Request Instance Status
|
||||
Sablier <-- Provider: Response Instance Status
|
||||
Proxy <-- Sablier: Returns the waiting page
|
||||
User <-- Proxy: Serve the waiting page
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
User <-- Proxy: Content
|
||||
|
||||
@enduml
|
||||
```
|
||||
## Blocking Strategy
|
||||
|
||||
The **Blocking Strategy** hangs the request until your session is ready.
|
||||
|
||||
?> This strategy is well suited for an API communication.
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
User -> Proxy: Website Request
|
||||
Proxy -> Sablier: Reverse Proxy Plugin Request Session Status
|
||||
Sablier -> Provider: Request Instance Status
|
||||
|
||||
alt `Instance` status is `not-ready`
|
||||
|
||||
end
|
||||
|
||||
Sablier <-- Provider: Response Instance Status
|
||||
Proxy <-- Sablier: Response
|
||||
|
||||
User <-- Proxy: Content
|
||||
|
||||
@enduml
|
||||
```
|
||||
@@ -1,24 +1,28 @@
|
||||
# Creating your own loading theme
|
||||
# Themes
|
||||
|
||||
Sablier comes with a set of default theme that you can use.
|
||||
|
||||
You can also extend the themes by providing your own and they will be templated as Go Templates.
|
||||
|
||||
## The embedded themes
|
||||
|
||||
|
||||
| Name | Preview |
|
||||
| :---------------: | :-------------------------------------------------------------------------------------------------------: |
|
||||
| `ghost` |  |
|
||||
| `shuffle` |  |
|
||||
| `hacker-terminal` |  |
|
||||
| `matrix` |  |
|
||||
|
||||
|
||||
- [Creating your own loading theme](#creating-your-own-loading-theme)
|
||||
- [Custom themes locations](#custom-themes-locations)
|
||||
- [Create a custom theme](#create-a-custom-theme)
|
||||
- [Available Go Template Values](#available-go-template-values)
|
||||
- [The `<meta http-equiv="refresh" />` tag](#the-meta-http-equivrefresh--tag)
|
||||
- [The `showDetails` option](#the-showdetails-option)
|
||||
- [The embedded themes](#the-embedded-themes)
|
||||
- [How to load my custom theme](#how-to-load-my-custom-theme)
|
||||
- [See the available themes from the API](#see-the-available-themes-from-the-api)
|
||||
|
||||
## Custom themes locations
|
||||
|
||||
You can use the argument `--strategy.dynamic.coustom-themes` to define the location to search upon starting.
|
||||
You can use the argument `--strategy.dynamic.custom-themes` to define the location to search upon starting.
|
||||
|
||||
By default, the docker image looks for theme inside the `/etc/sablier/themes` folder.
|
||||
By default, the docker image looks for themes located inside the `/etc/sablier/themes` folder.
|
||||
|
||||
```yaml
|
||||
version: 3.9
|
||||
|
||||
services:
|
||||
sablier:
|
||||
image: acouvreur/sablier:1.4.0-beta.3
|
||||
@@ -30,7 +34,6 @@ services:
|
||||
It will look recursively for themes with the `.html` extension.
|
||||
|
||||
- You **cannot** load new themes added in the folder without restarting
|
||||
- Why? Because we build a theme whitelist in order to prevent malicious payload crafting by using `theme=../../very_secret.txt`
|
||||
- You **can** modify the existing themes files
|
||||
|
||||
## Create a custom theme
|
||||
@@ -72,10 +75,6 @@ So the first step to create your own theme is to include the `HTML <meta> http-e
|
||||
|
||||
If `showDetails` is set to `false` then the `.InstanceStates` will be an empty array.
|
||||
|
||||
## The embedded themes
|
||||
|
||||
See the [embedded themes](../app/http/pages/themes/).
|
||||
|
||||
## How to load my custom theme
|
||||
|
||||
You can load themes by specifying their name and their relative path from the `--strategy.dynamic.custom-themes-path` value.
|
||||
@@ -90,14 +89,14 @@ You can load themes by specifying their name and their relative path from the `-
|
||||
|
||||
Such as
|
||||
|
||||
```shell
|
||||
```bash
|
||||
curl 'http://localhost:10000/api/strategies/dynamic?session_duration=1m&names=nginx&theme=custom1'
|
||||
```
|
||||
|
||||
## See the available themes from the API
|
||||
|
||||
```
|
||||
> curl 'http://localhost:10000/api/strategies/dynamic/themes'
|
||||
```bash
|
||||
curl 'http://localhost:10000/api/strategies/dynamic/themes'
|
||||
```
|
||||
```json
|
||||
{
|
||||
15
docs/versioning.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Versioning
|
||||
|
||||
Sablier follows the [Semantic Versioning 2.0.0](https://semver.org/) Specification (SemVer).
|
||||
|
||||
Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
|
||||
1. MAJOR version when you make incompatible API changes
|
||||
2. MINOR version when you add functionality in a backwards compatible manner
|
||||
3. PATCH version when you make backwards compatible bug fixes
|
||||
|
||||
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
|
||||
|
||||
This process is fully automated using [Semantic Release](https://github.com/semantic-release/semantic-release).
|
||||
|
||||
The configuration is [release.config.js](https://github.com/acouvreur/sablier/blob/main/release.config.js).
|
||||