Ops platform / Concepts
The project file
.ops/project.ts describes what a repository deploys, the way nuxt.config.ts describes a Nuxt app.
.ops/project.ts sits in the repository and says what it deploys: its services, the
domains in front of them, the steps ops may run, and what differs per environment. Ops
reads it on every scan of the default branch and turns it into resources. It never holds
a secret value: it names secret groups and variables, and ops holds the values.
import { defineProject } from '@syncronet/ops-project'
export default defineProject({
services: {
api: { dockerfile: 'deploy/api.Dockerfile', port: 8080, env_group: 'api',
address: { url: 'APP_BASE_URL', origins: 'PUBLIC_ORIGIN' } },
web: { dockerfile: 'deploy/web.Dockerfile', port: 3000, env_group: 'web',
uses: { api: { url: { internal: 'NUXT_API_ORIGIN' } } } },
},
domains: {
site: { target: { service: 'web' }, api: { service: 'api' } },
},
steps: {
migrate: { service: 'api', command: ['/usr/local/bin/api', 'migrate'] },
},
hooks: { 'build.finished': ['migrate'] },
$production: {
services: { api: { replicas: 2 } },
domains: { site: { hostname: 'app.rungholt.dk' } },
},
$staging: {
domains: { site: { hostname: 'staging.rungholt.dk' } },
},
})
You can edit the file in the console too: Studio opens it, checks a change before it is saved, and saves it as a pull request.
Services
| key | what it sets |
|---|---|
dockerfile | the Dockerfile, relative to the repository root |
context | the build context, default . |
target | a named build stage |
args | build arguments |
port | the port the container listens on |
healthcheck | the path that answers when the service is ready, starting with / |
replicas | 1 to 20 |
limits | { cpu, memory_mb }, 0.1 to 8 cores and 64 to 32768 MB |
env_group | the secret group the service gets at start |
address | variables of the group that receive the service's public address |
uses | the services it calls, and the variables their addresses land in |
volumes | SQLite databases mounted into the container |
replicas, limits, env_group and address are the file's only where it sets them;
left out, you set them in the console.
address writes https://<hostname> of the domain routing to the service into url,
and the hostname with its aliases into origins, in every environment and every preview.
The service picks a changed value up with its next restart, which ops does for you.
uses names another declared service and where its address goes: public gets its
https:// address, internal its address on the environment's private network, which a
staging caller resolves to the staging service and nothing else.
Environments
The top level holds the defaults. A $<environment> block, such as $production or
$staging, changes them for that environment: objects merge key by key, anything else
replaces, and null leaves a service or a domain out. Only services and domains vary.
Steps and hooks
A step is a command ops may run, in a declared service (borrowing its current image and
secret group) or in an image pinned by digest, with an optional timeout_secs. A hook
runs steps after an event, once each, in order, in the environment the event happened in:
| event | fires |
|---|---|
push | on a push to a branch an environment follows |
check_suite.completed | when the commit's GitHub checks finish |
build.finished | when a build reaches its verdict |
deploy.finished | when a rollout reaches its verdict |
pull_request.opened | in the preview the pull request brought up |
A hook reacts after the fact and never holds back a rollout. The first step that fails stops the rest.
Checks
checks lists the GitHub check runs a build waits for, by the name GitHub shows. See
Deployments and previews.
Docs
docs names a folder of the repository that every production deploy and every tag's
publish run publishes, and docsReader says the project shows doc sets. See Publish docs.
When the file changes
A merge to the default branch updates the resources: a new service or step is created, the declared keys of an existing one are updated, and everything the file does not set stays as it is. A service the file stops declaring keeps running and is listed as no longer declared, for you to delete.