OctoCompose - concept

It will be a micro service operator for go-orb and will work without go-orb as well.

OctoCompose - concept

Main Goal is to have a tool that makes it very simple to deploy an Application that comes with a subset of Services on a environment supported by one of the operators.

Operator can be one of baremetal, docker and kubernetes. It's planed to have operator replaceable, that means there can be more of them.

Initial goal will be the baremetal operator.

What can I expect as a user

  • easy to get started: Include configuration files from a Vendor/Project, customize/overwrite these settings in your own config.yaml and have a ready to use Application.
  • smart stepped upgrades: Single command to update the application, with smart stepping which means it will upgrade always to the latest minor version and then to the major.
  • Preflight checks: Validate you'r configuration before running it, have meaningfull error messages when something isn't right with the config.
  • secure secrets: Optionaly this will integrate with systems like HashiCorp Vault which means there are no plaintext secrets around.

For a Vendor/Project

  • Ship versioned configurations that works from your Servers/Github repo.
  • Let the user decide which components of your Application and which plugins he wanna use, by defining individual configurations per component.
  • powerfull configuration system: includes, globals, templating and merging are just some of the features of the config system.

Name finding

I found it very hard to find a good name for this tool, while writing this concept doc I changed the name multiple times.

There are either no free Domain Names, no Github or other clashes.

OctoCompose is a combination/mixture of Octopus and docker-compose. I'm still not sure this is the right name. Previous names have been octctl and orberator.

Technical Overview

Will be a operator/orchestration tool.

It can be used with go-orb but it's not limited to that.

You might see it as alternative to docker compose, but it will run baremetal and in kubernetes as well.

It should be able to download binaries from various sources or maybe build them from source using git.

Modular Architecture

With OctoCompose I want to follow the Unix Philosophy: "Do one thing and do it well.".

This is why it comes with a plugin based system. The Idea of running tools as commands and parsing theier output comes from the nagios project.

Configuration

OctoCompose will share its config with the app and the services, this means there will be a single config for the whole stack.

The services will get merged Config with just theier content over a CONFIG variable which contains a URL to an https endpoint to the operator. The service then might run a templating engine on it.

Example core config

I put a lot of features into these config files, there might be just a subset of these in the real tool.

Here is an example config which you might host at:

https://raw.githubusercontent.com/yourproject/octocompose-chart/refs/tags/v2.0.0/config/core.yaml

# Globals are applied to each service, individual services can overwrite them.
globals:
  client:
    preferredTransports: 
      - orbdrpc # orb uses it's own wire Format for results on top of DRPC to deliver responses for metadata.
      - grpc
  server:
    drpc:
      # Templating happens at the service level.
      listen: unix://{{env.XDG_RUNTIME_DIR}}/{{project.Name}}/{{project.ID}}/{{service.App.Name}}-drpc.sock
    grpc:
      listen: unix://{{env.XDG_RUNTIME_DIR}}/{{project.Name}}/{{project.ID}}/{{service.App.Name}}-grpc.sock
  kvstore:
    # kvstore/natsjs is fully compatible with these settings 
    # to go-micro/store/natsjs which is used in opencloud.
    plugin: natsjs
    servers:
      - nats://localhost:9233
    bucketPerTable: false
    jsonKeyValues: true
    compress: false
  registry:
    # registry/micro-kvstore is a opencloud/nats-js-kv compatible registry.
    plugin: micro-kvstore
    defaultTransport: grpc
    kvstore:
      plugin: natsjs
      bucketPerTable: false
      jsonKeyValues: true
      compress: false
      servers:
        - nats://localhost:9233

octoctl:
  operator: baremetal # One of `baremetal`, `docker`, `kubernetes` or you provide your own.
  project: yourproject # Path for the cache
  version: v2.0.0 # Version for the cache path

  # Prompts will be asked before the operator starts or before preflight checks.
  # Having prompts will disable all autostart features.
  prompts: 
    - name: "Enter the password for vault"
      type: password
      var: VAULT_PASSWORD

  secrets:
    # Secrets will be fetched per service from the given provider and supplied into the merged config
    # to the service, here we have HashiCorp Vault as provider.
    tool: vault-client
    depends:
      - service: vault
    external: false

operator:
  repos:
    core:
      url: https://raw.githubusercontent.com/yourproject/octocompose-chart/refs/tags/v2.0.0/repos/core.yaml
  services:
    nats:
      config:
        # This will disable the global config for this service.
        noGlobals: true
      priority: 100
      healthCheck:
        - tool: check-tcp # will check for an open port, it will only run in `baremetal` envs.
          port: {{service.nats.port}} # This is the 9233 defined below or 4222 in the users config.
          interval: 10s
          successTreshold: 1
          failureTreshold: 3
      preflightCheck:
        - tool: check-tcp-port # will check if a connection to that port is possible.
          port: {{service.nats.port}}
        - tool: operator-run # tool `operator-run` will run the service trough the operator with the given arguments.
          args: ["preflight"]
      hooks:
        preStart:
          - tool: operator-run
            args: ["migrate"] 
    idp:
      priority: 200
    auth-service:
      priority: 300
      depends:
        - service: idp
        - service: nats
    webdav: 
      priority: 1000
      healthCheck:
        - tool: check-grpc
          url: {{service.webdav.server.grpc.listen}}           
          endpoint: /health.v1alpha.Health/Healthz
          interval: 10s
          successTreshold: 1
          failureTreshold: 3
      preflightCheck:
        - tool: check-server-url # will check if the given url is valid (TCP Port or Unix socket)
          url: {{service.webdav.server.grpc.listen}}
        - tool: operator-run # tool `operator-run` will run the service trough the operator with the given arguments.
          args: ["preflight"]
      depends:
        - service: auth-service

# Service configurations:
service:
  nats:
    port: 9233

And here is an extensions for collabora

https://raw.githubusercontent.com/yourproject/octocompose-chart/refs/tags/v2.0.0/config/collabora.yaml

octoctl:
  repos:
    collabora:
      url: https://raw.githubusercontent.com/yourproject/octocompose-chart/refs/tags/v2.0.0/repos/collabora.yaml
  
  services:
    collabora:
      priority: 1500

The users config.yaml

Here is an example cli provided config.yaml:

project:
  name: yourproject
  # This will be generated by the octoctl if none is provided, it will be a shortUUID.
  id: 1234567890

include:
  # ?template=true means that the config will be templated by text/template with a yet to be defined set of variables.
  - url: https://raw.githubusercontent.com/yourproject/octocompose-chart/refs/tags/v2.0.0/config/core.yaml?template=true
    versions: github
  - url: https://raw.githubusercontent.com/yourproject/octocompose-chart/refs/tags/v2.0.0/config/collabora.yaml?template=true
    versions: github

# Globals are applied to each service.
globals:
  server:
    drpc:
      listen: tcp://0.0.0.0:8081
    grpc:
      listen: tcp://0.0.0.0:8080
  kvstore:
    servers:
      - nats://nats:4222
  registry:
    plugin: kubedns
    namespace: yourproject
    cluster_domain: cluster.local
  # This defines helper variables for the operator.
  operator:
    ports:
      drpc: 8081
      grpc: 8080

# The configuration to setup the operator, this wont get uploaded.
octoctl:
  # The kubernetes operator will run itself inside kubernetes and communicate via RPC with that "operator".
  # It will upload the merged config to a kubernetes secret, the operator then executes it.
  plugin: kubernetes 
  namespace: yourproject
  # Prefix for each resource item.
  prefix: instance1
  api: https://rancher.example.com/k8s/clusters/local
  token: <token>

operator:
  repos:
    mycustom:
      url: https://raw.githubusercontent.com/jochumdev/yourproject-plugins/refs/heads/main/repo.yaml
  
  services:
    nats:
      replicas: 3
    webdav:
      replicas: 2
    my-supi:
      priority: 2000
      depends:
        - service: auth-service
    badservice:
      # Its possible disable services
      enabled: false

        
  notifications:
    - notifier: smtp
      server: mail.example.com
      from: yourproject@example.com
      user: yourproject@example.com
      password: Abc123456
      to: yourproject-users@example.com

# Service configurations:
service:
  nats:
    port: 4222
    cluster: true

  my-supi:
    supibot:
      name: Alex
      number: 42

Example repo.yaml

This defines where to get binaries/sources/docker containers and howto run them.

# We allow includes in repos.
include:
    # This example might have some tools which yourproject v2.0.0 needs.
    # Full URL will be generated from the parent path: https://raw.githubusercontent.com/yourproject/orberator-chart/refs/tags/v2.0.0/repo/
    # This allows to use the same repo for Development and Production (file:// vs. https://)
  - url: ./tools/yourproject.yaml?template=true
  
    # This example will add the service abc.
  - url: ./services/abc.yaml?template=true

service:
  # Each service has it's own entry nats is just a template for many of them.
  nats:
    binary:
      - os: linux
        arch: amd64
        url: https://github.com/yourproject/yourproject/releases/download/v2.0.0/yourproject-nats-2.0.0-linux-amd64
        sha256URL: https://github.com/yourproject/yourproject/releases/download/v2.0.0/yourproject-nats-2.0.0-linux-amd64.sha256
        archiveBinaryPath: yourproject-nats
        args: ["server"]
      - os: linux
        arch: arm64
        url: https://github.com/yourproject/yourproject/releases/download/v2.0.0/yourproject-nats-2.0.0-linux-arm64
        sha256URL: https://github.com/yourproject/yourproject/releases/download/v2.0.0/yourproject-nats-2.0.0-linux-arm64.sha256
        archiveBinaryPath: yourproject-nats
        args: ["server"]
    oci:
      - arch: amd64
        registry: docker.io
        image: yourprojecters/yourproject-nats
        tag: v2.0.0
    source:
      url: https://github.com/yourproject/yourproject.git
      branch: v2.0.0
      buildCmds:
        - OS={{GOOS}} ARCH={{GOARCH}} make yourproject-nats
      binaryPath: dist/nats/yourproject-nats-{{GOOS}}-{{GOARCH}}

The operator aka engine

All operators will run a RPC Server which the cli and other tools can access.
The operators will provide a HTTP URL with basic auth for the service config and as well as a CONFIG env variable.

There will be 3 different operators, but it will beasy to create your own.

Authors

Community

Join our active community:

License of this document

CC-BY-SA 4.0