Repository navigation
Expand file tree
/
Copy pathdevctl.yaml
More file actions
162 lines (150 loc) · 6.78 KB
/
Copy pathdevctl.yaml
File metadata and controls
162 lines (150 loc) · 6.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# A worked example of every feature a devctl.yaml has: dependencies the machine
# provides, dependencies devctl forwards, a dependency with several sources it
# switches between (one of them a peer of a sibling devctl), a machine-provided
# secret composed into an address, an id so siblings can peer back, services with
# several listeners, pinned ports, watched directories and one-shot tasks.
# `devctl -example` prints this file.
#
# It is also the manifest devctl's own tests run against, so it cannot rot. It
# describes an imaginary shop rather than any real repository, so the tests
# assert on something stable and the example stays readable to everyone.
# This devctl's name to its siblings. With it set, devctl publishes its
# allocated ports on a socket, so another repository's devctl can read them with
# a peer dependency (see `inventory` below, which peers the other way, to a
# devctl called warehouse). Without an id nothing is published.
id: shop
x-shared:
# A value two places need. YAML anchors keep it stated once.
api_key: &api_key dev-key-0000
# Every process also appends to .devlogs/<name>.log, rotated to <name>.log.1
# when it is already over the cap at start.
logs:
dir: .devlogs
max_size: 2MB
# Named subsets worth running on their own. What a profile lists are the roots;
# what those need comes with them, so `devctl storefront-only` brings the
# catalogue and the database up too without saying so.
profiles:
- name: storefront-only
description: The web front end and what it reads
include: [storefront]
- name: everything-but-mail
description: The shop without the mailer
include: [storefront-only, seed]
# A profile can also say how a dependency is wired, not just which things run.
# This runs the storefront with stock forwarded from staging rather than read
# from the warehouse devctl. m still switches at runtime; this only sets where
# it starts.
- name: storefront-staging
description: The web front end, stock forwarded from staging
include: [storefront]
modes:
inventory: staging
# Run-level config for this profile, over every service's own env. Belongs to
# the run, not to any one dependency.
env:
SHOP_ENV: staging
dependencies:
# Provided by the machine. Its address comes from the environment or .env,
# under the name in `env`, and is checked before anything starts.
- name: db
description: Postgres holding every service's data
env: DATABASE_URL
example: postgres://localhost:5432/shop
kind: tcp
# Forwarded by devctl on demand. The local port is allocated like a service's,
# and the command states it once through a reference to itself.
- name: payments
description: The payments gateway, forwarded from staging
kind: tcp
port: 7100
forward: {cmd: "kubectl -n shop port-forward svc/payments {{ payments.port.number }}:8080"}
# Several sources, switched live with m. "local" reads the stock service's
# port from a sibling devctl, the one that runs with id: warehouse in the
# warehouse repository; "staging" opens a port-forward instead. A consumer
# refers to it as {{ inventory.address }}, which resolves to a dialable address
# whichever mode is live. A dependency you can switch is optional: nothing
# waits for a mode you can leave, and an absent sibling only shows as waiting.
# (A peer can also be a dependency's only source, written inline like a
# forward: peer: {id: ..., service: ..., port: ...}.)
- name: inventory
description: Stock levels, local from the warehouse devctl or forwarded from staging
default: local
modes:
# provides is config that rides the mode: a service depending on inventory
# is handed STOCK_SOURCE, and switching the mode swaps it with the address.
- name: local
peer: {id: warehouse, service: stock, port: grpc}
provides:
STOCK_SOURCE: local
- name: staging
port: 7110
forward: {cmd: "kubectl -n shop port-forward svc/stock {{ inventory.port.number }}:8080"}
provides:
STOCK_SOURCE: staging
# A secret the machine provides, not an address: the token the payments
# gateway wants. devctl reads it from .env like any machine-provided source and
# exposes it as {{ payments-key.address }}, but never dials it and shows it
# masked in the panel. The manifest composes it into the value the service
# reads, so the secret itself is never written down here.
- name: payments-key
description: API token for the payments gateway, from .env
env: PAYMENTS_KEY
example: sk_test_0000
kind: secret
services:
# Several listeners, one of them pinned. Anything reached by number from
# outside this repository has to be pinned; the rest may move when something
# else on the machine holds the default.
- name: catalogue
description: Product catalogue, the API everything else reads
depends_on: [db, inventory, payments-key]
ports:
- {name: http, port: 7200, kind: http, fixed: true, description: public API, its URL is written down elsewhere}
- {name: grpc, port: 7201, kind: grpc, description: internal API, resolved through the port table}
- {name: metrics, port: 7202, kind: http, description: Prometheus metrics}
autostart: true
dir: services/catalogue
watch: [services/catalogue, libs]
cmd: go run ./cmd/catalogue
listen: {http: HTTP_ADDR, grpc: GRPC_ADDR}
env:
DATABASE_URL: "{{ db.address }}"
PAYMENTS_ADDR: "{{ payments.port }}"
# The forwarded port and the secret token composed into one value: the
# secret never appears in the manifest, only its reference.
PAYMENTS_URL: "http://{{ payments-key.address }}@{{ payments.port }}"
INVENTORY_ADDR: "{{ inventory.address }}"
API_KEY: *api_key
# One listener, and a program that wants a bare port number rather than an
# address to bind. Pinned because a browser is told to go there.
- name: storefront
description: The web front end
depends_on: [catalogue]
ports:
- {name: web, port: 7300, kind: http, fixed: true, description: http://localhost:7300}
autostart: true
dir: services/storefront
cmd: npm run dev
listen: {web: {env: PORT, format: number}}
env:
CATALOGUE_URL: "{{ catalogue.http.url }}"
CATALOGUE_GRPC: "{{ catalogue.grpc }}"
# No ports at all: a worker is a perfectly good service.
- name: mailer
description: Sends the emails the catalogue queues
depends_on: [db]
dir: services/mailer
cmd: go run ./cmd/mailer
env:
DATABASE_URL: "{{ db.address }}"
tasks:
# Run on demand from the panel, not kept running.
- name: seed
description: Wipe the database and seed a shop to click around in
depends_on: [db]
dir: services/catalogue
cmd: go run ./cmd/seed
env:
DATABASE_URL: "{{ db.address }}"
API_KEY: *api_key