Developer Documentation

Deploy File Specification

Envirobly deploy file .envirobly/deploy.yml is formatted using YAML.

It allows you to build, configure and deploy one or multiple services that work together within a private subnet and expose some or all of them to the public internet.

It’s loosely based on the Docker Compose file format.

Example

# Top level "services" key is always required
services:
  # Alphanumerical name you give to each of your services.
  # It identifies them when interacting with your services
  # using the CLI tool.
  web:
    # All services are private by default, unless you make them public.
    public: true
    # Only route requests to this service if this 
    # HTTP path responds successfully.
    health_check_path: /up
    # Command to run before the service is started, during each deploy. 
    # Guaranteed to run only once, even if you have multiple instances.
    release_command: bin/rails db:prepare
    # Minimum number of instances that run at all times.
    min_instances: 1
    # Auto scaling configuration.
    # When CPU usage is over 60% for 1 minute, 
    # continue scaling up to max_instances.
    max_instances: 2
    # Environment variables that will be supplied to the container
    env:
      RAILS_ENV: production
      # Define a secret and pull it from a local file
      RAILS_MASTER_KEY: !secret <%= File.read("config/master.key") %>
      DATABASE_URL: $POSTGRES_URL # Pulled from "postgres" service
    # Before starting this service, first start the dependencies
    depends_on:
      - postgres
      - valkey
    domains:
      - example.com
      - www.example.com

  # Private worker, build using a custom Dockerfile and build context
  worker:
    # Specify non-default Dockerfile
    dockerfile: custom/Dockerfile.sidekiq
    # Specify custom build context (instead of project's root directory)
    build_context: some/other/directory
    # Override image run command
    command: bundle exec sidekiq
    # Specify bigger compute instance
    instance_type: t4g.small

  # Postgres database
  # Accessible from the outside over TLS with authentication due to `public: true`
  postgres:
    type: postgres
    public: true
    # Specify persistent volume size
    volume_size: 48 # GB

  # Valkey database
  # Available on private network only, because there is no `public: true`
  valkey:
    type: valkey

Service Attributes

The services top level key is required. It’s a mapping of service names with their configuration attributes.

public

By default, service is always private, reachable only by other services in the environ. To make it public:

services:
  blog:
    public: true

type

Type is used to create managed database services. You can choose between two types:

services:
  db1:
    type: postgres

  db2:
    type: valkey

Services without type attribute are considered to be a container, either build or if image attribute is present, pulled from a public repository.

image

To deploy a pre-build image from a public repository, like Docker Hub:

services:
  # Pull from Docker Hub
  whoami:
    image: traefik/whoami

  # Pull from AWS ECR
  nginx:
    image: public.ecr.aws/nginx/nginx:stable

dockerfile

If no image or type attributes are present, Envirobly considers this service buildable and by default expects a Dockerfile to be present in the root of your project directory.

You can specify a custom file to build from:

services:
  blog:
    dockerfile: my/custom/path

build_context

Services that are build from a dockerfile, can override the default . build context:

services:
  blog:
    build_context: my/custom/directory

command

Specify the startup command to launch the container with. If not set, image starts with it’s default command.

services:
  blog:
    command: bin/rails server --some-argument=hello

release_command

Specify a command to run during each deployment, exactly once, before the main command.

Useful for things like database migrations or other idempotent bootstrapping tasks.

It is guaranteed to run only on one instance, once during the deployment. If it fails, the deployment will roll back.

services:
  blog:
    release_command: bin/rails db:prepare

env

You can supply environment variables for your container as a mapping of name and value.

The value is interpolated and you can insert variables that other services export as well as local secrets.

services:
  blog:
    env:
      PLAIN_VALUE: abcd
      SENTENCE: "Hello world!"
      IMPORTED_FROM_ANOTHER_SERVICE: $WHOAMI_PUBLIC_HOST
      COMPLEX_INTERPOLATION: "https://${WHOAMI_HOST}"
      # Passing in a local env var as a secret using embedded Ruby
      SOME_PASSWORD: !secret <%= ENV["SOME_PASSWORD"] %>

  # Service that exports $WHOAMI_HOST and $WHOAMI_PUBLIC_HOST
  whoami:
    public: true

health_check_path

To support zero downtime deployments, you can specify a health check path. The requests are routed to a newly started service only once the health check passes.

If your service has multiple instances, if an instance fails a health check, requests won’t be send to it, until it passes the health check again.

services:
  blog:
    health_check_path: /up

volume_mount_path

Attaches a persistent data volume to the service and mounts it into the container within the given path.

services:
  blog:
    volume_mount_path: /rails/storage

Default volume size is 24 GB.

volume_size

Controls the size of persistent data volume attached with volume_mount_path.

The size must be a multiple of 4, as the volume consists of 4 EBS volumes in RAID 0 configuration, for optimal performance.

When a persistent volume is present, the service can only have a single instance.

Incrementing the volume size is a zero-downtime operation. After a volume size change, there is an AWS enforced cool-down period of 6 hours, during which you can’t change the volume size.

You can’t decrement the volume size. Removing this attribute from the service configuration, removes the volume, unless the service is of postgres or valkey type, which always has a persistent volume attached.

Deployments that change the instance type or container configuration, incur several seconds of downtime, while the volume is detached and then attached to a new instance.

services:
  blog:
    volume_mount_path: /rails/storage
    volume_size: 100

instance_type

Controls the type of the compute instance. This is how you can control the amount of vCPUs and memory your service has access to.

It defaults to t4g.nano, which is a 2 vCPU instance with 512 MB of memory. Note that ~140 MB of memory is taken by the underlying operating system.

services:
  blog:
    instance_type: t4g.xlarge

To list available instance types and their attributes use the command line:

# List instance types in the `.envirobly/defaults/region` region or 
# asks to set the default region
envirobly instance-types

# List instance types in the given region
envirobly instance-types us-east-1

min_instances

Controls the number of instances that are always running. Defaults to one.

Can only be used if the service doesn’t have a persistent data volume attached.

services:
  blog:
    min_instances: 2

max_instances

Set it to a number higher than min_instances to enable auto-scaling. Once the combined CPU usage is over 60% for over 1 minute, the system will spin up new service instances, until max_instances is reached.

If the combined CPU usage is under 30% for at least 2 minutes, the system will start scaling down, until max_instances is reached.

services:
  blog:
    min_instances: 1
    max_instances: 3

depends_on

If your service needs other services to run, before it starts, you can list the names of the services it depends on. The service will only be started once the health checks of the dependent services succeed.

services:
  blog:
    depends_on:
      - db1
      - db2

  db1:
    type: postgres

  db2:
    type: valkey

domains

You can route custom domains to your service.

You can also put your service behind a reverse proxy, like Cloudflare orange cloud, in which case set the additional proxy argument, for that domain, to true. This means an external service will be handling the HTTPS certificates and DNS.

services:
  blog:
    domains:
      - example.com
      - www.example.com
      # Wildcards are supported, on all levels.
      - "*.example.com" 
      - "*.sub.example.com"
      # When hiding your deployment behind reverse proxy, 
      # like Cloudflare orange cloud.
      - name: protected.example.com
        proxied: true

Once deployed, visit your Envirobly dashboard, navigate to the service and click “Domains” within the service sub-menu. Here you’ll see instructions on how to set up your DNS. Once set up, click the “Validate” button, to complete the process.