OmniArc docs Menu

Guides

Write arc.yaml

arc.yaml lives next to your compose file and says what compose cannot. This guide writes one for the shop, whose compose file is in the panel. Your own project goes the same way.

# Start from a draft

In the directory with your compose file:

omniarc sync

It reads your project through docker compose itself, prints a draft arc.yaml, and lists each guess it made. Nothing is written until you add --write. Run it again whenever your compose file changes: it adds entries for new services, drops the ones compose no longer defines, and never changes a decision you already made. It will not rewrite a file with comments in it, which would lose them: it prints the draft for you to merge by hand.

For the shop, the draft guesses three things, and one of them is cautious on purpose:

guess: db: assumed `contains_pii: true`, `branch: false`, `kind: database`: branches start it empty; add anonymize rules or set contains_pii: false for test data to branch its data
guess: web: assumed `contains_pii: false`: it keeps nothing (no named volume, no writable bind inside the project, no database or cache image)
guess: edge: web port 3000, the only published HTTP-looking port

# Name the arc

arc: shop

The name of the arc this file deploys to: lowercase letters, digits and hyphens, starting with a letter and ending with a letter or digit, at most 20 characters. A deploy to an arc of another name is refused, because that is almost always the wrong directory. See arc.

# Choose the edge

The edge is the one service that answers the arc's public address, and the container port it listens on. In the shop that is web on 3000:

edge: { service: web, port: 3000 }

Compose must publish that port at one fixed host port, as the shop does with ports: ["3000:3000"]. An arc with no web address at all says edge: none. The key is required either way, so that having no address is something you chose. See edge.

# Say what each service is

Every compose service needs an entry under services, by its compose name. Each one says whether it holds personal data, with contains_pii: true or false. The key has no default. The draft guesses it: a service that keeps data (a volume, a writable bind inside the project, a database or cache image) is never assumed to hold none, and one that keeps nothing gets false. Review every guess.

web is PostgREST, which keeps nothing of its own and serves what is in the database, so the draft's false stays, and its kind says what it is:

  web:
    kind: web-service
    contains_pii: false

db is Postgres, and its customers table holds email addresses. A branch is a copy that developers and CI can reach, so personal data in it must be rewritten. The draft plays safe with branch: false, which starts db empty in every branch. To branch its data instead, replace that line with anonymize, which rewrites it in the branch's copy only:

  db:
    kind: database
    contains_pii: true
    anonymize:
      engine: postgres
      database: shop
      user: shop
      rules:
        - { table: customers, column: email, transform: fake-email }

List every column that holds personal data. A rule can redact, hash, set "null", or write a made-up email, name or phone number. If a rule cannot be applied, the branch is not created, so a half-anonymized copy is never reachable. Only Postgres can be anonymized. A service with personal data in anything else needs branch: false, which starts it empty in every branch.

kind tunes the arc's storage: database gives it the small blocks a database writes best. See services for every kind and every key.

# Say what the arc needs

Optional, and for the arc as a whole, not one container:

resources: { cpu: "1", memory: 1Gi, disk: 5Gi }

See resources. Limits for a single container stay in compose.

# The whole file

Put together, the shop's arc.yaml:

arc: shop
edge: { service: web, port: 3000 }
resources: { cpu: "1", memory: 1Gi, disk: 5Gi }
services:
  web:
    kind: web-service
    contains_pii: false
  db:
    kind: database
    contains_pii: true
    anonymize:
      engine: postgres
      database: shop
      user: shop
      rules:
        - { table: customers, column: email, transform: fake-email }

# Check it

omniarc check

It runs the checks a deploy runs, on your machine, and uploads nothing. Each error names the file to fix and links to a page that explains it, from the list of errors. With docker compose installed it also checks arc.yaml against your compose services, and your compose file against what an arc supports.

For completion and checking as you type, put this line at the top of arc.yaml. Editors that use the YAML language server read it:

# yaml-language-server: $schema=https://docs.omniarc.eu/schema/arc.yaml.json

# Services the shop does not have

A cache whose data is not worth copying, or that holds personal data you do not want in a branch, starts empty in every branch:

  cache:
    kind: cache
    contains_pii: true
    branch: false

A service that only makes sense on your laptop, such as a mail catcher, is not run at all:

  mailhog:
    deploy: false

A database that should flush to disk before it is copied gets a quiesce command. Compose profiles and extra compose files are turned on with profiles and compose.

Next: Deploy.