mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
docs: add 'Deploy an app' how-to guide, init 'Image tag format' reference
This commit is contained in:
@@ -0,0 +1,434 @@
|
||||
# Deploy an app
|
||||
|
||||
Deploy a containerised application to your Uncloud cluster using either source code or pre-built images.
|
||||
|
||||
This guide covers both scenarios:
|
||||
|
||||
- **[Deploy from source code](#deploy-from-source-code)**: Build Docker images from your application code and use them
|
||||
to deploy service containers
|
||||
- **[Deploy pre-built images](#deploy-pre-built-images)**: Deploy service containers using existing images from a
|
||||
registry or your local machine
|
||||
|
||||
Uncloud uses [Compose Specification](https://compose-spec.io/) for defining the deployment configuration of your app's
|
||||
services. It implements the most common Compose features with some Uncloud-specific extensions. See
|
||||
[Compose support matrix](../8-compose-file-reference/1-support-matrix.md) for details.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `uc` CLI [installed](../2-getting-started/1-install-cli.md) on your local machine
|
||||
- An Uncloud cluster with at least one machine (see [Quick start](../2-getting-started/2-deploy-demo-app.md))
|
||||
- Basic knowledge of [Compose Specification](https://compose-spec.io/)
|
||||
|
||||
## Deploy from source code
|
||||
|
||||
Use this scenario when you want to build and deploy your application from
|
||||
a [Dockerfile](https://docs.docker.com/reference/dockerfile/) and source code available on your local machine.
|
||||
|
||||
### 1. Create a Compose file
|
||||
|
||||
Create a `compose.yaml` file in your application directory with a
|
||||
[`build`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#build) section for each service you want to
|
||||
build. Here is a minimal example of a Compose file that builds and deploys a web app that consists of a single service
|
||||
called `web`:
|
||||
|
||||
```yaml title="compose.yaml"
|
||||
services:
|
||||
web:
|
||||
# Build an image from the Dockerfile in the current directory
|
||||
build: .
|
||||
# Publish the container port 8000 as https://app.example.com
|
||||
x-ports:
|
||||
- app.example.com:8000/https
|
||||
```
|
||||
|
||||
If you don't have a Dockerfile for building an image from your source code, create one in the same directory.
|
||||
|
||||
### 2. Build and deploy your app
|
||||
|
||||
To build and deploy services defined in your Compose file, navigate to the directory with `compose.yaml` and run:
|
||||
|
||||
```shell
|
||||
uc deploy
|
||||
```
|
||||
|
||||
This command looks for a Compose file in your current working directory and:
|
||||
|
||||
1. **Builds images** for services with a `build` section using your local Docker and tags them with the current Git
|
||||
version
|
||||
2. **Pushes built images** directly **to cluster machines** using
|
||||
[unregistry](https://github.com/psviderski/unregistry), transferring only the missing layers
|
||||
3. **Plans the deployment** and shows you what will change, asking for confirmation
|
||||
4. **Creates any missing volumes** on target machines
|
||||
5. **Deploys service containers** using the built images and latest configuration changes with zero-downtime rolling
|
||||
updates
|
||||
|
||||
See the [uc deploy](../9-cli-reference/uc_deploy.md) reference for all available options.
|
||||
|
||||
Watch `uc deploy` building and deploying a demo app (18 seconds):
|
||||
|
||||
<video controls width="100%">
|
||||
<source src="https://media.uncloud.run/docs/uc-deploy-demo.mp4"/>
|
||||
</video>
|
||||
|
||||
### Customise the build configuration
|
||||
|
||||
If you need more control over the build configuration, you can specify additional attributes in the `build` section of
|
||||
your Compose file. For example, to specify a custom Dockerfile location, set build-time arguments, or build
|
||||
multi-platform images.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
# Relative path to the directory with your Dockerfile
|
||||
context: ./backend
|
||||
# Set build-time variables defined as ARG in your Dockerfile
|
||||
args:
|
||||
ALPINE_VERSION: 3.22
|
||||
BUILD_ENV: prod
|
||||
# Build a multi-platform image
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
```
|
||||
|
||||
You can pass additional build arguments or override existing ones using the `--build-arg` flag with `uc deploy`:
|
||||
|
||||
```shell
|
||||
uc deploy --build-arg BUILD_ENV=dev
|
||||
```
|
||||
|
||||
You can also use advanced features like build caches, secrets, and SSH access.
|
||||
See [Compose Build Specification](https://github.com/compose-spec/compose-spec/blob/main/build.md) for all supported
|
||||
attributes.
|
||||
|
||||
:::info note
|
||||
|
||||
To build multi-platform images, you need to configure your local Docker to use the
|
||||
[containerd image store](https://docs.docker.com/desktop/features/containerd/).
|
||||
|
||||
:::
|
||||
|
||||
### Customise image tags
|
||||
|
||||
If you don't specify the `image` attribute, `uc deploy` tags built images with a Git-based version like
|
||||
|
||||
```yaml
|
||||
# <project>/<service>:<git datetime>.<short git sha>
|
||||
myapp/web:2025-10-30-223604.84d33bb
|
||||
```
|
||||
|
||||
It uses your local date/time if the working directory is not a Git repository.
|
||||
|
||||
You can customise the image name and tag format using the `image` attribute. It can be a static name or a dynamic
|
||||
template using [environment variables](https://github.com/compose-spec/compose-spec/blob/main/spec.md#interpolation) and
|
||||
the [Go template](https://pkg.go.dev/text/template) syntax.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
# Custom image name and tag format
|
||||
image: myapp:{{gitdate "20060102"}}.{{gitsha 7}}.${GITHUB_RUN_ID:-local}{{if .Git.IsDirty}}.dirty{{end}}
|
||||
```
|
||||
|
||||
This generates tags like:
|
||||
|
||||
- `myapp:20251030.84d33bb.local.dirty` when building locally with uncommitted changes
|
||||
- `myapp:20251030.84d33bb.1234` when building in CI with `GITHUB_RUN_ID=1234` and a clean repo
|
||||
|
||||
`uc deploy` renders the image templates when it loads the Compose file and then uses the resulting names for the build
|
||||
and deploy stages.
|
||||
|
||||
See the [Image tag format](../8-compose-file-reference/2-image-tag-format.md) reference for all available template
|
||||
variables and functions.
|
||||
|
||||
### Separate build and deploy steps
|
||||
|
||||
You might want to build and deploy services as separate commands. For example, to run them as separate steps in your
|
||||
CI/CD pipeline or have more control over the build and deploy process. Here are the commands that are equivalent to
|
||||
`uc deploy`:
|
||||
|
||||
```shell
|
||||
# Build images and push to cluster machines
|
||||
uc build --push
|
||||
|
||||
# Deploy services using the built images
|
||||
uc deploy --no-build
|
||||
```
|
||||
|
||||
### Deploy configuration changes only
|
||||
|
||||
You can use the `--no-build` flag with `uc deploy` to deploy only the configuration changes in your Compose file if your
|
||||
source code and images haven't changed. However, the image tag may still change if you're using
|
||||
[dynamic tags](#customise-image-tags) based on the Git state (default). In that case, the deploy will likely fail
|
||||
because the new tag won't be found on cluster machines.
|
||||
|
||||
Use less sensitive dynamic tags or specify the built and pushed images you want to deploy explicitly to avoid this
|
||||
issue.
|
||||
|
||||
The recommended approach though is to commit all your changes, including the configuration ones, to the repo. Then
|
||||
rebuild and deploy your services from a clean repo state. This way, the image tags will always reflect the exact source
|
||||
code and configuration used for the deployment.
|
||||
|
||||
## Deploy pre-built images
|
||||
|
||||
Use this scenario when you want to deploy your application using pre-built images from a container registry (for
|
||||
example, Docker Hub or GitHub Container Registry) or your local Docker.
|
||||
|
||||
### 1. Create a Compose file
|
||||
|
||||
Create a `compose.yaml` file that references an image from a registry using the
|
||||
[`image`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#image) attribute. It's important that you don't
|
||||
include a `build` section for services using pre-built images. Here is a minimal example of a Compose file that deploys
|
||||
an app that consists of a single `nginx` service:
|
||||
|
||||
```yaml title="compose.yaml"
|
||||
services:
|
||||
nginx:
|
||||
# Use the nginx image from Docker Hub
|
||||
image: nginx:latest
|
||||
# Publish the container port 80 as https://nginx.example.com
|
||||
x-ports:
|
||||
- nginx.example.com:80/https
|
||||
```
|
||||
|
||||
### 2. Deploy your app
|
||||
|
||||
To deploy services defined in your Compose file, navigate to the directory with `compose.yaml` and run:
|
||||
|
||||
```shell
|
||||
uc deploy
|
||||
```
|
||||
|
||||
This command looks for a Compose file in your current working directory and:
|
||||
|
||||
1. **Plans the deployment** and shows you what will change, asking for confirmation
|
||||
2. **Creates any missing volumes** on target machines
|
||||
3. **Pulls images** from a registry on cluster machines where services are deployed according to the
|
||||
[`pull_policy`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#pull_policy)
|
||||
4. **Deploys service containers** using the pulled images and latest configuration changes with zero-downtime rolling
|
||||
updates
|
||||
|
||||
### Control image pulling
|
||||
|
||||
By default, `uc deploy` pulls an image from a registry only if it's missing on a target machine. You can change this
|
||||
behavior using the [`pull_policy`](https://github.com/compose-spec/compose-spec/blob/main/spec.md#pull_policy)
|
||||
attribute. For example, to always pull the latest version of an image before deploying.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
# Always pull the latest :alpine tag before deploying
|
||||
pull_policy: always
|
||||
```
|
||||
|
||||
Available `pull_policy` values:
|
||||
|
||||
- `always`: Always pull the image from the registry before deploying
|
||||
- `missing` (default): Pull only if the image isn't available on the target machine
|
||||
- `never`: Never pull, the image must be present on the target machine or the deploy will fail
|
||||
|
||||
### Pull from a private registry
|
||||
|
||||
If your images are in a private registry, `uc deploy` needs an authentication token to pull them. You can provide it by
|
||||
either:
|
||||
|
||||
- Logging in to the registry using your local Docker (recommended)
|
||||
- Logging in to the registry using Docker on each cluster machine you want to deploy to
|
||||
|
||||
When you're logged in using your local Docker, `uc deploy` automatically passes your local Docker credentials for the
|
||||
private registry to cluster machines when pulling images. This way, you don't need to log in on each machine manually.
|
||||
|
||||
See [`docker login`](https://docs.docker.com/reference/cli/docker/login/) for instructions on how to log in to a private
|
||||
registry.
|
||||
|
||||
### Push local images to cluster machines
|
||||
|
||||
You can also deploy pre-built images that exist only in your local Docker and are not available for pulling on cluster
|
||||
machines. For example, images you built locally outside of the Compose workflow or pulled from a private registry that
|
||||
is unreachable from your cluster machines. This is useful for deploying to air-gapped or restricted environments.
|
||||
|
||||
You can push these local images directly to your cluster machines using the
|
||||
[`uc image push`](../9-cli-reference/uc_image_push.md) command:
|
||||
|
||||
```shell
|
||||
# Push to *all* cluster machines
|
||||
uc image push myapp:latest
|
||||
|
||||
# Push to specific machines only
|
||||
uc image push myapp:latest -m machine1,machine2
|
||||
```
|
||||
|
||||
This command uploads the image from your local Docker to the cluster machines using
|
||||
[unregistry](https://github.com/psviderski/unregistry) running as part of the Uncloud daemon on each machine. It
|
||||
efficiently transfers only the image layers that don't already exist on the target machines.
|
||||
|
||||
After pushing the image, update your Compose file to reference it:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
# Reference the image you just pushed
|
||||
image: myapp:latest
|
||||
# Never try to pull from a registry since the image is only available locally
|
||||
pull_policy: never
|
||||
```
|
||||
|
||||
Run [`uc images`](../9-cli-reference/uc_images.md) to verify that the image is available on the target machines.
|
||||
|
||||
Then deploy as usual:
|
||||
|
||||
```shell
|
||||
uc deploy
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Set `pull_policy: never` when using local images to prevent `uc deploy` from trying to pull them from a registry.
|
||||
|
||||
:::
|
||||
|
||||
## Mix source builds and pre-built images
|
||||
|
||||
Define multiple services in your Compose file, mixing source builds and pre-built images:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
# Build web service from source
|
||||
build: .
|
||||
x-ports:
|
||||
- app.example.com:8000/https
|
||||
|
||||
db:
|
||||
# Pull a pre-built PostgreSQL image from Docker Hub
|
||||
image: postgres:18
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
```
|
||||
|
||||
`uc deploy` builds and pushes images for services with a `build` section and pulls images from a registry for services
|
||||
with only an `image` attribute.
|
||||
|
||||
:::warning
|
||||
|
||||
**Service names must be globally unique** across all Compose files deployed to the same cluster.
|
||||
|
||||
Unlike Docker Compose or Docker Swarm, Uncloud doesn't automatically prefix service names with project or stack names.
|
||||
Choose unique names to avoid conflicts with services deployed from other Compose files.
|
||||
|
||||
:::
|
||||
|
||||
## Deploy to specific machines
|
||||
|
||||
By default, Uncloud randomly chooses available machines to run your services on, spreading multiple replicas of a
|
||||
service across all machines for high availability. You can restrict which machines can run your service using the
|
||||
[`x-machines`](../8-compose-file-reference/1-support-matrix.md#x-machines) extension in your Compose file.
|
||||
|
||||
This is useful when you want to:
|
||||
|
||||
- Deploy services to machines in a specific region or data center
|
||||
- Run services only on machines with specific hardware (for example, GPUs or ARM processors)
|
||||
- Keep certain services isolated to dedicated machines
|
||||
- Deploy to a subset of machines for testing before rolling out cluster-wide
|
||||
|
||||
Here's a basic example:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
x-ports:
|
||||
- app.example.com:8000/https
|
||||
# Spread 3 replicas across machine-1 and machine-2 only
|
||||
scale: 3
|
||||
x-machines:
|
||||
- machine-1
|
||||
- machine-2
|
||||
|
||||
db:
|
||||
image: postgres:18
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql
|
||||
# Create the db-data volume and run the DB container on machine-db
|
||||
x-machines: machine-db
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
```
|
||||
|
||||
When you deploy this Compose file with `uc deploy`:
|
||||
|
||||
- The `web` service will create and spread its 3 replicas only across `machine-1` and `machine-2`
|
||||
- The `db` service will create its `db-data` volume and run only on `machine-db`
|
||||
|
||||
:::tip
|
||||
|
||||
Use [`uc machine ls`](../9-cli-reference/uc_machine_ls.md) to see available machines in your cluster.
|
||||
|
||||
:::
|
||||
|
||||
### Push images to specific machines only
|
||||
|
||||
When building from source, `uc deploy` and `uc build --push` automatically push images to **all** cluster machines by
|
||||
default. This ensures images are available wherever services might be deployed.
|
||||
|
||||
If you're using `x-machines` to restrict deployments to specific machines, `uc deploy` and `uc build --push` push images
|
||||
only to those machines. This saves time and bandwidth by uploading images only where they're needed.
|
||||
|
||||
## Run one replica on each machine
|
||||
|
||||
To deploy exactly one service replica on each machine in your cluster, set
|
||||
[`mode: global`](https://github.com/compose-spec/compose-spec/blob/main/deploy.md#mode) under the `deploy` section. It's
|
||||
useful for cluster-wide services like monitoring agents, log collectors, or reverse proxies.
|
||||
|
||||
You can also combine `mode: global` with `x-machines` to run one container on each machine in a specific set.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
monitoring:
|
||||
image: quay.io/prometheus/node-exporter:latest
|
||||
deploy:
|
||||
# Run one container on each machine in the cluster
|
||||
mode: global
|
||||
# Optionally run one container on each of these specific machines only
|
||||
#x-machines:
|
||||
# - machine-1
|
||||
# - machine-2
|
||||
```
|
||||
|
||||
## Use a different Compose file location
|
||||
|
||||
If your Compose file has a different name or location, use the `-f/--file` flag to specify its path:
|
||||
|
||||
```shell
|
||||
uc deploy -f path/to/your-compose.yaml
|
||||
```
|
||||
|
||||
You can also specify multiple Compose files to merge configurations:
|
||||
|
||||
```shell
|
||||
uc deploy -f compose.yaml -f compose.prod.yaml
|
||||
```
|
||||
|
||||
See [Use multiple Compose files](https://docs.docker.com/compose/how-tos/multiple-compose-files/) for details on how you
|
||||
can customise your Compose application for different environments or workflows.
|
||||
|
||||
## Verify your deployment
|
||||
|
||||
After deploying your app, you can verify that your services are running as expected by listing all deployed services in
|
||||
the cluster:
|
||||
|
||||
```shell
|
||||
uc ls
|
||||
```
|
||||
|
||||
and inspecting the status of containers for a specific service:
|
||||
|
||||
```shell
|
||||
uc inspect web
|
||||
```
|
||||
@@ -0,0 +1,3 @@
|
||||
# Image tag format
|
||||
|
||||
TBD
|
||||
Reference in New Issue
Block a user