Docker Compose
Deploy a docker-compose.yml as one sh0 app: each service becomes a container on a private network, with named volumes and a single public address.
Overview
sh0 imports a Compose file as one app. Every service becomes a container started from its image, in the order given by depends_on. Services cannot be built: a service that declares build: is refused, so build its image elsewhere or deploy it as a separate app from its Git repository.
Deploying a stack
In the dashboard, open a stack, click Add App, choose Docker Compose, give the app a name, paste the file into docker-compose.yml and click Deploy Now. From the CLI, sh0 compose validate checks a file and sh0 compose deploy deploys it. Example with a web service and a Redis cache:
services:
web:
image: traefik/whoami:v1.10
ports:
- "8080:80"
environment:
REDIS_URL: redis://cache:6379
depends_on:
- cache
deploy:
resources:
limits:
memory: 64M
cpus: "0.25"
healthcheck:
test: ["CMD", "true"]
cache:
image: redis:7-alpine
mem_limit: 128m
cpus: 0.5
volumes:
- cache-data:/data
volumes:
cache-data:$ sh0 compose validate docker-compose.yml
[ok] Compose file is valid
Services: web, cache
$ sh0 compose deploy --app-name my-stack --wait docker-compose.yml
[*] Deploying compose file 'docker-compose.yml' as 'my-stack'...
[ok] Compose stack 'my-stack' deployed (app ID: 79389ae4-4a59-42a5-b8f6-37a018c95ddc, status: deploying)
[*] Waiting for deployment to complete...
[ok] Deployment completed successfully--var KEY=VALUE (repeatable) replaces the value of the environment variable KEY in every service that defines it.
What validation checks
A file is refused if it has no service, if a service has no image, declares build:, has an invalid port or an unparsable command, or mounts a host path (/srv/data:/data, ./data:/data): only named volumes are allowed. Keys that sh0 does not read are not reported: the example above passes validation although its deploy and healthcheck blocks are ignored.
Compose keys
Keys read by sh0:
image: required, pulled from Docker Hub or any registry.ports: only the container port is used. The first service, in file order, that declares a port receives the app's public address through the reverse proxy. The host port you write is not opened on the server.environment: map or list form.volumes: named volumes only. A volumecache-dataof the appmy-stackis created assh0-my-stack-cache-dataand persists across restarts.depends_on: start order, list or extended form.command: string or list.mem_limitandcpus: the service's memory and CPU limits. These are the only resource keys sh0 reads.
Ignored keys
deploy (including deploy.resources), healthcheck, entrypoint, restart, labels and networks are accepted and ignored. Every container gets the restart policy unless-stopped, and a service without mem_limit or cpus gets the default limits. On the example stack, the 64 MB limit written under deploy.resources did not apply, while mem_limit: 128m did:
$ docker inspect -f "{{.Name}} mem={{.HostConfig.Memory}} nanocpus={{.HostConfig.NanoCpus}} restart={{.HostConfig.RestartPolicy.Name}}" \
sh0-17b83e1c-my-stack-web sh0-17b83e1c-my-stack-cache
/sh0-17b83e1c-my-stack-web mem=536870912 nanocpus=1000000000 restart=unless-stopped
/sh0-17b83e1c-my-stack-cache mem=134217728 nanocpus=500000000 restart=unless-stoppedNetworking
The services of a stack share a private network and reach each other by service name: in the example, the cache container gets an answer from http://web:80. Only the service that holds the public address is reachable from outside.
Managing the services
The stack appears as a single app in sh0 apps and in the dashboard. Its services are listed by GET /api/v1/apps/<app-id>/services and can be restarted, stopped or started one by one with POST /api/v1/apps/<app-id>/services/<service-id>/restart (or /stop, /start).
Changing a deployed stack
Version 1.10.2 has no way to apply a new version of the Compose file to an existing stack. Deploying the file again under the same name is refused, and redeploying the app fails because it has no repository:
$ sh0 compose deploy --app-name my-stack docker-compose.yml
[*] Deploying compose file 'docker-compose.yml' as 'my-stack'...
Error: An app with name 'my-stack' already exists (VALIDATION_ERROR)
$ sh0 deploy my-stack --wait
[*] Deploying my-stack...
Deployment ID: 34f99c19-adda-4a30-a1dc-4e670a3ff505
Status: queued
[*] Waiting for deployment to complete...
error: Deployment failed.
# Build log of that deployment:
[STEP 1/6] Cloning repository
[ERROR] App has no repository URL configuredThe running services are not affected by these failures. To change the stack, deploy the new file under a new name, move the traffic and the data, then delete the old app; sh0 delete removes an app and its resources.
environment and set the real one at deployment time with --var.