Skip to main content

Use docker-compose to manage multiple apps on a single host

Project description

Docker0s uses docker-compose to manage multiple containerised apps on a single host.

PyPI Tests Test coverage

Bring together standard docker-compose files across multiple projects in a single simple manifest file, written in either YAML or Python with pre- and post-operation hooks, to deploy to a single host.

It’s designed for small self-hosted low-maintenance deployments which don’t need the complexity of Kubernetes - think k8s with zero features and a much simpler config syntax, with simple app manifests instead of helm charts.

There is a collection of ready-to-use app manifests at docker0s-manifests, with examples for how to deploy them to your host.

Quickstart

Install:

pip install docker0s

Put together a manifest in YAML as d0s-manifest.yml:

apps:
  traefik:
    path: git+https://github.com/radiac/docker0s-manifests.git@main#traefik
    env_file: traefik.env
  mail:
    path: ../apps/mail
  website:
    type: MountedApp
    path: "git+ssh://git@github.com:radiac/example.com.git@main"
    env:
      DOMAIN: example.radiac.net
host:
  name: example.radiac.net

or in Python as d0s-manifest.py, using subclassing to perform actions before and after operations, and to add custom functionality:

from docker0s import MountedApp

class Website(MountedApp):
    # Clone a repo to the host and look for docker-compose.yml in there
    path = "git+ssh://git@github.com:radiac/example.com.git@main"
    env = {
        "DOMAIN": "example.radiac.net"
    }

    # Subclass methods to add your own logic
    def deploy(self):
        # Perform action before deployment, eg clean up any previous deployment
        super().deploy()
        # Perform action after deployment, eg push additional resources

    def up(self, *services):
        # Perform action before ``up``, eg report to a log
        super().up(*services)
        # Perform action after ``up``, eg wait and perform a test

    @App.command
    def say_hello(self, name):
        print(f"Hello {name}, this runs locally")
        self.host.exec("echo And {name}, this is on the host", args={'name': name})

class Vagrant(Host):
    name = "vagrant"

Then run a command, eg:

docker0s deploy
docker0s up
docker0s restart website.django
docker0s exec website.django /bin/bash
docker0s cmd website say_hello person

Commands

docker0s deploy [<app>[.<service>]]:

Deploy resources to the host

docker0s up [<app>[.<service>]]:

Start all apps, a specific app, or a specific app’s service

docker0s down [<app>[.<service>]]:

Stop all apps, a specific app, or a specific app’s service

docker0s restart [<app>[.<service>]]:

Restart all apps, a specific app, or a specific app’s service

docker0s exec <app>.<service> <command>:

Execute a command in the specific service

docker0s cmd <app> <command> [<args> ...]

Execute a local App command

Options:

--manifest=<file>, -m <file>:

Specify the manifest. If not specified, tries d0s-manifest.py then d0s-manifest.yml in the current directory.

Manifest file

A manifest file defines a list of more or apps which will be deployed to one host.

You can put everything in a single manifest, but usually you will define a generic app manifest next to a docker-compose.yml, and then extend it in a host manifest where you set environment variables. The syntax of both is the same, but an app manifest only defines apps, whereas a host manifest defines both apps and the host to deploy it to.

See docker0s-manifests for a collection of app manifests and examples for how to use them with your host manifest.

YAML

A manifest file has two sections:

apps:

The list of app definitions.

Each app starts with its identifier. This is used as its namespace for docker-compose.

Under the identifier you can declare the type of app with type; if not specified it will default to type: App. See “App Types” for more details and additional arguments for the app definition.

An app can also specify environment variables to pass to docker-compose, by setting env with a file path, a list of files, or key/value pairs.

host:

The host definition.

There can be only one per manifest. Manifests which define a host cannot be used as a base manifest (see extends attribute).

App types

App:

A project with a docker-compose ready for use in production.

Attributes:

path

Path to the app - a directory or repository containing the docker compose file and any other assets docker0s will require. Any app:// paths elsewhere in the app definition will use this as the base path.

extends

Path to a base docker0s manifest for this app.

A base manifest:

  • uses the same syntax

  • can define multiple apps

  • can reference further base manifests

  • must not define a host

This value can be one of two patterns:

  • path/to/d0s-manifest.yml or path/to/d0s-manifest.py - this app will extend using the app defined with the same name - see “App naming” below

  • path/to/d0s-manifest.yml::AppName or path/to/d0s-manifest.py::AppName - this app will extend using the app defined with the name AppName.

Default: app://d0s-manifest.py, app://d0s-manifest.yml (first found)

compose

Path to the app’s docker compose file.

Default: app://docker-compose.yml

assets:

Path or list of paths to assets which should be uploaded into an assets dir next to the docker-compose. Must be app:// paths.

env_file

Path or list of paths to files containing environment variables for docker-compose. See “Environment variables” below for details.

env

Key-value pairs of environment variables for docker-compose. See “Environment variables” below for details.

Example YAML:

apps:
  website:
    path: "git+ssh://git@github.com:radiac/example.com.git"
    extends: "app://docker0s-base.py"
    config: "app://docker-compose.live.yml"
    env_file:
    - app://base.env
    - website.env
    env:
      deployment=www.example.com
MountedApp:

A project which requires the repository to be cloned on the host and mounted into the service.

Takes the same arguments as an App, with the following differences:

path

Path to the app. This must be a git repository.

compose

Path to the app’s docker compose file. This must be an app:// path within the repository.

Example YAML:

apps:
  website:
    type: MountedApp
    path: "git+ssh://git@github.com:radiac/example.com.git"

App naming

Because apps are referenced by name in Python, YAML and on the command line, docker0s supports apps names in PascalCase, camelCase, snake_case and kebab-case in YAML and the command line. Python classes must always use PascalCase:

class WebsiteExampleCom(App):
    path = "../website"

YAML can use any - these four app definitions are equivalent (so would raise an error):

apps:
  website_example_com:
    path: ../website
  website-example-com:
    path: ../website
  websiteExampleCom:
    path: ../website
  WebsiteExampleCom:
    path: ../website

Paths

An App path can be:

  • relative to the manifest, eg traefik.env or ../apps/traefik/d0s-manifest.yml. Note this is relative to the manifest where this app definition is found, so relative paths in a base manifest loaded with extend will be relative to the base manifest.

  • absolute, eg /etc/docker0s/apps/traefik/d0s-manifest.yml.

  • a file in a git repository in the format git+<protocol>://<path>@<ref>#<file> where protocol is one of git+https or git+ssh, and the ref is a branch, commit or tag. For example:

    • git+ssh://git@github.com:radiac/docker0s-manifests@main#traefik

    • git+https://github.com/radiac/docker0s-manifests@v1.0#traefik/d0s-manifest.yml

Other fields which take a path argument (ie manifest, compose and env_file) can use these values, as well as:

  • relative to the app’s path with app://, eg if path = "../apps/traefik" then if extends = "app://docker0s-base.py" it will look for the base manifest at ../apps/traefik/docker0s-base.py

For security, when using a remote manifest from a third party git repository, we recommend performing a full audit of what you are going to deploy, and then pinning to that specific commit.

Environment variables

Environment variables for the docker-compose can be defined as one or more env files, as a dict within the manifest, or both.

If more than one env_file is specified, files are loaded in order. If a key appears in more than one file, the last value loaded will be used.

If a key appears in both the env dict and an env_file, the value in this field will be used.

Environment variables are evaluated before inheritance, meaning an env file key in a child manifest can override an env dict key in a parent. Precedence order, with winner first:

  1. Child env dict

  2. Child env file

  3. Parent env dict

  4. Parent env file

Environment variables are merged and written to an env file on the server for docker-compose to use.

App commands

Python App definitions can declare local commands - usually either utility functions to assist with manifest definition, such as a password encoder, or to use fabric to perform operations on the host, such as tailing docker logs.

To define an app, decorate it with App.command:

class Website(App):
    @App.command
    def say_hello(self, name):
        print(f"Hello {name}, this runs locally")
        self.host.exec("echo And {name}, this is on the host", args={'name': name})

This can then be called as:

./docker0s cmd website say_hello person

Commands currently do not have any support for validation or typing of arguments.

Deployment

Default deployment structure:

/home/user/
  apps/
    app_name/
      service_name/
        docker-compose.yml
        env
    mounted_app_with_store/
      service_name/
        repo/
          docker-compose.yml
        store/
        env

Roadmap

  • Jinja support for templated docker compose files

  • Base manifest hashes, for improved security when pulling remotely

  • Support for gitops through a repository monitoring mode

Changelog

  • 1.1.0 - Add command support, docker0s cmd ...; restore default extends; standardise manifest filenames

  • 1.0.1 - Fix for entrypoint

  • 1.0.0 - Initial release

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

docker0s-1.1.0.tar.gz (24.2 kB view hashes)

Uploaded Source

Built Distribution

docker0s-1.1.0-py3-none-any.whl (24.4 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page