v0.17.0

psviderski/uncloudv0.17.0Mar 1, 2026by psviderski

AI Summary

This release brings container health monitoring with automatic rollback during rolling deployments, and adds Compose spec support for healthcheck, devices, and ulimits.

Key Highlights

  • Container health monitoring with automatic rollback
  • Compose healthcheck support
  • Control container replacement order (start-first/stop-first)
  • Compose devices support for GPU mapping
  • Compose ulimits support
  • Auto-provision volumes for global services

New Features

  • Container health monitoring and rollback
  • Compose healthcheck configuration
  • deploy.update_config.order (start-first/stop-first)
  • devices mapping for host devices
  • ulimits configuration
  • Auto-provision volumes for global services
  • SSH connection reuse via control socket

Full Release Notes

This release brings container health monitoring with automatic rollback during rolling deployments, Compose spec support for `healthcheck`, `devices`, and `ulimits`, and various reliability improvements.

## ✨ Highlights

### Container health monitoring and rollback

Changes: [7a9eac5](https://github.com/psviderski/uncloud/commit/7a9eac593f9be0f02b42b1bef5b82f311e6af243), [7b88040](https://github.com/psviderski/uncloud/commit/7b88040c73a43e1dea8db79513fec1c3cd5eac79), [ce3cb8a](https://github.com/psviderski/uncloud/commit/ce3cb8a34f3ae027a4c17b3425eb58c466ce3dbc)

Rolling deployments now monitor crashes and health checks after starting new containers. If a container keeps restarting or becomes unhealthy, the deployment automatically rolls it back and fails to prevent downtime.

https://github.com/user-attachments/assets/4ee73048-9ca2-4c8a-b075-f8c6a0840ee7

#### Compose `healthcheck` support

Compose files now support the [`healthcheck`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#healthcheck) attribute, allowing you to define health checks for your services:

```yaml
services:
  app:
    image: myapp
    healthcheck:
      test: curl -f http://localhost:8000/health
      interval: 5s
      retries: 3
      start_period: 10s
      start_interval: 1s
```

Use `uc deploy --skip-health` flag to bypass health monitoring for faster emergency deployments.

See [Rolling deployments](https://uncloud.run/docs/guides/deployments/rolling-deployments) for more details on how rolling deployments work and how to configure health checks for your services.

### Control container replacement order during rolling deployments

PR: [#248](https://github.com/psviderski/uncloud/pull/248). Thanks to @nick-potts for the contribution ❤️

You can now control the order of container replacement during rolling deployments with `deploy.update_config.order` in your Compose file:
- `start-first` (default): starts a new container before stopping the old one
- `stop-first`: stops the old container before starting a new one (brief downtime)

```yaml
services:
  app:
    image: myapp
    deploy:
      update_config:
        order: stop-first
```

The default order automatically switches to `stop-first` if a service mounts a volume to prevent data corruption.

See [Rolling deployments](https://uncloud.run/docs/guides/deployments/rolling-deployments) for more details.

### Compose `devices` support

PR: [#250](https://github.com/psviderski/uncloud/pull/250). Thanks to @jabr for the contribution ❤️

You can now map host devices into containers, for example, Intel integrated GPU for video transcoding using the [`devices`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#devices) attribute in your Compose file:

```yaml
services:
  app:
    image: myapp
    devices:
      - /dev/dri:/dev/dri
      - /dev/ttyUSB0:/dev/ttyUSB0:rw
```

### Compose `ulimits` support

PR: [#244](https://github.com/psviderski/uncloud/pull/244). Thanks to @ipaddicting for the contribution ❤️

You can now set [`ulimits`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#ulimits) for service containers in your Compose file. For example, to increase the maximum number of open files:

```yaml
services:
  app:
    image: myapp
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
```

### Auto-provision volumes for global services

PR: [#243](https://github.com/psviderski/uncloud/pull/243). Thanks to @zasdaym for the contribution ❤️

When deploying a [global service](https://uncloud.run/docs/guides/deployments/deploy-global-services) with a volume, the volume is now automatically created on all machines in the cluster.

## Improvements

- SSH connections with `ssh+cli://` prefix (use `ssh` CLI instead of Go native SSH implementation) reuse a single SSH connection via control socket - significantly speeds up `uc` commands
- Improved `uc image push` support on macOS by always running proxy to virtualised Docker (except OrbStack that doesn't require it)
- Global service deployment stops all running conflicting containers, e.g. left from interrupted deploys, not just the first one
- Temporary socat proxy containers created by `uc image push` are labeled with `uncloud.managed`

## Bug fixes

- Fixed IPv6 address formatting for HTTP URLs ([#254](https://github.com/psviderski/uncloud/pull/254))
- Fixed `uc image push` when using Rancher Desktop locally ([#251](https://github.com/psviderski/uncloud/pull/251))
- Fixed `uc machine init` to reset an already initialised machine when using `ssh+cli://` connection

## Upgrade to 0.17.0

### Uncloud CLI locally

To upgrade the Uncloud CLI (`uc`) locally:

```bash
# Homebrew (macOS, Linux)
brew upgrade uncloud

# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh
```

### Machine daemon

To upgrade the Uncloud daemon on your machines, run the following commands on each machine:

```bash
# AMD64
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.17.0/uncloudd_linux_amd64.tar.gz
# ARM64
# curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.17.0/uncloudd_linux_arm64.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloud
```

## Changelog
* b48ebe2acc6035f403623e0d52cef7fb21259129 chore: UNCLOUD_HEALTH_MONITOR_PERIOD accepts duration (10s, 500ms, 0)
* f8d1945544400e8488c721eaf593a352ce3c4400 chore: add TODO for ReplaceContainerOperation
* fe56d6d7083abd00c9e3f132acea03300f68abbd chore: always run proxy to virtualised Docker on macOS for 'image push' except OrbStack
* f48dc250a910f7a11cfeee45cd89fb274e779661 chore: fix landing navbar github/discord buttons wrap on mobile
* 44013da33284511d4712c5eaa670110774ea6785 chore: format AGENTS, instruct to not use em dashes
* 6e59657fe2fb1d00a3b218689e47e0772e193b73 chore: global reconciliation: stop all running conflicting containers, not only replace the first one
* a5a9ef5444c36a32f1828d17be6e432206e375b2 chore: init container healthcheck const
* 87e49dfb62dcf318f39f0cd9a9b12f41ea1cf10b chore: label temporary socat proxy containers created by 'uc image push' with uncloud.managed
* 215f21439d49ea598a66b2f8873dd7fd5c1a2021 chore: lint and fix e2e deploy tests with ReplaceContainerOperation
* c91a9645137cf616acbfdb1f4bfb4d91880be89f chore: make ssh+cli connections reuse one SSH connection via control socket. Fix image push
* 185cf19a0c25ce029da0870265d58e62ab37a4bd chore: minor full-spec test change
* 1d4dbd96ce9113e7e357a07473c6544e79ff6db6 chore: minor sshcli refactgor
* 5c54e9d0595f51574cdf3888734d2213f008079e chore: refactor device mapping to be compliant with Compose (CDI requests)
* 93d7f29d316c48d9844b99f7651db2759dd6390c chore: remove TODO about encapsulating Client in deploy operations
* 808bda67d4fbbe4f3671f37396c404b84286866b chore: remove unused constants
* 2588279e52e8c7b4a9f9440d867f8a63d1371b36 chore: rename AI.md to AGENTS.md
* e6705599b334756a1b81a0109026c1b2216ed75a chore: rename env var UNCLOUD_DEFAULT_HEALTH_MONITOR_PERIOD_MS -> UNCLOUD_HEALTH_MONITOR_PERIOD_MS
* 7c4f739d07f33cd0093890dbad299607bb0e1a98 chore: specify machines to deploy website to
* 18ebd29032fc5b50358643e9595582c927c4424c chore: split deploy operations into separate files in operation package
* e0a63a3f493668bb85c9f8099d6a2ea2d9622e31 chore: typo
* 4443fa9e0e896104391c7b5b99bdf92875f8a694 chore: update full-spec test to include latest implemented Compose attributes
* 0b2e1bb7a222a7873b678c74aed957e4490305b0 chore: update newsletter form to substack
* 53bf446502f1142238a54a6d3c15805042f0e0c3 deploy.update_config.order support to start-first or stop-first when replacing containers (#248)
* ab6f8569878dbadc39bc280f1c9424003e86a9ba feat: Add support for compose `devices` mappings (#250)
* ce3cb8a34f3ae027a4c17b3425eb58c466ce3dbc feat: add --skip-health flag to bypass health monitoring during container deployment
* 17c1bb5c21da254ab4b02061b2162f14adda6b33 feat: add WaitContainerHealthy client method and health check utilities
* 3056e2af114681063a841ae7cdfce526f8bb4f19 feat: add support for healthcheck in Compose
* 3bd940005181c93614c2eae9f9925f78df89eb37 feat: add support for ulimits in compose and container creation (#221) (#244)
* 15d9ceb4d1857846823dbe30b57141a92433287d feat: auto-provision volumes on all machines for global services (#243)
* 7a9eac593f9be0f02b42b1bef5b82f311e6af243 feat: implement container health monitoring and rollback during rolling deployment (closes #24)
* 14056cc58424660b6b9b83ca81756c06bad46b83 fix: format IPv6 addr correclty for HTTP URL (#254)
* 7bfaf311387243adce676ff5caa82107640f7870 fix: image tag template formatting in docs
* 2940965e31fbf62a652da25515e8d862ec079721 fix: recreate container on ulimit changes, add test
* 476a2d57caf7a67b5dc64890365ea10d1632c11e fix: reset already initialised machine on 'uc machine init' when using ssh+cli connection
* 7b88040c73a43e1dea8db79513fec1c3cd5eac79 fix: rolling container replacement: if new container fails, rollback and run old container only if it was running
* ce46a67d6df342f0a03606a0ec2c5e91c6827506 fix: ssh args for machine init/add when using ssh+cli
* a4a8e70f9cff776b7323b368684b69ecfee91677 fix: sshcli tests
* d3ee7399eb06142f86abc34cb91665ee27c56b68 fix: support image push when using Rancher Desktop locally (#251)