sablier

command module
v1.0.0-beta.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2022 License: Apache-2.0 Imports: 2 Imported by: 0

README

⏳ Sablier

Github Actions Go Report Go Version Latest Release

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.

Hourglass

⚡️ Quick start

# Create and stop nginx container
docker run -d --name nginx nginx
docker stop nginx

# Create and stop whoami container
docker run -d --name whoami containous/whoami:v1.5.0
docker stop whoami

# Start Sablier with the docker provider
docker run -v /var/run/docker.sock:/var/run/docker.sock -p 10000:10000 ghcr.io/acouvreur/sablier:latest --provider.name=docker

# Start the containers, the request will hang until both containers are up and running
curl 'http://localhost:10000/api/strategies/blocking?names=nginx&names=whoami&session_duration=1m'
{
  "session": {
    "instances": [
  {
        "instance": {
          "name": "nginx",
          "currentReplicas": 1,
          "status": "ready"
    },
        "error": null
  },
  {
        "instance": {
          "name": "nginx",
          "currentReplicas": 1,
          "status": "ready"
    },
        "error": null
  }
    ],
    "status":"ready"
  }
}

⚙️ Configuration

Cli Yaml file Environment variable Default Description
--provider.name provider.name PROVIDER_NAME docker Provider to use to manage containers [docker swarm kubernetes]
--server.base-path server.base-path SERVER_BASE_PATH / The base path for the API
--server.port server.port SERVER_PORT 10000 The server port to use
--sessions.default-duration sessions.default-duration SESSIONS_DEFAULT_DURATION 5m The default session duration
--sessions.expiration-interval sessions.expiration-interval SESSIONS_EXPIRATION_INTERVAL 20s 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.
--storage.file storage.file STORAGE_FILE File path to save the state
--strategy.blocking.default-timeout strategy.blocking.default-timeout STRATEGY_BLOCKING_DEFAULT_TIMEOUT 1m Default timeout used for blocking strategy
--strategy.dynamic.custom-themes-path strategy.dynamic.custom-themes-path STRATEGY_DYNAMIC_CUSTOM_THEMES_PATH Custom themes folder, will load all .html files recursively
--strategy.dynamic.default-refresh-frequency strategy.dynamic.default-refresh-frequency STRATEGY_DYNAMIC_DEFAULT_REFRESH_FREQUENCY 5s Default refresh frequency in the HTML page for dynamic strategy
--strategy.dynamic.default-theme strategy.dynamic.default-theme STRATEGY_DYNAMIC_DEFAULT_THEME hacker-terminal Default theme used for dynamic strategy

Dynamic loading

The Dynamic Strategy provides a waiting UI with multiple themes. This is best suited when this interaction is made through a browser.

Name Preview
ghost [ghost
shuffle [shuffle
hacker-terminal [hacker-terminal
matrix [matrix
Dynamic Strategy Configuration
Cli Yaml file Environment variable Default Description
strategy
--strategy.dynamic.custom-themes-path strategy.dynamic.custom-themes-path STRATEGY_DYNAMIC_CUSTOM_THEMES_PATH Custom themes folder, will load all .html files recursively
--strategy.dynamic.default-refresh-frequency strategy.dynamic.default-refresh-frequency STRATEGY_DYNAMIC_DEFAULT_REFRESH_FREQUENCY 5s Default refresh frequency in the HTML page for dynamic strategy
--strategy.dynamic.default-theme strategy.dynamic.default-theme STRATEGY_DYNAMIC_DEFAULT_THEME hacker-terminal Default theme used for dynamic strategy
Custom Themes

Use --strategy.dynamic.custom-themes-path to specify the folder containing your themes.

Your theme will be rendered using a Go Template structure such as :

type TemplateValues struct {
	DisplayName      string
	InstanceStates   []RenderOptionsInstanceState
	SessionDuration  string
	RefreshFrequency string
	Version          string
}
type RenderOptionsInstanceState struct {
	Name            string
	CurrentReplicas int
	DesiredReplicas int
	Status          string
	Error           error
}
  • ⚠️ IMPORTANT ⚠️ You should always use RefreshFrequency like this:
    <head>
      ...
      <meta http-equiv="refresh" content="{{ .RefreshFrequency }}" />
      ...
    </head>
    
    This will refresh the loaded page automatically every RefreshFrequency.
  • You cannot load new themes added in the folder without restarting
  • You can modify the existing themes files
  • Why? Because we build a theme whitelist in order to prevent malicious payload crafting by using theme=../../very_secret.txt
  • Custom themes must end with .html
  • You can load themes by specifying their name and their relative path from the --strategy.dynamic.custom-themes-path value.
    /my/custom/themes/
    ├── custom1.html      # custom1
    ├── custom2.html      # custom2
    └── special
        └── secret.html   # special/secret
    

You can see the available themes from the API:

> curl 'http://localhost:10000/api/strategies/dynamic/themes'
{
  "custom": [
    "custom"
  ],
  "embedded": [
    "ghost",
    "hacker-terminal",
    "matrix",
    "shuffle"
  ]
}

Blocking strategy

The Blocking Strategy waits for the instances to load before serving the request This is best suited when this interaction from an API.

Reverse proxies integration plugins

Traefik Integration
  1. Add this snippet in the Traefik Static configuration
experimental:
  plugins:
    sablier:
      moduleName: "github.com/acouvreur/sablier"
      version: "v1.0.0"
  1. Configure the plugin using the Dynamic Configuration. Example:
http:
  middlewares:
    my-sablier:
      plugin:
        sablier:
          sablierUrl: http://sablier:10000
          names: whoami,nginx # comma separated names
          sessionDuration: 1m
          # Dynamic strategy, provides the waiting webui
          dynamic:
            displayName: My Title
            theme: hacker-terminal
          # Blocking strategy, waits until services are up and running
          # but will not wait more than `timeout`
          blocking: 
            timeout: 1m

Or for Kubernetes CRD

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: my-sablier
  namespace: my-namespace
spec:
  plugin:
    sablier:
      sablierUrl: http://sablier:10000
      names: whoami,nginx # comma separated names
      sessionDuration: 1m
      # Dynamic strategy, provides the waiting webui
      dynamic:
        displayName: My Title
        theme: hacker-terminal
      # Blocking strategy, waits until services are up and running
      # but will not wait more than `timeout`
      blocking: 
        timeout: 1m

You can also checkout the End to End tests here: plugins/traefik/e2e.

Traefik with Docker classic

⚠️ Limitations

  • Traefik will evict the container from its pool if it's exited. You must use the dynamic configuration.

docker-compose.yml

version: "3.9"

services:
  traefik:
    image: traefik:2.9.1
    command:
      - --entryPoints.http.address=:80
      - --providers.docker=true
      - --providers.file.filename=/etc/traefik/dynamic-config.yml
      - --experimental.plugins.sablier.moduleName=github.com/acouvreur/sablier/plugins/traefik
      - --experimental.plugins.sablier.version=v1.0.0
    ports:
      - "8080:80"
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'
      - './dynamic-config.yml:/etc/traefik/dynamic-config.yml'

  sablier:
    image: ghcr.io/acouvreur/sablier:local
    command:
      - start
      - --provider.name=docker
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'
    labels:
      - traefik.enable=true
      # Dynamic Middleware
      - traefik.http.middlewares.dynamic.plugin.sablier.names=sablier-whoami-1
      - traefik.http.middlewares.dynamic.plugin.sablier.sablierUrl=http://sablier:10000
      - traefik.http.middlewares.dynamic.plugin.sablier.dynamic.sessionDuration=1m
      - traefik.http.middlewares.dynamic.plugin.sablier.dynamic.displayName=Dynamic Whoami

  whoami:
    image: containous/whoami:v1.5.0
    # Cannot use labels because as soon as the container is stopped, the labels are not treated by Traefik
    # The route doesn't exist anymore. Use dynamic-config.yml file instead.
    # labels:
    #  - traefik.enable
    #  - traefik.http.routers.whoami-dynamic.rule=PathPrefix(`/dynamic/whoami`)
    #  - traefik.http.routers.whoami-dynamic.middlewares=dynamic@docker

dynamic-config.yaml

http:
  services:
    whoami:
      loadBalancer:
        servers:
        - url: "http://whoami:80"

  routers:
    whoami-dynamic:
      rule: PathPrefix(`/dynamic/whoami`)
      entryPoints:
        - "http"
      middlewares:
        - dynamic@docker
      service: "whoami"
Traefik with Docker Swarm
  • The value from the names section will do a strict match if possible, if it is not found it will match by suffix only if there's one match.
    • names=nginx matches nginx from MYSTACK_nginx and nginx services
    • names=nginx matches MYSTACK_nginx from MYSTACK_nginx and nginx-2 services

⚠️ Limitations

  • Traefik will evict the service from its pool as soon as the service is 0/0. You must add the traefik.docker.lbswarm label.
    services:
      whoami:
        image: containous/whoami:v1.5.0
        deploy:
          replicas: 0
          labels:
            - traefik.docker.lbswarm=true
    
  • We cannot use allowEmptyServices because if you use the blocking strategy you will receive a 503.
  • Replicas is set to 1
Traefik with Kubernetes
  • The format of the names section is <KIND>_<NAMESPACE>_<NAME>_<REPLICACOUNT> where _ is the delimiter.
    • Thus no _ are allowed in <NAME>
  • KIND can be either deployment or statefulset

⚠️ Limitations

  • Traefik will evict the service from its pool as soon as there is no endpoint available. You must use allowEmptyServices
  • Blocking Strategy is not yet supported because of how Traefik handles the pod ip.

See Kubernetes E2E Traefik Test script to see how it is reproduced

Caddy Integration

TODO

Credits

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
app
pkg
tinykv
Package heap provides heap operations for any type that implements heap.Interface.
Package heap provides heap operations for any type that implements heap.Interface.
plugins
caddy Module
traefik Module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL