mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-28 12:03:33 +00:00
feat: support compose stop_grace_period to change timeout before sending SIGKILL
This commit is contained in:
+5
-2
@@ -55,6 +55,8 @@ type ServiceSpec struct {
|
|||||||
// Caddy is the optional Caddy reverse proxy configuration for the service.
|
// Caddy is the optional Caddy reverse proxy configuration for the service.
|
||||||
// Caddy and Ports cannot be specified simultaneously.
|
// Caddy and Ports cannot be specified simultaneously.
|
||||||
Caddy *CaddySpec `json:",omitempty"`
|
Caddy *CaddySpec `json:",omitempty"`
|
||||||
|
// Configs is list of configuration objects that can be mounted into the container.
|
||||||
|
Configs []ConfigSpec
|
||||||
// Container defines the desired state of each container in the service.
|
// Container defines the desired state of each container in the service.
|
||||||
Container ContainerSpec
|
Container ContainerSpec
|
||||||
// Mode is the replication mode of the service. Default is ServiceModeReplicated if empty.
|
// Mode is the replication mode of the service. Default is ServiceModeReplicated if empty.
|
||||||
@@ -67,12 +69,13 @@ type ServiceSpec struct {
|
|||||||
Ports []PortSpec
|
Ports []PortSpec
|
||||||
// Replicas is the number of containers to run for the service. Only valid for a replicated service.
|
// Replicas is the number of containers to run for the service. Only valid for a replicated service.
|
||||||
Replicas uint `json:",omitempty"`
|
Replicas uint `json:",omitempty"`
|
||||||
|
// StopGracePeriod is how long to wait after SIGTERM before sending SIGKILL when stopping a container.
|
||||||
|
// Default is 10 seconds if not specified.
|
||||||
|
StopGracePeriod *time.Duration `json:",omitempty"`
|
||||||
// UpdateConfig configures how the service is updated during a deployment.
|
// UpdateConfig configures how the service is updated during a deployment.
|
||||||
UpdateConfig UpdateConfig `json:",omitempty"`
|
UpdateConfig UpdateConfig `json:",omitempty"`
|
||||||
// Volumes is list of data volumes that can be mounted into the container.
|
// Volumes is list of data volumes that can be mounted into the container.
|
||||||
Volumes []VolumeSpec
|
Volumes []VolumeSpec
|
||||||
// Configs is list of configuration objects that can be mounted into the container.
|
|
||||||
Configs []ConfigSpec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaddyConfig returns the Caddy reverse proxy configuration for the service or an empty string if it's not defined.
|
// CaddyConfig returns the Caddy reverse proxy configuration for the service or an empty string if it's not defined.
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ func ServiceSpecFromCompose(project *types.Project, serviceName string) (api.Ser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if service.StopGracePeriod != nil {
|
||||||
|
d := time.Duration(*service.StopGracePeriod)
|
||||||
|
spec.StopGracePeriod = &d
|
||||||
|
}
|
||||||
|
|
||||||
if service.Scale != nil {
|
if service.Scale != nil {
|
||||||
spec.Replicas = uint(*service.Scale)
|
spec.Replicas = uint(*service.Scale)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,8 @@ func TestServiceSpecFromCompose(t *testing.T) {
|
|||||||
Placement: api.Placement{
|
Placement: api.Placement{
|
||||||
Machines: []string{"machine-1", "machine-2"},
|
Machines: []string{"machine-1", "machine-2"},
|
||||||
},
|
},
|
||||||
Replicas: 3,
|
Replicas: 3,
|
||||||
|
StopGracePeriod: api.AsPtr(30 * time.Second),
|
||||||
UpdateConfig: api.UpdateConfig{
|
UpdateConfig: api.UpdateConfig{
|
||||||
Order: api.UpdateOrderStopFirst,
|
Order: api.UpdateOrderStopFirst,
|
||||||
MonitorPeriod: &api.DefaultHealthMonitorPeriod,
|
MonitorPeriod: &api.DefaultHealthMonitorPeriod,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ services:
|
|||||||
privileged: true
|
privileged: true
|
||||||
pull_policy: always
|
pull_policy: always
|
||||||
scale: 3
|
scale: 3
|
||||||
|
stop_grace_period: 30s
|
||||||
sysctls:
|
sysctls:
|
||||||
- net.ipv4.ip_forward=1
|
- net.ipv4.ip_forward=1
|
||||||
ulimits:
|
ulimits:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package operation
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
@@ -53,13 +54,14 @@ func (o *RunContainerOperation) String() string {
|
|||||||
|
|
||||||
// StopContainerOperation stops a container on a specific machine.
|
// StopContainerOperation stops a container on a specific machine.
|
||||||
type StopContainerOperation struct {
|
type StopContainerOperation struct {
|
||||||
ServiceID string
|
ServiceID string
|
||||||
ContainerID string
|
ContainerID string
|
||||||
MachineID string
|
MachineID string
|
||||||
|
StopGracePeriod *time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *StopContainerOperation) Execute(ctx context.Context, cli Client) error {
|
func (o *StopContainerOperation) Execute(ctx context.Context, cli Client) error {
|
||||||
if err := cli.StopContainer(ctx, o.ServiceID, o.ContainerID, container.StopOptions{}); err != nil {
|
if err := cli.StopContainer(ctx, o.ServiceID, o.ContainerID, stopOptions(o.StopGracePeriod)); err != nil {
|
||||||
return fmt.Errorf("stop container: %w", err)
|
return fmt.Errorf("stop container: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -78,15 +80,18 @@ func (o *StopContainerOperation) String() string {
|
|||||||
|
|
||||||
// RemoveContainerOperation stops and removes a container from a specific machine.
|
// RemoveContainerOperation stops and removes a container from a specific machine.
|
||||||
type RemoveContainerOperation struct {
|
type RemoveContainerOperation struct {
|
||||||
MachineID string
|
MachineID string
|
||||||
Container api.ServiceContainer
|
Container api.ServiceContainer
|
||||||
|
StopGracePeriod *time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *RemoveContainerOperation) Execute(ctx context.Context, cli Client) error {
|
func (o *RemoveContainerOperation) Execute(ctx context.Context, cli Client) error {
|
||||||
if err := cli.StopContainer(ctx, o.Container.ServiceID(), o.Container.ID, container.StopOptions{}); err != nil {
|
err := cli.StopContainer(ctx, o.Container.ServiceID(), o.Container.ID, stopOptions(o.StopGracePeriod))
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("stop container: %w", err)
|
return fmt.Errorf("stop container: %w", err)
|
||||||
}
|
}
|
||||||
if err := cli.RemoveContainer(ctx, o.Container.ServiceID(), o.Container.ID, container.RemoveOptions{
|
|
||||||
|
if err = cli.RemoveContainer(ctx, o.Container.ServiceID(), o.Container.ID, container.RemoveOptions{
|
||||||
// Remove anonymous volumes created by the container.
|
// Remove anonymous volumes created by the container.
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -119,6 +124,7 @@ type ReplaceContainerOperation struct {
|
|||||||
Order string
|
Order string
|
||||||
// SkipHealthMonitor skips the monitoring period and health checks after starting a new container.
|
// SkipHealthMonitor skips the monitoring period and health checks after starting a new container.
|
||||||
SkipHealthMonitor bool
|
SkipHealthMonitor bool
|
||||||
|
StopGracePeriod *time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReplaceContainerOperation) Execute(ctx context.Context, cli Client) error {
|
func (o *ReplaceContainerOperation) Execute(ctx context.Context, cli Client) error {
|
||||||
@@ -133,7 +139,8 @@ func (o *ReplaceContainerOperation) Execute(ctx context.Context, cli Client) err
|
|||||||
}
|
}
|
||||||
wasRunning = ctr.Container.State.Running
|
wasRunning = ctr.Container.State.Running
|
||||||
if wasRunning {
|
if wasRunning {
|
||||||
if err = cli.StopContainer(ctx, o.ServiceID, o.OldContainer.ID, container.StopOptions{}); err != nil {
|
err = cli.StopContainer(ctx, o.ServiceID, o.OldContainer.ID, stopOptions(o.StopGracePeriod))
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("stop old container: %w", err)
|
return fmt.Errorf("stop old container: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +163,7 @@ func (o *ReplaceContainerOperation) Execute(ctx context.Context, cli Client) err
|
|||||||
|
|
||||||
// Use context without progress to not overwrite the container Unhealthy status with Stopped.
|
// Use context without progress to not overwrite the container Unhealthy status with Stopped.
|
||||||
ctxWithoutProgress := progress.WithContextWriter(ctx, nil)
|
ctxWithoutProgress := progress.WithContextWriter(ctx, nil)
|
||||||
_ = cli.StopContainer(ctxWithoutProgress, o.ServiceID, resp.ID, container.StopOptions{})
|
_ = cli.StopContainer(ctxWithoutProgress, o.ServiceID, resp.ID, stopOptions(o.StopGracePeriod))
|
||||||
|
|
||||||
newCtr := fmt.Sprintf("%s/%s", o.Spec.Name, stringid.TruncateID(resp.ID))
|
newCtr := fmt.Sprintf("%s/%s", o.Spec.Name, stringid.TruncateID(resp.ID))
|
||||||
healthErr := fmt.Errorf(
|
healthErr := fmt.Errorf(
|
||||||
@@ -186,12 +193,12 @@ func (o *ReplaceContainerOperation) Execute(ctx context.Context, cli Client) err
|
|||||||
// There still might be a brief downtime (for a 1 replica service) when Caddy doesn't know about
|
// There still might be a brief downtime (for a 1 replica service) when Caddy doesn't know about
|
||||||
// the new container but we're stopping the old container. We should somehow ensure Caddy is updated
|
// the new container but we're stopping the old container. We should somehow ensure Caddy is updated
|
||||||
// with the new container before we stop the old one to avoid this downtime.
|
// with the new container before we stop the old one to avoid this downtime.
|
||||||
if err := cli.StopContainer(ctx, o.ServiceID, o.OldContainer.ID, container.StopOptions{}); err != nil {
|
if err = cli.StopContainer(ctx, o.ServiceID, o.OldContainer.ID, stopOptions(o.StopGracePeriod)); err != nil {
|
||||||
return fmt.Errorf("stop old container: %w", err)
|
return fmt.Errorf("stop old container: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cli.RemoveContainer(ctx, o.ServiceID, o.OldContainer.ID, container.RemoveOptions{
|
if err = cli.RemoveContainer(ctx, o.ServiceID, o.OldContainer.ID, container.RemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("remove old container: %w", err)
|
return fmt.Errorf("remove old container: %w", err)
|
||||||
@@ -209,3 +216,12 @@ func (o *ReplaceContainerOperation) String() string {
|
|||||||
return fmt.Sprintf("ReplaceContainerOperation[machine_id=%s service_id=%s old_container_id=%s order=%s]",
|
return fmt.Sprintf("ReplaceContainerOperation[machine_id=%s service_id=%s old_container_id=%s order=%s]",
|
||||||
o.MachineID, o.ServiceID, o.OldContainer.ID, o.Order)
|
o.MachineID, o.ServiceID, o.OldContainer.ID, o.Order)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stopOptions converts a stop grace period duration to Docker container stop options.
|
||||||
|
func stopOptions(gracePeriod *time.Duration) container.StopOptions {
|
||||||
|
if gracePeriod == nil {
|
||||||
|
return container.StopOptions{}
|
||||||
|
}
|
||||||
|
t := int(gracePeriod.Seconds())
|
||||||
|
return container.StopOptions{Timeout: &t}
|
||||||
|
}
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ func (s *RollingStrategy) planReplicated(svc *api.Service, spec api.ServiceSpec)
|
|||||||
OldContainer: ctr,
|
OldContainer: ctr,
|
||||||
Order: order,
|
Order: order,
|
||||||
SkipHealthMonitor: s.SkipHealthMonitor,
|
SkipHealthMonitor: s.SkipHealthMonitor,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,8 +183,9 @@ func (s *RollingStrategy) planReplicated(svc *api.Service, spec api.ServiceSpec)
|
|||||||
for mid, containers := range containersOnMachine {
|
for mid, containers := range containersOnMachine {
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
plan.Operations = append(plan.Operations, &operation.RemoveContainerOperation{
|
plan.Operations = append(plan.Operations, &operation.RemoveContainerOperation{
|
||||||
MachineID: mid,
|
MachineID: mid,
|
||||||
Container: c,
|
Container: c,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,8 +236,9 @@ func (s *RollingStrategy) planGlobal(svc *api.Service, spec api.ServiceSpec) (Pl
|
|||||||
for _, containers := range containersOnMachine {
|
for _, containers := range containersOnMachine {
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
plan.Operations = append(plan.Operations, &operation.RemoveContainerOperation{
|
plan.Operations = append(plan.Operations, &operation.RemoveContainerOperation{
|
||||||
MachineID: c.MachineID,
|
MachineID: c.MachineID,
|
||||||
Container: c.Container,
|
Container: c.Container,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,8 +289,9 @@ func reconcileGlobalContainer(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ops = append(ops, &operation.RemoveContainerOperation{
|
ops = append(ops, &operation.RemoveContainerOperation{
|
||||||
MachineID: old.MachineID,
|
MachineID: old.MachineID,
|
||||||
Container: old.Container,
|
Container: old.Container,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@@ -319,9 +323,10 @@ func reconcileGlobalContainer(
|
|||||||
conflictingPorts, err := c.Container.ConflictingServicePorts(spec.Ports)
|
conflictingPorts, err := c.Container.ConflictingServicePorts(spec.Ports)
|
||||||
if err != nil || len(conflictingPorts) > 0 {
|
if err != nil || len(conflictingPorts) > 0 {
|
||||||
ops = append(ops, &operation.StopContainerOperation{
|
ops = append(ops, &operation.StopContainerOperation{
|
||||||
ServiceID: serviceID,
|
ServiceID: serviceID,
|
||||||
ContainerID: c.Container.ID,
|
ContainerID: c.Container.ID,
|
||||||
MachineID: machineID,
|
MachineID: machineID,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,6 +340,7 @@ func reconcileGlobalContainer(
|
|||||||
OldContainer: containerToReplace.Container,
|
OldContainer: containerToReplace.Container,
|
||||||
Order: order,
|
Order: order,
|
||||||
SkipHealthMonitor: skipHealthCheck,
|
SkipHealthMonitor: skipHealthCheck,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Remove any other containers (there shouldn't be any in normal operation).
|
// Remove any other containers (there shouldn't be any in normal operation).
|
||||||
@@ -343,8 +349,9 @@ func reconcileGlobalContainer(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ops = append(ops, &operation.RemoveContainerOperation{
|
ops = append(ops, &operation.RemoveContainerOperation{
|
||||||
MachineID: c.MachineID,
|
MachineID: c.MachineID,
|
||||||
Container: c.Container,
|
Container: c.Container,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -357,8 +364,9 @@ func reconcileGlobalContainer(
|
|||||||
})
|
})
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
ops = append(ops, &operation.RemoveContainerOperation{
|
ops = append(ops, &operation.RemoveContainerOperation{
|
||||||
MachineID: c.MachineID,
|
MachineID: c.MachineID,
|
||||||
Container: c.Container,
|
Container: c.Container,
|
||||||
|
StopGracePeriod: spec.StopGracePeriod,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,68 +3,69 @@
|
|||||||
Uncloud supports a subset of the [Compose specification](https://compose-spec.io/) with some extensions and limitations.
|
Uncloud supports a subset of the [Compose specification](https://compose-spec.io/) with some extensions and limitations.
|
||||||
The following table shows the support status for main Compose features:
|
The following table shows the support status for main Compose features:
|
||||||
|
|
||||||
| Feature | Support Status | Notes |
|
| Feature | Support Status | Notes |
|
||||||
|--------------------|--------------------|----------------------------------------------------------------------------------------------------------------|
|
|---------------------|--------------------|----------------------------------------------------------------------------------------------------------------|
|
||||||
| **Services** | | |
|
| **Services** | | |
|
||||||
| `build` | ✅ Supported | Build context and Dockerfile |
|
| `build` | ✅ Supported | Build context and Dockerfile |
|
||||||
| `cap_add` | ✅ Supported | Additional kernel [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) |
|
| `cap_add` | ✅ Supported | Additional kernel [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) |
|
||||||
| `cap_drop` | ✅ Supported | Which kernel [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) to drop |
|
| `cap_drop` | ✅ Supported | Which kernel [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) to drop |
|
||||||
| `command` | ✅ Supported | Override container command |
|
| `command` | ✅ Supported | Override container command |
|
||||||
| `configs` | ✅ Supported | File-based and inline configs |
|
| `configs` | ✅ Supported | File-based and inline configs |
|
||||||
| `cpus` | ✅ Supported | CPU limit |
|
| `cpus` | ✅ Supported | CPU limit |
|
||||||
| `depends_on` | ⚠️ Limited | Services deployed in order but conditions not checked |
|
| `depends_on` | ⚠️ Limited | Services deployed in order but conditions not checked |
|
||||||
| `devices` | ✅ Supported | Device mappings |
|
| `devices` | ✅ Supported | Device mappings |
|
||||||
| `dns` | ❌ Not supported | Built-in service discovery |
|
| `dns` | ❌ Not supported | Built-in service discovery |
|
||||||
| `dns_search` | ❌ Not supported | Built-in service discovery |
|
| `dns_search` | ❌ Not supported | Built-in service discovery |
|
||||||
| `entrypoint` | ✅ Supported | Override container entrypoint |
|
| `entrypoint` | ✅ Supported | Override container entrypoint |
|
||||||
| `env_file` | ✅ Supported | Environment file |
|
| `env_file` | ✅ Supported | Environment file |
|
||||||
| `environment` | ✅ Supported | Environment variables |
|
| `environment` | ✅ Supported | Environment variables |
|
||||||
| `gpus` | ✅ Supported | GPU device access |
|
| `gpus` | ✅ Supported | GPU device access |
|
||||||
| `healthcheck` | ✅ Supported | Health check configuration |
|
| `healthcheck` | ✅ Supported | Health check configuration |
|
||||||
| `image` | ✅ Supported | Container image specification |
|
| `image` | ✅ Supported | Container image specification |
|
||||||
| `init` | ✅ Supported | Run init process in container |
|
| `init` | ✅ Supported | Run init process in container |
|
||||||
| `labels` | ❌ Not supported | |
|
| `labels` | ❌ Not supported | |
|
||||||
| `links` | ❌ Not supported | Use service names for communication |
|
| `links` | ❌ Not supported | Use service names for communication |
|
||||||
| `logging` | ✅ Supported | Defaults to [local](https://docs.docker.com/engine/logging/drivers/local/) log driver |
|
| `logging` | ✅ Supported | Defaults to [local](https://docs.docker.com/engine/logging/drivers/local/) log driver |
|
||||||
| `mem_limit` | ✅ Supported | Memory limit |
|
| `mem_limit` | ✅ Supported | Memory limit |
|
||||||
| `mem_reservation` | ✅ Supported | Memory reservation |
|
| `mem_reservation` | ✅ Supported | Memory reservation |
|
||||||
| `mem_swappiness` | ❌ Not supported | |
|
| `mem_swappiness` | ❌ Not supported | |
|
||||||
| `memswap_limit` | ❌ Not supported | |
|
| `memswap_limit` | ❌ Not supported | |
|
||||||
| `networks` | ❌ Not supported | All containers share cluster network |
|
| `networks` | ❌ Not supported | All containers share cluster network |
|
||||||
| `ports` | ⚠️ Limited | `mode: host` only, use [`x-ports`](#x-ports) for HTTP/HTTPS |
|
| `ports` | ⚠️ Limited | `mode: host` only, use [`x-ports`](#x-ports) for HTTP/HTTPS |
|
||||||
| `privileged` | ✅ Supported | Run containers in privileged mode |
|
| `privileged` | ✅ Supported | Run containers in privileged mode |
|
||||||
| `pull_policy` | ✅ Supported | `always`, `missing`, `never` |
|
| `pull_policy` | ✅ Supported | `always`, `missing`, `never` |
|
||||||
| `secrets` | ❌ Not supported | Use configs or environment variables |
|
| `secrets` | ❌ Not supported | Use configs or environment variables |
|
||||||
| `security_opt` | ❌ Not supported | |
|
| `security_opt` | ❌ Not supported | |
|
||||||
| `storage_opt` | ❌ Not supported | |
|
| `stop_grace_period` | ✅ Supported | Time to wait after SIGTERM before SIGKILL |
|
||||||
| `sysctls` | ✅ Supported | Namespaced kernel parameters |
|
| `storage_opt` | ❌ Not supported | |
|
||||||
| `user` | ✅ Supported | Set container user |
|
| `sysctls` | ✅ Supported | Namespaced kernel parameters |
|
||||||
| `volumes` | ✅ Supported | Named volumes, bind mounts, tmpfs |
|
| `user` | ✅ Supported | Set container user |
|
||||||
| **Deploy** | | |
|
| `volumes` | ✅ Supported | Named volumes, bind mounts, tmpfs |
|
||||||
| `labels` | ❌ Not supported | |
|
| **Deploy** | | |
|
||||||
| `mode` | ✅ Supported | Either `global` or `replicated` |
|
| `labels` | ❌ Not supported | |
|
||||||
| `placement` | ❌ Not supported | Use [`x-machines`](#x-machines) extension |
|
| `mode` | ✅ Supported | Either `global` or `replicated` |
|
||||||
| `replicas` | ✅ Supported | Number of container replicas |
|
| `placement` | ❌ Not supported | Use [`x-machines`](#x-machines) extension |
|
||||||
| `resources` | ⚠️ Limited | CPU, memory limits and device reservations |
|
| `replicas` | ✅ Supported | Number of container replicas |
|
||||||
| `restart_policy` | ❌ Not supported | Defaults to `unless-stopped` |
|
| `resources` | ⚠️ Limited | CPU, memory limits and device reservations |
|
||||||
| `rollback_config` | ❌ Not supported | See [#151](https://github.com/psviderski/uncloud/issues/151) |
|
| `restart_policy` | ❌ Not supported | Defaults to `unless-stopped` |
|
||||||
| `update_config` | ⚠️ Limited | `order` and `monitor` supported. See [rolling deployments](../4-guides/1-deployments/4-rolling-deployments.md) |
|
| `rollback_config` | ❌ Not supported | See [#151](https://github.com/psviderski/uncloud/issues/151) |
|
||||||
| **Volumes** | | |
|
| `update_config` | ⚠️ Limited | `order` and `monitor` supported. See [rolling deployments](../4-guides/1-deployments/4-rolling-deployments.md) |
|
||||||
| Named volumes | ✅ Supported | Docker volumes |
|
| **Volumes** | | |
|
||||||
| Bind mounts | ✅ Supported | Host path binding |
|
| Named volumes | ✅ Supported | Docker volumes |
|
||||||
| Tmpfs mounts | ✅ Supported | In-memory filesystems |
|
| Bind mounts | ✅ Supported | Host path binding |
|
||||||
| Volume labels | ✅ Supported | Custom labels |
|
| Tmpfs mounts | ✅ Supported | In-memory filesystems |
|
||||||
| External volumes | ✅ Supported | Must exist before deployment |
|
| Volume labels | ✅ Supported | Custom labels |
|
||||||
| Volume drivers | ⚠️ Limited | Local driver only |
|
| External volumes | ✅ Supported | Must exist before deployment |
|
||||||
| **Configs** | | |
|
| Volume drivers | ⚠️ Limited | Local driver only |
|
||||||
| File-based configs | ✅ Supported | Read from file |
|
| **Configs** | | |
|
||||||
| Inline configs | ✅ Supported | Defined in compose file |
|
| File-based configs | ✅ Supported | Read from file |
|
||||||
| External configs | ❌ Not supported | Not supported |
|
| Inline configs | ✅ Supported | Defined in compose file |
|
||||||
| Short syntax | ❌ Not supported | Use long syntax only |
|
| External configs | ❌ Not supported | Not supported |
|
||||||
| **Extensions** | | |
|
| Short syntax | ❌ Not supported | Use long syntax only |
|
||||||
| `x-caddy` | ✅ Uncloud-specific | Custom Caddy configuration |
|
| **Extensions** | | |
|
||||||
| `x-machines` | ✅ Uncloud-specific | Machine placement constraints |
|
| `x-caddy` | ✅ Uncloud-specific | Custom Caddy configuration |
|
||||||
| `x-ports` | ✅ Uncloud-specific | Service port publishing |
|
| `x-machines` | ✅ Uncloud-specific | Machine placement constraints |
|
||||||
|
| `x-ports` | ✅ Uncloud-specific | Service port publishing |
|
||||||
|
|
||||||
### Legend
|
### Legend
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user