diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..c21e359 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +golang 1.25.4 diff --git a/docs/configuration.md b/docs/configuration.md index f49f5f1..5471cab 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -28,7 +28,10 @@ sablier --configFile=path/to/myconfigfile.yml ```yaml provider: # Provider to use to manage containers (docker, swarm, kubernetes) - name: docker + name: docker + docker: + # Strategy to use for stopping Docker containers: stop or pause (default: stop) + strategy: stop server: # The server port to use port: 10000 @@ -113,6 +116,7 @@ sablier start --strategy.dynamic.custom-themes-path /my/path ``` -h, --help help for start + --provider.docker.strategy string Strategy to use to stop docker containers (stop or pause) (default "stop") --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) diff --git a/docs/providers/docker.md b/docs/providers/docker.md index 86027db..7bb09fa 100644 --- a/docs/providers/docker.md +++ b/docs/providers/docker.md @@ -59,6 +59,66 @@ services: - sablier.group=mygroup ``` +## Strategies + +The Docker provider supports two strategies for managing containers: + +### Stop Strategy (default) + +The `stop` strategy completely stops containers when they become idle and starts them again when needed. + + + +#### **File (YAML)** + +```yaml +provider: + docker: + strategy: stop +``` + +#### **CLI** + +```bash +sablier start --provider.docker.strategy=stop +``` + +#### **Environment Variable** + +```bash +PROVIDER_DOCKER_STRATEGY=stop +``` + + + +### Pause Strategy + +The `pause` strategy pauses containers instead of stopping them. This is faster than stop/start as the container state remains in memory, but uses more system resources. + + + +#### **File (YAML)** + +```yaml +provider: + docker: + strategy: pause +``` + +#### **CLI** + +```bash +sablier start --provider.docker.strategy=pause +``` + +#### **Environment Variable** + +```bash +PROVIDER_DOCKER_STRATEGY=pause +``` + + + ## 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. diff --git a/pkg/config/provider.go b/pkg/config/provider.go index 9833700..b36459c 100644 --- a/pkg/config/provider.go +++ b/pkg/config/provider.go @@ -12,6 +12,7 @@ type Provider struct { AutoStopOnStartup bool `yaml:"auto-stop-on-startup,omitempty" default:"true"` Kubernetes Kubernetes Podman Podman + Docker Docker } type Kubernetes struct { @@ -34,7 +35,12 @@ type Podman struct { Uri string `mapstructure:"URI" yaml:"uri,omitempty" default:"unix:///run/podman/podman.sock"` } +type Docker struct { + Strategy string `mapstructure:"STRATEGY" yaml:"strategy,omitempty" default:"stop"` +} + var providers = []string{"docker", "docker_swarm", "swarm", "kubernetes", "podman"} +var dockerStrategies = []string{"stop", "pause"} func NewProviderConfig() Provider { return Provider{ @@ -48,18 +54,36 @@ func NewProviderConfig() Provider { Podman: Podman{ Uri: "unix:///run/podman/podman.sock", }, + Docker: Docker{ + Strategy: "stop", + }, } } func (provider Provider) IsValid() error { for _, p := range providers { if p == provider.Name { + // Validate Docker-specific settings when using Docker provider + if p == "docker" { + if err := provider.Docker.IsValid(); err != nil { + return err + } + } return nil } } return fmt.Errorf("unrecognized provider %s. providers available: %v", provider.Name, providers) } +func (docker Docker) IsValid() error { + for _, s := range dockerStrategies { + if s == docker.Strategy { + return nil + } + } + return fmt.Errorf("unrecognized docker strategy %s. strategies available: %v", docker.Strategy, dockerStrategies) +} + func GetProviders() []string { return providers } diff --git a/pkg/config/provider_test.go b/pkg/config/provider_test.go new file mode 100644 index 0000000..e5ed14d --- /dev/null +++ b/pkg/config/provider_test.go @@ -0,0 +1,141 @@ +package config + +import ( + "fmt" + "testing" + + "gotest.tools/v3/assert" +) + +func TestProvider_IsValid(t *testing.T) { + tests := []struct { + name string + provider Provider + wantErr error + }{ + { + name: "valid docker provider with stop strategy", + provider: Provider{ + Name: "docker", + Docker: Docker{ + Strategy: "stop", + }, + }, + wantErr: nil, + }, + { + name: "valid docker provider with pause strategy", + provider: Provider{ + Name: "docker", + Docker: Docker{ + Strategy: "pause", + }, + }, + wantErr: nil, + }, + { + name: "invalid docker strategy", + provider: Provider{ + Name: "docker", + Docker: Docker{ + Strategy: "invalid", + }, + }, + wantErr: fmt.Errorf("unrecognized docker strategy invalid. strategies available: [stop pause]"), + }, + { + name: "valid kubernetes provider", + provider: Provider{ + Name: "kubernetes", + }, + wantErr: nil, + }, + { + name: "valid swarm provider", + provider: Provider{ + Name: "swarm", + }, + wantErr: nil, + }, + { + name: "valid docker_swarm provider", + provider: Provider{ + Name: "docker_swarm", + }, + wantErr: nil, + }, + { + name: "valid podman provider", + provider: Provider{ + Name: "podman", + }, + wantErr: nil, + }, + { + name: "invalid provider name", + provider: Provider{ + Name: "invalid", + }, + wantErr: fmt.Errorf("unrecognized provider invalid. providers available: [docker docker_swarm swarm kubernetes podman]"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.provider.IsValid() + if tt.wantErr != nil { + assert.Error(t, err, tt.wantErr.Error()) + } else { + assert.NilError(t, err) + } + }) + } +} + +func TestDocker_IsValid(t *testing.T) { + tests := []struct { + name string + docker Docker + wantErr error + }{ + { + name: "valid stop strategy", + docker: Docker{ + Strategy: "stop", + }, + wantErr: nil, + }, + { + name: "valid pause strategy", + docker: Docker{ + Strategy: "pause", + }, + wantErr: nil, + }, + { + name: "invalid strategy", + docker: Docker{ + Strategy: "restart", + }, + wantErr: fmt.Errorf("unrecognized docker strategy restart. strategies available: [stop pause]"), + }, + { + name: "empty strategy", + docker: Docker{ + Strategy: "", + }, + wantErr: fmt.Errorf("unrecognized docker strategy . strategies available: [stop pause]"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.docker.IsValid() + if tt.wantErr != nil { + assert.Error(t, err, tt.wantErr.Error()) + } else { + assert.NilError(t, err) + } + }) + } +} diff --git a/pkg/provider/docker/container_inspect_test.go b/pkg/provider/docker/container_inspect_test.go index 7ca30ec..0d7bbae 100644 --- a/pkg/provider/docker/container_inspect_test.go +++ b/pkg/provider/docker/container_inspect_test.go @@ -264,7 +264,7 @@ func TestDockerClassicProvider_GetState(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - p, err := docker.New(ctx, c.client, slogt.New(t)) + p, err := docker.New(ctx, c.client, slogt.New(t), "stop") assert.NilError(t, err) name, err := tt.args.do(c) diff --git a/pkg/provider/docker/container_list_test.go b/pkg/provider/docker/container_list_test.go index 68873cb..38be3e4 100644 --- a/pkg/provider/docker/container_list_test.go +++ b/pkg/provider/docker/container_list_test.go @@ -1,14 +1,15 @@ package docker_test import ( + "sort" + "strings" + "testing" + "github.com/neilotoole/slogt" "github.com/sablierapp/sablier/pkg/provider" "github.com/sablierapp/sablier/pkg/provider/docker" "github.com/sablierapp/sablier/pkg/sablier" "gotest.tools/v3/assert" - "sort" - "strings" - "testing" ) func TestDockerClassicProvider_InstanceList(t *testing.T) { @@ -18,7 +19,7 @@ func TestDockerClassicProvider_InstanceList(t *testing.T) { ctx := t.Context() dind := setupDinD(t) - p, err := docker.New(ctx, dind.client, slogt.New(t)) + p, err := docker.New(ctx, dind.client, slogt.New(t), "stop") assert.NilError(t, err) c1, err := dind.CreateMimic(ctx, MimicOptions{ @@ -77,7 +78,7 @@ func TestDockerClassicProvider_GetGroups(t *testing.T) { ctx := t.Context() dind := setupDinD(t) - p, err := docker.New(ctx, dind.client, slogt.New(t)) + p, err := docker.New(ctx, dind.client, slogt.New(t), "stop") assert.NilError(t, err) c1, err := dind.CreateMimic(ctx, MimicOptions{ diff --git a/pkg/provider/docker/container_start.go b/pkg/provider/docker/container_start.go index d5f7ac0..c19c573 100644 --- a/pkg/provider/docker/container_start.go +++ b/pkg/provider/docker/container_start.go @@ -9,6 +9,13 @@ import ( ) func (p *Provider) InstanceStart(ctx context.Context, name string) error { + if p.strategy == "pause" { + return p.dockerUnpause(ctx, name) + } + return p.dockerStart(ctx, name) +} + +func (p *Provider) dockerStart(ctx context.Context, name string) error { // TODO: InstanceStart should block until the container is ready. p.l.DebugContext(ctx, "starting container", "name", name) err := p.Client.ContainerStart(ctx, name, container.StartOptions{}) @@ -18,3 +25,26 @@ func (p *Provider) InstanceStart(ctx context.Context, name string) error { } return nil } + +func (p *Provider) dockerUnpause(ctx context.Context, name string) error { + container, inspectErr := p.Client.ContainerInspect(ctx, name) + if inspectErr != nil { + p.l.ErrorContext(ctx, "cannot inspect container before unpausing", slog.String("name", name), slog.Any("error", inspectErr)) + return fmt.Errorf("cannot inspect container %s before unpausing: %w", name, inspectErr) + } + + if !container.State.Paused { + p.l.DebugContext(ctx, "container is not paused, starting container", slog.String("name", name)) + return p.dockerStart(ctx, name) + } + + p.l.DebugContext(ctx, "unpausing container", slog.String("name", name)) + err := p.Client.ContainerUnpause(ctx, name) + if err != nil { + p.l.ErrorContext(ctx, "cannot unpause container", slog.String("name", name), slog.Any("error", err)) + return fmt.Errorf("cannot unpause container %s: %w", name, err) + } + + p.l.DebugContext(ctx, "container unpaused", slog.String("name", name)) + return nil +} diff --git a/pkg/provider/docker/container_start_test.go b/pkg/provider/docker/container_start_test.go index 8a83072..dda6acf 100644 --- a/pkg/provider/docker/container_start_test.go +++ b/pkg/provider/docker/container_start_test.go @@ -3,10 +3,12 @@ package docker_test import ( "context" "fmt" + "testing" + + "github.com/docker/docker/api/types/container" "github.com/neilotoole/slogt" "github.com/sablierapp/sablier/pkg/provider/docker" "gotest.tools/v3/assert" - "testing" ) func TestDockerClassicProvider_Start(t *testing.T) { @@ -47,7 +49,99 @@ func TestDockerClassicProvider_Start(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - p, err := docker.New(ctx, c.client, slogt.New(t)) + p, err := docker.New(ctx, c.client, slogt.New(t), "stop") + assert.NilError(t, err) + + name, err := tt.args.do(c) + assert.NilError(t, err) + + err = p.InstanceStart(t.Context(), name) + if tt.err != nil { + assert.Error(t, err, tt.err.Error()) + } else { + assert.NilError(t, err) + } + }) + } +} + +func TestDockerClassicProvider_Unpause(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + ctx := context.Background() + type args struct { + do func(dind *dindContainer) (string, error) + } + tests := []struct { + name string + args args + err error + }{ + { + name: "non existing container unpause", + args: args{ + do: func(dind *dindContainer) (string, error) { + return "non-existent", nil + }, + }, + err: fmt.Errorf("cannot inspect container non-existent before unpausing: Error response from daemon: No such container: non-existent"), + }, + { + name: "container starts because was not paused", + args: args{ + do: func(dind *dindContainer) (string, error) { + c, err := dind.CreateMimic(ctx, MimicOptions{}) + if err != nil { + return "", err + } + + err = dind.client.ContainerStart(ctx, c.ID, container.StartOptions{}) + if err != nil { + return "", err + } + + err = dind.client.ContainerStop(ctx, c.ID, container.StopOptions{}) + if err != nil { + return "", err + } + + return c.ID, nil + }, + }, + err: nil, + }, + { + name: "container unpause as expected", + args: args{ + do: func(dind *dindContainer) (string, error) { + c, err := dind.CreateMimic(ctx, MimicOptions{}) + if err != nil { + return "", err + } + + err = dind.client.ContainerStart(ctx, c.ID, container.StartOptions{}) + if err != nil { + return "", err + } + + err = dind.client.ContainerPause(ctx, c.ID) + if err != nil { + return "", err + } + + return c.ID, nil + }, + }, + err: nil, + }, + } + c := setupDinD(t) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + p, err := docker.New(ctx, c.client, slogt.New(t), "pause") assert.NilError(t, err) name, err := tt.args.do(c) diff --git a/pkg/provider/docker/container_stop.go b/pkg/provider/docker/container_stop.go index e01a21f..91f6cfd 100644 --- a/pkg/provider/docker/container_stop.go +++ b/pkg/provider/docker/container_stop.go @@ -9,6 +9,13 @@ import ( ) func (p *Provider) InstanceStop(ctx context.Context, name string) error { + if p.strategy == "pause" { + return p.dockerPause(ctx, name) + } + return p.dockerStop(ctx, name) +} + +func (p *Provider) dockerStop(ctx context.Context, name string) error { p.l.DebugContext(ctx, "stopping container", slog.String("name", name)) err := p.Client.ContainerStop(ctx, name, container.StopOptions{}) if err != nil { @@ -30,3 +37,15 @@ func (p *Provider) InstanceStop(ctx context.Context, name string) error { return ctx.Err() } } + +func (p *Provider) dockerPause(ctx context.Context, name string) error { + p.l.DebugContext(ctx, "pausing container", slog.String("name", name)) + err := p.Client.ContainerPause(ctx, name) + if err != nil { + p.l.ErrorContext(ctx, "cannot pause container", slog.String("name", name), slog.Any("error", err)) + return fmt.Errorf("cannot pause container %s: %w", name, err) + } + + p.l.DebugContext(ctx, "container paused", slog.String("name", name)) + return nil +} diff --git a/pkg/provider/docker/container_stop_test.go b/pkg/provider/docker/container_stop_test.go index 99d331d..8e11100 100644 --- a/pkg/provider/docker/container_stop_test.go +++ b/pkg/provider/docker/container_stop_test.go @@ -58,7 +58,70 @@ func TestDockerClassicProvider_Stop(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - p, err := docker.New(ctx, c.client, slogt.New(t)) + p, err := docker.New(ctx, c.client, slogt.New(t), "stop") + assert.NilError(t, err) + + name, err := tt.args.do(c) + assert.NilError(t, err) + + err = p.InstanceStop(t.Context(), name) + if tt.err != nil { + assert.Error(t, err, tt.err.Error()) + } else { + assert.NilError(t, err) + } + }) + } +} + +func TestDockerClassicProvider_Pause(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + ctx := context.Background() + type args struct { + do func(dind *dindContainer) (string, error) + } + tests := []struct { + name string + args args + err error + }{ + { + name: "non existing container pause", + args: args{ + do: func(dind *dindContainer) (string, error) { + return "non-existent", nil + }, + }, + err: fmt.Errorf("cannot pause container non-existent: Error response from daemon: No such container: non-existent"), + }, + { + name: "container pause as expected", + args: args{ + do: func(dind *dindContainer) (string, error) { + c, err := dind.CreateMimic(ctx, MimicOptions{}) + if err != nil { + return "", err + } + + err = dind.client.ContainerStart(ctx, c.ID, container.StartOptions{}) + if err != nil { + return "", err + } + + return c.ID, nil + }, + }, + err: nil, + }, + } + c := setupDinD(t) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + p, err := docker.New(ctx, c.client, slogt.New(t), "pause") assert.NilError(t, err) name, err := tt.args.do(c) diff --git a/pkg/provider/docker/docker.go b/pkg/provider/docker/docker.go index d16c9f3..7ef3be2 100644 --- a/pkg/provider/docker/docker.go +++ b/pkg/provider/docker/docker.go @@ -3,9 +3,10 @@ package docker import ( "context" "fmt" + "log/slog" + "github.com/docker/docker/client" "github.com/sablierapp/sablier/pkg/sablier" - "log/slog" ) // Interface guard @@ -15,10 +16,11 @@ type Provider struct { Client client.APIClient desiredReplicas int32 l *slog.Logger + strategy string } -func New(ctx context.Context, cli *client.Client, logger *slog.Logger) (*Provider, error) { - logger = logger.With(slog.String("provider", "docker")) +func New(ctx context.Context, cli *client.Client, logger *slog.Logger, strategy string) (*Provider, error) { + logger = logger.With(slog.String("provider", "docker"), slog.String("strategy", strategy)) serverVersion, err := cli.ServerVersion(ctx) if err != nil { @@ -33,5 +35,6 @@ func New(ctx context.Context, cli *client.Client, logger *slog.Logger) (*Provide Client: cli, desiredReplicas: 1, l: logger, + strategy: strategy, }, nil } diff --git a/pkg/provider/docker/events_test.go b/pkg/provider/docker/events_test.go index 1629838..bd0634a 100644 --- a/pkg/provider/docker/events_test.go +++ b/pkg/provider/docker/events_test.go @@ -2,12 +2,13 @@ package docker_test import ( "context" + "testing" + "time" + "github.com/docker/docker/api/types/container" "github.com/neilotoole/slogt" "github.com/sablierapp/sablier/pkg/provider/docker" "gotest.tools/v3/assert" - "testing" - "time" ) func TestDockerClassicProvider_NotifyInstanceStopped(t *testing.T) { @@ -18,7 +19,7 @@ func TestDockerClassicProvider_NotifyInstanceStopped(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), 30*time.Second) defer cancel() dind := setupDinD(t) - p, err := docker.New(ctx, dind.client, slogt.New(t)) + p, err := docker.New(ctx, dind.client, slogt.New(t), "stop") assert.NilError(t, err) c, err := dind.CreateMimic(ctx, MimicOptions{}) diff --git a/pkg/sabliercmd/cmd_test.go b/pkg/sabliercmd/cmd_test.go index 8f49d81..20a661c 100644 --- a/pkg/sabliercmd/cmd_test.go +++ b/pkg/sabliercmd/cmd_test.go @@ -111,6 +111,7 @@ func TestPrecedence(t *testing.T) { "--provider.kubernetes.burst", "512", "--provider.kubernetes.delimiter", "_", "--provider.podman.uri", "unix:///run/podman/podman.sock.cli", + "--provider.docker.strategy", "pause", "--server.port", "3333", "--server.base-path", "/cli/", "--storage.file", "/tmp/cli.json", diff --git a/pkg/sabliercmd/provider.go b/pkg/sabliercmd/provider.go index 6010a84..2fca35f 100644 --- a/pkg/sabliercmd/provider.go +++ b/pkg/sabliercmd/provider.go @@ -34,7 +34,7 @@ func setupProvider(ctx context.Context, logger *slog.Logger, config config.Provi if err != nil { return nil, fmt.Errorf("cannot create docker client: %v", err) } - return docker.New(ctx, cli, logger) + return docker.New(ctx, cli, logger, config.Docker.Strategy) case "kubernetes": kubeclientConfig, err := rest.InClusterConfig() if err != nil { diff --git a/pkg/sabliercmd/root.go b/pkg/sabliercmd/root.go index acf920d..3475188 100644 --- a/pkg/sabliercmd/root.go +++ b/pkg/sabliercmd/root.go @@ -50,6 +50,8 @@ It provides integrations with multiple reverse proxies and different loading str _ = viper.BindPFlag("provider.kubernetes.delimiter", startCmd.Flags().Lookup("provider.kubernetes.delimiter")) startCmd.Flags().StringVar(&conf.Provider.Podman.Uri, "provider.podman.uri", "unix:///run/podman/podman.sock", "Uri is the URI to connect to the Podman service.") _ = viper.BindPFlag("provider.podman.uri", startCmd.Flags().Lookup("provider.podman.uri")) + startCmd.Flags().StringVar(&conf.Provider.Docker.Strategy, "provider.docker.strategy", "stop", "Strategy to use to stop docker containers (stop or pause)") + _ = viper.BindPFlag("provider.docker.strategy", startCmd.Flags().Lookup("provider.docker.strategy")) // Server flags startCmd.Flags().IntVar(&conf.Server.Port, "server.port", 10000, "The server port to use") diff --git a/pkg/sabliercmd/testdata/config.env b/pkg/sabliercmd/testdata/config.env index 33ebaba..762917e 100644 --- a/pkg/sabliercmd/testdata/config.env +++ b/pkg/sabliercmd/testdata/config.env @@ -4,6 +4,7 @@ PROVIDER_KUBERNETES_QPS=16 PROVIDER_KUBERNETES_BURST=32 PROVIDER_KUBERNETES_DELIMITER=/ PROVIDER_PODMAN_URI=unix:///run/podman/podman.sock.env +PROVIDER_DOCKER_STRATEGY=pause SERVER_PORT=2222 SERVER_BASE_PATH=/envvar/ STORAGE_FILE=/tmp/envvar.json diff --git a/pkg/sabliercmd/testdata/config.yml b/pkg/sabliercmd/testdata/config.yml index 9a4667a..87f662b 100644 --- a/pkg/sabliercmd/testdata/config.yml +++ b/pkg/sabliercmd/testdata/config.yml @@ -7,6 +7,8 @@ provider: delimiter: . podman: uri: unix:///run/podman/podman.sock.yml + docker: + strategy: pause server: port: 1111 base-path: /configfile/ diff --git a/pkg/sabliercmd/testdata/config_cli_wanted.json b/pkg/sabliercmd/testdata/config_cli_wanted.json index b685729..b71e5c5 100644 --- a/pkg/sabliercmd/testdata/config_cli_wanted.json +++ b/pkg/sabliercmd/testdata/config_cli_wanted.json @@ -16,6 +16,9 @@ }, "Podman": { "Uri": "unix:///run/podman/podman.sock.cli" + }, + "Docker": { + "Strategy": "pause" } }, "Sessions": { diff --git a/pkg/sabliercmd/testdata/config_default.json b/pkg/sabliercmd/testdata/config_default.json index 5921bf9..afdb9ea 100644 --- a/pkg/sabliercmd/testdata/config_default.json +++ b/pkg/sabliercmd/testdata/config_default.json @@ -16,6 +16,9 @@ }, "Podman": { "Uri": "unix:///run/podman/podman.sock" + }, + "Docker": { + "Strategy": "stop" } }, "Sessions": { diff --git a/pkg/sabliercmd/testdata/config_env_wanted.json b/pkg/sabliercmd/testdata/config_env_wanted.json index 8e0e0b2..8da50a7 100644 --- a/pkg/sabliercmd/testdata/config_env_wanted.json +++ b/pkg/sabliercmd/testdata/config_env_wanted.json @@ -16,6 +16,9 @@ }, "Podman": { "Uri": "unix:///run/podman/podman.sock.env" + }, + "Docker": { + "Strategy": "pause" } }, "Sessions": { diff --git a/pkg/sabliercmd/testdata/config_yaml_wanted.json b/pkg/sabliercmd/testdata/config_yaml_wanted.json index 3c3ae9d..1494211 100644 --- a/pkg/sabliercmd/testdata/config_yaml_wanted.json +++ b/pkg/sabliercmd/testdata/config_yaml_wanted.json @@ -16,6 +16,9 @@ }, "Podman": { "Uri": "unix:///run/podman/podman.sock.yml" + }, + "Docker": { + "Strategy": "pause" } }, "Sessions": { diff --git a/sablier.sample.yaml b/sablier.sample.yaml index ced527e..1e7f47a 100644 --- a/sablier.sample.yaml +++ b/sablier.sample.yaml @@ -1,5 +1,7 @@ provider: name: docker + docker: + strategy: stop server: port: 10000 base-path: /